blob: c63adade446ca61f965bc02da8cd9e8ae5ceef76 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2007 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
* Chris Grindstaff <chris@gstaff.org> - Fix for bug 158016
* Tonny Madsen, RCP Company - bug 201055
*******************************************************************************/
package org.eclipse.ui.internal;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.HashMap;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CBanner;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.CoolItem;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPageListener;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PerspectiveAdapter;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
import org.eclipse.ui.internal.dnd.AbstractDropTarget;
import org.eclipse.ui.internal.dnd.DragUtil;
import org.eclipse.ui.internal.dnd.IDragOverListener;
import org.eclipse.ui.internal.dnd.IDropTarget;
import org.eclipse.ui.internal.layout.CacheWrapper;
import org.eclipse.ui.internal.layout.CellLayout;
import org.eclipse.ui.internal.layout.ITrimManager;
import org.eclipse.ui.internal.layout.IWindowTrim;
import org.eclipse.ui.internal.layout.LayoutUtil;
import org.eclipse.ui.internal.layout.Row;
import org.eclipse.ui.internal.util.PrefUtil;
import org.eclipse.ui.presentations.PresentationUtil;
/**
* A utility class to manage the perspective switcher. At some point, it might be nice to
* move all this into PerspectiveViewBar.
*
* @since 3.0
*/
public class PerspectiveSwitcher implements IWindowTrim {
/**
* The minimal width for the switcher (i.e. for the open button and chevron).
*/
private static final int MIN_WIDTH = 45;
/**
* The average width for each perspective button.
*/
private static final int ITEM_WIDTH = 80;
/**
* The minimum default width.
*/
private static final int MIN_DEFAULT_WIDTH = 160;
private IWorkbenchWindow window;
private CBanner topBar;
private int style;
private Composite parent;
private Composite trimControl;
private Label trimSeparator;
private GridData trimLayoutData;
private boolean trimVisible = false;
private int trimOldLength = 0;
private PerspectiveBarManager perspectiveBar;
private CoolBar perspectiveCoolBar;
private CacheWrapper perspectiveCoolBarWrapper;
private CoolItem coolItem;
private CacheWrapper toolbarWrapper;
// The menus are cached, so the radio buttons should not be disposed until
// the switcher is disposed.
private Menu popupMenu;
private Menu genericMenu;
private static final int INITIAL = -1;
private static final int TOP_RIGHT = 1;
private static final int TOP_LEFT = 2;
private static final int LEFT = 3;
private int currentLocation = INITIAL;
private IPreferenceStore apiPreferenceStore = PrefUtil
.getAPIPreferenceStore();
private IPropertyChangeListener propertyChangeListener;
private Listener popupListener = new Listener() {
public void handleEvent(Event event) {
if (event.type == SWT.MenuDetect) {
showPerspectiveBarPopup(new Point(event.x, event.y));
}
}
};
class ChangeListener extends PerspectiveAdapter implements IPageListener {
public void perspectiveOpened(IWorkbenchPage page,
IPerspectiveDescriptor perspective) {
if (findPerspectiveShortcut(perspective, page) == null) {
addPerspectiveShortcut(perspective, page);
}
}
public void perspectiveClosed(IWorkbenchPage page,
IPerspectiveDescriptor perspective) {
// Don't remove the shortcut if the workbench is
// closing. This causes a spurious 'layout' on the
// shell during close, leading to possible life-cycle issues
if (page != null && !page.getWorkbenchWindow().getWorkbench().isClosing()) {
removePerspectiveShortcut(perspective, page);
}
}
public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
selectPerspectiveShortcut(perspective, page, true);
}
public void perspectiveDeactivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
selectPerspectiveShortcut(perspective, page, false);
}
public void perspectiveSavedAs(IWorkbenchPage page,
IPerspectiveDescriptor oldPerspective,
IPerspectiveDescriptor newPerspective) {
updatePerspectiveShortcut(oldPerspective, newPerspective, page);
}
public void pageActivated(IWorkbenchPage page) {
}
public void pageClosed(IWorkbenchPage page) {
}
public void pageOpened(IWorkbenchPage page) {
}
}
private ChangeListener changeListener = new ChangeListener();
private Listener dragListener;
private IDragOverListener dragTarget;
private DisposeListener toolBarListener;
private IReorderListener reorderListener;
/**
* Creates an instance of the perspective switcher.
* @param window it's window
* @param topBar the CBanner to place this widget in
* @param style the widget style to use
*/
public PerspectiveSwitcher(IWorkbenchWindow window, CBanner topBar, int style) {
this.window = window;
this.topBar = topBar;
this.style = style;
setPropertyChangeListener();
// this listener will only be run when the Shell is being disposed
// and each WorkbenchWindow has its own PerspectiveSwitcher
toolBarListener = new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
dispose();
}
};
window.addPerspectiveListener(changeListener);
window.addPageListener(changeListener);
}
private static int convertLocation(String preference) {
if (IWorkbenchPreferenceConstants.TOP_RIGHT.equals(preference)) {
return TOP_RIGHT;
}
if (IWorkbenchPreferenceConstants.TOP_LEFT.equals(preference)) {
return TOP_LEFT;
}
if (IWorkbenchPreferenceConstants.LEFT.equals(preference)) {
return LEFT;
}
return TOP_RIGHT;
}
/**
* Create the contents of the receiver
* @param parent
*/
public void createControl(Composite parent) {
Assert.isTrue(this.parent == null);
this.parent = parent;
// set the initial location read from the preference
setPerspectiveBarLocation(PrefUtil.getAPIPreferenceStore().getString(
IWorkbenchPreferenceConstants.DOCK_PERSPECTIVE_BAR));
}
private void addPerspectiveShortcut(IPerspectiveDescriptor perspective,
IWorkbenchPage workbenchPage) {
if (perspectiveBar == null) {
return;
}
PerspectiveBarContributionItem item = new PerspectiveBarContributionItem(
perspective, workbenchPage);
perspectiveBar.addItem(item);
setCoolItemSize(coolItem);
// This is need to update the vertical size of the tool bar on GTK+ when
// using large fonts.
if (perspectiveBar != null) {
perspectiveBar.update(true);
}
if (currentLocation == LEFT) {
updatePerspectiveBar();
}
}
/**
* Find a contribution item that matches the perspective provided.
*
* @param perspective
* @param page
* @return the <code>IContributionItem</code> or null if no matches were found
*/
public IContributionItem findPerspectiveShortcut(
IPerspectiveDescriptor perspective, IWorkbenchPage page) {
if (perspectiveBar == null) {
return null;
}
IContributionItem[] items = perspectiveBar.getItems();
int length = items.length;
for (int i = 0; i < length; i++) {
IContributionItem item = items[i];
if (item instanceof PerspectiveBarContributionItem
&& ((PerspectiveBarContributionItem) item).handles(
perspective, page)) {
return item;
}
}
return null;
}
private void removePerspectiveShortcut(IPerspectiveDescriptor perspective,
IWorkbenchPage page) {
if (perspectiveBar == null) {
return;
}
IContributionItem item = findPerspectiveShortcut(perspective, page);
if (item != null) {
if (item instanceof PerspectiveBarContributionItem) {
perspectiveBar
.removeItem((PerspectiveBarContributionItem) item);
}
item.dispose();
perspectiveBar.update(false);
setCoolItemSize(coolItem);
if (currentLocation == LEFT) {
updatePerspectiveBar();
LayoutUtil.resize(perspectiveBar.getControl());
}
}
}
/**
* Locate the perspective bar according to the provided location
* @param preference the location to put the perspective bar at
*/
public void setPerspectiveBarLocation(String preference) {
// return if the control has not been created. createControl(...) will
// handle updating the state in that case
if (parent == null) {
return;
}
int newLocation = convertLocation(preference);
if (newLocation == currentLocation) {
return;
}
createControlForLocation(newLocation);
currentLocation = newLocation;
showPerspectiveBar();
if (newLocation == TOP_LEFT || newLocation == TOP_RIGHT) {
updatePerspectiveBar();
updateBarParent();
}
}
/**
* Make the perspective bar visible in its current location. This method
* should not be used unless the control has been successfully created.
*/
private void showPerspectiveBar() {
switch (currentLocation) {
case TOP_LEFT:
topBar.setRight(null);
topBar.setBottom(perspectiveCoolBarWrapper.getControl());
break;
case TOP_RIGHT:
topBar.setBottom(null);
topBar.setRight(perspectiveCoolBarWrapper.getControl());
topBar.setRightWidth(getDefaultWidth());
break;
case LEFT:
topBar.setBottom(null);
topBar.setRight(null);
LayoutUtil.resize(topBar);
getTrimManager().addTrim(SWT.LEFT, this);
break;
default:
return;
}
LayoutUtil.resize(perspectiveBar.getControl());
}
/**
* Returns the default width for the switcher.
*/
private int getDefaultWidth() {
String extras = PrefUtil.getAPIPreferenceStore().getString(
IWorkbenchPreferenceConstants.PERSPECTIVE_BAR_EXTRAS);
StringTokenizer tok = new StringTokenizer(extras, ", "); //$NON-NLS-1$
int numExtras = tok.countTokens();
int numPersps = Math.max(numExtras, 1); // assume initial perspective is also listed in extras
return Math.max(MIN_DEFAULT_WIDTH, MIN_WIDTH + (numPersps*ITEM_WIDTH));
}
/**
* Get the trim manager from the default workbench window. If the current
* workbench window is -not- the <code>WorkbenchWindow</code> then return null.
*
* @return The trim manager for the current workbench window
*/
private ITrimManager getTrimManager() {
if (window instanceof WorkbenchWindow)
return ((WorkbenchWindow)window).getTrimManager();
return null; // not using the default workbench window
}
/**
* Update the receiver
* @param force
*/
public void update(boolean force) {
if (perspectiveBar == null) {
return;
}
perspectiveBar.update(force);
if (currentLocation == LEFT) {
ToolItem[] items = perspectiveBar.getControl().getItems();
boolean shouldExpand = items.length > 0;
if (shouldExpand != trimVisible) {
perspectiveBar.getControl().setVisible(true);
trimVisible = shouldExpand;
}
if (items.length != trimOldLength) {
LayoutUtil.resize(trimControl);
trimOldLength = items.length;
}
}
}
private void selectPerspectiveShortcut(IPerspectiveDescriptor perspective,
IWorkbenchPage page, boolean selected) {
IContributionItem item = findPerspectiveShortcut(perspective, page);
if (item != null && (item instanceof PerspectiveBarContributionItem)) {
if (selected) {
// check if not visible and ensure visible
PerspectiveBarContributionItem contribItem = (PerspectiveBarContributionItem) item;
perspectiveBar.select(contribItem);
}
// select or de-select
((PerspectiveBarContributionItem) item).setSelection(selected);
}
}
private void updatePerspectiveShortcut(IPerspectiveDescriptor oldDesc,
IPerspectiveDescriptor newDesc, IWorkbenchPage page) {
IContributionItem item = findPerspectiveShortcut(oldDesc, page);
if (item != null && (item instanceof PerspectiveBarContributionItem)) {
((PerspectiveBarContributionItem) item).update(newDesc);
}
}
/**
* Answer the perspective bar manager
* @return the manager
*/
public PerspectiveBarManager getPerspectiveBar() {
return perspectiveBar;
}
/**
* Dispose resources being held by the receiver
*/
public void dispose() {
window.removePerspectiveListener(changeListener);
window.removePageListener(changeListener);
if (propertyChangeListener != null) {
apiPreferenceStore
.removePropertyChangeListener(propertyChangeListener);
propertyChangeListener = null;
}
unhookDragSupport();
disposeChildControls();
toolBarListener = null;
}
private void disposeChildControls() {
if (trimControl != null) {
trimControl.dispose();
trimControl = null;
}
if (trimSeparator != null) {
trimSeparator.dispose();
trimSeparator = null;
}
if (perspectiveCoolBar != null) {
perspectiveCoolBar.dispose();
perspectiveCoolBar = null;
}
if (toolbarWrapper != null) {
toolbarWrapper.dispose();
toolbarWrapper = null;
}
if (perspectiveBar != null) {
perspectiveBar.dispose();
perspectiveBar = null;
}
perspectiveCoolBarWrapper = null;
}
/**
* Ensures the control has been set for the argument location. If the
* control already exists and can be used the argument location, nothing
* happens. Updates the location attribute.
*
* @param newLocation
*/
private void createControlForLocation(int newLocation) {
// if there is a control, then perhaps it can be reused
if (perspectiveBar != null && perspectiveBar.getControl() != null
&& !perspectiveBar.getControl().isDisposed()) {
if (newLocation == LEFT && currentLocation == LEFT) {
return;
}
if ((newLocation == TOP_LEFT || newLocation == TOP_RIGHT)
&& (currentLocation == TOP_LEFT || currentLocation == TOP_RIGHT)) {
return;
}
}
if (perspectiveBar != null) {
perspectiveBar.getControl().removeDisposeListener(toolBarListener);
unhookDragSupport();
}
// otherwise dispose the current controls and make new ones
// First, make sure that the existing verion is removed from the trim layout
getTrimManager().removeTrim(this);
disposeChildControls();
if (newLocation == LEFT) {
createControlForLeft();
} else {
createControlForTop();
}
hookDragSupport();
perspectiveBar.getControl().addDisposeListener(toolBarListener);
}
/**
* Remove any drag and drop support and associated listeners hooked for the
* perspective switcher.
*/
private void unhookDragSupport() {
ToolBar bar = perspectiveBar.getControl();
if (bar == null || bar.isDisposed() || dragListener == null) {
return;
}
PresentationUtil.removeDragListener(bar, dragListener);
DragUtil.removeDragTarget(perspectiveBar.getControl(), dragTarget);
dragListener = null;
dragTarget = null;
}
/**
* Attach drag and drop support and associated listeners hooked for
* the perspective switcher.
*/
private void hookDragSupport() {
dragListener = new Listener() {
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
*/
public void handleEvent(Event event) {
ToolBar toolbar = perspectiveBar.getControl();
ToolItem item = toolbar.getItem(new Point(event.x, event.y));
if (item != null) {
//ignore the first item, which remains in position Zero
if (item.getData() instanceof PerspectiveBarNewContributionItem) {
return;
}
Rectangle bounds = item.getBounds();
Rectangle parentBounds = toolbar.getBounds();
bounds.x += parentBounds.x;
bounds.y += parentBounds.y;
startDragging(item.getData(), toolbar.getDisplay().map(toolbar, null, bounds));
} else {
//startDragging(toolbar, toolbar.getDisplay().map(toolbar, null, toolbar.getBounds()));
}
}
private void startDragging(Object widget, Rectangle bounds) {
if(!DragUtil.performDrag(widget, bounds, new Point(bounds.x, bounds.y), true)) {
//currently do nothing on a failed drag
}
}
};
dragTarget = new IDragOverListener() {
protected PerspectiveDropTarget perspectiveDropTarget;
class PerspectiveDropTarget extends AbstractDropTarget {
private PerspectiveBarContributionItem perspective;
private Point location;
/**
* @param location
* @param draggedObject
*/
public PerspectiveDropTarget(Object draggedObject,
Point location) {
update(draggedObject, location);
}
/**
*
* @param draggedObject
* @param location
*/
private void update(Object draggedObject, Point location) {
this.location = location;
this.perspective = (PerspectiveBarContributionItem) draggedObject;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.dnd.IDropTarget#drop()
*/
public void drop() {
ToolBar toolBar = perspectiveBar.getControl();
ToolItem item = toolBar.getItem(toolBar.getDisplay().map(
null, toolBar, location));
if (toolBar.getItem(0) == item) {
return;
}
ToolItem[] items = toolBar.getItems();
ToolItem droppedItem = null;
int dropIndex = -1;
for (int i = 0; i < items.length; i++) {
if (item == items[i]) {
dropIndex = i;
}
if (items[i].getData() == perspective) {
droppedItem = items[i];
}
}
if (dropIndex != -1 && droppedItem != null && (droppedItem != item)) {
PerspectiveBarContributionItem barItem = (PerspectiveBarContributionItem) droppedItem.getData();
// policy is to insert at the beginning so mirror the value when indicating a
// new position for the perspective
if (reorderListener != null) {
reorderListener.reorder(barItem.getPerspective(), Math.abs(dropIndex - (items.length - 1)));
}
perspectiveBar.relocate(barItem, dropIndex);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.dnd.IDropTarget#getCursor()
*/
public Cursor getCursor() {
return DragCursors.getCursor(DragCursors.CENTER);
}
boolean sameShell() {
return perspective.getToolItem().getParent().getShell().equals(perspectiveBar.getControl().getShell());
}
public Rectangle getSnapRectangle() {
ToolBar toolBar = perspectiveBar.getControl();
ToolItem item = toolBar.getItem(toolBar.getDisplay().map(
null, toolBar, location));
Rectangle bounds;
if (item != null && item != toolBar.getItem(0)) {
bounds = item.getBounds();
} else {
// it should not be possible to start a drag with item 0
return null;
}
return toolBar.getDisplay().map(toolBar, null, bounds);
}
}
public IDropTarget drag(Control currentControl,
Object draggedObject, Point position,
Rectangle dragRectangle) {
if (draggedObject instanceof PerspectiveBarContributionItem) {
if (perspectiveDropTarget == null) {
perspectiveDropTarget = new PerspectiveDropTarget(
draggedObject, position);
} else {
perspectiveDropTarget.update(draggedObject, position);
}
// do not support drag to perspective bars between shells.
if (!perspectiveDropTarget.sameShell()) {
return null;
}
return perspectiveDropTarget;
}// else if (draggedObject instanceof IPerspectiveBar) {
// return new PerspectiveBarDropTarget();
//}
return null;
}
};
PresentationUtil.addDragListener(perspectiveBar.getControl(),
dragListener);
DragUtil.addDragTarget(perspectiveBar.getControl(), dragTarget);
}
private void setPropertyChangeListener() {
propertyChangeListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
if (IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR
.equals(propertyChangeEvent.getProperty())) {
if (perspectiveBar == null) {
return;
}
updatePerspectiveBar();
updateBarParent();
}
}
};
apiPreferenceStore.addPropertyChangeListener(propertyChangeListener);
}
private void createControlForLeft() {
trimControl = new Composite(parent, SWT.NONE);
trimControl.setLayout(new CellLayout(1).setMargins(0, 0).setSpacing(3,
3).setDefaultRow(Row.fixed()).setDefaultColumn(Row.growing()));
perspectiveBar = createBarManager(SWT.VERTICAL);
perspectiveBar.createControl(trimControl);
perspectiveBar.getControl().addListener(SWT.MenuDetect, popupListener);
// trimSeparator = new Label(trimControl, SWT.SEPARATOR | SWT.HORIZONTAL);
// GridData sepData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING
// | GridData.HORIZONTAL_ALIGN_CENTER);
// sepData.widthHint = SEPARATOR_LENGTH;
// trimSeparator.setLayoutData(sepData);
// trimSeparator.setVisible(false);
trimLayoutData = new GridData(GridData.FILL_BOTH);
trimVisible = false;
perspectiveBar.getControl().setLayoutData(trimLayoutData);
}
private void createControlForTop() {
perspectiveBar = createBarManager(SWT.HORIZONTAL);
perspectiveCoolBarWrapper = new CacheWrapper(topBar);
perspectiveCoolBar = new CoolBar(
perspectiveCoolBarWrapper.getControl(), SWT.FLAT);
coolItem = new CoolItem(perspectiveCoolBar, SWT.DROP_DOWN);
toolbarWrapper = new CacheWrapper(perspectiveCoolBar);
perspectiveBar.createControl(toolbarWrapper.getControl());
coolItem.setControl(toolbarWrapper.getControl());
perspectiveCoolBar.setLocked(true);
perspectiveBar.setParent(perspectiveCoolBar);
perspectiveBar.update(true);
// adjust the toolbar size to display as many items as possible
perspectiveCoolBar.addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
setCoolItemSize(coolItem);
}
});
coolItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (e.detail == SWT.ARROW) {
if (perspectiveBar != null) {
perspectiveBar.handleChevron(e);
}
}
}
});
coolItem.setMinimumSize(0, 0);
perspectiveBar.getControl().addListener(SWT.MenuDetect, popupListener);
}
/**
* @param coolItem
*/
private void setCoolItemSize(final CoolItem coolItem) {
// there is no coolItem when the bar is on the left
if (currentLocation == LEFT) {
return;
}
ToolBar toolbar = perspectiveBar.getControl();
if (toolbar == null) {
return;
}
int rowHeight = 0;
ToolItem[] toolItems = toolbar.getItems();
for (int i = 0; i < toolItems.length; i++) {
rowHeight = Math.max(rowHeight, toolItems[i].getBounds().height);
}
Rectangle area = perspectiveCoolBar.getClientArea();
int rows = rowHeight <= 0 ? 1 : (int) Math.max(1, Math
.floor(area.height / rowHeight));
if (rows == 1 || (toolbar.getStyle() & SWT.WRAP) == 0
|| currentLocation == TOP_LEFT) {
Point p = toolbar.computeSize(SWT.DEFAULT, SWT.DEFAULT);
coolItem.setSize(coolItem.computeSize(p.x, p.y));
return;
}
Point offset = coolItem.computeSize(0, 0);
Point wrappedSize = toolbar.computeSize(area.width - offset.x,
SWT.DEFAULT);
int h = rows * rowHeight;
int w = wrappedSize.y <= h ? wrappedSize.x : wrappedSize.x + 1;
coolItem.setSize(coolItem.computeSize(w, h));
}
private void showPerspectiveBarPopup(Point pt) {
if (perspectiveBar == null) {
return;
}
// Get the tool item under the mouse.
ToolBar toolBar = perspectiveBar.getControl();
ToolItem toolItem = toolBar.getItem(toolBar.toControl(pt));
// Get the action for the tool item.
Object data = null;
if (toolItem != null){
data = toolItem.getData();
}
if (toolItem == null
|| !(data instanceof PerspectiveBarContributionItem)) {
if (genericMenu == null) {
Menu menu = new Menu(toolBar);
addDockOnSubMenu(menu);
addShowTextItem(menu);
genericMenu = menu;
}
// set the state of the menu items to match the preferences
genericMenu
.getItem(1)
.setSelection(
PrefUtil
.getAPIPreferenceStore()
.getBoolean(
IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR));
updateLocationItems(genericMenu.getItem(0).getMenu(),
currentLocation);
// Show popup menu.
genericMenu.setLocation(pt.x, pt.y);
genericMenu.setVisible(true);
return;
}
if (data == null || !(data instanceof PerspectiveBarContributionItem)) {
return;
}
PerspectiveBarContributionItem pbci = (PerspectiveBarContributionItem) data;
IPerspectiveDescriptor selectedPerspective = pbci.getPerspective();
// The perspective bar menu is created lazily here.
// Its data is set (each time) to the tool item, which refers to the SetPagePerspectiveAction
// which in turn refers to the page and perspective.
// It is important not to refer to the action, the page or the perspective directly
// since otherwise the menu hangs on to them after they are closed.
// By hanging onto the tool item instead, these references are cleared when the
// corresponding page or perspective is closed.
// See bug 11282 for more details on why it is done this way.
if (popupMenu != null) {
popupMenu.dispose();
popupMenu = null;
}
popupMenu = createPopup(toolBar, selectedPerspective);
popupMenu.setData(toolItem);
// Show popup menu.
popupMenu.setLocation(pt.x, pt.y);
popupMenu.setVisible(true);
}
/**
* @param persp the perspective
* @return <code>true</code> if the perspective is active in the active page
*/
private boolean perspectiveIsActive(IPerspectiveDescriptor persp) {
IWorkbenchPage page = window.getActivePage();
return page != null && persp.equals(page.getPerspective());
}
/**
* @param persp the perspective
* @return <code>true</code> if the perspective is open in the active page
*/
private boolean perspectiveIsOpen(IPerspectiveDescriptor persp) {
IWorkbenchPage page = window.getActivePage();
return page != null && Arrays.asList(page.getOpenPerspectives()).contains(persp);
}
private Menu createPopup(ToolBar toolBar, IPerspectiveDescriptor persp){
Menu menu = new Menu(toolBar);
if (perspectiveIsActive(persp)) {
addCustomizeItem(menu);
addSaveAsItem(menu);
addResetItem(menu);
}
if (perspectiveIsOpen(persp)) {
addCloseItem(menu);
}
new MenuItem(menu, SWT.SEPARATOR);
addDockOnSubMenu(menu);
addShowTextItem(menu);
return menu;
}
private void addCloseItem(Menu menu) {
MenuItem menuItem = new MenuItem(menu, SWT.NONE);
menuItem.setText(WorkbenchMessages.WorkbenchWindow_close);
window.getWorkbench().getHelpSystem().setHelp(menuItem,
IWorkbenchHelpContextIds.CLOSE_PAGE_ACTION);
menuItem.addSelectionListener(new SelectionAdapter() {
private static final String COMMAND_CLOSE_PERSP = "org.eclipse.ui.window.closePerspective"; //$NON-NLS-1$
private static final String PARAMETER_CLOSE_PERSP_ID = "org.eclipse.ui.window.closePerspective.perspectiveId"; //$NON-NLS-1$
public void widgetSelected(SelectionEvent e) {
ToolItem perspectiveToolItem = (ToolItem) popupMenu
.getData();
if (perspectiveToolItem != null
&& !perspectiveToolItem.isDisposed()) {
PerspectiveBarContributionItem item = (PerspectiveBarContributionItem) perspectiveToolItem
.getData();
IPerspectiveDescriptor persp = item.getPerspective();
ICommandService commandService = (ICommandService) window.getService(ICommandService.class);
Command command = commandService.getCommand(COMMAND_CLOSE_PERSP);
HashMap parameters = new HashMap();
parameters.put(PARAMETER_CLOSE_PERSP_ID, persp.getId());
ParameterizedCommand pCommand = ParameterizedCommand.generateCommand(command, parameters);
IHandlerService handlerService = (IHandlerService) window
.getService(IHandlerService.class);
try {
handlerService.executeCommand(pCommand, new Event());
} catch (ExecutionException e1) {
} catch (NotDefinedException e1) {
} catch (NotEnabledException e1) {
} catch (NotHandledException e1) {
}
}
}
});
}
/**
* @param direction one of <code>SWT.HORIZONTAL</code> or <code>SWT.VERTICAL</code>
*/
private PerspectiveBarManager createBarManager(int direction) {
PerspectiveBarManager barManager = new PerspectiveBarManager(style
| direction);
if (apiPreferenceStore.getBoolean(IWorkbenchPreferenceConstants.SHOW_OPEN_ON_PERSPECTIVE_BAR)) {
barManager.add(new PerspectiveBarNewContributionItem(window));
}
// add an item for all open perspectives
IWorkbenchPage page = window.getActivePage();
if (page != null) {
// these are returned with the most recently opened one first
IPerspectiveDescriptor[] perspectives = page
.getOpenPerspectives();
for (int i = 0; i < perspectives.length; i++) {
barManager.insert(1, new PerspectiveBarContributionItem(
perspectives[i], page));
}
}
return barManager;
}
private void updateLocationItems(Menu parent, int newLocation) {
MenuItem left;
MenuItem topLeft;
MenuItem topRight;
topRight = parent.getItem(0);
topLeft = parent.getItem(1);
left = parent.getItem(2);
if (newLocation == LEFT) {
left.setSelection(true);
topRight.setSelection(false);
topLeft.setSelection(false);
} else if (newLocation == TOP_LEFT) {
topLeft.setSelection(true);
left.setSelection(false);
topRight.setSelection(false);
} else {
topRight.setSelection(true);
left.setSelection(false);
topLeft.setSelection(false);
}
}
private void addDockOnSubMenu(Menu menu) {
MenuItem item = new MenuItem(menu, SWT.CASCADE);
item.setText(WorkbenchMessages.PerspectiveSwitcher_dockOn);
final Menu subMenu = new Menu(item);
final MenuItem menuItemTopRight = new MenuItem(subMenu, SWT.RADIO);
menuItemTopRight.setText(WorkbenchMessages.PerspectiveSwitcher_topRight);
window.getWorkbench().getHelpSystem().setHelp(menuItemTopRight,
IWorkbenchHelpContextIds.DOCK_ON_PERSPECTIVE_ACTION);
final MenuItem menuItemTopLeft = new MenuItem(subMenu, SWT.RADIO);
menuItemTopLeft.setText(WorkbenchMessages.PerspectiveSwitcher_topLeft);
window.getWorkbench().getHelpSystem().setHelp(menuItemTopLeft,
IWorkbenchHelpContextIds.DOCK_ON_PERSPECTIVE_ACTION);
final MenuItem menuItemLeft = new MenuItem(subMenu, SWT.RADIO);
menuItemLeft.setText(WorkbenchMessages.PerspectiveSwitcher_left);
window.getWorkbench().getHelpSystem().setHelp(menuItemLeft,
IWorkbenchHelpContextIds.DOCK_ON_PERSPECTIVE_ACTION);
SelectionListener listener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
MenuItem item = (MenuItem) e.widget;
String pref = null;
if (item.equals(menuItemLeft)) {
updateLocationItems(subMenu, LEFT);
pref = IWorkbenchPreferenceConstants.LEFT;
} else if (item.equals(menuItemTopLeft)) {
updateLocationItems(subMenu, TOP_LEFT);
pref = IWorkbenchPreferenceConstants.TOP_LEFT;
} else {
updateLocationItems(subMenu, TOP_RIGHT);
pref = IWorkbenchPreferenceConstants.TOP_RIGHT;
}
IPreferenceStore apiStore = PrefUtil.getAPIPreferenceStore();
if (!pref
.equals(apiStore
.getDefaultString(IWorkbenchPreferenceConstants.DOCK_PERSPECTIVE_BAR))) {
PrefUtil.getInternalPreferenceStore().setValue(
IPreferenceConstants.OVERRIDE_PRESENTATION, true);
}
apiStore.setValue(
IWorkbenchPreferenceConstants.DOCK_PERSPECTIVE_BAR,
pref);
}
};
menuItemTopRight.addSelectionListener(listener);
menuItemTopLeft.addSelectionListener(listener);
menuItemLeft.addSelectionListener(listener);
item.setMenu(subMenu);
updateLocationItems(subMenu, currentLocation);
}
private void addShowTextItem(Menu menu) {
final MenuItem showtextMenuItem = new MenuItem(menu, SWT.CHECK);
showtextMenuItem.setText(WorkbenchMessages.PerspectiveBar_showText);
window.getWorkbench().getHelpSystem().setHelp(showtextMenuItem,
IWorkbenchHelpContextIds.SHOW_TEXT_PERSPECTIVE_ACTION);
showtextMenuItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (perspectiveBar == null) {
return;
}
boolean preference = showtextMenuItem.getSelection();
if (preference != PrefUtil
.getAPIPreferenceStore()
.getDefaultBoolean(
IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR)) {
PrefUtil.getInternalPreferenceStore().setValue(
IPreferenceConstants.OVERRIDE_PRESENTATION, true);
}
PrefUtil
.getAPIPreferenceStore()
.setValue(
IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR,
preference);
}
});
showtextMenuItem.setSelection(
PrefUtil
.getAPIPreferenceStore()
.getBoolean(
IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR));
}
private void addCustomizeItem(Menu menu) {
final MenuItem customizeMenuItem = new MenuItem(menu, SWT.Activate);
customizeMenuItem.setText(WorkbenchMessages.PerspectiveBar_customize);
window.getWorkbench().getHelpSystem().setHelp(customizeMenuItem,
IWorkbenchHelpContextIds.EDIT_ACTION_SETS_ACTION);
customizeMenuItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (perspectiveBar == null) {
return;
}
IHandlerService handlerService = (IHandlerService) window
.getService(IHandlerService.class);
try {
handlerService.executeCommand(
"org.eclipse.ui.window.customizePerspective", null); //$NON-NLS-1$
} catch (ExecutionException e1) {
} catch (NotDefinedException e1) {
} catch (NotEnabledException e1) {
} catch (NotHandledException e1) {
}
}
});
}
private void addSaveAsItem(Menu menu) {
final MenuItem saveasMenuItem = new MenuItem(menu, SWT.Activate);
saveasMenuItem.setText(WorkbenchMessages.PerspectiveBar_saveAs);
window.getWorkbench().getHelpSystem().setHelp(saveasMenuItem,
IWorkbenchHelpContextIds.SAVE_PERSPECTIVE_ACTION);
saveasMenuItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (perspectiveBar == null) {
return;
}
SavePerspectiveAction saveAction=new SavePerspectiveAction(window);
saveAction.setEnabled(true);
saveAction.run();
}
});
}
private void addResetItem(Menu menu) {
final MenuItem resetMenuItem = new MenuItem(menu, SWT.Activate);
resetMenuItem.setText(WorkbenchMessages.PerspectiveBar_reset);
window.getWorkbench().getHelpSystem().setHelp(resetMenuItem,
IWorkbenchHelpContextIds.RESET_PERSPECTIVE_ACTION);
resetMenuItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (perspectiveBar == null) {
return;
}
ResetPerspectiveAction resetAction=new ResetPerspectiveAction(window);
resetAction.setEnabled(true);
resetAction.run();
}
});
}
/**
* Method to save the width of the perspective bar in the
* @param persBarMem
*/
public void saveState(IMemento persBarMem) {
// save the width of the perspective bar
IMemento childMem = persBarMem
.createChild(IWorkbenchConstants.TAG_ITEM_SIZE);
int x;
if (currentLocation == TOP_RIGHT && topBar != null) {
x = topBar.getRightWidth();
} else {
x = getDefaultWidth();
}
childMem.putString(IWorkbenchConstants.TAG_X, Integer.toString(x));
}
/**
* Method to restore the width of the perspective bar
* @param memento
*/
public void restoreState(IMemento memento) {
if (memento == null) {
return;
}
// restore the width of the perspective bar
IMemento attributes = memento
.getChild(IWorkbenchConstants.TAG_PERSPECTIVE_BAR);
IMemento size = null;
if (attributes != null) {
size = attributes.getChild(IWorkbenchConstants.TAG_ITEM_SIZE);
}
if (size != null && currentLocation == TOP_RIGHT && topBar != null) {
final Integer x = size.getInteger(IWorkbenchConstants.TAG_X);
StartupThreading.runWithoutExceptions(new StartupRunnable() {
public void runWithException() {
if (x != null) {
topBar.setRightWidth(x.intValue());
} else {
topBar.setRightWidth(getDefaultWidth());
}
}});
}
}
/**
* Method to rebuild and update the toolbar when necessary
*/
void updatePerspectiveBar() {
// Update each item as the text may have to be shortened.
IContributionItem[] items = perspectiveBar.getItems();
for (int i = 0; i < items.length; i++) {
items[i].update();
}
// make sure the selected item is visible
perspectiveBar.arrangeToolbar();
setCoolItemSize(coolItem);
perspectiveBar.getControl().redraw();
if (getControl() != null)
getControl().pack(true);
}
/**
* Updates the height of the CBanner if the perspective bar
* is docked on the top right
*/
public void updateBarParent() {
if (perspectiveBar == null || perspectiveBar.getControl() == null) {
return;
}
// TOP_LEFT and LEFT need only relayout in this case, however TOP_RIGHT
// will need to set the minimum height of the CBanner as it might have changed.
if (currentLocation == TOP_RIGHT && topBar != null) {
// This gets the height of the tallest tool item.
int maxRowHeight = 0;
ToolItem[] toolItems = perspectiveBar.getControl().getItems();
for (int i = 0; i < toolItems.length; i++) {
maxRowHeight = Math.max(maxRowHeight,
toolItems[i].getBounds().height);
}
// This sets the CBanner's minimum height to support large fonts
// TODO: Actually calculate the correct 'min' size for the right side
topBar.setRightMinimumSize(new Point(MIN_WIDTH, maxRowHeight));
}
LayoutUtil.resize(perspectiveBar.getControl());
}
/**
* Add a listener for reordering of perspectives (usually done through drag
* and drop).
*
* @param listener
*/
public void addReorderListener(IReorderListener listener) {
reorderListener = listener;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.IWindowTrim#dock(int)
*/
public void dock(int dropSide) {
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.IWindowTrim#getControl()
*/
public Control getControl() {
return trimControl;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.IWindowTrim#getId()
*/
public String getId() {
return "org.eclipse.ui.internal.PerspectiveSwitcher"; //$NON-NLS-1$
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.IWindowTrim#getDisplayName()
*/
public String getDisplayName() {
return WorkbenchMessages.TrimCommon_PerspectiveSwitcher_TrimName;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.IWindowTrim#getValidSides()
*/
public int getValidSides() {
return SWT.NONE;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.IWindowTrim#isCloseable()
*/
public boolean isCloseable() {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.IWindowTrim#handleClose()
*/
public void handleClose() {
// nothing to do...
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWindowTrim#getWidthHint()
*/
public int getWidthHint() {
return SWT.DEFAULT;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWindowTrim#getHeightHint()
*/
public int getHeightHint() {
return SWT.DEFAULT;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWindowTrim#isResizeable()
*/
public boolean isResizeable() {
return false;
}
}