changeset 70:46a6e0e6ccd4

Merge with d-fied sources of 3.4M7
author Frank Benoit <benoit@tionex.de>
date Thu, 22 May 2008 01:36:46 +0200
parents 07b9d96fd764
children 4878bef4a38e
files dwtx/core/commands/AbstractHandler.d dwtx/core/commands/Command.d dwtx/core/commands/CommandManager.d dwtx/core/commands/IHandler.d dwtx/core/commands/IHandler2.d dwtx/core/commands/ParameterizedCommand.d dwtx/core/commands/common/CommandException.d dwtx/core/commands/common/IIdentifiable.d dwtx/core/commands/common/NamedHandleObjectComparator.d dwtx/core/commands/operations/AbstractOperation.d dwtx/core/commands/operations/IUndoableOperation.d dwtx/core/internal/runtime/LocalizationUtils.d dwtx/core/internal/runtime/PrintStackUtil.d dwtx/core/internal/runtime/messages.properties dwtx/core/runtime/Assert.d dwtx/core/runtime/AssertionFailedException.d dwtx/core/runtime/IAdapterManager.d dwtx/core/runtime/ILogListener.d dwtx/core/runtime/IPath.d dwtx/core/runtime/IProgressMonitorWithBlocking.d dwtx/core/runtime/ISafeRunnable.d dwtx/core/runtime/OperationCanceledException.d dwtx/core/runtime/Path.d dwtx/core/runtime/QualifiedName.d dwtx/core/runtime/SubMonitor.d dwtx/jface/action/Action.d dwtx/jface/action/ActionContributionItem.d dwtx/jface/action/ContributionItem.d dwtx/jface/action/ContributionManager.d dwtx/jface/action/CoolBarManager.d dwtx/jface/action/ExternalActionManager.d dwtx/jface/action/ExternalActionManager.properties dwtx/jface/action/IAction.d dwtx/jface/action/IContributionManager.d dwtx/jface/action/IContributionManagerOverrides.d dwtx/jface/action/MenuManager.d dwtx/jface/action/StatusLine.d dwtx/jface/action/StatusLineContributionItem.d dwtx/jface/action/SubMenuManager.d dwtx/jface/action/ToolBarManager.d dwtx/jface/action/images/stop.gif dwtx/jface/bindings/Binding.d dwtx/jface/bindings/BindingManager.d dwtx/jface/bindings/keys/KeySequenceText.d dwtx/jface/commands/RadioState.d dwtx/jface/commands/ToggleState.d dwtx/jface/dialogs/Dialog.d dwtx/jface/dialogs/ErrorDialog.d dwtx/jface/dialogs/IconAndMessageDialog.d dwtx/jface/dialogs/InputDialog.d dwtx/jface/dialogs/MessageDialogWithToggle.d dwtx/jface/dialogs/PopupDialog.d dwtx/jface/dialogs/ProgressIndicator.d dwtx/jface/dialogs/ProgressMonitorDialog.d dwtx/jface/dialogs/TrayDialog.d dwtx/jface/fieldassist/ComboContentAdapter.d dwtx/jface/fieldassist/ContentProposalAdapter.d dwtx/jface/fieldassist/ControlDecoration.d dwtx/jface/fieldassist/DecoratedField.d dwtx/jface/fieldassist/IControlContentAdapter2.d dwtx/jface/fieldassist/SimpleContentProposalProvider.d dwtx/jface/fieldassist/TextContentAdapter.d dwtx/jface/internal/ConfigureColumnsDialog.d dwtx/jface/layout/AbstractColumnLayout.d dwtx/jface/operation/AccumulatingProgressMonitor.d dwtx/jface/operation/ModalContext.d dwtx/jface/preference/ComboFieldEditor.d dwtx/jface/preference/FieldEditorPreferencePage.d dwtx/jface/preference/FileFieldEditor.d dwtx/jface/preference/IntegerFieldEditor.d dwtx/jface/preference/JFacePreferences.d dwtx/jface/preference/PreferenceDialog.d dwtx/jface/preference/PreferenceManager.d dwtx/jface/preference/PreferencePage.d dwtx/jface/preference/StringFieldEditor.d dwtx/jface/resource/ColorRegistry.d dwtx/jface/resource/FileImageDescriptor.d dwtx/jface/resource/ImageRegistry.d dwtx/jface/resource/JFaceResources.d dwtx/jface/resource/StringConverter.d dwtx/jface/resource/URLImageDescriptor.d dwtx/jface/util/Geometry.d dwtx/jface/util/Policy.d dwtx/jface/util/SafeRunnable.d dwtx/jface/util/SafeRunnableDialog.d dwtx/jface/util/StatusHandler.d dwtx/jface/util/Util.d dwtx/jface/viewers/AbstractComboBoxCellEditor.d dwtx/jface/viewers/AbstractListViewer.d dwtx/jface/viewers/AbstractTableViewer.d dwtx/jface/viewers/AbstractTreeViewer.d dwtx/jface/viewers/CellEditor.d dwtx/jface/viewers/CellLabelProvider.d dwtx/jface/viewers/CheckboxCellEditor.d dwtx/jface/viewers/CheckboxTreeViewer.d dwtx/jface/viewers/ColumnViewer.d dwtx/jface/viewers/ColumnViewerEditor.d dwtx/jface/viewers/ColumnViewerEditorActivationEvent.d dwtx/jface/viewers/ColumnViewerEditorDeactivationEvent.d dwtx/jface/viewers/ColumnViewerToolTipSupport.d dwtx/jface/viewers/ComboBoxCellEditor.d dwtx/jface/viewers/ComboBoxViewerCellEditor.d dwtx/jface/viewers/ComboViewer.d dwtx/jface/viewers/ContentViewer.d dwtx/jface/viewers/DecoratingLabelProvider.d dwtx/jface/viewers/DecoratingStyledCellLabelProvider.d dwtx/jface/viewers/DecorationContext.d dwtx/jface/viewers/DecorationOverlayIcon.d dwtx/jface/viewers/DelegatingStyledCellLabelProvider.d dwtx/jface/viewers/EditingSupport.d dwtx/jface/viewers/FocusCellHighlighter.d dwtx/jface/viewers/FocusCellOwnerDrawHighlighter.d dwtx/jface/viewers/IDecoration.d dwtx/jface/viewers/IStructuredContentProvider.d dwtx/jface/viewers/IStructuredSelection.d dwtx/jface/viewers/ITreeSelection.d dwtx/jface/viewers/NamedHandleObjectLabelProvider.d dwtx/jface/viewers/SWTFocusCellManager.d dwtx/jface/viewers/StructuredSelection.d dwtx/jface/viewers/StructuredViewer.d dwtx/jface/viewers/StyledCellLabelProvider.d dwtx/jface/viewers/StyledString.d dwtx/jface/viewers/TableLayout.d dwtx/jface/viewers/TableViewer.d dwtx/jface/viewers/TableViewerEditor.d dwtx/jface/viewers/TableViewerFocusCellManager.d dwtx/jface/viewers/TableViewerRow.d dwtx/jface/viewers/TextCellEditor.d dwtx/jface/viewers/TreeNode.d dwtx/jface/viewers/TreeNodeContentProvider.d dwtx/jface/viewers/TreeViewer.d dwtx/jface/viewers/TreeViewerEditor.d dwtx/jface/viewers/TreeViewerFocusCellManager.d dwtx/jface/viewers/TreeViewerRow.d dwtx/jface/viewers/ViewerCell.d dwtx/jface/viewers/ViewerColumn.d dwtx/jface/viewers/ViewerDropAdapter.d dwtx/jface/viewers/ViewerRow.d dwtx/jface/viewers/deferred/DeferredContentProvider.d dwtx/jface/window/ToolTip.d dwtx/jface/window/Window.d dwtx/jface/wizard/ProgressMonitorPart.d dwtx/jface/wizard/WizardDialog.d
diffstat 143 files changed, 8340 insertions(+), 2245 deletions(-) [+]
line wrap: on
line diff
--- 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 <code>true</code>
+     * @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 <code>null</code>
+     * @since 3.4
+     * @see #setBaseEnabled(bool)
+     */
+    public void setEnabled(Object evaluationContext) {
     }
 
     /**
--- 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
      *         <code>null</code> 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 <code>null</code>
+     *            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) {
--- 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.
+     * <p>
+     * See also ParameterizedCommand.escape(String)
+     * </p>
      *
      * @param escapedText
      *            a <code>String</code> that may contain escaped special
@@ -220,7 +223,6 @@
      * @throws SerializationException
      *             if <code>escapedText</code> 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
      *            <code>null</code>.
      * @return an array of parameterizations; may be <code>null</code>.
-     * @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 <code>notEnabled</code> event for
+     * <code>executionListeners</code>.
+     * <p>
+     * <b>Note:</b> This supports bridging actions to the command framework,
+     * and should not be used outside the framework.
+     * </p>
+     * 
+     * @param commandId
+     *            The command id of the command about to execute, never
+     *            <code>null</code>.
+     * @param exception
+     *            The exception, never <code>null</code>.
+     * @since 3.4
+     */
+    public void fireNotEnabled(String commandId, NotEnabledException exception) {
+        if (executionListener !is null) {
+            executionListener.notEnabled(commandId, exception);
+        }
+    }
+    
+    /**
+     * Fires the <code>notDefined</code> event for
+     * <code>executionListeners</code>.
+     * <p>
+     * <b>Note:</b> This supports bridging actions to the command framework,
+     * and should not be used outside the framework.
+     * </p>
+     * 
+     * @param commandId
+     *            The command id of the command about to execute, never
+     *            <code>null</code>.
+     * @param exception
+     *            The exception, never <code>null</code>.
+     * @since 3.4
+     */
+    public void fireNotDefined(String commandId, NotDefinedException exception) {
+        if (executionListener !is null) {
+            executionListener.notDefined(commandId, exception);
+        }
+    }
+    
+    /**
+     * Fires the <code>preExecute</code> event for
+     * <code>executionListeners</code>.
+     * <p>
+     * <b>Note:</b> This supports bridging actions to the command framework,
+     * and should not be used outside the framework.
+     * </p>
+     * 
+     * @param commandId
+     *            The command id of the command about to execute, never
+     *            <code>null</code>.
+     * @param event
+     *            The event that triggered the command, may be <code>null</code>.
+     * @since 3.4
+     */
+    public void firePreExecute(String commandId, ExecutionEvent event) {
+        if (executionListener !is null) {
+            executionListener.preExecute(commandId, event);
+        }
+    }
+    
+    /**
+     * Fires the <code>postExecuteSuccess</code> event for
+     * <code>executionListeners</code>.
+     * <p>
+     * <b>Note:</b> This supports bridging actions to the command framework,
+     * and should not be used outside the framework.
+     * </p>
+     * 
+     * @param commandId
+     *            The command id of the command executed, never
+     *            <code>null</code>.
+     * @param returnValue
+     *            The value returned from the command, may be <code>null</code>.
+     * @since 3.4
+     */
+    public void firePostExecuteSuccess(String commandId, Object returnValue) {
+        if (executionListener !is null) {
+            executionListener.postExecuteSuccess(commandId, returnValue);
+        }
+    }
+    
+    /**
+     * Fires the <code>postExecuteFailure</code> event for
+     * <code>executionListeners</code>.
+     * <p>
+     * <b>Note:</b> This supports bridging actions to the command framework,
+     * and should not be used outside the framework.
+     * </p>
+     * 
+     * @param commandId
+     *            The command id of the command executed, never
+     *            <code>null</code>.
+     * @param exception
+     *            The exception, never <code>null</code>.
+     * @since 3.4
+     */
+    public void firePostExecuteFailure(String commandId, 
+            ExecutionException exception) {
+        if (executionListener !is null) {
+            executionListener.postExecuteFailure(commandId, exception);
+        }
+    }
 }
