blob: bcd1ecffe39eaf2fe305bc712cb93839e51b96fb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2009 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
* Tonny Madsen, RCP Company - bug 201055
*******************************************************************************/
package org.eclipse.ui.actions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.ibm.icu.text.Collator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IPerspectiveRegistry;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.activities.WorkbenchActivityHelper;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.util.PrefUtil;
import org.eclipse.ui.statushandlers.StatusManager;
/**
* A menu for perspective selection.
* <p>
* A <code>PerspectiveMenu</code> is used to populate a menu with
* perspective shortcut items. If the user selects one of these items
* an action is performed for the selected perspective.
* </p><p>
* The visible perspective items within the menu are dynamic and reflect the
* available set generated by each subclass. The default available set consists
* of the perspective shortcut list of the current perspective.
* </p><p>
* This class is abstract. Subclasses must implement the <code>run</code> method,
* which performs a specialized action for the selected perspective.
* </p>
*/
public abstract class PerspectiveMenu extends ContributionItem {
/**
* @since 3.4
* @deprecated As of 3.5, replaced by {@link IWorkbenchCommandConstants#PERSPECTIVES_SHOW_PERSPECTIVE}
*/
protected static final String SHOW_PERSP_ID = IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE;
private IPerspectiveRegistry reg;
private IWorkbenchWindow window;
private boolean showActive = false;
private boolean dirty = true;
private IMenuListener menuListener = new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
manager.markDirty();
dirty = true;
}
};
private Comparator comparator = new Comparator() {
private Collator collator = Collator.getInstance();
public int compare(Object ob1, Object ob2) {
IPerspectiveDescriptor d1 = (IPerspectiveDescriptor) ob1;
IPerspectiveDescriptor d2 = (IPerspectiveDescriptor) ob2;
return collator.compare(d1.getLabel(), d2.getLabel());
}
};
/**
* The translatable message to show when there are no perspectives.
*
* @since 3.1
*/
private static final String NO_TARGETS_MSG = WorkbenchMessages.Workbench_showInNoPerspectives;
/**
* The map of perspective identifiers (String) to actions
* (OpenPerspectiveAction). This map may be empty, but it is never
* <code>null</code>.
*
* @since 3.1
*/
private Map actions = new HashMap();
/**
* The action for that allows the user to choose any perspective to open.
*
* @since 3.1
*/
private Action openOtherAction = new Action(WorkbenchMessages.PerspectiveMenu_otherItem) {
public final void runWithEvent(final Event event) {
runOther(new SelectionEvent(event));
}
};
/**
* Constructs a new instance of <code>PerspectiveMenu</code>.
*
* @param window the window containing this menu
* @param id the menu id
*/
public PerspectiveMenu(IWorkbenchWindow window, String id) {
super(id);
this.window = window;
reg = window.getWorkbench().getPerspectiveRegistry();
openOtherAction
.setActionDefinitionId(IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE);
}
/*
* (non-Javadoc) Fills the menu with perspective items.
*/
public void fill(Menu menu, int index) {
if (getParent() instanceof MenuManager) {
((MenuManager) getParent()).addMenuListener(menuListener);
}
if (!dirty) {
return;
}
final MenuManager manager = new MenuManager();
fillMenu(manager);
final IContributionItem items[] = manager.getItems();
if (items.length == 0) {
MenuItem item = new MenuItem(menu, SWT.NONE, index++);
item.setText(NO_TARGETS_MSG);
item.setEnabled(false);
} else {
for (int i = 0; i < items.length; i++) {
items[i].fill(menu, index++);
}
}
dirty = false;
}
/**
* Fills the given menu manager with all the open perspective actions
* appropriate for the currently active perspective. Filtering is applied to
* the actions based on the activities and capabilities mechanism.
*
* @param manager
* The menu manager that should receive the menu items; must not
* be <code>null</code>.
* @since 3.1
*/
private final void fillMenu(final MenuManager manager) {
// Clear out the manager so that we have a blank slate.
manager.removeAll();
// Collect and sort perspective descriptors.
final List persps = getPerspectiveItems();
Collections.sort(persps, comparator);
/*
* Convert the perspective descriptors to actions, and filter out
* actions using the activity/capability mechanism.
*/
final List actions = new ArrayList(persps.size());
for (Iterator i = persps.iterator(); i.hasNext();) {
final IPerspectiveDescriptor descriptor = (IPerspectiveDescriptor) i
.next();
final IAction action = getAction(descriptor.getId());
if (action != null) {
if (WorkbenchActivityHelper.filterItem(action)) {
continue;
}
actions.add(action);
}
}
// Go through and add each of the actions to the menu manager.
for (Iterator i = actions.iterator(); i.hasNext();) {
manager.add((IAction) i.next());
}
if (PrefUtil
.getAPIPreferenceStore()
.getBoolean(
IWorkbenchPreferenceConstants.SHOW_OTHER_IN_PERSPECTIVE_MENU)) {
// Add a separator and then "Other..."
if (actions.size() > 0) {
manager.add(new Separator());
}
manager.add(openOtherAction);
}
}
/**
* Returns the action for the given perspective id. This is a lazy cache. If
* the action does not already exist, then it is created. If there is no
* perspective with the given identifier, then the action is not created.
*
* @param id
* The identifier of the perspective for which the action should
* be retrieved.
* @return The action for the given identifier; or <code>null</code> if
* there is no perspective with the given identifier.
* @since 3.1
*/
private final IAction getAction(final String id) {
IAction action = (IAction) actions.get(id);
if (action == null) {
IPerspectiveDescriptor descriptor = reg.findPerspectiveWithId(id);
if (descriptor != null) {
action = new OpenPerspectiveAction(window, descriptor, this);
action.setActionDefinitionId(id);
actions.put(id, action);
}
}
return action;
}
/* (non-Javadoc)
* Returns the perspective shortcut items for the active perspective.
*
* @return a list of <code>IPerspectiveDescriptor</code> items
*/
private ArrayList getPerspectiveShortcuts() {
ArrayList list = new ArrayList();
IWorkbenchPage page = window.getActivePage();
if (page == null) {
return list;
}
String[] ids = page.getPerspectiveShortcuts();
for (int i = 0; i < ids.length; i++) {
IPerspectiveDescriptor desc = reg.findPerspectiveWithId(ids[i]);
if (desc != null && !list.contains(desc)) {
if (WorkbenchActivityHelper.filterItem(desc)) {
continue;
}
list.add(desc);
}
}
return list;
}
/**
* Returns the available list of perspectives to display in the menu.
* <p>
* By default, the list contains the perspective shortcuts
* for the current perspective.
* </p><p>
* Subclasses can override this method to return a different list.
* </p>
*
* @return an <code>ArrayList<code> of perspective items <code>IPerspectiveDescriptor</code>
*/
protected ArrayList getPerspectiveItems() {
/* Allow the user to see all the perspectives they have
* selected via Customize Perspective. Bugzilla bug #23445 */
ArrayList shortcuts = getPerspectiveShortcuts();
ArrayList list = new ArrayList(shortcuts.size());
// Add perspective shortcuts from the active perspective
int size = shortcuts.size();
for (int i = 0; i < size; i++) {
if (!list.contains(shortcuts.get(i))) {
list.add(shortcuts.get(i));
}
}
return list;
}
/**
* Returns whether the menu item representing the active perspective
* will have a check mark.
*
* @return <code>true</code> if a check mark is shown, <code>false</code> otherwise
*/
protected boolean getShowActive() {
return showActive;
}
/**
* Returns the window for this menu.
*
* @return the window
*/
protected IWorkbenchWindow getWindow() {
return window;
}
/* (non-Javadoc)
* Returns whether this menu is dynamic.
*/
public boolean isDirty() {
return dirty;
}
/* (non-Javadoc)
* Returns whether this menu is dynamic.
*/
public boolean isDynamic() {
return true;
}
/**
* Runs an action for a particular perspective. The behavior of the
* action is defined by the subclass.
*
* @param desc the selected perspective
*/
protected abstract void run(IPerspectiveDescriptor desc);
/**
* Runs an action for a particular perspective. The behavior of the action
* is defined by the subclass. By default, this just calls
* <code>run(IPerspectiveDescriptor)</code>.
*
* @param desc
* the selected perspective
* @param event
* SelectionEvent - the event send along with the selection
* callback
*/
protected void run(IPerspectiveDescriptor desc, SelectionEvent event) {
//Do a run without the event by default
run(desc);
}
/**
* Show the "other" dialog, select a perspective, and run it. Pass on the selection event should
* the menu need it.
*
* @param event the selection event
*/
void runOther(SelectionEvent event) {
IHandlerService handlerService = (IHandlerService) window
.getService(IHandlerService.class);
try {
handlerService.executeCommand(IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, null);
} catch (ExecutionException e) {
StatusManager.getManager().handle(
new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
} catch (NotDefinedException e) {
StatusManager.getManager().handle(
new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
} catch (NotEnabledException e) {
StatusManager.getManager().handle(
new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
} catch (NotHandledException e) {
StatusManager.getManager().handle(
new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
}
}
/**
* Sets the showActive flag. If <code>showActive == true</code> then the
* active perspective is hilighted with a check mark.
*
* @param b the new showActive flag
*/
protected void showActive(boolean b) {
showActive = b;
}
}