org.eclipse.jface.action.StatusLine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.jface Show documentation
Show all versions of org.eclipse.jface Show documentation
This is org.eclipse.jface jar used by Scout SDK
The newest version!
/*******************************************************************************
* Copyright (c) 2000, 2015 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
* Lars Vogel - Bug 440270
* Jan-Ove Weichel - Bug 475879
*******************************************************************************/
package org.eclipse.jface.action;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.ProgressIndicator;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceColors;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.Util;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.AccessibleControlAdapter;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
/**
* A StatusLine control is a SWT 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 extends Composite implements IProgressMonitor {
/** Horizontal gaps between items. */
public static final int GAP = 3;
/** Progress bar creation is delayed by this ms */
public static final int DELAY_PROGRESS = 500;
/** visibility state of the progressbar */
protected boolean fProgressIsVisible = false;
/** visibility state of the cancle button */
protected boolean fCancelButtonIsVisible = false;
/** enablement state of the cancle button */
protected boolean fCancelEnabled = false;
/** name of the task */
protected String fTaskName;
/** is the task is cancled */
protected volatile boolean 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 = ImageDescriptor
.createFromFile(StatusLine.class, "images/stop.png");//$NON-NLS-1$
private MenuItem copyMenuItem;
static {
JFaceResources.getImageRegistry().put(
"org.eclipse.jface.parts.StatusLine.stopImage", fgStopImage);//$NON-NLS-1$
}
/**
* Layout the contribution item controls on the status line.
*/
public class StatusLineLayout extends Layout {
private final StatusLineLayoutData DEFAULT_DATA = new StatusLineLayoutData();
@Override
public Point computeSize(Composite composite, int wHint, int hHint,
boolean changed) {
if (wHint != SWT.DEFAULT && hHint != SWT.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++) {
boolean useWidth = true;
Control w = children[i];
if (w == fProgressBarComposite && !fProgressIsVisible) {
useWidth = false;
} else if (w == fToolBar && !fCancelButtonIsVisible) {
useWidth = false;
}
StatusLineLayoutData data = (StatusLineLayoutData) w
.getLayoutData();
if (data == 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);
}
@Override
public void layout(Composite composite, boolean flushCache) {
if (composite == 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 == fProgressBarComposite && !fProgressIsVisible) {
continue;
}
if (w == fToolBar && !fCancelButtonIsVisible) {
continue;
}
StatusLineLayoutData data = (StatusLineLayoutData) w
.getLayoutData();
if (data == 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 == fProgressBarComposite && !fProgressIsVisible
|| w == 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 StatusLine(Composite parent, int style) {
super(parent, style);
getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() {
@Override
public void getRole(AccessibleControlEvent e) {
e.detail = ACC.ROLE_STATUSBAR;
}
});
addDisposeListener(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, SWT.NONE);// SWT.SHADOW_IN);
// this would need extra work to make this accessible
// from the workbench command framework.
Menu menu = new Menu(fMessageLabel);
fMessageLabel.setMenu(menu);
copyMenuItem = new MenuItem(menu, SWT.PUSH);
copyMenuItem.setText(JFaceResources.getString("copy")); //$NON-NLS-1$
copyMenuItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String text = fMessageLabel.getText();
if (text != null && text.length() > 0) {
text = LegacyActionTools.removeMnemonics(text);
Clipboard cp = new Clipboard(e.display);
cp.setContents(new Object[] { text },
new Transfer[] { TextTransfer.getInstance() });
cp.dispose();
}
}
});
fProgressIsVisible = false;
fCancelEnabled = false;
fToolBar = new ToolBar(this, SWT.FLAT);
fCancelButton = new ToolItem(fToolBar, SWT.PUSH);
fCancelButton.setImage(fgStopImage.createImage());
fCancelButton.setToolTipText(JFaceResources
.getString("Cancel_Current_Operation")); //$NON-NLS-1$
fCancelButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setCanceled(true);
}
});
fCancelButton.addDisposeListener(e -> {
Image i = fCancelButton.getImage();
if ((i != 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, SWT.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(), SWT.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.
*/
@Override
public void beginTask(String name, int totalWork) {
final long timestamp = System.currentTimeMillis();
fStartTime = timestamp;
final boolean animated = (totalWork == UNKNOWN || totalWork == 0);
// make sure the progress bar is made visible while
// the task is running. Fixes bug 32198 for the non-animated case.
Runnable timer = () -> StatusLine.this.startTask(timestamp, animated);
if (fProgressBar == null) {
return;
}
fProgressBar.getDisplay().timerExec(DELAY_PROGRESS, timer);
if (!animated) {
fProgressBar.beginTask(totalWork);
}
if (name == null) {
fTaskName = Util.ZERO_LENGTH_STRING;
} 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.
*/
@Override
public void done() {
fStartTime = 0;
if (fProgressBar != 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 != null) {
fStopButtonCursor.dispose();
fStopButtonCursor = null;
}
if (fProgressBar != null) {
fProgressBar.dispose();
fProgressBar = null;
}
}
/**
* Hides the Cancel button and ProgressIndicator.
*
*/
protected void hideProgress() {
if (fProgressIsVisible && !isDisposed()) {
fProgressIsVisible = false;
fCancelEnabled = false;
fCancelButtonIsVisible = false;
if (fToolBar != null && !fToolBar.isDisposed()) {
fToolBar.setVisible(false);
}
if (fProgressBarComposite != null
&& !fProgressBarComposite.isDisposed()) {
fProgressBarComposite.setVisible(false);
}
layout();
}
}
/**
* @see IProgressMonitor#internalWorked(double)
*/
@Override
public void internalWorked(double work) {
if (!fProgressIsVisible) {
if (System.currentTimeMillis() - fStartTime > DELAY_PROGRESS) {
showProgress();
}
}
if (fProgressBar != 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().
*/
@Override
public boolean 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 boolean 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.
*/
@Override
public void setCanceled(boolean b) {
fIsCanceled = b;
if (fCancelButton != 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(boolean enabled) {
fCancelEnabled = enabled;
if (fProgressIsVisible && !fCancelButtonIsVisible && enabled) {
showButton();
layout();
}
if (fCancelButton != 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.
*/
@Override
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)
*/
@Override
public void setTaskName(String name) {
if (name == null)
fTaskName = Util.ZERO_LENGTH_STRING;
else
fTaskName = name;
}
/**
* Makes the Cancel button visible.
*
*/
protected void showButton() {
if (fToolBar != null && !fToolBar.isDisposed()) {
fToolBar.setVisible(true);
fToolBar.setEnabled(true);
fToolBar.setCursor(fStopButtonCursor);
fCancelButtonIsVisible = true;
}
}
/**
* Shows the Cancel button and ProgressIndicator.
*
*/
protected void showProgress() {
if (!fProgressIsVisible && !isDisposed()) {
fProgressIsVisible = true;
if (fCancelEnabled) {
showButton();
}
if (fProgressBarComposite != null
&& !fProgressBarComposite.isDisposed()) {
fProgressBarComposite.setVisible(true);
}
layout();
}
}
/**
* @private
*/
void startTask(final long timestamp, final boolean animated) {
if (!fProgressIsVisible && fStartTime == timestamp) {
showProgress();
if (animated) {
if (fProgressBar != 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)
*/
@Override
public void subTask(String name) {
String newName;
if (name == null)
newName = Util.ZERO_LENGTH_STRING;
else
newName = name;
String text;
if (fTaskName == null || fTaskName.length() == 0) {
text = newName;
} else {
text = JFaceResources.format("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.
*/
String trim(String message) {
if (message == null) {
return null;
}
message = LegacyActionTools.escapeMnemonics(message);
int cr = message.indexOf('\r');
int lf = message.indexOf('\n');
if (cr == -1 && lf == -1) {
return message;
}
int len;
if (cr == -1) {
len = lf;
} else if (lf == -1) {
len = cr;
} else {
len = Math.min(cr, lf);
}
return message.substring(0, len);
}
/**
* Updates the message label widget.
*/
protected void updateMessageLabel() {
if (fMessageLabel != null && !fMessageLabel.isDisposed()) {
Display display = fMessageLabel.getDisplay();
if ((fErrorText != null && fErrorText.length() > 0)
|| fErrorImage != null) {
fMessageLabel.setForeground(JFaceColors.getErrorText(display));
fMessageLabel.setText(fErrorText);
fMessageLabel.setImage(fErrorImage);
} else {
fMessageLabel.setForeground(getForeground());
fMessageLabel.setText(fMessageText == null ? "" : fMessageText); //$NON-NLS-1$
fMessageLabel.setImage(fMessageImage);
}
if (copyMenuItem != null && !copyMenuItem.isDisposed()) {
String text = fMessageLabel.getText();
copyMenuItem.setEnabled(text != null && text.length() > 0);
}
}
}
/**
* @see IProgressMonitor#worked(int)
*/
@Override
public void worked(int work) {
internalWorked(work);
}
}