org.eclipse.jface.window.ApplicationWindow Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2000, 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
* Roman Dawydkin - bug 55116
*******************************************************************************/
package org.eclipse.jface.window;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.CoolBarManager;
import org.eclipse.jface.action.ICoolBarManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.StatusLineManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.internal.provisional.action.ICoolBarManager2;
import org.eclipse.jface.internal.provisional.action.IToolBarManager2;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.operation.ModalContext;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.Util;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.Decorations;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
/**
* An application window is a high-level "main window", with built-in support
* for an optional menu bar with standard menus, an optional toolbar, and an
* optional status line.
*
* Creating an application window involves the following steps:
*
*
* - creating an instance of
ApplicationWindow
* - assigning the window to a window manager (optional)
* - opening the window by calling
open
*
*
* Only on the last step, when the window is told to open, are the window's
* shell and widget tree created. When the window is closed, the shell and
* widget tree are disposed of and are no longer referenced, and the window is
* automatically removed from its window manager. Like all windows, an
* application window may be reopened.
*
*
* An application window is also a suitable context in which to perform
* long-running operations (that is, it implements
* IRunnableContext
).
*
*/
public class ApplicationWindow extends Window implements IRunnableContext {
/**
* Menu bar manager, or null
if none (default).
*
* @see #addMenuBar
*/
private MenuManager menuBarManager = null;
/**
* Tool bar manager, or null
if none (default).
*
* @see #addToolBar
*/
private IToolBarManager toolBarManager = null;
/**
* Status line manager, or null
if none (default).
*
* @see #addStatusLine
*/
private StatusLineManager statusLineManager = null;
/**
* Cool bar manager, or null
if none (default).
*
* @see #addCoolBar
* @since 3.0
*/
private ICoolBarManager coolBarManager = null;
/**
* The seperator between the menu bar and the rest of the window.
*/
protected Label seperator1;
/**
* A flag indicating that an operation is running.
*/
private boolean operationInProgress = false;
/**
* Internal application window layout class.
* This vertical layout supports a tool bar area (fixed size),
* a separator line, the content area (variable size), and a
* status line (fixed size).
*/
/*package*/class ApplicationWindowLayout extends Layout {
static final int VGAP = 2;
static final int BAR_SIZE = 23;
@Override
protected Point computeSize(Composite composite, int wHint, int hHint,
boolean flushCache) {
if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) {
return new Point(wHint, hHint);
}
Point result = new Point(0, 0);
Control[] ws = composite.getChildren();
for (int i = 0; i < ws.length; i++) {
Control w = ws[i];
boolean hide = false;
if (getToolBarControl() == w) {
if (!toolBarChildrenExist()) {
hide = true;
result.y += BAR_SIZE; // REVISIT
}
} else if (getCoolBarControl() == w) {
if (!coolBarChildrenExist()) {
hide = true;
result.y += BAR_SIZE;
}
} else if (statusLineManager != null
&& statusLineManager.getControl() == w) {
} else if (i > 0) { /* we assume this window is contents */
hide = false;
}
if (!hide) {
Point e = w.computeSize(wHint, hHint, flushCache);
result.x = Math.max(result.x, e.x);
result.y += e.y + VGAP;
}
}
if (wHint != SWT.DEFAULT) {
result.x = wHint;
}
if (hHint != SWT.DEFAULT) {
result.y = hHint;
}
return result;
}
@Override
protected void layout(Composite composite, boolean flushCache) {
Rectangle clientArea = composite.getClientArea();
Control[] ws = composite.getChildren();
// Lay out the separator, the tool bar control, the cool bar control, the status line, and the page composite.
// The following code assumes that the page composite is the last child, and that there are no unexpected other controls.
for (Control w : ws) {
if (w == seperator1) { // Separator
Point e = w.computeSize(SWT.DEFAULT, SWT.DEFAULT,
flushCache);
w.setBounds(clientArea.x, clientArea.y, clientArea.width,
e.y);
clientArea.y += e.y;
clientArea.height -= e.y;
} else if (getToolBarControl() == w) {
if (toolBarChildrenExist()) {
Point e = w.computeSize(SWT.DEFAULT, SWT.DEFAULT,
flushCache);
w.setBounds(clientArea.x, clientArea.y,
clientArea.width, e.y);
clientArea.y += e.y + VGAP;
clientArea.height -= e.y + VGAP;
}
} else if (getCoolBarControl() == w) {
if (coolBarChildrenExist()) {
Point e = w.computeSize(clientArea.width, SWT.DEFAULT,
flushCache);
w.setBounds(clientArea.x, clientArea.y,
clientArea.width, e.y);
clientArea.y += e.y + VGAP;
clientArea.height -= e.y + VGAP;
}
} else if (statusLineManager != null
&& statusLineManager.getControl() == w) {
Point e = w.computeSize(SWT.DEFAULT, SWT.DEFAULT,
flushCache);
w.setBounds(clientArea.x, clientArea.y + clientArea.height
- e.y, clientArea.width, e.y);
clientArea.height -= e.y + VGAP;
} else {
w.setBounds(clientArea.x, clientArea.y + VGAP,
clientArea.width, clientArea.height - VGAP);
}
}
}
}
/**
* Return the top seperator.
* @return Label
*/
protected Label getSeperator1() {
return seperator1;
}
/**
* Create an application window instance, whose shell will be created under the
* given parent shell.
* Note that the window will have no visual representation (no widgets)
* until it is told to open. By default, open
does not block.
*
* @param parentShell the parent shell, or null
to create a top-level shell
*/
public ApplicationWindow(Shell parentShell) {
super(parentShell);
}
/**
* Configures this window to have a menu bar.
* Does nothing if it already has one.
* This method must be called before this window's shell is created.
*/
protected void addMenuBar() {
if ((getShell() == null) && (menuBarManager == null)) {
menuBarManager = createMenuManager();
}
}
/**
* Configures this window to have a status line.
* Does nothing if it already has one.
* This method must be called before this window's shell is created.
*/
protected void addStatusLine() {
if ((getShell() == null) && (statusLineManager == null)) {
statusLineManager = createStatusLineManager();
}
}
/**
* Configures this window to have a tool bar.
* Does nothing if it already has one.
* This method must be called before this window's shell is created.
* @param style swt style bits used to create the Toolbar
* @see ToolBarManager#ToolBarManager(int)
* @see ToolBar for style bits
*/
protected void addToolBar(int style) {
if ((getShell() == null) && (toolBarManager == null)
&& (coolBarManager == null)) {
toolBarManager = createToolBarManager2(style);
}
}
/**
* Configures this window to have a cool bar.
* Does nothing if it already has one.
* This method must be called before this window's shell is created.
*
* @param style the cool bar style
* @since 3.0
*/
protected void addCoolBar(int style) {
if ((getShell() == null) && (toolBarManager == null)
&& (coolBarManager == null)) {
coolBarManager = createCoolBarManager2(style);
}
}
@Override
protected boolean canHandleShellCloseEvent() {
return super.canHandleShellCloseEvent() && !operationInProgress;
}
@Override
public boolean close() {
if (operationInProgress) {
return false;
}
if (super.close()) {
if (menuBarManager != null) {
menuBarManager.dispose();
menuBarManager = null;
}
if (toolBarManager != null) {
if (toolBarManager instanceof IToolBarManager2) {
((IToolBarManager2) toolBarManager).dispose();
} else if (toolBarManager instanceof ToolBarManager) {
((ToolBarManager) toolBarManager).dispose();
}
toolBarManager.removeAll();
toolBarManager = null;
}
if (statusLineManager != null) {
statusLineManager.dispose();
statusLineManager.removeAll();
statusLineManager = null;
}
if (coolBarManager != null) {
if (coolBarManager instanceof ICoolBarManager2) {
((ICoolBarManager2) coolBarManager).dispose();
} else if (coolBarManager instanceof CoolBarManager) {
((CoolBarManager) coolBarManager).dispose();
}
coolBarManager.removeAll();
coolBarManager = null;
}
return true;
}
return false;
}
/**
* Extends the super implementation by creating the trim widgets using createTrimWidgets
.
*/
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
createTrimWidgets(shell);
}
/**
* Creates the trim widgets around the content area.
*
* @param shell the shell
* @since 3.0
*/
protected void createTrimWidgets(Shell shell) {
if (menuBarManager != null) {
boolean resizeHasOccurredBackup = this.resizeHasOccurred;
shell.setMenuBar(menuBarManager.createMenuBar((Decorations) shell));
this.resizeHasOccurred = resizeHasOccurredBackup;
menuBarManager.updateAll(true);
}
if (showTopSeperator()) {
seperator1 = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
}
// will create either a cool bar or a tool bar
createToolBarControl(shell);
createCoolBarControl(shell);
createStatusLine(shell);
}
@Override
protected Layout getLayout() {
return new ApplicationWindowLayout();
}
/**
* Returns whether to show a top separator line between the menu bar
* and the rest of the window contents. On some platforms such as the Mac,
* the menu is separated from the main window already, so a separator line
* is not desired.
*
* @return true
to show the top separator, false
* to not show it
* @since 3.0
*/
protected boolean showTopSeperator() {
return !Util.isMac();
}
/**
* Create the status line if required.
*
* @param shell the shell to create status line into
*/
protected void createStatusLine(Shell shell) {
if (statusLineManager != null) {
statusLineManager.createControl(shell, SWT.NONE);
}
}
/**
* Returns a new menu manager for the window.
*
* Subclasses may override this method to customize the menu manager.
*
* @return a menu manager
*/
protected MenuManager createMenuManager() {
return new MenuManager();
}
/**
* Returns a new status line manager for the window.
*
* Subclasses may override this method to customize the status line manager.
*
* @return a status line manager
*/
protected StatusLineManager createStatusLineManager() {
return new StatusLineManager();
}
/**
* Returns a new tool bar manager for the window.
*
* Subclasses may override this method to customize the tool bar manager.
*
* @param style swt style bits used to create the Toolbar
*
* @return a tool bar manager
* @see ToolBarManager#ToolBarManager(int)
* @see ToolBar for style bits
*/
protected ToolBarManager createToolBarManager(int style) {
return new ToolBarManager(style);
}
/**
* Returns a new tool bar manager for the window.
*
* By default this method calls createToolBarManager
. Subclasses
* may override this method to provide an alternative implementation for the
* tool bar manager.
*
*
* @param style swt style bits used to create the Toolbar
*
* @return a tool bar manager
* @since 3.2
* @see #createToolBarManager(int)
*/
protected IToolBarManager createToolBarManager2(int style) {
return createToolBarManager(style);
}
/**
* Returns a new cool bar manager for the window.
*
* Subclasses may override this method to customize the cool bar manager.
*
*
* @param style swt style bits used to create the Coolbar
*
* @return a cool bar manager
* @since 3.0
* @see CoolBarManager#CoolBarManager(int)
* @see CoolBar for style bits
*/
protected CoolBarManager createCoolBarManager(int style) {
return new CoolBarManager(style);
}
/**
* Returns a new cool bar manager for the window.
*
* By default this method calls createCoolBarManager
. Subclasses
* may override this method to provide an alternative implementation for the
* cool bar manager.
*
*
* @param style swt style bits used to create the Coolbar
*
* @return a cool bar manager
* @since 3.2
* @see #createCoolBarManager(int)
*/
protected ICoolBarManager createCoolBarManager2(int style) {
return createCoolBarManager(style);
}
/**
* Creates the control for the tool bar manager.
*
* Subclasses may override this method to customize the tool bar manager.
*
* @param parent the parent used for the control
* @return a Control
*/
protected Control createToolBarControl(Composite parent) {
if (toolBarManager != null) {
if (toolBarManager instanceof IToolBarManager2) {
return ((IToolBarManager2) toolBarManager).createControl2(parent);
}
if (toolBarManager instanceof ToolBarManager) {
return ((ToolBarManager) toolBarManager).createControl(parent);
}
}
return null;
}
/**
* Creates the control for the cool bar manager.
*
* Subclasses may override this method to customize the cool bar manager.
*
* @param composite the parent used for the control
*
* @return an instance of CoolBar
* @since 3.0
*/
protected Control createCoolBarControl(Composite composite) {
if (coolBarManager != null) {
if (coolBarManager instanceof ICoolBarManager2) {
return ((ICoolBarManager2) coolBarManager).createControl2(composite);
}
if (coolBarManager instanceof CoolBarManager) {
return ((CoolBarManager) coolBarManager).createControl(composite);
}
}
return null;
}
/**
* Returns the default font used for this window.
*
* The default implementation of this framework method
* obtains the symbolic name of the font from the
* getSymbolicFontName
framework method
* and retrieves this font from JFace's font
* registry using JFaceResources.getFont
.
* Subclasses may override to use a different registry,
* etc.
*
*
* @return the default font, or null
if none
*/
protected Font getFont() {
return JFaceResources.getFont(getSymbolicFontName());
}
/**
* Returns the menu bar manager for this window (if it has one).
*
* @return the menu bar manager, or null
if
* this window does not have a menu bar
* @see #addMenuBar()
*/
public MenuManager getMenuBarManager() {
return menuBarManager;
}
/**
* Returns the status line manager for this window (if it has one).
*
* @return the status line manager, or null
if
* this window does not have a status line
* @see #addStatusLine
*/
protected StatusLineManager getStatusLineManager() {
return statusLineManager;
}
/**
* Returns the symbolic font name of the font to be
* used to display text in this window.
* This is not recommended and is included for backwards
* compatability.
* It is recommended to use the default font provided by
* SWT (that is, do not set the font).
*
* @return the symbolic font name
*/
public String getSymbolicFontName() {
return JFaceResources.TEXT_FONT;
}
/**
* Returns the tool bar manager for this window (if it has one).
*
* @return the tool bar manager, or null
if
* this window does not have a tool bar
* @see #addToolBar(int)
*/
public ToolBarManager getToolBarManager() {
if (toolBarManager instanceof ToolBarManager) {
return (ToolBarManager)toolBarManager;
}
return null;
}
/**
* Returns the tool bar manager for this window (if it has one).
*
* @return the tool bar manager, or null
if
* this window does not have a tool bar
* @see #addToolBar(int)
* @since 3.2
*/
public IToolBarManager getToolBarManager2() {
return toolBarManager;
}
/**
* Returns the cool bar manager for this window.
*
* @return the cool bar manager, or null
if
* this window does not have a cool bar
* @see #addCoolBar(int)
* @since 3.0
*/
public CoolBarManager getCoolBarManager() {
if (coolBarManager instanceof CoolBarManager) {
return (CoolBarManager)coolBarManager;
}
return null;
}
/**
* Returns the cool bar manager for this window.
*
* @return the cool bar manager, or null
if
* this window does not have a cool bar
* @see #addCoolBar(int)
* @since 3.2
*/
public ICoolBarManager getCoolBarManager2() {
return coolBarManager;
}
/**
* Returns the control for the window's toolbar.
*
* Subclasses may override this method to customize the tool bar manager.
*
* @return a Control
*/
protected Control getToolBarControl() {
if (toolBarManager != null) {
if (toolBarManager instanceof IToolBarManager2) {
return ((IToolBarManager2) toolBarManager).getControl2();
}
if (toolBarManager instanceof ToolBarManager) {
return ((ToolBarManager) toolBarManager).getControl();
}
}
return null;
}
/**
* Returns the control for the window's cool bar.
*
* Subclasses may override this method to customize the cool bar manager.
*
*
* @return an instance of CoolBar
* @since 3.0
*/
protected Control getCoolBarControl() {
if (coolBarManager != null) {
if (coolBarManager instanceof ICoolBarManager2) {
return ((ICoolBarManager2) coolBarManager).getControl2();
}
if (coolBarManager instanceof CoolBarManager) {
return ((CoolBarManager) coolBarManager).getControl();
}
}
return null;
}
/**
* This implementation of IRunnableContext#run(boolean, boolean,
* IRunnableWithProgress) blocks until the runnable has been run,
* regardless of the value of fork
.
* It is recommended that fork
is set to
* true in most cases. If fork
is set to false
,
* the runnable will run in the UI thread and it is the runnable's
* responsibility to call Display.readAndDispatch()
* to ensure UI responsiveness.
*/
@Override
public void run(final boolean fork, boolean cancelable,
final IRunnableWithProgress runnable)
throws InvocationTargetException, InterruptedException {
try {
operationInProgress = true;
final StatusLineManager mgr = getStatusLineManager();
if (mgr == null) {
runnable.run(new NullProgressMonitor());
return;
}
boolean cancelWasEnabled = mgr.isCancelEnabled();
final Control contents = getContents();
final Display display = contents.getDisplay();
Shell shell = getShell();
boolean contentsWasEnabled = contents.getEnabled();
MenuManager manager = getMenuBarManager();
Menu menuBar = null;
if (manager != null) {
menuBar = manager.getMenu();
manager = null;
}
boolean menuBarWasEnabled = false;
if (menuBar != null) {
menuBarWasEnabled = menuBar.getEnabled();
}
Control toolbarControl = getToolBarControl();
boolean toolbarWasEnabled = false;
if (toolbarControl != null) {
toolbarWasEnabled = toolbarControl.getEnabled();
}
Control coolbarControl = getCoolBarControl();
boolean coolbarWasEnabled = false;
if (coolbarControl != null) {
coolbarWasEnabled = coolbarControl.getEnabled();
}
// Disable the rest of the shells on the current display
Shell[] shells = display.getShells();
boolean[] enabled = new boolean[shells.length];
for (int i = 0; i < shells.length; i++) {
Shell current = shells[i];
if (current == shell) {
continue;
}
if (current != null && !current.isDisposed()) {
enabled[i] = current.getEnabled();
current.setEnabled(false);
}
}
Control currentFocus = display.getFocusControl();
try {
contents.setEnabled(false);
if (menuBar != null) {
menuBar.setEnabled(false);
}
if (toolbarControl != null) {
toolbarControl.setEnabled(false);
}
if (coolbarControl != null) {
coolbarControl.setEnabled(false);
}
mgr.setCancelEnabled(cancelable);
final Exception[] holder = new Exception[1];
BusyIndicator.showWhile(display, () -> {
try {
ModalContext.run(runnable, fork, mgr
.getProgressMonitor(), display);
} catch (InvocationTargetException | InterruptedException ie) {
holder[0] = ie;
}
});
if (holder[0] != null) {
if (holder[0] instanceof InvocationTargetException) {
throw (InvocationTargetException) holder[0];
} else if (holder[0] instanceof InterruptedException) {
throw (InterruptedException) holder[0];
}
}
} finally {
operationInProgress = false;
// Enable the rest of the shells on the current display
for (int i = 0; i < shells.length; i++) {
Shell current = shells[i];
if (current == shell) {
continue;
}
if (current != null && !current.isDisposed()) {
current.setEnabled(enabled[i]);
}
}
if (!contents.isDisposed()) {
contents.setEnabled(contentsWasEnabled);
}
if (menuBar != null && !menuBar.isDisposed()) {
menuBar.setEnabled(menuBarWasEnabled);
}
if (toolbarControl != null && !toolbarControl.isDisposed()) {
toolbarControl.setEnabled(toolbarWasEnabled);
}
if (coolbarControl != null && !coolbarControl.isDisposed()) {
coolbarControl.setEnabled(coolbarWasEnabled);
}
mgr.setCancelEnabled(cancelWasEnabled);
if (currentFocus != null && !currentFocus.isDisposed()) {
// It's necessary to restore focus after reenabling the controls
// because disabling them causes focus to jump elsewhere.
// Use forceFocus rather than setFocus to avoid SWT's
// search for children which can take focus, so focus
// ends up back on the actual control that previously had it.
currentFocus.forceFocus();
}
}
} finally {
operationInProgress = false;
}
}
/**
* Sets or clears the message displayed in this window's status
* line (if it has one). This method has no effect if the
* window does not have a status line.
*
* @param message the status message, or null
to clear it
*/
public void setStatus(String message) {
if (statusLineManager != null) {
statusLineManager.setMessage(message);
}
}
/**
* Returns whether or not children exist for the Application Window's toolbar
* control.
*
* @return boolean true if children exist, false otherwise
*/
protected boolean toolBarChildrenExist() {
Control toolControl = getToolBarControl();
if (toolControl instanceof ToolBar) {
return ((ToolBar) toolControl).getItemCount() > 0;
}
return false;
}
/**
* Returns whether or not children exist for this application window's
* cool bar control.
*
* @return boolean true if children exist, false otherwise
* @since 3.0
*/
protected boolean coolBarChildrenExist() {
Control coolControl = getCoolBarControl();
if (coolControl instanceof CoolBar) {
return ((CoolBar) coolControl).getItemCount() > 0;
}
return false;
}
}