# HG changeset patch # User Frank Benoit # Date 1207191789 -7200 # Node ID 87d8cf0a30745ced061c604e6f74ddf7b9dba06c # Parent ca63e2bea4bf461c09617545a56a659d3c211a91 StatusLine diff -r ca63e2bea4bf -r 87d8cf0a3074 dwtx/jface/action/IStatusLineManager.d --- /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 + *******************************************************************************/ +module dwtx.jface.action.IStatusLineManager; + +import dwtx.jface.action.IContributionManager; + +import dwt.graphics.Image; +import dwtx.core.runtime.IProgressMonitor; + +import dwt.dwthelper.utils; + +/** + * The IStatusLineManager interface provides protocol + * for displaying messages on a status line, for monitoring progress, + * and for managing contributions to the status line. + *

+ * Note: An error message overrides the current message until + * the error message is cleared. + *

+ * This package also provides a concrete status line manager implementation, + * {@link StatusLineManager StatusLineManager}. + *

+ */ +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 true if the cancel button is enabled, or false if not + */ + public bool isCancelEnabled(); + + /** + * Sets whether the cancel button on the status line's progress monitor + * is enabled. + * + * @param enabled true if the cancel button is enabled, or false 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. + *

+ * An error message overrides the current message until the error + * message is cleared (set to null). + *

+ * + * @param message the error message, or null to clear + * the current error message. + */ + public void setErrorMessage(String message); + + /** + * Sets the image and error message to be displayed on the status line. + *

+ * An error message overrides the current message until the error + * message is cleared (set to null). + *

+ * + * @param image the image to use, or null for no image + * @param message the error message, or null 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. + *

+ * 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 null). + *

+ * + * @param message the message, or null for no message + */ + public void setMessage(String message); + + /** + * Sets the image and message to be displayed on the status line. + *

+ * 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 null). + *

+ * + * @param image the image to use, or null for no image + * @param message the message, or null for no message + */ + public void setMessage(Image image, String message); +} diff -r ca63e2bea4bf -r 87d8cf0a3074 dwtx/jface/action/StatusLine.d --- /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 + *******************************************************************************/ + +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. + *

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

+ *

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

+ */ +/* 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 true if the ProgressIndication provides UI for canceling + * a long running operation. + * @return 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 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 null 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 null for no image + * @param message the error message, or null for no error message + */ + public void setErrorMessage(Image image, String message) { + fErrorText = trim(message); + 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 null 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 null for no image + * @param message the message, or null 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); + } +} diff -r ca63e2bea4bf -r 87d8cf0a3074 dwtx/jface/action/StatusLineLayoutData.d --- /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 + *******************************************************************************/ + +module dwtx.jface.action.StatusLineLayoutData; + +import dwt.DWT; + +import dwt.dwthelper.utils; + +/** + * Represents the layout data object for Control within the status line. + * To set a StatusLineLayoutData object into a Control, use + * the setLayoutData() method. + *

+ * NOTE: Do not reuse StatusLineLayoutData objects. Every control in the + * status line must have a unique StatusLineLayoutData instance or + * null. + *

+ * + * @since 2.1 + */ +public class StatusLineLayoutData { + /** + * The widthHint specifies a minimum width for + * the Control. A value of DWT.DEFAULT + * indicates that no minimum width is specified. + * + * The default value is DWT.DEFAULT. + */ + public int widthHint = DWT.DEFAULT; + + /** + * The heightHint specifies a minimum height for + * the Control. A value of DWT.DEFAULT + * indicates that no minimum height is specified. + * + * The default value is DWT.DEFAULT. + */ + public int heightHint = DWT.DEFAULT; + + /** + * Creates an initial status line layout data object. + */ + public this() { + //super(); + } +} diff -r ca63e2bea4bf -r 87d8cf0a3074 dwtx/jface/action/StatusLineManager.d --- /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 + *******************************************************************************/ +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. + *

+ * This class may be instantiated; it may also be subclassed if a more + * sophisticated layout is required. + *

+ */ +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; null before + * creation and after disposal. + */ + private Composite statusLine = null; + + /** + * Creates a new status line manager. + * Use the createControl 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. + *

+ * Note: Since 3.0 the return type is Control. Before 3.0, the return type was + * the package-private class StatusLine. + *

+ * + * @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 removeAll 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 true if the control is created + * and not disposed, false 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); + } + } + } + +}