--- 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 <code>true</code> if the command is enabled; <code>false</code>
      *         otherwise.
+     * @see IHandler2#setEnabled(Object)
      */
     public bool isEnabled();
 
--- /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 <benoit@tionex.de>
+ ******************************************************************************/
+
+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 <code>null</code>
+     *            which indicates that the handler can query whatever model that
+     *            is necessary. This context must not be cached.
+     */
+    public void setEnabled(Object evaluationContext);
+}
--- 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -121,7 +122,6 @@
      *            serialization.
      * @return a <code>String</code> representing <code>rawText</code> 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 <code>null</code>.
+     * @param parameters
+     *            A map of String parameter ids to objects. May be
+     *            <code>null</code>.
+     * @return the parameterized command, or <code>null</code> 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
      * <code>null</code>.
      */
@@ -346,10 +409,7 @@
      *            <code>null</code>.
      * @param parameterizations
      *            An array of parameterizations binding parameters to values for
-     *            the command. This value may be <code>null</code>. 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 <code>null</code>.
      */
     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() {
--- 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 @@
  * </p>
  *
  * @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 <code>null</code>.
      */
--- 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 <benoit@tionex.de>
 ******************************************************************************/

module dwtx.core.commands.common.IIdentifiable;
import dwt.dwthelper.utils;
/**
 * <p>
 * An object that is unique identifiable based on the combination of its class
 * and its identifier.
 * </p>
 *
 * @see HandleObject
 * @since 3.2
 */
public interface IIdentifiable {

    /**
     * Returns the identifier for this object.
     *
     * @return The identifier; never <code>null</code>.
     */
   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 <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.core.commands.common.IIdentifiable;
+import dwt.dwthelper.utils;
+/**
+ * <p>
+ * An object that is unique identifiable based on the combination of its class
+ * and its identifier.
+ * </p>
+ *
+ * @see HandleObject
+ * @since 3.2
+ */
+public interface IIdentifiable {
+
+    /**
+     * Returns the identifier for this object.
+     *
+     * @return The identifier; never <code>null</code>.
+     */
+    String getId();
+}
--- 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 <benoit@tionex.de>
 ******************************************************************************/

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 <code>NamedHandleObject</code> 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 <code>null</code>.
     * @param right
     *            The second object to compare; may be <code>null</code>.
     * @return <code>-1</code> if <code>left</code> is <code>null</code>
     *         and <code>right</code> is not <code>null</code>;
     *         <code>0</code> if they are both <code>null</code>;
     *         <code>1</code> if <code>left</code> is not <code>null</code>
     *         and <code>right</code> is <code>null</code>. Otherwise, the
     *         result of <code>left.compareTo(right)</code>.
     */
    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 <benoit@tionex.de>
+ *******************************************************************************/
+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 <code>NamedHandleObject</code> 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 <code>null</code>.
+     * @param right
+     *            The second object to compare; may be <code>null</code>.
+     * @return <code>-1</code> if <code>left</code> is <code>null</code>
+     *         and <code>right</code> is not <code>null</code>;
+     *         <code>0</code> if they are both <code>null</code>;
+     *         <code>1</code> if <code>left</code> is not <code>null</code>
+     *         and <code>right</code> is <code>null</code>. Otherwise, the
+     *         result of <code>left.compareTo(right)</code>.
+     */
+    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);
+    }
+}
--- 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
+     *            <code>null</code>.
      */
     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
+     *            <code>null</code>.
      */
     public void setLabel(String name) {
         label = name;
--- 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 <code>null</code>.
      */
     String getLabel();
 
--- 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?
--- /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 <benoit@tionex.de>
+ *******************************************************************************/
+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);
+        }
+    }
+
+}
--- /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}.
--- 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.
  * </p>
  * @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. */
--- 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 @@
  * </p>
  * @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 {
 
--- 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 @@
  * </p>
  * @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 {
 
--- 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.
  * <p>
@@ -23,8 +22,6 @@
  * </p><p>
  * Clients may implement this interface.
  * </p>
- * @see ILog#addLogListener(ILogListener)
- * @see Platform#addLogListener(ILogListener)
  */
 public interface ILogListener : EventListener {
     /**
--- 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.
  * </p>
  * @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 <code>true</code> if the given string is a valid path,
--- 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 <code>null</code> if this
      * information is not available.
      * @see #clearBlocked()
-     * @see dwtx.core.runtime.jobs.IJobStatus
      */
     public void setBlocked(IStatus reason);
 
--- 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 @@
  * </p><p>
  * Clients may implement this interface.
  * </p>
- * @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 <code>run()</code>)
-     * @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 <code>handleException</code>
-     * @see Platform#run(ISafeRunnable)
+     * @see SafeRunner#run(ISafeRunnable)
      */
     public void run();
 }
--- 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.
  * </p>
+ * @noextend This class is not intended to be subclassed by clients.
  */
 public final class OperationCanceledException : RuntimeException {
     /**
--- 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.
  * </p>
  * @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 (<code>"/"</code>). */
     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();
--- 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 @@
  * </p><p>
  * This class is not intended to be subclassed by clients.
  * </p>
+ * @noextend This class is not intended to be subclassed by clients.
  */
 public final class QualifiedName {
 
--- 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -204,14 +205,14 @@
  *
  * <pre>
  *      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);
--- 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
      * <code>null</code> if neither have been set.
      * <p>
      * The value of this field affects the value of <code>getStyle()</code>.
@@ -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);
         }
     }
 
--- 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.
+     * <p>
+     * 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.
+     * </p>
+     * 
+     * @return the widget, or <code>null</code> depending on the lifecycle.
+     * @since 3.4
+     */
+    public Widget getWidget() {
+        return widget;
+    }
 }
--- 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;
+    }
 }
--- 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;
                 }
 
--- 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();
--- 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 <code>ICallback</code> mechanism that
      * simply takes a <code>BindingManager</code> and a
      * <code>CommandManager</code>.
+     * <p>
+     * <b>Note:</b> this class is not intended to be subclassed by clients.
+     * </p>
      *
      * @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 (<code>String</code>)
-         * to listeners (<code>IPropertyChangeListener</code>).
+         * to listeners (<code>IPropertyChangeListener</code> or
+         * <code>ListenerList</code> of <code>IPropertyChangeListener</code>).
          */
         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 <code>CommandCallback</code> 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 <code>CommandCallback</code> with the
+         * workbench it should be using.
+         * 
+         * @param bindingManager
+         *            The binding manager which will provide the callback; must
+         *            not be <code>null</code>.
+         * @param commandManager
+         *            The command manager which will provide the callback; must
+         *            not be <code>null</code>.
+         * @param activeChecker
+         *            The callback mechanism for checking whether a command is
+         *            active; must not be <code>null</code>.
+         * @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);
+    }
+    
+    /**
+     * <p>
+     * A callback for executing execution events. Allows
+     * <code>ActionContributionItems</code> to fire useful events.
+     * </p>
+     * <p>
+     * Clients must not implement this interface and must not extend.
+     * </p>
+     * 
+     * @since 3.4
+     * 
+     */
+    public static interface IExecuteCallback {
+        
+        /**
+         * Fires a <code>NotEnabledException</code> because the action was not
+         * enabled.
+         * 
+         * @param action
+         *          The action contribution that caused the exception,
+         *          never <code>null</code>.
+         * @param exception
+         *          The <code>NotEnabledException</code>, never <code>null</code>.
+         */
+        public void notEnabled(IAction action, NotEnabledException exception);
+
+        /**
+         * Fires a <code>NotDefinedException</code> because the action was not
+         * defined.
+         * 
+         * @param action
+         *          The action contribution that caused the exception,
+         *          never <code>null</code>.
+         * @param exception
+         *          The <code>NotDefinedException</code>, never <code>null</code>.
+         */
+        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 <code>null</code>.
+         * @param e
+         *            The DWT Event, may be <code>null</code>.
+         * 
+         */
+        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 <code>null</code>.
+         * @param returnValue
+         *            The command's result, may be <code>null</code>.
+         * 
+         */
+        public void postExecuteSuccess(IAction action,
+                Object returnValue);
+        
+        /**
+         * Creates an <code>ExecutionException</code> when the action returned
+         * a failure.
+         * 
+         * @param action
+         *          The action contribution that caused the exception,
+         *          never <code>null</code>.
+         * @param exception
+         *          The <code>ExecutionException</code>, never <code>null</code>.
+         */
+        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.
          * </p>
          * <p>
-         * 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 <code>identifier</code>.
          * </p>
          *
          * @param identifier
@@ -505,6 +727,7 @@
          */
         public void removePropertyChangeListener(String identifier,
                 IPropertyChangeListener listener);
+
     }
 
     /**
--- /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
--- 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 <code>"result"</code>). The values are
-     * <code>bool.TRUE</code> if running the action succeeded and
-     * <code>bool.FALSE</code> if running the action failed or did not
+     * <code>Boolean.TRUE</code> if running the action succeeded and 
+     * <code>Boolean.FALSE</code> if running the action failed or did not
      * complete.
      * <p>
      * Not all actions report whether they succeed or fail. This property
--- 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 <code>add(new ActionContributionItem(action))</code>.
      *
-     * @param action the action
+     * @param action the action, this cannot be <code>null</code>
      */
     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 <code>null</code>
      */
     public void add(IContributionItem item);
 
