/******************************************************************************* * Copyright (c) 2000, 2016 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 *******************************************************************************/ package org.eclipse.debug.ui.actions; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.ILaunchHistoryChangedListener; import org.eclipse.debug.internal.ui.ILaunchLabelChangedListener; import org.eclipse.debug.internal.ui.actions.ActionMessages; import org.eclipse.debug.internal.ui.contextlaunching.LaunchingResourceManager; import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationManager; import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationSelectionDialog; import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationsMessages; import org.eclipse.debug.internal.ui.launchConfigurations.LaunchHistory; import org.eclipse.debug.internal.ui.launchConfigurations.LaunchShortcutExtension; import org.eclipse.debug.internal.ui.launchConfigurations.LaunchShortcutSelectionDialog; import org.eclipse.debug.internal.ui.stringsubstitution.SelectedResourceManager; import org.eclipse.debug.ui.ILaunchGroup; import org.eclipse.debug.ui.ILaunchShortcut; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MenuAdapter; import org.eclipse.swt.events.MenuEvent; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.ui.IActionDelegate2; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2; import com.ibm.icu.text.MessageFormat; /** * Abstract implementation of an action that displays a drop-down launch * history for a specific launch group. * <p> * Clients may subclass this class. * </p> * @see LaunchingResourceManager * @see ILaunchLabelChangedListener * @since 2.1 */ public abstract class AbstractLaunchHistoryAction implements IActionDelegate2, IWorkbenchWindowPulldownDelegate2, ILaunchHistoryChangedListener { /** * The menu created by this action */ private Menu fMenu; /** * The action used to render this delegate. */ private IAction fAction; /** * The associated <code>ILaunchGroup</code> * @since 3.3 */ private ILaunchGroup fLaunchGroup = null; /** * Indicates whether the launch history has changed and * the sub menu needs to be recreated. */ protected boolean fRecreateMenu = false; /** * Constructs a launch history action. * * @param launchGroupIdentifier unique identifier of the launch group * extension that this action displays a launch history for. */ public AbstractLaunchHistoryAction(String launchGroupIdentifier) { fLaunchGroup = getLaunchConfigurationManager().getLaunchGroup(launchGroupIdentifier); } /** * A listener to be notified of launch label updates * @since 3.3 */ private ILaunchLabelChangedListener fLabelListener = new ILaunchLabelChangedListener() { @Override public ILaunchGroup getLaunchGroup() { return fLaunchGroup; } @Override public void labelChanged() { updateTooltip(); } }; /** * Sets the action used to render this delegate. * * @param action the action used to render this delegate */ private void setAction(IAction action) { fAction = action; } /** * Returns the action used to render this delegate. * * @return the action used to render this delegate */ protected IAction getAction() { return fAction; } /** * Adds the given action to the specified menu with an accelerator specified * by the given number. * * @param menu the menu to add the action to * @param action the action to add * @param accelerator the number that should appear as an accelerator */ protected void addToMenu(Menu menu, IAction action, int accelerator) { StringBuffer label= new StringBuffer(); if (accelerator >= 0 && accelerator < 10) { //add the numerical accelerator label.append('&'); label.append(accelerator); label.append(' '); } label.append(action.getText()); action.setText(label.toString()); ActionContributionItem item= new ActionContributionItem(action); item.fill(menu, -1); } /** * Initialize this action so that it can dynamically set its tool-tip. Also set the enabled state * of the underlying action based on whether there are any registered launch configuration types that * understand how to launch in the mode of this action. * @param action the {@link IAction} to initialize */ private void initialize(IAction action) { getLaunchConfigurationManager().addLaunchHistoryListener(this); setAction(action); updateTooltip(); action.setEnabled(existsConfigTypesForMode()); } /** * Return whether there are any registered launch configuration types for * the mode of this action. * * @return whether there are any registered launch configuration types for * the mode of this action */ private boolean existsConfigTypesForMode() { ILaunchConfigurationType[] configTypes = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationTypes(); for (int i = 0; i < configTypes.length; i++) { if (configTypes[i].supportsMode(getMode())) { return true; } } return false; } /** * Updates this action's tool-tip. The tooltip is based on user preference settings * for launching - either the previous launch, or based on the selection and which * configuration will be launched. * <p> * Subclasses may override as required. * </p> */ protected void updateTooltip() { getAction().setToolTipText(getToolTip()); } /** * Returns the tooltip specific to a configuration. * * @param configuration a <code>ILauncConfiguration</code> * @return the string for the tool tip */ protected String getToolTip(ILaunchConfiguration configuration) { String launchName= configuration.getName(); String mode= getMode(); String label; if (mode.equals(ILaunchManager.RUN_MODE)) { label= ActionMessages.AbstractLaunchHistoryAction_1; } else if (mode.equals(ILaunchManager.DEBUG_MODE)){ label= ActionMessages.AbstractLaunchHistoryAction_2; } else if (mode.equals(ILaunchManager.PROFILE_MODE)){ label= ActionMessages.AbstractLaunchHistoryAction_3; } else { label= ActionMessages.AbstractLaunchHistoryAction_4; } return MessageFormat.format(ActionMessages.AbstractLaunchHistoryAction_0, new Object[] { label, launchName }); } /** * Returns this action's tooltip. The tooltip is retrieved from the launch resource manager * which builds tool tips asynchronously for context launching support. * * @return the string for the tool tip */ private String getToolTip() { String launchName = DebugUIPlugin.getDefault().getLaunchingResourceManager().getLaunchLabel(fLaunchGroup); if(launchName == null) { return DebugUIPlugin.removeAccelerators(internalGetHistory().getLaunchGroup().getLabel()); } String label = null; String mode = getMode(); if (mode.equals(ILaunchManager.RUN_MODE)) { label = ActionMessages.AbstractLaunchHistoryAction_1; } else if (mode.equals(ILaunchManager.DEBUG_MODE)){ label = ActionMessages.AbstractLaunchHistoryAction_2; } else if (mode.equals(ILaunchManager.PROFILE_MODE)){ label = ActionMessages.AbstractLaunchHistoryAction_3; } else { label = ActionMessages.AbstractLaunchHistoryAction_4; } if(IInternalDebugCoreConstants.EMPTY_STRING.equals(launchName)) { return MessageFormat.format(ActionMessages.AbstractLaunchHistoryAction_5, new Object[] { label }); } else { return MessageFormat.format(ActionMessages.AbstractLaunchHistoryAction_0, new Object[] { label, launchName }); } } /** * @see ILaunchHistoryChangedListener#launchHistoryChanged() */ @Override public void launchHistoryChanged() { fRecreateMenu = true; } /** * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose() */ @Override public void dispose() { setMenu(null); getLaunchConfigurationManager().removeLaunchHistoryListener(this); DebugUIPlugin.getDefault().getLaunchingResourceManager().removeLaunchLabelChangedListener(fLabelListener); } /** * Return the last launch in this action's launch history. * * @return the most recent configuration that was launched from this * action's launch history that is not filtered from the menu */ protected ILaunchConfiguration getLastLaunch() { return getLaunchConfigurationManager().getFilteredLastLaunch(getLaunchGroupIdentifier()); } /** * @see org.eclipse.ui.IWorkbenchWindowPulldownDelegate#getMenu(org.eclipse.swt.widgets.Control) */ @Override public Menu getMenu(Control parent) { setMenu(new Menu(parent)); fillMenu(fMenu); initMenu(); return fMenu; } /* (non-Javadoc) * @see org.eclipse.ui.IWorkbenchWindowPulldownDelegate2#getMenu(org.eclipse.swt.widgets.Menu) */ @Override public Menu getMenu(Menu parent) { setMenu(new Menu(parent)); fillMenu(fMenu); initMenu(); return fMenu; } /** * Creates the menu for the action */ private void initMenu() { // Add listener to re-populate the menu each time // it is shown because of dynamic history list fMenu.addMenuListener(new MenuAdapter() { @Override public void menuShown(MenuEvent e) { if (fRecreateMenu) { Menu m = (Menu)e.widget; MenuItem[] items = m.getItems(); for (int i=0; i < items.length; i++) { items[i].dispose(); } fillMenu(m); fRecreateMenu= false; } } }); } /** * Sets this action's drop-down menu, disposing the previous menu. * * @param menu the new menu */ private void setMenu(Menu menu) { if (fMenu != null) { fMenu.dispose(); } fMenu = menu; } /** * Fills the drop-down menu with favorites and launch history * * @param menu the menu to fill */ protected void fillMenu(Menu menu) { ILaunchConfiguration[] historyList= getHistory(); ILaunchConfiguration[] favoriteList = getFavorites(); // Add favorites int accelerator = 1; for (int i = 0; i < favoriteList.length; i++) { ILaunchConfiguration launch= favoriteList[i]; LaunchAction action= new LaunchAction(launch, getMode()); addToMenu(menu, action, accelerator); accelerator++; } // Separator between favorites and history if (favoriteList.length > 0 && historyList.length > 0) { addSeparator(menu); } // Add history launches next for (int i = 0; i < historyList.length; i++) { ILaunchConfiguration launch= historyList[i]; LaunchAction action= new LaunchAction(launch, getMode()); addToMenu(menu, action, accelerator); accelerator++; } if(accelerator == 1) { IAction action = new Action(ActionMessages.AbstractLaunchHistoryAction_6) {}; action.setEnabled(false); ActionContributionItem item= new ActionContributionItem(action); item.fill(menu, -1); } } /** * Adds a separator to the given menu * * @param menu the menu to add the separator to */ protected void addSeparator(Menu menu) { new MenuItem(menu, SWT.SEPARATOR); } /** * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) */ @Override public void run(IAction action) { // do nothing - this is just a menu } /** * @see org.eclipse.ui.IActionDelegate2#runWithEvent(org.eclipse.jface.action.IAction, org.eclipse.swt.widgets.Event) * @since 3.6 */ @Override public void runWithEvent(IAction action, Event event) { if(((event.stateMask & SWT.MOD1) > 0) && (event.type != SWT.KeyDown)) { ILaunchConfiguration configuration = null; String groupid = getLaunchGroupIdentifier(); if(LaunchingResourceManager.isContextLaunchEnabled(groupid)) { configuration = resolveContextConfiguration(); } else { configuration = getLaunchConfigurationManager().getFilteredLastLaunch(groupid); } ArrayList<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(1); if (configuration != null){ configs.add(configuration); } DebugUIPlugin.openLaunchConfigurationsDialog( DebugUIPlugin.getShell(), new StructuredSelection(configs), groupid, true); return; } runInternal(action, ((event.stateMask & SWT.SHIFT) > 0) ? true : false); } /** * @since 3.12 */ protected void runInternal(IAction action, boolean isShift) { run(action); } /** * Resolves the configuration to show in the dialog when opened via the Ctrl+Click. * If no configuration exists a new one is created using its respective {@link ILaunchShortcut} * @return the configuration to show in the launch dialog * @since 3.6 */ private ILaunchConfiguration resolveContextConfiguration() { SelectedResourceManager srm = SelectedResourceManager.getDefault(); IStructuredSelection selection = srm.getCurrentSelection(); List<LaunchShortcutExtension> shortcuts = null; IResource resource = srm.getSelectedResource(); LaunchingResourceManager lrm = DebugUIPlugin.getDefault().getLaunchingResourceManager(); shortcuts = lrm.getShortcutsForSelection(selection, getMode()); if(resource == null) { resource = lrm.getLaunchableResource(shortcuts, selection); } List<ILaunchConfiguration> configs = lrm.getParticipatingLaunchConfigurations(selection, resource, shortcuts, getMode()); if(configs.size() == 1) { return configs.get(0); } else if(configs.size() > 1) { // launch most recently launched config ILaunchConfiguration config = getLaunchConfigurationManager().getMRUConfiguration(configs, fLaunchGroup, resource); if(config != null) { return config; } else { // Let the use select which config to open LaunchConfigurationSelectionDialog dialog = new LaunchConfigurationSelectionDialog(DebugUIPlugin.getShell(), configs); if(dialog.open() == IDialogConstants.OK_ID) { return (ILaunchConfiguration) dialog.getResult()[0]; } } return null; } else if(shortcuts.size() > 1) { //no configs, choose shortcut to create a new one LaunchShortcutSelectionDialog dialog = new LaunchShortcutSelectionDialog(shortcuts, resource, getMode()); if(dialog.open() == IDialogConstants.OK_ID) { LaunchShortcutExtension ext = (LaunchShortcutExtension) dialog.getResult()[0]; return createConfigurationFromTypes(ext.getAssociatedConfigurationTypes()); } return null; } else if(shortcuts.size() == 1) { LaunchShortcutExtension ext = shortcuts.get(0); return createConfigurationFromTypes(ext.getAssociatedConfigurationTypes()); } return getLaunchConfigurationManager().getFilteredLastLaunch(getLaunchGroupIdentifier()); } /** * Creates an {@link ILaunchConfiguration} from the given set of {@link ILaunchConfigurationType}s * @param types the set of {@link String} {@link ILaunchConfigurationType} identifiers * @return a new {@link ILaunchConfiguration} * @since 3.6 */ private ILaunchConfiguration createConfigurationFromTypes(Set<String> types) { //context launching always takes the first type, so we do that here as well if(types != null && types.size() > 0) { try { ILaunchConfigurationType type = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType((String) types.toArray()[0]); ILaunchConfigurationWorkingCopy copy = type.newInstance(null, DebugPlugin.getDefault().getLaunchManager().generateLaunchConfigurationName(LaunchConfigurationsMessages.CreateLaunchConfigurationAction_New_configuration_2)); return copy; } catch(CoreException ce) { //do nothing return null } } return null; } /** * @see org.eclipse.ui.IActionDelegate2#init(org.eclipse.jface.action.IAction) * @since 3.6 */ @Override public void init(IAction action) { // do nothing by default } /** * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection) */ @Override public void selectionChanged(IAction action, ISelection selection){ if (fAction == null) { initialize(action); } } /** * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow) */ @Override public void init(IWorkbenchWindow window) { if (this instanceof AbstractLaunchToolbarAction) { DebugUIPlugin.getDefault().getLaunchingResourceManager().addLaunchLabelUpdateListener(fLabelListener); } } /** * Returns the launch history associated with this action's launch group. * * @return the launch history associated with this action's launch group * @deprecated this method returns a class that is not API and is not intended * for clients of the debug platform. Instead, use <code>getHistory()</code>, * <code>getFavorites()</code>, and <code>getLastLaunch()</code>. */ @Deprecated protected LaunchHistory getLaunchHistory() { return getLaunchConfigurationManager().getLaunchHistory(getLaunchGroupIdentifier()); } /** * Returns the launch history associated with this action's launch group. * * @return the launch history associated with this action's launch group * @since 3.3 */ private LaunchHistory internalGetHistory() { return getLaunchConfigurationManager().getLaunchHistory(getLaunchGroupIdentifier()); } /** * Returns the launch history associated with this action's launch mode and group in most * recently launched order. Configurations associated with disabled activities are not included * in the list. As well, configurations are filtered based on workspace preference settings * to filter configurations from closed projects, deleted projects, working sets and to filter * specific launch configuration types. * * @return launch history * @since 3.3 */ protected ILaunchConfiguration[] getHistory() { return LaunchConfigurationManager.filterConfigs(internalGetHistory().getHistory()); } /** * Returns the launch favorites associated with this action's launch mode and group in user * preference order. Configurations associated with disabled activities are not included * in the list. As well, configurations are filtered based on workspace preference settings * to filter configurations from closed projects, deleted projects, working sets and to filter * specific launch configuration types. * * @return favorite launch configurations * @since 3.3 */ protected ILaunchConfiguration[] getFavorites() { return LaunchConfigurationManager.filterConfigs(internalGetHistory().getFavorites()); } /** * Returns the mode (e.g., 'run' or 'debug') of this drop down. * * @return the mode of this action */ protected String getMode() { return internalGetHistory().getLaunchGroup().getMode(); } /** * Returns the launch configuration manager. * * @return launch configuration manager */ private LaunchConfigurationManager getLaunchConfigurationManager() { return DebugUIPlugin.getDefault().getLaunchConfigurationManager(); } /** * Returns the identifier of the launch group this action is associated * with. * * @return the identifier of the launch group this action is associated * with */ protected String getLaunchGroupIdentifier() { return fLaunchGroup.getIdentifier(); } }