blob: b0c5dae7b37eb1944c699a045d2759f726eec718 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stefan Winkler <stefan@winklerweb.net> - Bug 430848
*******************************************************************************/
package org.eclipse.ui.splash;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.e4.ui.css.swt.CSSSWTConstants;
import org.eclipse.jface.dialogs.ProgressIndicator;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
/**
* Basic splash implementation that provides an absolute positioned progress bar
* and message string that is hooked up to a progress monitor.
*
* @since 3.3
*/
public abstract class BasicSplashHandler extends AbstractSplashHandler {
private static final String SPLASH_PROGRESS_PART_ID = "org-eclipse-ui-splash-progressPart"; //$NON-NLS-1$
private static final String SPLASH_PROGRESS_INDICATOR_ID = "org-eclipse-ui-splash-progressIndicator"; //$NON-NLS-1$
private static final String SPLASH_PROGRESS_TEXT_ID = "org-eclipse-ui-splash-progressText"; //$NON-NLS-1$
/**
* Hacks the progress monitor to have absolute positioning for its controls. In
* addition, all methods that access the controls will be wrapped in an
* asynchExec().
*/
class AbsolutePositionProgressMonitorPart extends ProgressMonitorPart {
public AbsolutePositionProgressMonitorPart(Composite parent) {
super(parent, null);
setLayout(null);
setCSSData();
}
private void setCSSData() {
this.setData(CSSSWTConstants.CSS_ID_KEY, SPLASH_PROGRESS_PART_ID);
fProgressIndicator.setData(CSSSWTConstants.CSS_ID_KEY, SPLASH_PROGRESS_INDICATOR_ID);
fLabel.setData(CSSSWTConstants.CSS_ID_KEY, SPLASH_PROGRESS_TEXT_ID);
}
public ProgressIndicator getProgressIndicator() {
return fProgressIndicator;
}
public Label getProgressText() {
return fLabel;
}
@Override
public void beginTask(final String name, final int totalWork) {
updateUI(() -> {
if (isDisposed())
return;
AbsolutePositionProgressMonitorPart.super.beginTask(name, totalWork);
});
}
@Override
public void done() {
updateUI(() -> {
if (isDisposed())
return;
AbsolutePositionProgressMonitorPart.super.done();
});
}
@Override
public void internalWorked(final double work) {
updateUI(() -> {
if (isDisposed())
return;
AbsolutePositionProgressMonitorPart.super.internalWorked(work);
});
}
@Override
public void setFont(final Font font) {
updateUI(() -> {
if (isDisposed())
return;
AbsolutePositionProgressMonitorPart.super.setFont(font);
});
}
@Override
protected void updateLabel() {
updateUI(() -> {
if (isDisposed())
return;
AbsolutePositionProgressMonitorPart.super.updateLabel();
});
}
}
private Color foreground = null;
private AbsolutePositionProgressMonitorPart monitor;
private Rectangle messageRect;
private Rectangle progressRect;
@Override
public IProgressMonitor getBundleProgressMonitor() {
if (monitor == null) {
Composite parent = new Composite(getSplash(), Window.getDefaultOrientation());
Point size = getSplash().getSize();
parent.setBounds(new Rectangle(0, 0, size.x, size.y));
monitor = new AbsolutePositionProgressMonitorPart(parent);
monitor.setSize(size);
if (progressRect != null)
monitor.getProgressIndicator().setBounds(progressRect);
else
monitor.getProgressIndicator().setVisible(false);
if (messageRect != null)
monitor.getProgressText().setBounds(messageRect);
else
monitor.getProgressText().setVisible(false);
if (foreground != null)
monitor.getProgressText().setForeground(foreground);
monitor.setBackgroundMode(SWT.INHERIT_FORCE);
monitor.setBackgroundImage(getSplash().getShell().getBackgroundImage());
}
return monitor;
}
/**
* Set the foreground text color. This method has no effect after
* {@link #getBundleProgressMonitor()} has been invoked.
*
* @param foregroundRGB the color
*/
protected void setForeground(RGB foregroundRGB) {
if (monitor != null)
return;
this.foreground = new Color(getSplash().getShell().getDisplay(), foregroundRGB);
}
/**
* Get the foreground text color. This color should not be disposed by callers.
*
* @return the foreground color
*/
protected Color getForeground() {
return foreground;
}
/**
* Set the location of the message text in the splash. This method has no effect
* after {@link #getBundleProgressMonitor()} has been invoked.
*
* @param messageRect the location of the message text
*/
protected void setMessageRect(Rectangle messageRect) {
this.messageRect = messageRect;
}
/**
* Set the location of the progress bar in the splash. This method has no effect
* after {@link #getBundleProgressMonitor()} has been invoked.
*
* @param progressRect the location of the progress bar
*/
protected void setProgressRect(Rectangle progressRect) {
this.progressRect = progressRect;
}
/**
* Get the composite on which any supplemental controls should be drawn. This
* will not have a layout set and clients are responsible for setting the
* location of child controls manually.
*
* <p>
* This method must be called in the
* {@link #init(org.eclipse.swt.widgets.Shell)} method of a subclasses to ensure
* proper creation of controls
* </p>
*
* <p>
* Please note that the default implementation of this method assumes that the
* {@link IProgressMonitor} returned from {@link #getBundleProgressMonitor()}
* can be safely casted to a {@link Composite}. If this is not the case this
* method must be reimplemented to reflect the new progress controls.
* </p>
*
* @see #init(org.eclipse.swt.widgets.Shell)
* @return the composite
*/
protected Composite getContent() {
return (Composite) getBundleProgressMonitor();
}
/**
* Perform some update on the splash. If called from a non-UI thread it will be
* wrapped by a runnable that may be run before the workbench has been fully
* realized.
*
* @param r the update runnable
* @throws Throwable
*/
private void updateUI(final Runnable r) {
Shell splashShell = getSplash();
if (splashShell == null || splashShell.isDisposed())
return;
Display display = splashShell.getDisplay();
if (Thread.currentThread() == display.getThread())
r.run(); // run immediatley if we're on the UI thread
else {
// wrapper with a StartupRunnable to ensure that it will run before
// the UI is fully initialized
StartupRunnable startupRunnable = new StartupRunnable() {
@Override
public void runWithException() throws Throwable {
r.run();
}
};
display.asyncExec(startupRunnable);
}
}
}