--- 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 <ul>
-     *              <li><code>bool.TRUE</code> if the given contribution item should be enabled</li>
-     *              <li><code>bool.FALSE</code> if the item should be disabled</li>
+     *              <li><code>Boolean.TRUE</code> if the given contribution item should be enabled</li>
+     *              <li><code>Boolean.FALSE</code> if the item should be disabled</li>
      *              <li><code>null</code> if the item may determine its own enablement</li>
      *          </ul>
      * @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
--- 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 <remy.suen@gmail.com> - Bug 12116 [Contributions] widgets: MenuManager.setImageDescriptor() method needed
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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 <code>null</code>.
      * 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 <code>null</code> if none
      */
     public this(String text) {
-        this(text, null);
+        this(text, null, null);
     }
 
     /**
@@ -132,8 +154,22 @@
      * @param id the menu id, or <code>null</code> 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 <code>null</code> if none
+     * @param image the image for the menu, or <code>null</code> if none
+     * @param id the menu id, or <code>null</code> 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 <code>null</code> 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 <code>true</code> if the control is created
      *  and not disposed, <code>false</code> 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 <code>IContributionItem</code>'s fill method with the
+     * implementation's widget. The default is to use the <code>Menu</code>
+     * widget.<br>
+     * <code>fill(Menu menu, int index)</code>
+     * 
+     * @param ci
+     *            An <code>IContributionItem</code> whose <code>fill()</code>
+     *            method should be called.
+     * @param index
+     *            The position the <code>fill()</code> 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)
--- 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.
  * <p>
- * 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.
  * </p>
  * <p>
- * 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.
  * </p>
  */
 /* 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 <code>true</true> if the ProgressIndication provides UI for canceling
+     * Returns
+     * <code>true</true> if the ProgressIndication provides UI for canceling
      * a long running operation.
      * @return <code>true</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 <code>true</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
+     *            <code>true</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 <code>null</code> for no error message
+     * @param message
+     *            the error message, or <code>null</code> 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 <code>null</code> for no image
-     * @param message the error message, or <code>null</code> for no error message
+     * @param image
+     *            the image to use, or <code>null</code> for no image
+     * @param message
+     *            the error message, or <code>null</code> 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 <code>null</code> for no error message
+     * @param message
+     *            the error message, or <code>null</code> 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 <code>null</code> for no image
-     * @param message the message, or <code>null</code> for no message
+     * @param image
+     *            the image to use, or <code>null</code> for no image
+     * @param message
+     *            the message, or <code>null</code> 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) {
--- /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 <benoit@tionex.de>
+ *******************************************************************************/
+
+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.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * 
+ * @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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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; <code>null</code> 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 <code>null</code>
+     */
+    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$
+    }
+}
--- 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 <code>null</code>.
-     */
-    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)
      */
--- 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.
      * <p>
      * 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);
             }
 
Binary file dwtx/jface/action/images/stop.gif has changed
--- 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());
     }
 
     /**
--- 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 @@
      *         <code>null</code> 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;
     }
-
     /**
      * <p>
      * Returns the set of all bindings managed by this class.
--- 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 <code>null</code>, 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 <code>insertStrokeAt</code> 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();
--- 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 @@
 /**
  * <p>
  * 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}.
  * </p>
  * <p>
  * 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 <code>bool</code>.
+     *            The new value; should be a <code>Boolean</code>.
      */
     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);
         }
 
--- 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 @@
 
 /**
  * <p>
- * A piece of state storing a {@link bool}.
+ * A piece of state storing a {@link Boolean}.
  * </p>
  * <p>
  * If this state is registered using {@link IMenuStateIds#STYLE}, then it will
@@ -42,16 +42,16 @@
      * off (e.g., <code>false</code>).
      */
     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);
--- 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 <remy.suen@gmail.com> - Bug 218553 [JFace] mis-spelling of their in applyDialogFont(...)
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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 
+     * <code>false</code>, 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;
+    }
 }
--- 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 <code>super</code>
      * 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;
+    }
+
 }
--- 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}.
      * </p>
+     * 
      * @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);
--- 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;
+    }
 }
--- 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;
--- 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
      *            <code>showDialogMenu</code> is <code>false</code>.
      * @param titleText
      *            Text to be shown in an upper title area, or <code>null</code>
@@ -347,23 +433,149 @@
      * @param infoText
      *            Text to be shown in a lower info area, or <code>null</code>
      *            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 <code>PopupDialog</code>.
+     * 
+     * @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 <code>showDialogMenu</code> is <code>false</code>.
+     * @param titleText
+     *            Text to be shown in an upper title area, or <code>null</code>
+     *            if there is no title.
+     * @param infoText
+     *            Text to be shown in a lower info area, or <code>null</code>
+     *            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 <code>PopupDialog</code>.
+     * 
+     * @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 <code>showDialogMenu</code> is <code>false</code>.
+     * @param titleText
+     *            Text to be shown in an upper title area, or <code>null</code>
+     *            if there is no title.
+     * @param infoText
+     *            Text to be shown in a lower info area, or <code>null</code>
+     *            if there is no info area.
+     * @param use34API
+     *            <code>true</code> 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 <code>PopupDialog</code> implementation of this <code>Window</code>
      * 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 <true> if the dialogs bounds will be persisted, false if it will
-     *         not.
+     * @return <code>true</code> if the dialog's bounds will be persisted,
+     *         <code>false</code> 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 <code>true</code> if the dialog's location will be persisted,
+     *         <code>false</code> 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 <code>true</code> if the dialog's size will be persisted,
+     *         <code>false</code> 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
+     *            <code>getInitialSize</code>.
+     * @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 <code>null</code>.
+     * 
+     * @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 <code>null</code>.
+     * 
+     * @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
-     * <code>PopupDialog.getForegroundColorExclusions</code>.
+     * {@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
-     * <code>PopupDialog.getBackgroundColorExclusions</code>.
+     * {@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
      * <code>super.getForegroundColorExclusions</code> 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
      * <code>super.getBackgroundColorExclusions</code> 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()) {
--- 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 <mark.siegel@businessobjects.com> - Fix for Bug 184533
+ *              [Progress] ProgressIndicator uses hardcoded style for ProgressBar
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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);
+        
+    }
 }
--- 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
--- 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;
     }
--- 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 <code>true</code> 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);
+    }
+
 }
--- 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. <code>FILTER_NONE</code>
      *         specifies that no filtering will occur in the content proposal
-     *         list as keys are typed. <code>FILTER_CUMULATIVE</code>
-     *         specifies that the content of the popup will be filtered by a
-     *         string containing all the characters typed since the popup has
-     *         been open. <code>FILTER_CHARACTER</code> specifies the content
-     *         of the popup will be filtered by the most recently typed
-     *         character. The default is <code>FILTER_NONE</code>.
+     *         list as keys are typed. <code>FILTER_CHARACTER</code> specifies
+     *         the content of the popup will be filtered by the most recently
+     *         typed character. <code>FILTER_CUMULATIVE</code> 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
+     *         <code>FILTER_NONE</code>.
      */
     public int getFilterStyle() {
         return filterStyle;
@@ -1479,12 +1509,12 @@
      *            popup affect filtering of the proposals shown.
      *            <code>FILTER_NONE</code> specifies that no automatic
      *            filtering of the content proposal list will occur as keys are
-     *            typed in the popup. <code>FILTER_CUMULATIVE</code> specifies
-     *            that the content of the popup will be filtered by a string
-     *            containing all the characters typed since the popup has been
-     *            open. <code>FILTER_CHARACTER</code> specifies that the
-     *            content of the popup will be filtered by the most recently
-     *            typed character.
+     *            typed in the popup. <code>FILTER_CHARACTER</code> specifies
+     *            that the content of the popup will be filtered by the most
+     *            recently typed character. <code>FILTER_CUMULATIVE</code> 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 <code>true</code> 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;
+    }
 }
--- 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 <code>null</code>
@@ -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
+     *            <code>null</code>.
      */
     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();
--- 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
--- /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 <benoit@tionex.de>
+ *******************************************************************************/
+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);
+
+}
--- 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 <amir@pyrus.us> - bug 200762
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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]));
--- 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);
+    }
 }
--- /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 <benoit@tionex.de>
+ ******************************************************************************/
+
+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);
+        }
+    }
+}
--- 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 <tom.schindl@bestsolution.at> - refactored to be widget independent (bug 171824)
- *                                               - fix for bug 178280, 184342, 184045
+ *                                               - fix for bug 178280, 184342, 184045, 208014, 214532
+ *     Micah Hainline <micah_hainline@yahoo.com> - fix in bug: 208335
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 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.
  *
- * <p><b>You can only add the layout to a container whose
- * only child is the table/tree control you want the layouts applied to.</b>
+ * <p>
+ * <b>You can only add the layout to a container whose only child is the
+ * table/tree control you want the layouts applied to.</b>
  * </p>
  *
- * @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;
+    }
 }
--- 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;
--- 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 <code>run</code> 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
+ * <code>run</code> 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.
  * <p>
  * This class is not intended to be subclassed.
  * </p>
