changeset 26:87d8cf0a3074

StatusLine
author Frank Benoit <benoit@tionex.de>
date Thu, 03 Apr 2008 05:03:09 +0200
parents ca63e2bea4bf
children 7ec2fd279c28
files dwtx/jface/action/IStatusLineManager.d dwtx/jface/action/StatusLine.d dwtx/jface/action/StatusLineLayoutData.d dwtx/jface/action/StatusLineManager.d
diffstat 4 files changed, 1202 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/action/IStatusLineManager.d	Thu Apr 03 05:03:09 2008 +0200
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.action.IStatusLineManager;
+
+import dwtx.jface.action.IContributionManager;
+
+import dwt.graphics.Image;
+import dwtx.core.runtime.IProgressMonitor;
+
+import dwt.dwthelper.utils;
+
+/**
+ * The <code>IStatusLineManager</code> interface provides protocol
+ * for displaying messages on a status line, for monitoring progress,
+ * and for managing contributions to the status line.
+ * <p>
+ * <b>Note:</b> An error message overrides the current message until
+ * the error message is cleared.
+ * </p><p>
+ * This package also provides a concrete status line manager implementation,
+ * {@link StatusLineManager <code>StatusLineManager</code>}.
+ * </p>
+ */
+public interface IStatusLineManager : IContributionManager {
+    /**
+     * Returns a progress monitor which reports progress
+     * in the status line.
+     *
+     * @return the progress monitor
+     *
+     * Note: There is a delay after a beginTask message before the monitor is shown.
+     *   This may not be appropriate for all apps.
+     */
+    public IProgressMonitor getProgressMonitor();
+
+    /**
+     * Returns whether the cancel button on the status line's progress monitor
+     * is enabled.
+     *
+     * @return <code>true</code> if the cancel button is enabled, or <code>false</code> if not
+     */
+    public bool isCancelEnabled();
+
+    /**
+     * Sets whether the cancel button on the status line's progress monitor
+     * is enabled.
+     *
+     * @param enabled <code>true</code> if the cancel button is enabled, or <code>false</code> if not
+     */
+    public void setCancelEnabled(bool enabled);
+
+    /**
+     * Sets the error message text to be displayed on the status line.
+     * The image on the status line is cleared.
+     * <p>
+     * An error message overrides the current message until the error
+     * message is cleared (set to <code>null</code>).
+     * </p>
+     *
+     * @param message the error message, or <code>null</code> to clear
+     *      the current error message.
+     */
+    public void setErrorMessage(String message);
+
+    /**
+     * Sets the image and error message to be displayed on the status line.
+     * <p>
+     * An error message overrides the current message until the error
+     * message is cleared (set to <code>null</code>).
+     * </p>
+     *
+     * @param image the image to use, or <code>null</code> for no image
+     * @param message the error message, or <code>null</code> to clear
+     *      the current error message.
+     */
+    public void setErrorMessage(Image image, String message);
+
+    /**
+     * Sets the message text to be displayed on the status line.
+     * The image on the status line is cleared.
+     * <p>
+     * This method replaces the current message but does not affect the
+     * error message. That is, the error message, if set, will continue
+     * to be displayed until it is cleared (set to <code>null</code>).
+     * </p>
+     *
+     * @param message the message, or <code>null</code> for no message
+     */
+    public void setMessage(String message);
+
+    /**
+     * Sets the image and message to be displayed on the status line.
+     * <p>
+     * This method replaces the current message but does not affect the
+     * error message. That is, the error message, if set, will continue
+     * to be displayed until it is cleared (set to <code>null</code>).
+     * </p>
+     *
+     * @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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/action/StatusLine.d	Thu Apr 03 05:03:09 2008 +0200
@@ -0,0 +1,672 @@
+/*******************************************************************************
+ * 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+
+module dwtx.jface.action.StatusLine;
+
+import dwtx.jface.action.StatusLineLayoutData;
+
+import dwt.DWT;
+import dwt.custom.CLabel;
+import dwt.events.DisposeEvent;
+import dwt.events.DisposeListener;
+import dwt.events.SelectionAdapter;
+import dwt.events.SelectionEvent;
+import dwt.graphics.Cursor;
+import dwt.graphics.Font;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Layout;
+import dwt.widgets.ToolBar;
+import dwt.widgets.ToolItem;
+import dwtx.core.runtime.IProgressMonitor;
+import dwtx.jface.dialogs.ProgressIndicator;
+import dwtx.jface.resource.ImageDescriptor;
+import dwtx.jface.resource.JFaceColors;
+import dwtx.jface.resource.JFaceResources;
+
+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.
+ * <p>
+ * 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.
+ * </p>
+ */
+/* package */class StatusLine : Composite, IProgressMonitor {
+
+    /** Horizontal gaps between items. */
+    public static const int GAP = 3;
+
+    /** Progress bar creation is delayed by this ms */
+    public static const int DELAY_PROGRESS = 500;
+
+    /** visibility state of the progressbar */
+    protected bool fProgressIsVisible = false;
+
+    /** visibility state of the cancle button */
+    protected bool fCancelButtonIsVisible = false;
+
+    /** enablement state of the cancle button */
+    protected bool fCancelEnabled = false;
+
+    /** name of the task */
+    protected String fTaskName;
+
+    /** is the task is cancled */
+    protected bool fIsCanceled;
+
+    /** the start time of the task */
+    protected long fStartTime;
+
+    private Cursor fStopButtonCursor;
+
+    /** the message text */
+    protected String fMessageText;
+
+    /** the message image */
+    protected Image fMessageImage;
+
+    /** the error text */
+    protected String fErrorText;
+
+    /** the error image */
+    protected Image fErrorImage;
+
+    /** the message label */
+    protected CLabel fMessageLabel;
+
+    /** the composite parent of the progress bar */
+    protected Composite fProgressBarComposite;
+
+    /** the progress bar */
+    protected ProgressIndicator fProgressBar;
+
+    /** the toolbar */
+    protected ToolBar fToolBar;
+
+    /** the cancle button */
+    protected ToolItem fCancelButton;
+
+    /** stop image descriptor */
+    protected static ImageDescriptor fgStopImage;
+
+    static this() {
+        JFaceResources.getImageRegistry().put(
+                "dwtx.jface.parts.StatusLine.stopImage", fgStopImage);//$NON-NLS-1$
+        fgStopImage = ImageDescriptor
+            .createFromFile(StatusLine.classinfo, "images/stop.gif");//$NON-NLS-1$
+    }
+
+    /**
+     * Layout the contribution item controls on the status line.
+     */
+    public class StatusLineLayout : Layout {
+        private const StatusLineLayoutData DEFAULT_DATA;
+
+        this(){
+            DEFAULT_DATA = new StatusLineLayoutData();
+        }
+
+        public Point computeSize(Composite composite, int wHint, int hHint,
+                bool changed) {
+
+            if (wHint !is DWT.DEFAULT && hHint !is DWT.DEFAULT) {
+                return new Point(wHint, hHint);
+            }
+
+            Control[] children = composite.getChildren();
+            int totalWidth = 0;
+            int maxHeight = 0;
+            int totalCnt = 0;
+            for (int i = 0; i < children.length; i++) {
+                bool useWidth = true;
+                Control w = children[i];
+                if (w is fProgressBarComposite && !fProgressIsVisible) {
+                    useWidth = false;
+                } else if (w is fToolBar && !fCancelButtonIsVisible) {
+                    useWidth = false;
+                }
+                StatusLineLayoutData data = cast(StatusLineLayoutData) w
+                        .getLayoutData();
+                if (data is null) {
+                    data = DEFAULT_DATA;
+                }
+                Point e = w.computeSize(data.widthHint, data.heightHint,
+                        changed);
+                if (useWidth) {
+                    totalWidth += e.x;
+                    totalCnt++;
+                }
+                maxHeight = Math.max(maxHeight, e.y);
+            }
+            if (totalCnt > 0) {
+                totalWidth += (totalCnt - 1) * GAP;
+            }
+            if (totalWidth <= 0) {
+                totalWidth = maxHeight * 4;
+            }
+            return new Point(totalWidth, maxHeight);
+        }
+
+        public void layout(Composite composite, bool flushCache) {
+
+            if (composite is null) {
+                return;
+            }
+
+            // StatusLineManager skips over the standard status line widgets
+            // 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.
+            fMessageLabel.moveAbove(null);
+            fToolBar.moveBelow(fMessageLabel);
+            fProgressBarComposite.moveBelow(fToolBar);
+
+            Rectangle rect = composite.getClientArea();
+            Control[] children = composite.getChildren();
+            int count = children.length;
+
+            int ws[] = new int[count];
+
+            int h = rect.height;
+            int totalWidth = -GAP;
+            for (int i = 0; i < count; i++) {
+                Control w = children[i];
+                if (w is fProgressBarComposite && !fProgressIsVisible) {
+                    continue;
+                }
+                if (w is fToolBar && !fCancelButtonIsVisible) {
+                    continue;
+                }
+                StatusLineLayoutData data = cast(StatusLineLayoutData) w
+                        .getLayoutData();
+                if (data is null) {
+                    data = DEFAULT_DATA;
+                }
+                int width = w.computeSize(data.widthHint, h, flushCache).x;
+                ws[i] = width;
+                totalWidth += width + GAP;
+            }
+
+            int diff = rect.width - totalWidth;
+            ws[0] += diff; // make the first StatusLabel wider
+
+            // Check against minimum recommended width
+            final int msgMinWidth = rect.width / 3;
+            if (ws[0] < msgMinWidth) {
+                diff = ws[0] - msgMinWidth;
+                ws[0] = msgMinWidth;
+            } else {
+                diff = 0;
+            }
+
+            // Take space away from the contributions first.
+            for (int i = count - 1; i >= 0 && diff < 0; --i) {
+                int min = Math.min(ws[i], -diff);
+                ws[i] -= min;
+                diff += min + GAP;
+            }
+
+            int x = rect.x;
+            int y = rect.y;
+            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.
+                 *
+                 * 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) {
+                    w.setBounds(x + rect.width, y, ws[i], h);
+                    continue;
+                }
+                w.setBounds(x, y, ws[i], h);
+                if (ws[i] > 0) {
+                    x += ws[i] + GAP;
+                }
+            }
+        }
+    }
+
+    /**
+     * 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
+     */
+    public this(Composite parent, int style) {
+        super(parent, style);
+
+        addDisposeListener(new class DisposeListener {
+            public void widgetDisposed(DisposeEvent e) {
+                handleDispose();
+            }
+        });
+
+        // StatusLineManager skips over the standard status line widgets
+        // in its update method. There is thus a dependency
+        // between this code defining the creation and layout of the standard
+        // widgets and the update method.
+
+        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);
+
+        fProgressIsVisible = false;
+        fCancelEnabled = false;
+
+        fToolBar = new ToolBar(this, DWT.FLAT);
+        fCancelButton = new ToolItem(fToolBar, DWT.PUSH);
+        fCancelButton.setImage(fgStopImage.createImage());
+        fCancelButton.setToolTipText(JFaceResources
+                .getString("Cancel_Current_Operation")); //$NON-NLS-1$
+        fCancelButton.addSelectionListener(new class SelectionAdapter {
+            public void widgetSelected(SelectionEvent e) {
+                setCanceled(true);
+            }
+        });
+        fCancelButton.addDisposeListener(new class DisposeListener {
+            public void widgetDisposed(DisposeEvent e) {
+                Image i = fCancelButton.getImage();
+                if ((i !is null) && (!i.isDisposed())) {
+                    i.dispose();
+                }
+            }
+        });
+
+        // We create a composite to create the progress bar in
+        // so that it can be centered. See bug #32331
+        fProgressBarComposite = new Composite(this, DWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.horizontalSpacing = 0;
+        layout.verticalSpacing = 0;
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+        fProgressBarComposite.setLayout(layout);
+        fProgressBar = new ProgressIndicator(fProgressBarComposite);
+        fProgressBar.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
+                | GridData.GRAB_VERTICAL));
+
+        fStopButtonCursor = new Cursor(getDisplay(), DWT.CURSOR_ARROW);
+    }
+
+    /**
+     * 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.
+     */
+    public void beginTask(String name, int totalWork) {
+        long timestamp = System.currentTimeMillis();
+        fStartTime = timestamp;
+        bool animated = (totalWork is UNKNOWN || totalWork is 0);
+        // make sure the progress bar is made visible while
+        // the task is running. Fixes bug 32198 for the non-animated case.
+        Runnable timer = new class Runnable {
+            bool animated_;
+            long timestamp_;
+            this(){
+                animated_=animated;
+                timestamp_=timestamp;
+            }
+            public void run() {
+                this.outer.startTask(timestamp_, animated_);
+            }
+        };
+        if (fProgressBar is null) {
+            return;
+        }
+
+        fProgressBar.getDisplay().timerExec(DELAY_PROGRESS, timer);
+        if (!animated) {
+            fProgressBar.beginTask(totalWork);
+        }
+        if (name is null) {
+            fTaskName = "";//$NON-NLS-1$
+        } else {
+            fTaskName = name;
+        }
+        setMessage(fTaskName);
+    }
+
+    /**
+     * 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() {
+
+        fStartTime = 0;
+
+        if (fProgressBar !is null) {
+            fProgressBar.sendRemainingWork();
+            fProgressBar.done();
+        }
+        setMessage(null);
+
+        hideProgress();
+    }
+
+    /**
+     * Returns the status line's progress monitor
+     * @return {@link IProgressMonitor} the progress monitor
+     */
+    public IProgressMonitor getProgressMonitor() {
+        return this;
+    }
+
+    /**
+     * @private
+     */
+    protected void handleDispose() {
+        if (fStopButtonCursor !is null) {
+            fStopButtonCursor.dispose();
+            fStopButtonCursor = null;
+        }
+        if (fProgressBar !is null) {
+            fProgressBar.dispose();
+            fProgressBar = null;
+        }
+    }
+
+    /**
+     * Hides the Cancel button and ProgressIndicator.
+     * @private
+     */
+    protected void hideProgress() {
+
+        if (fProgressIsVisible && !isDisposed()) {
+            fProgressIsVisible = false;
+            fCancelEnabled = false;
+            fCancelButtonIsVisible = false;
+            if (fToolBar !is null && !fToolBar.isDisposed()) {
+                fToolBar.setVisible(false);
+            }
+            if (fProgressBarComposite !is null
+                    && !fProgressBarComposite.isDisposed()) {
+                fProgressBarComposite.setVisible(false);
+            }
+            layout();
+        }
+    }
+
+    /**
+     * @see IProgressMonitor#internalWorked(double)
+     */
+    public void internalWorked(double work) {
+        if (!fProgressIsVisible) {
+            if (System.currentTimeMillis() - fStartTime > DELAY_PROGRESS) {
+                showProgress();
+            }
+        }
+
+        if (fProgressBar !is null) {
+            fProgressBar.worked(work);
+        }
+    }
+
+    /**
+     * 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().
+     */
+    public bool isCanceled() {
+        return fIsCanceled;
+    }
+
+    /**
+     * 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
+     */
+    public bool isCancelEnabled() {
+        return fCancelEnabled;
+    }
+
+    /**
+     * 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;
+        if (fCancelButton !is null) {
+            fCancelButton.setEnabled(!b);
+        }
+    }
+
+    /**
+     * 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;
+        if (fProgressIsVisible && !fCancelButtonIsVisible && enabled) {
+            showButton();
+            layout();
+        }
+        if (fCancelButton !is null && !fCancelButton.isDisposed()) {
+            fCancelButton.setEnabled(enabled);
+        }
+    }
+
+    /**
+     * 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
+     */
+    public void setErrorMessage(String message) {
+        setErrorMessage(null, message);
+    }
+
+    /**
+     * 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
+     */
+    public void setErrorMessage(Image image, String message) {
+        fErrorText = trim(message);
+        fErrorImage = image;
+        updateMessageLabel();
+    }
+
+    /**
+     * Applies the given font to this status line.
+     */
+    public void setFont(Font font) {
+        super.setFont(font);
+        Control[] children = getChildren();
+        for (int i = 0; i < children.length; i++) {
+            children[i].setFont(font);
+        }
+    }
+
+    /**
+     * 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
+     */
+    public void setMessage(String message) {
+        setMessage(null, message);
+    }
+
+    /**
+     * 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
+     */
+    public void setMessage(Image image, String message) {
+        fMessageText = trim(message);
+        fMessageImage = image;
+        updateMessageLabel();
+    }
+
+    /**
+     * @see IProgressMonitor#setTaskName(java.lang.String)
+     */
+    public void setTaskName(String name) {
+        fTaskName = name;
+    }
+
+    /**
+     * Makes the Cancel button visible.
+     * @private
+     */
+    protected void showButton() {
+        if (fToolBar !is null && !fToolBar.isDisposed()) {
+            fToolBar.setVisible(true);
+            fToolBar.setEnabled(true);
+            fToolBar.setCursor(fStopButtonCursor);
+            fCancelButtonIsVisible = true;
+        }
+    }
+
+    /**
+     * Shows the Cancel button and ProgressIndicator.
+     * @private
+     */
+    protected void showProgress() {
+        if (!fProgressIsVisible && !isDisposed()) {
+            fProgressIsVisible = true;
+            if (fCancelEnabled) {
+                showButton();
+            }
+            if (fProgressBarComposite !is null
+                    && !fProgressBarComposite.isDisposed()) {
+                fProgressBarComposite.setVisible(true);
+            }
+            layout();
+        }
+    }
+
+    /**
+     * @private
+     */
+    void startTask(long timestamp, bool animated) {
+        if (!fProgressIsVisible && fStartTime is timestamp) {
+            showProgress();
+            if (animated) {
+                if (fProgressBar !is null && !fProgressBar.isDisposed()) {
+                    fProgressBar.beginAnimatedTask();
+                }
+            }
+        }
+    }
+
+    /**
+     * 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 text;
+        if (fTaskName.length is 0) {
+            text = name;
+        } else {
+            text = JFaceResources.format(
+                    "Set_SubTask", [ fTaskName, name ]);//$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.
+     */
+    String trim(String message) {
+        if (message is null) {
+            return null;
+        }
+        int cr = message.indexOf('\r');
+        int lf = message.indexOf('\n');
+        if (cr is -1 && lf is -1) {
+            return message;
+        }
+        int len;
+        if (cr is -1) {
+            len = lf;
+        } else if (lf is -1) {
+            len = cr;
+        } else {
+            len = Math.min(cr, lf);
+        }
+        return message.substring(0, len);
+    }
+
+    /**
+     * Updates the message label widget.
+     */
+    protected void updateMessageLabel() {
+        if (fMessageLabel !is null && !fMessageLabel.isDisposed()) {
+            Display display = fMessageLabel.getDisplay();
+            if ((fErrorText !is null && fErrorText.length > 0)
+                    || fErrorImage !is null) {
+                fMessageLabel.setForeground(JFaceColors.getErrorText(display));
+                fMessageLabel.setText(fErrorText);
+                fMessageLabel.setImage(fErrorImage);
+            } else {
+                fMessageLabel.setForeground(display
+                        .getSystemColor(DWT.COLOR_WIDGET_FOREGROUND));
+                fMessageLabel.setText(fMessageText is null ? "" : fMessageText); //$NON-NLS-1$
+                fMessageLabel.setImage(fMessageImage);
+            }
+        }
+    }
+
+    /**
+     * @see IProgressMonitor#worked(int)
+     */
+    public void worked(int work) {
+        internalWorked(work);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/action/StatusLineLayoutData.d	Thu Apr 03 05:03:09 2008 +0200
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+
+module dwtx.jface.action.StatusLineLayoutData;
+
+import dwt.DWT;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Represents the layout data object for <code>Control</code> within the status line.
+ * To set a <code>StatusLineLayoutData</code> object into a <code>Control</code>, use
+ * the <code>setLayoutData()</code> method.
+ * <p>
+ * NOTE: Do not reuse <code>StatusLineLayoutData</code> objects. Every control in the
+ * status line must have a unique <code>StatusLineLayoutData</code> instance or
+ * <code>null</code>.
+ * </p>
+ *
+ * @since 2.1
+ */
+public class StatusLineLayoutData {
+    /**
+     * The <code>widthHint</code> specifies a minimum width for
+     * the <code>Control</code>. A value of <code>DWT.DEFAULT</code>
+     * indicates that no minimum width is specified.
+     *
+     * The default value is <code>DWT.DEFAULT</code>.
+     */
+    public int widthHint = DWT.DEFAULT;
+
+    /**
+     * The <code>heightHint</code> specifies a minimum height for
+     * the <code>Control</code>. A value of <code>DWT.DEFAULT</code>
+     * indicates that no minimum height is specified.
+     *
+     * The default value is <code>DWT.DEFAULT</code>.
+     */
+    public int heightHint = DWT.DEFAULT;
+
+    /**
+     * Creates an initial status line layout data object.
+     */
+    public this() {
+        //super();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/action/StatusLineManager.d	Thu Apr 03 05:03:09 2008 +0200
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.action.StatusLineManager;
+
+import dwtx.jface.action.ContributionManager;
+import dwtx.jface.action.IStatusLineManager;
+import dwtx.jface.action.GroupMarker;
+import dwtx.jface.action.StatusLine;
+import dwtx.jface.action.IContributionManager;
+import dwtx.jface.action.IContributionItem;
+
+import dwt.DWT;
+import dwt.graphics.Image;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwtx.core.runtime.IProgressMonitor;
+import dwtx.core.runtime.IProgressMonitorWithBlocking;
+import dwtx.core.runtime.IStatus;
+
+import dwt.dwthelper.utils;
+
+/**
+ * A status line manager is a contribution manager which realizes itself and its items
+ * in a status line control.
+ * <p>
+ * This class may be instantiated; it may also be subclassed if a more
+ * sophisticated layout is required.
+ * </p>
+ */
+public class StatusLineManager : ContributionManager,
+        IStatusLineManager {
+
+    /**
+     * Identifier of group marker used to position contributions at the beginning
+     * of the status line.
+     *
+     * @since 3.0
+     */
+    public static const String BEGIN_GROUP = "BEGIN_GROUP"; //$NON-NLS-1$
+
+    /**
+     * Identifier of group marker used to position contributions in the middle
+     * of the status line.
+     *
+     * @since 3.0
+     */
+    public static const String MIDDLE_GROUP = "MIDDLE_GROUP"; //$NON-NLS-1$
+
+    /**
+     * Identifier of group marker used to position contributions at the end
+     * of the status line.
+     *
+     * @since 3.0
+     */
+    public static const String END_GROUP = "END_GROUP"; //$NON-NLS-1$
+
+    /**
+     * The status line control; <code>null</code> before
+     * creation and after disposal.
+     */
+    private Composite statusLine = null;
+
+    /**
+     * Creates a new status line manager.
+     * Use the <code>createControl</code> method to create the
+     * status line control.
+     */
+    public this() {
+        add(new GroupMarker(BEGIN_GROUP));
+        add(new GroupMarker(MIDDLE_GROUP));
+        add(new GroupMarker(END_GROUP));
+    }
+
+    /**
+     * Creates and returns this manager's status line control.
+     * Does not create a new control if one already exists.
+     * <p>
+     * Note: Since 3.0 the return type is <code>Control</code>.  Before 3.0, the return type was
+     *   the package-private class <code>StatusLine</code>.
+     * </p>
+     *
+     * @param parent the parent control
+     * @return the status line control
+     */
+    public Control createControl(Composite parent) {
+        return createControl(parent, DWT.NONE);
+    }
+
+    /**
+     * Creates and returns this manager's status line control.
+     * Does not create a new control if one already exists.
+     *
+     * @param parent the parent control
+     * @param style the style for the control
+     * @return the status line control
+     * @since 3.0
+     */
+    public Control createControl(Composite parent, int style) {
+        if (!statusLineExist() && parent !is null) {
+            statusLine = new StatusLine(parent, style);
+            update(false);
+        }
+        return statusLine;
+    }
+
+    /**
+     * Disposes of this status line manager and frees all allocated DWT resources.
+     * Notifies all contribution items of the dispose. Note that this method does
+     * not clean up references between this status line manager and its associated
+     * contribution items. Use <code>removeAll</code> for that purpose.
+     */
+    public void dispose() {
+        if (statusLineExist()) {
+            statusLine.dispose();
+        }
+        statusLine = null;
+
+        IContributionItem items[] = getItems();
+        for (int i = 0; i < items.length; i++) {
+            items[i].dispose();
+        }
+    }
+
+    /**
+     * Returns the control used by this StatusLineManager.
+     *
+     * @return the control used by this manager
+     */
+    public Control getControl() {
+        return statusLine;
+    }
+
+    /**
+     * Returns the progress monitor delegate. Override this method
+     * to provide your own object used to handle progress.
+     *
+     * @return the IProgressMonitor delegate
+     * @since 3.0
+     */
+    protected IProgressMonitor getProgressMonitorDelegate() {
+        return cast(IProgressMonitor) getControl();
+    }
+
+    /*
+     * (non-Javadoc)
+     * Method declared on IStatusLineManager
+     */
+    public IProgressMonitor getProgressMonitor() {
+
+        return new class IProgressMonitorWithBlocking {
+
+            IProgressMonitor progressDelegate;
+            this(){
+                progressDelegate = getProgressMonitorDelegate();
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitor#beginTask(java.lang.String, int)
+             */
+            public void beginTask(String name, int totalWork) {
+                progressDelegate.beginTask(name, totalWork);
+
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitor#done()
+             */
+            public void done() {
+                progressDelegate.done();
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitor#internalWorked(double)
+             */
+            public void internalWorked(double work) {
+                progressDelegate.internalWorked(work);
+
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitor#isCanceled()
+             */
+            public bool isCanceled() {
+                return progressDelegate.isCanceled();
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitor#setCanceled(bool)
+             */
+            public void setCanceled(bool value) {
+                //Don't bother updating for disposed status
+                if (statusLine.isDisposed()) {
+                    return;
+                }
+                progressDelegate.setCanceled(value);
+
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitor#setTaskName(java.lang.String)
+             */
+            public void setTaskName(String name) {
+                progressDelegate.setTaskName(name);
+
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitor#subTask(java.lang.String)
+             */
+            public void subTask(String name) {
+                progressDelegate.subTask(name);
+
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitor#worked(int)
+             */
+            public void worked(int work) {
+                progressDelegate.worked(work);
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitorWithBlocking#clearBlocked()
+             */
+            public void clearBlocked() {
+                //Do nothing here as we let the modal context handle it
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.IProgressMonitorWithBlocking#setBlocked(dwtx.core.runtime.IStatus)
+             */
+            public void setBlocked(IStatus reason) {
+                //          Do nothing here as we let the modal context handle it
+            }
+        };
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IStatueLineManager
+     */
+    public bool isCancelEnabled() {
+        return statusLineExist() && (cast(StatusLine) statusLine).isCancelEnabled();
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IStatueLineManager
+     */
+    public void setCancelEnabled(bool enabled) {
+        if (statusLineExist()) {
+            (cast(StatusLine) statusLine).setCancelEnabled(enabled);
+        }
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IStatusLineManager.
+     */
+    public void setErrorMessage(String message) {
+        if (statusLineExist()) {
+            (cast(StatusLine) statusLine).setErrorMessage(message);
+        }
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IStatusLineManager.
+     */
+    public void setErrorMessage(Image image, String message) {
+        if (statusLineExist()) {
+            (cast(StatusLine) statusLine).setErrorMessage(image, message);
+        }
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IStatusLineManager.
+     */
+    public void setMessage(String message) {
+        if (statusLineExist()) {
+            (cast(StatusLine) statusLine).setMessage(message);
+        }
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IStatusLineManager.
+     */
+    public void setMessage(Image image, String message) {
+        if (statusLineExist()) {
+            (cast(StatusLine) statusLine).setMessage(image, message);
+        }
+    }
+
+    /**
+     * Returns whether the status line control is created
+     * and not disposed.
+     *
+     * @return <code>true</code> if the control is created
+     *  and not disposed, <code>false</code> otherwise
+     */
+    private bool statusLineExist() {
+        return statusLine !is null && !statusLine.isDisposed();
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IContributionManager.
+     */
+    public void update(bool force) {
+
+        //bool DEBUG= false;
+
+        if (isDirty() || force) {
+
+            if (statusLineExist()) {
+                statusLine.setRedraw(false);
+
+                // NOTE: the update algorithm is non-incremental.
+                // An incremental algorithm requires that DWT items can be created in the middle of the list
+                // but the ContributionItem.fill(Composite) method used here does not take an index, so this
+                // is not possible.
+
+                Control ws[] = statusLine.getChildren();
+                for (int i = 0; i < ws.length; i++) {
+                    Control w = ws[i];
+                    Object data = w.getData();
+                    if (cast(IContributionItem) data ) {
+                        w.dispose();
+                    }
+                }
+
+                int oldChildCount = statusLine.getChildren().length;
+                IContributionItem[] items = getItems();
+                for (int i = 0; i < items.length; ++i) {
+                    IContributionItem ci = items[i];
+                    if (ci.isVisible()) {
+                        ci.fill(statusLine);
+                        // associate controls with contribution item
+                        Control[] newChildren = statusLine.getChildren();
+                        for (int j = oldChildCount; j < newChildren.length; j++) {
+                            newChildren[j].setData(cast(Object)ci);
+                        }
+                        oldChildCount = newChildren.length;
+                    }
+                }
+
+                setDirty(false);
+
+                statusLine.layout();
+                statusLine.setRedraw(true);
+            }
+        }
+    }
+
+}