blob: ecd29fbcb14d06caf94102b7e70b45930fb2d4bf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.window;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.runtime.NullProgressMonitor;
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.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;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.StatusLineManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.operation.ModalContext;
import org.eclipse.jface.resource.JFaceResources;
/**
* 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.
* <p>
* Creating an application window involves the following steps:
* <ul>
* <li>creating an instance of <code>ApplicationWindow</code>
* </li>
* <li>assigning the window to a window manager (optional)
* </li>
* <li>opening the window by calling <code>open</code>
* </li>
* </ul>
* 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.
* </p>
* <p>
* An application window is also a suitable context in which to perform
* long-running operations (that is, it implements <code>IRunnableContext</code>).
* </p>
*/
public class ApplicationWindow extends Window implements IRunnableContext {
/**
* Menu bar manager, or <code>null</code> if none (default).
*
* @see #addMenuBar
*/
private MenuManager menuBarManager = null;
/**
* Tool bar manager, or <code>null</code> if none (default).
*
* @see #addToolBar
*/
private ToolBarManager toolBarManager = null;
/**
* Status line manager, or <code>null</code> if none (default).
*
* @see #addStatusLine
*/
private StatusLineManager statusLineManager = 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;
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+= 23; // REVISIT
}
} 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;
}
protected void layout(Composite composite, boolean flushCache) {
Rectangle clientArea= composite.getClientArea();
Control[] ws= composite.getChildren();
for (int i= 0; i < ws.length; i++) {
Control w= ws[i];
if (i == 0) { // 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 (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, <code>open</code> does not block.
*
* @param parentShell the parent shell, or <code>null</code> 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.
*/
protected void addToolBar(int style) {
if ((getShell() == null) && (toolBarManager == null)) {
toolBarManager = createToolBarManager(style);
}
}
/* (non-Javadoc)
* Method declared on Window.
*/
protected boolean canHandleShellCloseEvent() {
return super.canHandleShellCloseEvent() && !operationInProgress;
}
/* (non-Javadoc)
* Method declared on Window.
*/
public boolean close() {
if(operationInProgress)
return false;
if (super.close()) {
menuBarManager = null;
toolBarManager = null;
statusLineManager = null;
return true;
}
return false;
}
/* (non-Javadoc)
* Method declared on Window.
* Sets the ApplicationWindows's content layout.
* This vertical layout supports a fixed size Toolbar area, a separator line,
* the variable size content area,
* and a fixed size status line.
*/
protected void configureShell(Shell shell) {
super.configureShell(shell);
if (menuBarManager != null) {
menuBarManager.updateAll(true);
shell.setMenuBar(menuBarManager.createMenuBar((Decorations)shell));
}
// we need a special layout
shell.setLayout(new ApplicationWindowLayout());
if (! "carbon".equals(SWT.getPlatform())) //$NON-NLS-1$
seperator1 = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
createToolBarControl(shell);
if (statusLineManager != null) {
statusLineManager.createControl(shell);
}
}
/**
* Returns a new menu manager for the window.
* <p>
* Subclasses may override this method to customize the menu manager.
* </p>
* @return a menu manager
*/
protected MenuManager createMenuManager() {
return new MenuManager();
}
/**
* Returns a new status line manager for the window.
* <p>
* Subclasses may override this method to customize the status line manager.
* </p>
* @return a status line manager
*/
protected StatusLineManager createStatusLineManager() {
return new StatusLineManager();
}
/**
* Returns a new tool bar manager for the window.
* <p>
* Subclasses may override this method to customize the tool bar manager.
* </p>
* @return a tool bar manager
*/
protected ToolBarManager createToolBarManager(int style) {
return new ToolBarManager(style);
}
/**
* Creates the control for the tool bar manager.
* <p>
* Subclasses may override this method to customize the tool bar manager.
* </p>
* @return a Control
*/
protected Control createToolBarControl(Shell shell) {
if (toolBarManager instanceof ToolBarManager) {
return ((ToolBarManager)toolBarManager).createControl(shell);
}
return null;
}
/**
* Returns the default font used for this window.
* <p>
* The default implementation of this framework method
* obtains the symbolic name of the font from the
* <code>getSymbolicFontName</code> framework method
* and retrieves this font from JFace's font
* registry using <code>JFaceResources.getFont</code>.
* Subclasses may override to use a different registry,
* etc.
* </p>
*
* @return the default font, or <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> if
* this window does not have a tool bar
* @see #addToolBar
*/
public ToolBarManager getToolBarManager() {
return toolBarManager;
}
/**
* Returns the control for the window's toolbar.
* <p>
* Subclasses may override this method to customize the tool bar manager.
* </p>
* @return a Control
*/
protected Control getToolBarControl() {
if (toolBarManager == null) return null;
if (toolBarManager instanceof ToolBarManager) {
return ((ToolBarManager)toolBarManager).getControl();
}
return null;
}
/* (non-Javadoc)
* Method declared on IRunnableContext.
*/
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.isEnabled();
Control toolbarControl = getToolBarControl();
boolean toolbarWasEnabled = false;
if (toolbarControl != null)
toolbarWasEnabled = toolbarControl.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);
mgr.setCancelEnabled(cancelable);
final Exception[] holder = new Exception[1];
BusyIndicator.showWhile(display, new Runnable() {
public void run() {
try {
ModalContext.run(runnable, fork, mgr.getProgressMonitor(), display);
} catch (InvocationTargetException ite) {
holder[0] = ite;
} catch (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);
mgr.setCancelEnabled(cancelWasEnabled);
if (currentFocus != null && !currentFocus.isDisposed()) currentFocus.setFocus();
}
} 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 <code>null</code> 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.
* <p>
* @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;
}
}