@@ -41,21 +44,21 @@
 public class ModalContext {
 
     /**
-     * Indicated whether ModalContext is in debug mode;
-     * <code>false</code> by default.
+     * Indicated whether ModalContext is in debug mode; <code>false</code> 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 <code>true</code> 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 <code>true</code> 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
      * <code>InterruptedException</code> if it has been canceled.
      * <p>
-     * 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.
      * </p>
      * <p>
      * Convenience for:
+     * 
      * <pre>
      * if (monitor.isCanceled())
-     *    throw new InterruptedException();
+     *  throw new InterruptedException();
      * </pre>
+     * 
      * </p>
-     *
-     * @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.
      * <p>
      * The modal nesting level increases by one each time the
-     * <code>ModalContext.run</code> method is called within the
-     * dynamic scope of another call to <code>ModalContext.run</code>.
+     * <code>ModalContext.run</code> method is called within the dynamic scope
+     * of another call to <code>ModalContext.run</code>.
      * </p>
-     *
-     * @return the modal nesting level, or <code>0</code> if
-     *  this method is called outside the dynamic scope of any
-     *  invocation of <code>ModalContext.run</code>
+     * 
+     * @return the modal nesting level, or <code>0</code> if this method is
+     *         called outside the dynamic scope of any invocation of
+     *         <code>ModalContext.run</code>
      */
     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 <code>true</code> if the given thread is running a modal context, <code>false</code> if not
+     * @param thread
+     *            The thread to be checked
+     * @return <code>true</code> if the given thread is running a modal
+     *         context, <code>false</code> 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.
      * <p>
-     * 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.
      * </p>
-     *<p>
+     * <p>
      * If the supplied operation implements <code>IThreadListener</code>, 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
-     * <code>run</code> 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.
-     *</p>
-     * @param operation the runnable to run
-     * @param fork <code>true</code> if the runnable should run in a separate thread,
-     *   and <code>false</code> 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 <code>InvocationTargetException</code>; runtime exceptions and errors are automatically
-     *  wrapped in an <code>InvocationTargetException</code> by this method
-     * @exception InterruptedException if the operation detects a request to cancel,
-     *  using <code>IProgressMonitor.isCanceled()</code>, it should exit by throwing
-     *  <code>InterruptedException</code>; this method propagates the exception
+     * Specifically, the operation will be notified of the thread that will call
+     * its <code>run</code> 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.
+     * </p>
+     * 
+     * @param operation
+     *            the runnable to run
+     * @param fork
+     *            <code>true</code> if the runnable should run in a separate
+     *            thread, and <code>false</code> 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
+     *                <code>InvocationTargetException</code>; runtime
+     *                exceptions and errors are automatically wrapped in an
+     *                <code>InvocationTargetException</code> by this method
+     * @exception InterruptedException
+     *                if the operation detects a request to cancel, using
+     *                <code>IProgressMonitor.isCanceled()</code>, it should
+     *                exit by throwing <code>InterruptedException</code>;
+     *                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 <code>true</code> for debug mode,
-     *  and <code>false</code> for normal mode (the default)
+     * 
+     * @param debugMode
+     *            <code>true</code> for debug mode, and <code>false</code>
+     *            for normal mode (the default)
      */
     public static void setDebugMode(bool debugMode) {
         debug_ = debugMode;
     }
 
     /**
-     * Sets whether ModalContext may process events (by calling <code>Display.readAndDispatch()</code>)
-     * while running operations. By default, ModalContext will process events while running operations.
-     * Use this method to disallow event processing temporarily.
-     * @param allowReadAndDispatch <code>true</code> (the default) if events may be processed while
-     * running an operation, <code>false</code> if Display.readAndDispatch() should not be called
-     * from ModalContext.
+     * Sets whether ModalContext may process events (by calling
+     * <code>Display.readAndDispatch()</code>) while running operations. By
+     * default, ModalContext will process events while running operations. Use
+     * this method to disallow event processing temporarily.
+     * 
+     * @param allowReadAndDispatch
+     *            <code>true</code> (the default) if events may be processed
+     *            while running an operation, <code>false</code> if
+     *            Display.readAndDispatch() should not be called from
+     *            ModalContext.
      * @since 3.2
      */
     public static void setAllowReadAndDispatch(bool allowReadAndDispatch) {
--- 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 <remy.suen@gmail.com> - Bug 214392 missing implementation of ComboFieldEditor.setEnabled
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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);
+    }
 }
--- 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) {
--- 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 <code>false</code> 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 <code>true</code> if the file path
+     *  must be absolute, and <code>false</code> 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);
     }
 
--- 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
+ *     <sgandon@nds.com> - Fix for bug 109389 - IntegerFieldEditor
+ *     does not fire property change all the time
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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$
         }
 
     }
--- 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;
--- 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;
+    }
+
 }
--- 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -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;
     }
 
     /**
--- 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 <code>Composite</code>
      * that has a layout with default margins (for example, a <code>GridLayout</code>)
      * it is expected to set the margins of this <code>Layout</code> 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 <code>setValid(false)</code>
      * 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.
      * <p>
-     * 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.
      * </p>
@@ -420,6 +423,7 @@
      * The <code>PreferencePage</code> implementation of this
      * <code>IPreferencePage</code> method returns <code>true</code>
      * 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.
      * <p>
-     * 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 <code>true</code>.
+     * @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 <code>PreferencePage</code> implementation of this <code>IDialogPage</code>
      * method extends the <code>DialogPage</code> 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();
--- 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 <code>null</code> if none.
--- 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 <code>Display</code>. 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 <code>RGB</code> data.
+     * @return the <code>RGB</code> data, or <code>null</code> 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() {
--- 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 <code>null</code> if none.
+     * The class whose resource directory contain the file, or <code>null</code>
+     * 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 <code>null</code>, 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
+     * <code>null</code>, the file name must be absolute.
      * <p>
-     * Note that the file is not accessed until its
-     * <code>getImageDate</code> method is called.
+     * Note that the file is not accessed until its <code>getImageDate</code>
+     * method is called.
      * </p>
-     *
-     * @param clazz class for resource directory, or
-     *   <code>null</code>
-     * @param filename the name of the file
+     * 
+     * @param clazz
+     *            class for resource directory, or <code>null</code>
+     * @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 <code>null</code>
-     * if the file cannot be found
+     * @return the buffered stream on the file or <code>null</code> 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 <code>FileImageDescriptor</code> implementation of this <code>Object</code> method
-     * returns a string representation of this object which is suitable only for debugging.
+     * The <code>FileImageDescriptor</code> implementation of this
+     * <code>Object</code> 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 <code>null</code>
+     */
+    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 <code>null</code> 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;
+//      }
     }
 }
--- 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());
 
--- 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.
+    }
 }
--- 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);
--- 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 <code>URLImageDescriptor</code> implementation of this <code>Object</code> method
-     * returns a string representation of this object which is suitable only for debugging.
+     * The <code>URLImageDescriptor</code> implementation of this
+     * <code>Object</code> 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 <code>null</code> 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);
+    }
+
 }
--- 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;
     }
 
     /**
--- 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 <code>null</code> 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 <code>null</code> if this has not been set
+     * @return ErrorSupportProvider or <code>null</code> 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));
+
+    }
+
 }
--- 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 <code>handleException</code> opens a message dialog.
+ * implementation of <code>handleException</code> opens a dialog to show any
+ * errors as they accumulate.
  * <p>
- * <b>Note:<b> This class can open an error dialog and should not be used
- * outside of the UI Thread.
- * </p>
+ * 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);
                     }
--- 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);
--- /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 <benoit@tionex.de>
+ ******************************************************************************/
+
+module dwtx.jface.util.StatusHandler;
+
+import dwtx.core.runtime.IStatus;
+
+/**
+ * A mechanism to handle statuses throughout JFace.
+ * <p>
+ * Clients may provide their own implementation to change how statuses are
+ * handled from within JFace.
+ * </p>
+ * 
+ * @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);
+}
--- 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<len) {
+            buf.append(src.substring(beginIndex, (idxis-1?len:idx)));
+        }
+        return buf.toString();
+    }
 
     /**
      * This class should never be constructed.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/viewers/AbstractComboBoxCellEditor.d	Thu May 22 01:36:46 2008 +0200
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2008 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 <tom.schindl@bestsolution.at> - initial API and implementation (bug 174739)
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ ******************************************************************************/
+
+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;
+    }
+}
--- 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 <code>null</code> 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 {
--- 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 <tom.schindl@bestsolution.at> - 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -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);
--- 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 <tom.schindl@bestsolution.at> - 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -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.
      * <p>
      * The value <code>ALL_LEVELS</code> means that all subtrees should be
      * expanded.
      * </p>
+     * <p>
+     * Note that in previous releases, the Javadoc for this method had an off-by
+     * one error. See bug 177669 for details.
+     * </p>
      *
      * @param level
      *            non-negative level, or <code>ALL_LEVELS</code> 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[]
+     * <strong>NOTE:</strong> 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 <code>isExpandable</code> 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;
--- 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 <tom.schindl@bestsolution.at> - bugfix in: 187963, 218336
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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; <code>true</code> by default.
+         * Indicates control grabs additional space; <code>true</code> by
+         * default.
          */
         public bool grabHorizontal = true;
 
@@ -48,32 +51,45 @@
          * Minimum width in pixels; <code>50</code> 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; <code>DWT.CENTER</code> 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.
  * <p>
- * 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:
  * <ul>
- *   <li><code>TextCellEditor</code> - for simple text strings</li>
- *   <li><code>ColorCellEditor</code> - for colors</li>
- *   <li><code>ComboBoxCellEditor</code> - value selected from drop-down combo box</li>
- *   <li><code>CheckboxCellEditor</code> - bool valued checkbox</li>
- *   <li><code>DialogCellEditor</code> - value from arbitrary dialog</li>
+ * <li><code>TextCellEditor</code> - for simple text strings</li>
+ * <li><code>ColorCellEditor</code> - for colors</li>
+ * <li><code>ComboBoxCellEditor</code> - value selected from drop-down combo
+ * box</li>
+ * <li><code>CheckboxCellEditor</code> - bool valued checkbox</li>
+ * <li><code>DialogCellEditor</code> - value from arbitrary dialog</li>
  * </ul>
  * </p>
  */
 public abstract class CellEditor {
 
     /**
-     * List of cell editor listeners (element type: <code>ICellEditorListener</code>).
+     * List of cell editor listeners (element type:
+     * <code>ICellEditorListener</code>).
      */
     private ListenerList listeners;
 
     /**
-     * List of cell editor property change listeners
-     * (element type: <code>IPropertyChangeListener</code>).
+     * List of cell editor property change listeners (element type:
+     * <code>IPropertyChangeListener</code>).
      */
     private ListenerList propertyChangeListeners;
 
@@ -88,8 +104,8 @@
     private ICellEditorValidator validator = null;
 
     /**
-     * The error message string to display for invalid values;
-     * <code>null</code> if none (that is, the value is valid).
+     * The error message string to display for invalid values; <code>null</code>
+     * 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 <code>null</code>
-     * if not created yet.
+     * This cell editor's control, or <code>null</code> 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.
      * <p>
-     * The default implementation of this framework method
-     * does nothing. Subclasses may reimplement.
+     * The default implementation of this framework method does nothing.
+     * Subclasses may reimplement.
      * </p>
      */
     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.
      * <p>
-     * This framework method must be implemented by concrete
-     * subclasses.
+     * This framework method must be implemented by concrete subclasses.
      * </p>
      *
-     * @param parent the parent control
-     * @return the new control, or <code>null</code> if this cell editor has no control
+     * @param parent
+     *            the parent control
+     * @return the new control, or <code>null</code> 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.
      * </p>
      *
-     * @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 <code>null</code> if this cell editor has no control
+     * @return the control, or <code>null</code> 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 <code>null</code> if the cell editor is valid
+     * @return the error message if the cell editor is in an invalid state, and
+     *         <code>null</code> 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.
      * <p>
-     * 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.
      * </p>
      *
      * @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 <code>null</code>
-     *   if the cell editor does not contain a valid value
+     * @return the value of this cell editor, or <code>null</code> 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 <code>true</code> if this cell editor's control is
-     *   currently activated, and <code>false</code> if not activated
+     * @return <code>true</code> if this cell editor's control is currently
+     *         activated, and <code>false</code> if not activated
      */
     public bool isActivated() {
         // Use the state of the visible style bit (getVisible()) rather than the
@@ -493,29 +520,31 @@
     }
 
     /**
-     * Returns <code>true</code> if this cell editor is
-     * able to perform the copy action.
+     * Returns <code>true</code> if this cell editor is able to perform the
+     * copy action.
      * <p>
-     * This default implementation always returns
-     * <code>false</code>.
+     * This default implementation always returns <code>false</code>.
      * </p>
      * <p>
      * Subclasses may override
      * </p>
-     * @return <code>true</code> if copy is possible,
-     *  <code>false</code> otherwise
+     *
+     * @return <code>true</code> if copy is possible, <code>false</code>
+     *         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 <code>true</code> if the value is valid, and <code>false</code>
-     *  if invalid
+     *         if invalid
      */
     protected bool isCorrect(Object value) {
         errorMessage = null;
@@ -528,45 +557,45 @@
     }
 
     /**
-     * Returns <code>true</code> if this cell editor is
-     * able to perform the cut action.
+     * Returns <code>true</code> if this cell editor is able to perform the
+     * cut action.
      * <p>
-     * This default implementation always returns
-     * <code>false</code>.
+     * This default implementation always returns <code>false</code>.
      * </p>
      * <p>
      * Subclasses may override
      * </p>
-     * @return <code>true</code> if cut is possible,
-     *  <code>false</code> otherwise
+     *
+     * @return <code>true</code> if cut is possible, <code>false</code>
+     *         otherwise
      */
     public bool isCutEnabled() {
         return false;
     }
 
     /**
-     * Returns <code>true</code> if this cell editor is
-     * able to perform the delete action.
+     * Returns <code>true</code> if this cell editor is able to perform the
+     * delete action.
      * <p>
-     * This default implementation always returns
-     * <code>false</code>.
+     * This default implementation always returns <code>false</code>.
      * </p>
      * <p>
      * Subclasses may override
      * </p>
-     * @return <code>true</code> if delete is possible,
-     *  <code>false</code> otherwise
+     *
+     * @return <code>true</code> if delete is possible, <code>false</code>
+     *         otherwise
      */
     public bool isDeleteEnabled() {
         return false;
     }
 
     /**
-     * Returns whether the value of this cell editor has changed since the
-     * last call to <code>setValue</code>.
+     * Returns whether the value of this cell editor has changed since the last
+     * call to <code>setValue</code>.
      *
-     * @return <code>true</code> if the value has changed, and <code>false</code>
-     *  if unchanged
+     * @return <code>true</code> if the value has changed, and
+     *         <code>false</code> 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 <code>true</code> if this cell editor is
-     * able to perform the find action.
+     * Returns <code>true</code> if this cell editor is able to perform the
+     * find action.
      * <p>
-     * This default implementation always returns
-     * <code>false</code>.
+     * This default implementation always returns <code>false</code>.
      * </p>
      * <p>
      * Subclasses may override
      * </p>
-     * @return <code>true</code> if find is possible,
-     *  <code>false</code> otherwise
+     *
+     * @return <code>true</code> if find is possible, <code>false</code>
+     *         otherwise
      */
     public bool isFindEnabled() {
         return false;
     }
 
     /**
-     * Returns <code>true</code> if this cell editor is
-     * able to perform the paste action.
+     * Returns <code>true</code> if this cell editor is able to perform the
+     * paste action.
      * <p>
-     * This default implementation always returns
-     * <code>false</code>.
+     * This default implementation always returns <code>false</code>.
      * </p>
      * <p>
      * Subclasses may override
      * </p>
-     * @return <code>true</code> if paste is possible,
-     *  <code>false</code> otherwise
+     *
+     * @return <code>true</code> if paste is possible, <code>false</code>
+     *         otherwise
      */
     public bool isPasteEnabled() {
         return false;
     }
 
     /**
-     * Returns <code>true</code> if this cell editor is
-     * able to perform the redo action.
+     * Returns <code>true</code> if this cell editor is able to perform the
+     * redo action.
      * <p>
-     * This default implementation always returns
-     * <code>false</code>.
+     * This default implementation always returns <code>false</code>.
      * </p>
      * <p>
      * Subclasses may override
      * </p>
-     * @return <code>true</code> if redo is possible,
-     *  <code>false</code> otherwise
+     *
+     * @return <code>true</code> if redo is possible, <code>false</code>
+     *         otherwise
      */
     public bool isRedoEnabled() {
         return false;
     }
 
     /**
-     * Returns <code>true</code> if this cell editor is
-     * able to perform the select all action.
+     * Returns <code>true</code> if this cell editor is able to perform the
+     * select all action.
      * <p>
-     * This default implementation always returns
-     * <code>false</code>.
+     * This default implementation always returns <code>false</code>.
      * </p>
      * <p>
      * Subclasses may override
      * </p>
-     * @return <code>true</code> if select all is possible,
-     *  <code>false</code> otherwise
+     *
+     * @return <code>true</code> if select all is possible, <code>false</code>
+     *         otherwise
      */
     public bool isSelectAllEnabled() {
         return false;
     }
 
     /**
-     * Returns <code>true</code> if this cell editor is
-     * able to perform the undo action.
+     * Returns <code>true</code> if this cell editor is able to perform the
+     * undo action.
      * <p>
-     * This default implementation always returns
-     * <code>false</code>.
+     * This default implementation always returns <code>false</code>.
      * </p>
      * <p>
      * Subclasses may override
      * </p>
-     * @return <code>true</code> if undo is possible,
-     *  <code>false</code> otherwise
+     *
+     * @return <code>true</code> if undo is possible, <code>false</code>
+     *         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 <code>true</code> if the value is valid, and <code>false</code>
-     *  if invalid
+     *         if invalid
      *
      * @see #setValueValid(bool)
      */
@@ -681,14 +711,14 @@
     /**
      * Processes a key release event that occurred in this cell editor.
      * <p>
-     * 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.
      * </p>
      *
-     * @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.
      * <p>
      * 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.
      * </p>
      */
     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.
      * <p>
      * Subclasses may override
      * </p>
@@ -726,8 +754,7 @@
     }
 
     /**
-     * Performs the cut action.
-     * This default implementation does nothing.
+     * Performs the cut action. This default implementation does nothing.
      * <p>
      * Subclasses may override
      * </p>
@@ -736,8 +763,7 @@
     }
 
     /**
-     * Performs the delete action.
-     * This default implementation does nothing.
+     * Performs the delete action. This default implementation does nothing.
      * <p>
      * Subclasses may override
      * </p>
@@ -746,8 +772,7 @@
     }
 
     /**
-     * Performs the find action.
-     * This default implementation does nothing.
+     * Performs the find action. This default implementation does nothing.
      * <p>
      * Subclasses may override
      * </p>
@@ -756,8 +781,7 @@
     }
 
     /**
-     * Performs the paste action.
-     * This default implementation does nothing.
+     * Performs the paste action. This default implementation does nothing.
      * <p>
      * Subclasses may override
      * </p>
@@ -766,8 +790,7 @@
     }
 
     /**
-     * Performs the redo action.
-     * This default implementation does nothing.
+     * Performs the redo action. This default implementation does nothing.
      * <p>
      * Subclasses may override
      * </p>
@@ -776,8 +799,7 @@
     }
 
     /**
-     * Performs the select all action.
-     * This default implementation does nothing.
+     * Performs the select all action. This default implementation does nothing.
      * <p>
      * Subclasses may override
      * </p>
@@ -786,8 +808,7 @@
     }
 
     /**
-     * Performs the undo action.
-     * This default implementation does nothing.
+     * Performs the undo action. This default implementation does nothing.
      * <p>
      * Subclasses may override
      * </p>
@@ -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.
      * <p>
-     * 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.
      * </p>
-     * @param message the error message, or <code>null</code> to clear
+     *
+     * @param message
+     *            the error message, or <code>null</code> 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 <code>null</code> if none
+     * @param validator
+     *            the input validator, or <code>null</code> 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 <code>true</code> if the current value is valid,
-     *  and <code>false</code> if invalid
+     * @param valid
+     *            <code>true</code> if the current value is valid, and
+     *            <code>false</code> 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.
-     * <b>The default implementation simply calls {@link #activate()}</b>
+     * Activate the editor but also inform the editor which event triggered its
+     * activation. <b>The default implementation simply calls
+     * {@link #activate()}</b>
      *
-     * @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 <code>true</code> to indicate that a focus listener has to be attached
+     * @return <code>true</code> 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 <em>double click</em> 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 <code>0</code>
+     */
+    protected int getDoubleClickTimeout() {
+        return Display.getCurrent().getDoubleClickTime();
+    }
 }
--- 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 <code>null</code> 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 <code>null</code> if a column is not
+     *            available.
+     * 
+     * @since 3.4
+     */
+    public void dispose(ColumnViewer viewer, ViewerColumn column) {
+        dispose();
+    }
+    
 }
--- 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 <code>CheckboxCellEditor</code> implementation of
      * this <code>CellEditor</code> framework method returns
-     * the checkbox setting wrapped as a <code>bool</code>.
+     * the checkbox setting wrapped as a <code>Boolean</code>.
      *
-     * @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 <code>CheckboxCellEditor</code> implementation of
      * this <code>CellEditor</code> framework method accepts
-     * a value wrapped as a <code>bool</code>.
+     * a value wrapped as a <code>Boolean</code>.
      *
-     * @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) {
--- 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 <code>expandToLevel</code>
+     * for the element.
      *
      * @param state <code>true</code> if the element should be checked,
      *  and <code>false</code> 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++) {
--- 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 <tom.schindl@bestsolution.at> - 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -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}.
+ * 
  * <strong> This class is not intended to be subclassed outside of the JFace
  * viewers framework.</strong>
- *
+ * 
  * @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 <code>null</code> if this viewer does not
-     *         support editing cell contents.
+     * 
+     * @return the editor, or <code>null</code> if this viewer does not support
+     *  editing cell contents.
      */
     protected abstract ColumnViewerEditor createViewerEditor();
 
     /**
      * Returns the viewer cell at the given widget-relative coordinates, or
      * <code>null</code> if there is no cell at that location
-     *
+     * 
      * @param point
-     *            the widget-relative coordinates
+     *      the widget-relative coordinates
      * @return the cell or <code>null</code> 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 <code>null</code> if no row is found at
-     *         the given coordinates
+     *      the widget-relative coordinates of the viewer row
+     * @return ViewerRow the row or <code>null</code> 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 <code>null</code> 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
      * <code>null</code> if there is no item at the given coordinates.
-     *
+     * 
      * @param point
-     *            the widget-relative coordinates
-     * @return the {@link Item} at the coordinates or <code>null</code> if
-     *         there is no item at the given coordinates
+     *      the widget-relative coordinates
+     * @return the {@link Item} at the coordinates or <code>null</code> 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 @@
      * <code>ITableLabelProvider</code>, <code>ILabelProvider</code>, or
      * <code>CellLabelProvider</code>.
      * <p>
-     * 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
-     * <code>ITableLabelProvider</code> may also implement
-     * {@link ITableColorProvider} and/or {@link ITableFontProvider} to provide
-     * colors and/or fonts.
+     * <code>ITableLabelProvider</code> may also implement {@link
+     * ITableColorProvider} and/or {@link ITableFontProvider} to provide colors
+     * and/or fonts.
      * </p>
      * <p>
-     * If the label provider is an <code>ILabelProvider</code>, then it
+     * If the label provider is an <code>ILabelProvider</code> , then it
      * provides only the label text and image for the first column, and any
      * remaining columns are blank. Implementers of <code>ILabelProvider</code>
      * may also implement {@link IColorProvider} and/or {@link IFontProvider} to
      * provide colors and/or fonts.
      * </p>
-     *
+     * 
      */
     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 <code>null</code> if no
-     * cell editors are set.
+     * Return the CellEditors for the receiver, or <code>null</code> if no cell
+     * editors are set.
      * <p>
-     * 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.
      * </p>
-     *
+     * 
+     * 
      * @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 <code>null</code> if none
      * has been set.
-     *
+     * 
      * <p>
-     * 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.
      * </p>
-     *
+     * 
      * @return the cell modifier, or <code>null</code>
      * @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.
-     *
+     * 
      * <p>
-     * 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.
      * </p>
-     *
+     * 
      * @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.
-     *
+     * 
      * <p>
-     * 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.
      * </p>
-     *
+     * 
      * @return <code>true</code> if there is an active cell editor, and
-     *         <code>false</code> otherwise
+     *  <code>false</code> 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.
-     *
+     * 
      * <p>
-     * 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.
      * </p>
-     *
+     * <p>
+     * Users setting up an editable {@link TreeViewer} or {@link TableViewer} with more than 1 column <b>have</b>
+     * to pass the DWT.FULL_SELECTION style bit
+     * </p>
      * @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.
-     *
+     * 
      * <p>
-     * 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.
      * </p>
-     *
+     * <p>
+     * Users setting up an editable {@link TreeViewer} or {@link TableViewer} with more than 1 column <b>have</b>
+     * to pass the DWT.FULL_SELECTION style bit
+     * </p>
      * @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.
-     *
+     * 
      * <p>
-     * 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.
      * </p>
-     *
+     * <p>
+     * Users setting up an editable {@link TreeViewer} or {@link TableViewer} with more than 1 column <b>have</b>
+     * to pass the DWT.FULL_SELECTION style bit
+     * </p>
      * @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 <code>null</code> 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
-     *         <code>null</code> if no column with this index is known
-     *
+     *  <code>null</code> 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
+     * <code>true</code> 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 <code>true</code>
+     * 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.
+     * 
+     * <p>
+     * This method is not intended to be overridden by subclasses.
+     * </p>
+     * 
+     * @return <code>true</code> 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 <code>try</code>
+     * ...<code>finally</code> as follows to ensure that the busy flag is reset
+     * to its original value:
+     * 
+     * <pre>
+     * bool oldBusy = isBusy();
+     * setBusy(true);
+     * try {
+     *  // do work
+     * } finally {
+     *  setBusy(oldBusy);
+     * }
+     * </pre>
+     * 
+     * <p>
+     * This method is not intended to be overridden by subclasses.
+     * </p>
+     * 
+     * @param busy
+     *      the new value of the busy flag
+     * 
+     * @since 3.4
+     */
+    protected void setBusy(bool busy) {
+        this.busy = busy;
+    }
+
+    /**
+     * Returns <code>true</code> 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.
+     * 
+     * <p>
+     * This method is not intended to be overridden by subclasses.
+     * </p>
+     * 
+     * @return Returns whether this viewer is busy.
+     * 
+     * @since 3.4
+     */
+    public bool isBusy() {
+        return busy;
+    }
 }
--- 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 <tom.schindl@bestsolution.at> - 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -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 <b>off</b> 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);
                 }
             }
         }
--- 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;
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
+ *                                                 fixes in bug: 178946
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  ******************************************************************************/
@@ -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);
     }
-
 }
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
+ *                                                 bugfix in: 195137, 198089
  *     Fredy Dobler <fredy@dobler.net> - bug 159600
  *     Brock Janiczak <brockj@tpg.com.au> - 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
      *            <code>true</code> 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.
+     *
+     * <p>
+     * This method is called from
+     * {@link #createToolTipContentArea(Event, Composite)} and by default calls
+     * the {@link DefaultToolTip#createToolTipContentArea(Event, Composite)}.
+     * </p>
+     *
+     * @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();
         }
     }
 }
--- 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 <tom.schindl@bestsolution.at> - bugfix in 199775
+ *     Tom Schindl <tom.schindl@bestsolution.at> - bugfix in 174739
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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.
  * <p>
  * This class may be instantiated; it is not intended to be subclassed.
  * </p>
  */
-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 <code>ComboBoxCellEditor</code> implementation of
-     * this <code>CellEditor</code> framework method returns
-     * the zero-based index of the current selection.
+     * The <code>ComboBoxCellEditor</code> implementation of this
+     * <code>CellEditor</code> framework method returns the zero-based index
+     * of the current selection.
      *
-     * @return the zero-based index of the current selection wrapped
-     *  as an <code>Integer</code>
+     * @return the zero-based index of the current selection wrapped as an
+     *         <code>Integer</code>
      */
     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 <code>ComboBoxCellEditor</code> implementation of
-     * this <code>CellEditor</code> framework method sets the
-     * minimum width of the cell.  The minimum width is 10 characters
-     * if <code>comboBox</code> is not <code>null</code> or <code>disposed</code>
-     * 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 <code>ComboBoxCellEditor</code> implementation of this
+     * <code>CellEditor</code> framework method sets the minimum width of the
+     * cell. The minimum width is 10 characters if <code>comboBox</code> is
+     * not <code>null</code> or <code>disposed</code> 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 <code>ComboBoxCellEditor</code> implementation of
-     * this <code>CellEditor</code> framework method
-     * accepts a zero-based index of a selection.
+     * The <code>ComboBoxCellEditor</code> implementation of this
+     * <code>CellEditor</code> framework method accepts a zero-based index of
+     * a selection.
      *
-     * @param value the zero-based index of the selection wrapped
-     *   as an <code>Integer</code>
+     * @param value
+     *            the zero-based index of the selection wrapped as an
+     *            <code>Integer</code>
      */
     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) {
--- /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 <tom.schindl@bestsolution.at> - initial API and implementation
+ *                                                 bugfix in 174739
+ *     Eric Rizzo - bug 213315
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+
+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 <code>ComboBoxCellEditor</code> implementation of this
+     * <code>CellEditor</code> framework method returns the zero-based index
+     * of the current selection.
+     *
+     * @return the zero-based index of the current selection wrapped as an
+     *         <code>Integer</code>
+     */
+    protected Object doGetValue() {
+        return selectedValue;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on CellEditor.
+     */
+    protected void doSetFocus() {
+        viewer.getControl().setFocus();
+    }
+
+    /**
+     * The <code>ComboBoxCellEditor</code> implementation of this
+     * <code>CellEditor</code> framework method sets the minimum width of the
+     * cell. The minimum width is 10 characters if <code>comboBox</code> is
+     * not <code>null</code> or <code>disposed</code> 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();
+        }
+    }
+}
--- 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 @@
  * </p>
  *
  * @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
--- 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 @@
      * <p>
      * The <code>ContentViewer</code> implementation of this method returns the label
      * provider recorded in an internal state variable; if none has been
-     * set (with <code>setLabelProvider</code>) a <code>SimpleLabelProvider</code>
+     * set (with <code>setLabelProvider</code>) 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();
+    }
 }
--- 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
--- /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 <benoit@tionex.de>
+ *******************************************************************************/
+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.
+ * 
+ * <p>
+ * Use this label provider as a replacement for the
+ * {@link DecoratingLabelProvider} when decorating styled text labels.
+ * </p>
+ * 
+ * <p>
+ * 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)}
+ * </p>
+ * <p>
+ * The {@link ILabelDecorator} can optionally implement {@link IColorDecorator}
+ * and {@link IFontDecorator} to provide foreground and background color and
+ * font decoration.
+ * </p>
+ * 
+ * @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 <code>null</code> to not decorate the
+     *            label
+     * @param decorationContext
+     *            a decoration context or <code>null</code> 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 <code>null</code> if no decorator is installed
+     * 
+     * @return the decorator or <code>null</code> 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 <code>null</code> 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;
+        }
+    }
+
+}
--- 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
--- 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);
     }
 
--- /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 <benoit@tionex.de>
+ *******************************************************************************/
+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}.
+ * 
+ * <p>
+ * Existing label providers can be enhanced by implementing
+ * {@link DelegatingStyledCellLabelProvider.IStyledLabelProvider} so they can be
+ * used in viewers with styled labels.
+ * </p>
+ * 
+ * <p>
+ * The {@link DelegatingStyledCellLabelProvider.IStyledLabelProvider} can
+ * optionally implement {@link IColorProvider} and {@link IFontProvider} to
+ * provide foreground and background color and a default font.
+ * </p>
+ * 
+ * @since 3.4
+ */
+public class DelegatingStyledCellLabelProvider extends StyledCellLabelProvider {
+
+    /**
+     * Interface marking a label provider that provides styled text labels and
+     * images.
+     * <p>
+     * The {@link DelegatingStyledCellLabelProvider.IStyledLabelProvider} can
+     * optionally implement {@link IColorProvider} and {@link IFontProvider} to
+     * provide foreground and background color and a default font.
+     * </p>
+     */
+    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 <code>null</code>
+         *         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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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();
+    }
+
+}
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
- *                                                 fix in bug 151295,167325,200558
+ *                                                 fix in bug 151295,167325,201905
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
+ *                                                 bugfix in: 182800
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  ******************************************************************************/
@@ -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.
+     * <p>
+     * <b>The default implementation for this method calls
+     * focusCellChanged(ViewerCell). Subclasses should override this method
+     * rather than {@link #focusCellChanged(ViewerCell)} .</b>
+     *
+     * @param newCell
+     *            the new focus cell or <code>null</code> if no new cell
+     *            receives the focus
+     * @param oldCell
+     *            the old focus cell or <code>null</code> 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.
      */
--- 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 <tom.schindl@bestsolution.at> - 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 <benoit@tionex.de>
- ******************************************************************************/
+ *******************************************************************************/
 
 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 <code>null</code> 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 <code>null</code> 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 <b>no</b> input focus
+     * 
+     * @param cell
+     *            the cell which is colored
+     * @return the color or <code>null</code> 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 <b>no</b> input focus
+     * 
+     * @param cell
+     *            the cell which is colored
+     * @return the color or <code>null</code> 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 <code>true</code> 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;
     }
 }
--- 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
--- 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.
-     *
+     * <p>
+     * <b>NOTE:</b> For instances where the viewer is displaying a tree
+     * containing a single 'root' element it is still necessary that the
+     * 'input' does not return <i>itself</i> from this method. This leads
+     * to recursion issues (see bug 9262).
+     * </p>
      * @param inputElement the input element
      * @return the array of elements to display in the viewer
      */
--- 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 <code>List</code>.
+     * <strong>Note</strong> 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
      */
--- 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.
+ * <p>
+ * It is recommended that clients do not implement this interface but instead
+ * use the standard implementation of this interface, {@link TreeSelection}.
+ * <code>TreeSelection</code> 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:
+ * <pre>
+ * 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);
+ * </pre>
+ * See bugs 135818 and 133375 for details.
+ * </p>
  *
  * @since 3.2
  *
--- 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 <benoit@tionex.de>
- *******************************************************************************/
-
-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 <code>NamedHandlerObject</code>, 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 <code>NamedHandleObject</code>. Otherwise, this
-     * method just returns <code>null</code>.
-     *
-     * @param element
-     *            The element for which the text should be retrieved; may be
-     *            <code>null</code>.
-     * @return the name of the handle object; <code>null</code> 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 <benoit@tionex.de>
+ *******************************************************************************/
+
+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 <code>NamedHandlerObject</code>, 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 <code>NamedHandleObject</code>. Otherwise, this
+     * method just returns <code>null</code>.
+     * 
+     * @param element
+     *            The element for which the text should be retrieved; may be
+     *            <code>null</code>.
+     * @return the name of the handle object; <code>null</code> 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;
+    }
+}
+
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
- *                                               - bug fix for bug 187189
+ *                                               - bug fix for bug 187189, 182800, 215069
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
- ******************************************************************************/
+ *******************************************************************************/
 
 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() {
--- 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 <code>null</code>
+     */
+    private IElementComparer comparer;
+
+    /**
      * The canonical empty selection. This selection should be used instead of
      * <code>null</code>.
      */
@@ -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 <code>List</code> 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;
--- 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 @@
      * <code>setSelectionToWidget</code></li>
      * <li>rediscovers the resulting selection (via <code>getSelection</code>)
      * </li>
-     * <li>calls <code>handleInvalidSelection</code> if the selection did not
-     * take</li>
-     * <li>calls <code>postUpdateHook</code></li>
+     * <li>calls <code>handleInvalidSelection</code> if the resulting selection is different from the old selection</li>
      * </ul>
      * </p>
      *
@@ -1410,7 +1408,6 @@
      * </li>
      * <li>calls <code>handleInvalidSelection</code> if the selection did not
      * take</li>
-     * <li>calls <code>postUpdateHook</code></li>
      * </ul>
      * </p>
      *
@@ -1539,7 +1536,7 @@
 
     /**
      *
-     * Refreshes the given TableItem with the given element. Calls
+     * Refreshes the given item with the given element. Calls
      * <code>doUpdateItem(..., false)</code>.
      * <p>
      * 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;
--- /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 <benoit@tionex.de>
+ *******************************************************************************/
+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:
+ * <ul>
+ * <li>similar image and label positioning</li>
+ * <li>native drawing of focus and selection</li>
+ * </ul>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ * 
+ * <p><strong>NOTE:</strong> This API is experimental and may be deleted or
+ * changed before 3.4 is released.</p>
+ * 
+ * @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 <code>true</code> 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 <code>true</code> 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 <code>null</code> if the
+     * label provider is not installed.
+     * 
+     * @return the viewer on which this label provider is installed on or <code>null</code> 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 <code>null</code> if the
+     * label provider is not installed.
+     * 
+     * @return the column on which this label provider is installed on or <code>null</code> 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);
+        }
+    }
+
+}
--- /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 <benoit@tionex.de>
+ *******************************************************************************/
+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:
+ * <ul>
+ * <li>new strings with stylers can be appended</li>
+ * <li>stylers can by applied to ranges of the existing string</li>
+ * </ul>
+ * 
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * 
+ * @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 <code>null</code> 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
+     *            <code>null</code> 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
+     *            <code>null</code> 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
+     *            <code>null</code> 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 <code>start</code> 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);
+            }
+        }
+    }
+
+}
--- 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -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_;
     }
 
     /**
--- 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 @@
  * </p>
  * <p>
  * Label providers for table viewers must implement either the
- * <code>ITableLabelProvider</code> or the <code>ILabelProvider</code>
- * interface (see <code>TableViewer.setLabelProvider</code> for more details).
+ * <code>ITableLabelProvider</code> or the <code>ILabelProvider</code> interface
+ * (see <code>TableViewer.setLabelProvider</code> for more details).
  * </p>
  * <p>
  * 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.
  * </p>
  * <p>
  * 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.
  * </p>
- *
+ * <p>
+ * Users setting up an editable table with more than 1 column <b>have</b> to pass the
+ * DWT.FULL_SELECTION style bit
+ * </p>
+ * 
  * @see DWT#VIRTUAL
  * @see #doFindItem(Object)
  * @see #internalRefresh(Object, bool)
@@ -89,9 +92,9 @@
      * <code>MULTI, H_SCROLL, V_SCROLL,</code> and <code>BORDER</code>. 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.
      * </p>
-     *
+     * 
      * @param selection
-     *            the new selection
+     *      the new selection
      * @param reveal
-     *            <code>true</code> if the selection is to be made visible,
-     *            and <code>false</code> otherwise
+     *      <code>true</code> if the selection is to be made visible, and
+     *      <code>false</code> 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 <code>refresh(bool updateLabels)</code>. The
-     * methods attempts to preserve the selection.
+     * as described in <code>refresh(bool updateLabels)</code>. The methods
+     * attempts to preserve the selection.
      * <p>
      * Unlike the <code>update</code> 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
      * <code>update</code> methods.
      * </p>
-     *
+     * 
      * <p>
      * Subclasses who can provide this feature can open this method for the
      * public
      * </p>
-     *
+     * 
      * @param element
-     *            the element
+     *      the element
      * @param updateLabels
-     *            <code>true</code> to update labels for existing elements,
-     *            <code>false</code> to only update labels as needed, assuming
-     *            that labels for existing elements are unchanged.
+     *      <code>true</code> to update labels for existing elements,
+     *      <code>false</code> to only update labels as needed, assuming that labels
+     *      for existing elements are unchanged.
      * @param reveal
-     *            <code>true</code> to make the preserved selection visible
-     *            afterwards
-     *
+     *      <code>true</code> 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 <code>updateLabels</code> is <code>true</code>
-     * 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 <code>updateLabels</code> is <code>true</code> 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).
      * <p>
      * Calling <code>refresh(true)</code> has the same effect as
      * <code>refresh()</code>.
      * <p>
      * Note that the implementation may still obtain labels for existing
-     * elements even if <code>updateLabels</code> is false. The intent is
-     * simply to allow optimization where possible.
-     *
+     * elements even if <code>updateLabels</code> is false. The intent is simply
+     * to allow optimization where possible.
+     * 
      * @param updateLabels
-     *            <code>true</code> to update labels for existing elements,
-     *            <code>false</code> to only update labels as needed, assuming
-     *            that labels for existing elements are unchanged.
+     *      <code>true</code> to update labels for existing elements,
+     *      <code>false</code> to only update labels as needed, assuming that labels
+     *      for existing elements are unchanged.
      * @param reveal
-     *            <code>true</code> to make the preserved selection visible
-     *            afterwards
-     *
+     *      <code>true</code> to make the preserved selection visible afterwards
+     * 
      * @since 3.3
      */
     public void refresh(bool updateLabels, bool reveal) {
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
- *                                                 fixes in bug 198665
+ *                                                 fixes in bug 198665, 200731
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
- ******************************************************************************/
+ *******************************************************************************/
 
 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() {
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
+ *                                                 fix in bug: 210752
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
- ******************************************************************************/
+ *******************************************************************************/
 
 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:
+     * <ul>
+     * <li><code>DWT.ARROW_UP</code>: navigate to cell above</li>
+     * <li><code>DWT.ARROW_DOWN</code>: navigate to cell below</li>
+     * <li><code>DWT.ARROW_RIGHT</code>: navigate to next visible cell on
+     * the right</li>
+     * <li><code>DWT.ARROW_LEFT</code>: navigate to next visible cell on the
+     * left</li>
+     * </ul>
+     *
+     * @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();
+    }
+
 }
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
- *                                              - Fix for bug 174355
+ *     Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
+ *                                               - fix in bug: 174355,195908,198035,215069
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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;
+    }
 }
--- 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;
     }
 }
--- 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 <benoit@tionex.de>
- ******************************************************************************/
-
-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
-     * <code>null</code>. There should be no <code>null</code> children in
-     * the array.
-     */
-    private TreeNode[] children;
-
-    /**
-     * The parent tree node for this tree node. This value may be
-     * <code>null</code> 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 <code>TreeNode</code>.
-     *
-     * @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 <code>null</code>
-     * before being returned.
-     *
-     * @return The child nodes; may be <code>null</code>, but never empty.
-     *         There should be no <code>null</code> 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 <code>null</code> 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 <code>true</code> if its array of children is not
-     *         <code>null</code> and is non-empty; <code>false</code>
-     *         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 <code>null</code> or empty. There
-     *            should be no <code>null</code> 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 <code>null</code>.
-     */
-    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 <benoit@tionex.de>
+ *******************************************************************************/
+
+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
+     * <code>null</code>. There should be no <code>null</code> children in
+     * the array.
+     */
+    private TreeNode[] children;
+
+    /**
+     * The parent tree node for this tree node. This value may be
+     * <code>null</code> 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 <code>TreeNode</code>.
+     *
+     * @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 <code>null</code>
+     * before being returned.
+     *
+     * @return The child nodes; may be <code>null</code>, but never empty.
+     *         There should be no <code>null</code> 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 <code>null</code> 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 <code>true</code> if its array of children is not
+     *         <code>null</code> and is non-empty; <code>false</code>
+     *         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 <code>null</code> or empty. There
+     *            should be no <code>null</code> 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 <code>null</code>.
+     */
+    public void setParent(TreeNode parent) {
+        this.parent = parent;
+    }
+}
+
--- 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 <benoit@tionex.de>
- ******************************************************************************/
-
-module dwtx.jface.viewers.TreeNodeContentProvider;
-
-import dwtx.jface.viewers.ITreeContentProvider;
-import dwtx.jface.viewers.Viewer;
-import dwtx.jface.viewers.TreeNode;
-
-import dwt.dwthelper.utils;
-
-/**
- * <p>
- * A content provider that expects every element to be a <code>TreeNode</code>.
- * Most methods delegate to <code>TreeNode</code>. <code>dispose()</code>
- * and <code>inputChanged(Viewer, Object, Object)</code> do nothing by
- * default.
- * </p>
- * <p>
- * This class and all of its methods may be overridden or extended.
- * </p>
- *
- * @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 <benoit@tionex.de>
+ *******************************************************************************/
+
+module dwtx.jface.viewers.TreeNodeContentProvider;
+
+import dwtx.jface.viewers.ITreeContentProvider;
+import dwtx.jface.viewers.Viewer;
+import dwtx.jface.viewers.TreeNode;
+
+import dwt.dwthelper.utils;
+
+/**
+ * <p>
+ * A content provider that expects every element to be a <code>TreeNode</code>.
+ * Most methods delegate to <code>TreeNode</code>. <code>dispose()</code>
+ * and <code>inputChanged(Viewer, Object, Object)</code> do nothing by
+ * default.
+ * </p>
+ * <p>
+ * This class and all of its methods may be overridden or extended.
+ * </p>
+ *
+ * @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
+    }
+}
+
--- 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 <tom.schindl@bestsolution.at> - 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -70,8 +71,13 @@
  * {@link ILazyTreePathContentProvider}. If the content provider is an
  * <code>ILazyTreeContentProvider</code> or an
  * <code>ILazyTreePathContentProvider</code>, 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)}.
+ * </p>
+ * <p>
+ * Users setting up an editable tree with more than 1 column <b>have</b> to pass the
+ * DWT.FULL_SELECTION style bit
  * </p>
  */
 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);
         }
     }
+
 }
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
- *                                                 fixes in bug 198665
+ *                                                 fixes in bug 198665, 200731, 187963
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
- ******************************************************************************/
+ *******************************************************************************/
 
 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() {
--- 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<tom.schindl@bestsolution.at> - initial API and implementation
+ *                                              - fix in bug: 195908, 210752
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
- ******************************************************************************/
+ *******************************************************************************/
 
 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:
+     * <ul>
+     * <li><code>DWT.ARROW_UP</code>: navigate to cell above</li>
+     * <li><code>DWT.ARROW_DOWN</code>: navigate to cell below</li>
+     * <li><code>DWT.ARROW_RIGHT</code>: on first column (collapses if item
+     * is expanded) else navigate to next visible cell on the right</li>
+     * <li><code>DWT.ARROW_LEFT</code>: on first column (expands if item is
+     * collapsed) else navigate to next visible cell on the left</li>
+     * </ul>
      *
      * @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();
+    }
 }
--- 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 <tom.schindl@bestsolution.at> - 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 <benoit@tionex.de>
  *******************************************************************************/
@@ -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;
+    }
 }
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
+ *     Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
+ *                                               - fix in bug: 195908,198035,215069,215735
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 
 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 <code>null</code> 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 <code>null</code> 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 <code>null</code>
+     *         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 <code>null</code>
+     *         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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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;
+    }
 }
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
- *                                                fix for bug 163317,200558
+ *                                                fix for bug 163317, 201905
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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.
-     *
+     * <p>
+     * Users setting up an editable {@link TreeViewer} or {@link TableViewer} with more than 1 column <b>have</b>
+     * to pass the DWT.FULL_SELECTION style bit when creating the viewer
+     * </p>
      * @param editingSupport
      *            The {@link EditingSupport} to set.
      */
@@ -145,7 +155,7 @@
      * Refresh the cell for the given columnIndex. <strong>NOTE:</strong>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;
+    }
 }
--- 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 <code>true</code>.
+     * on or off. Default is <code>true</code>.
      */
-    private bool scrollExpandEnabled = true;
+    private bool scrollEnabled = true;
 
     /**
+     * A flag that allows adapter users to turn auto
+     * expanding on or off. Default is <code>true</code>.
+     */
+    private bool expandEnabled = true;
+    
+    /**
      * A flag that allows adapter users to turn selection feedback
      *  on or off. Default is <code>true</code>.
      */
@@ -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 <code>true</code> if expanding is desired, and
+     *   <code>false</code> if not
+     * @since 3.4
+     */
+    public void setExpandEnabled(bool value) {
+        expandEnabled = value;
+    }
+    
+    /**
+     * Sets whether auto scrolling should be provided during dragging.
+     *
+     * @param value <code>true</code> if scrolling is desired, and
+     *   <code>false</code> if not
+     * @since 3.4
+     */
+    public void setScrollEnabled(bool value) {
+        scrollEnabled = value;
     }
 
     /**
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
- *                                                fix for bug 166346, bug 167325s
- *                                              - Fix for bug 174355
+ *     Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
+ *                                               - fix in bug: 166346,167325,174355,195908,198035,215069
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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.
+     * <p>
+     * <b>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</b>
+     * </p>
+     * 
+     * @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.
+     * <p>
+     * <b>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</b>
+     * </p>
+     * 
+     * @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 <code>null</code>
+     *         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 <code>null</code>
+     *         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 <code>null</code> 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);
+    }
 }
--- 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)
--- 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 <tom.schindl@bestsolution.at> - initial API and implementation
+ *                                                 bugfix in: 195137, 198089, 225190
  * Port to the D programming language:
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
@@ -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
      *            <code>true</code> 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
      *         <code>null</code> 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_;
--- 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 (<code>super.close</code> must
      * be called).
      * </p>
+     * <p>
+     *  Note that in order to prevent recursive calls to this method 
+     *  it does not call <code>Shell#close()</code>. As a result <code>ShellListener</code>s 
+     *  will not receive a <code>shellClosed</code> event.
+     *  </p>
      *
      * @return <code>true</code> if the window is (or was already) closed, and
      *         <code>false</code> if it is still open
--- 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 <code>null</code>
+     * according to the given layout. If the layout is <code>null</code>
      * 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);
     }
 
     /**
--- 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: <code>String</code>, element type:
-     *            <code>bool</code>)
+     *            <code>Boolean</code>)
      * @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 <code>null</code> if none
      * @param h
      *            the map (key type: <code>String</code>, element type:
-     *            <code>bool</code>)
+     *            <code>Boolean</code>)
      * @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();
             }
         }