blob: b6cf1c442ae100423132f43f3565205ee4575ed5 [file] [log] [blame]
package org.eclipse.debug.internal.ui.launchConfigurations;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationListener;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.PixelConverter;
import org.eclipse.debug.internal.ui.SWTUtil;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.ILaunchConfigurationDialog;
import org.eclipse.debug.ui.ILaunchConfigurationTab;
import org.eclipse.debug.ui.ILaunchConfigurationTabGroup;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.ControlEnableState;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.operation.ModalContext;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.ui.model.WorkbenchViewerSorter;
/**
* The dialog used to edit and launch launch configurations.
*/
public class LaunchConfigurationDialog extends TitleAreaDialog
implements ISelectionChangedListener,
ILaunchConfigurationListener,
ILaunchConfigurationDialog,
IDoubleClickListener {
/**
* The tree of launch configurations
*/
private TreeViewer fConfigTree;
/**
* The workbench context present when this dialog is opened.
*/
private Object fContext;
/**
* The IResource corresponding to <code>fContext</code>.
*/
private IResource fResourceContext;
/**
* The mode (run or debug) for this dialog.
*/
private String fMode;
/**
* The Composite used to insert an adjustable 'sash' between the tree and the tabs.
*/
private SashForm fSashForm;
/**
* Default weights for the SashForm that specify how wide the selection and
* edit areas aree relative to each other.
*/
private static final int[] DEFAULT_SASH_WEIGHTS = new int[] {11, 30};
/**
* The launch configuration selection area.
*/
private Composite fSelectionArea;
/**
* The launch configuration edit area.
*/
private Composite fEditArea;
/**
* The 'New configuration' action.
*/
private ButtonAction fButtonActionNew;
/**
* The 'Duplicate configuration' action.
*/
private ButtonAction fButtonActionDuplicate;
/**
* The 'Delete configuration' action.
*/
private ButtonAction fButtonActionDelete;
/**
* The 'apply' button
*/
private Button fApplyButton;
/**
* The 'revert' button
*/
private Button fRevertButton;
/**
* The 'cancel' button that appears when the in-dialog progress monitor is shown.
*/
private Button fProgressMonitorCancelButton;
/**
* Flag indicating if the progress monitor part's Cancel button has been pressed.
*/
private boolean fCancelButtonPressed;
/**
* The text widget displaying the name of the
* launch configuration under edit
*/
private Text fNameText;
private String fLastSavedName = null;
/**
* Container for the edit area <code>TabFolder</code>
*/
private Composite fTabComposite;
/**
* The tab folder that contains tabs for the selected configuration
*/
private TabFolder fTabFolder;
/**
* Flag that indicates when the tabs are being disposed.
*/
private boolean fDisposingTabs = false;
/**
* The current (working copy) launch configuration
* being displayed/edited or <code>null</code> if
* none
*/
private ILaunchConfigurationWorkingCopy fWorkingCopy;
/**
* The actual (non-working copy) launch configuration that underlies the current working copy
*/
private ILaunchConfiguration fUnderlyingConfig;
/**
* Clients of this dialog may set an 'initial configuration type', which means that when
* the dialog is opened, a configuration of that type will be created, initialized, and
* saved. Note that the initial config type is ignored if single-click launching is enabled.
*/
private ILaunchConfigurationType fInitialConfigType;
/**
* When this dialog is opened in <code>LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_SELECTION</code>
* mode, this specifies the selection that is initially shown in the dialog.
*/
private IStructuredSelection fInitialSelection;
/**
* The current tab group being displayed
*/
private ILaunchConfigurationTabGroup fTabGroup;
/**
* The type of config tabs are currently displayed
* for
*/
private ILaunchConfigurationType fTabType;
/**
* The index of the currently selected tab
*/
private int fCurrentTabIndex;
private ProgressMonitorPart fProgressMonitorPart;
private Cursor waitCursor;
private Cursor arrowCursor;
private MessageDialog fWindowClosingDialog;
/**
* Whether initlialing tabs
*/
private boolean fInitializingTabs = false;
/**
* Indicates if selection changes in the tree should be ignored
*/
private boolean fIgnoreSelectionChanges = false;
/**
* Previously selected element in the tree
*/
private Object fSelectedTreeObject;
/**
* The number of 'long-running' operations currently taking place in this dialog
*/
private long fActiveRunningOperations = 0;
/**
* Id for 'Launch' button.
*/
protected static final int ID_LAUNCH_BUTTON = IDialogConstants.CLIENT_ID + 1;
/**
* Id for 'Close' button.
*/
protected static final int ID_CLOSE_BUTTON = IDialogConstants.CLIENT_ID + 2;
/**
* Id for 'Cancel' button.
*/
protected static final int ID_CANCEL_BUTTON = IDialogConstants.CLIENT_ID + 3;
/**
* Constrant String used as key for setting and retrieving current Control with focus
*/
private static final String FOCUS_CONTROL = "focusControl";//$NON-NLS-1$
/**
* The height in pixels of this dialog's progress indicator
*/
private static int PROGRESS_INDICATOR_HEIGHT = 18;
/**
* Constant specifying how wide this dialog is allowed to get (as a percentage of
* total available screen width) as a result of tab labels in the edit area.
*/
private static final float MAX_DIALOG_WIDTH_PERCENT = 0.75f;
/**
* Empty array
*/
protected static final Object[] EMPTY_ARRAY = new Object[0];
protected static final String DEFAULT_NEW_CONFIG_NAME = LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.New_configuration_1"); //$NON-NLS-1$
/**
* Size of this dialog if there is no preference specifying a size.
*/
protected static final Point DEFAULT_INITIAL_DIALOG_SIZE = new Point(620, 560);
/**
* Status area messages
*/
protected static final String LAUNCH_STATUS_OK_MESSAGE = LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Ready_to_launch_2"); //$NON-NLS-1$
protected static final String LAUNCH_STATUS_STARTING_FROM_SCRATCH_MESSAGE
= LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Select_a_configuration_to_launch_or_a_config_type_to_create_a_new_configuration_3"); //$NON-NLS-1$
private String fCantSaveErrorMessage;
/**
* Constant specifying that the launch configuration dialog should not actually open,
* but instead should attempt to re-launch the last configuration that was sucessfully
* launched in the workspace. If there is no last launched configuration, just open the dialog.
*/
public static final int LAUNCH_CONFIGURATION_DIALOG_LAUNCH_LAST = 0;
/**
* Constant specifying that this dialog should be opened with a new configuration of a type
* specified via <code>setInitialConfigType()</code> selected.
*/
public static final int LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_NEW_CONFIG_OF_TYPE = 1;
/**
* Constant specifying that this dialog should be opened with the last configuration launched
* in the workspace selected.
*/
public static final int LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_LAST_LAUNCHED = 2;
/**
* Constant specifying that this dialog should be opened with the value specified via
* <code>setInitialSelection()</code> selected.
*/
public static final int LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_SELECTION = 3;
/**
* Specifies how this dialog behaves when opened. Value is one of the
* 'LAUNCH_CONFIGURATION_DIALOG' constants defined in this class.
*/
private int fOpenMode = LAUNCH_CONFIGURATION_DIALOG_LAUNCH_LAST;
/**
* Constructs a new launch configuration dialog on the given
* parent shell.
*
* @param shell the parent shell
* @param selection the selection used to initialize this dialog, typically the
* current workbench selection
* @param mode one of <code>ILaunchManager.RUN_MODE</code> or
* <code>ILaunchManager.DEBUG_MODE</code>
*/
public LaunchConfigurationDialog(Shell shell, IStructuredSelection selection, String mode) {
super(shell);
setShellStyle(getShellStyle() | SWT.RESIZE);
setContext(resolveContext(selection));
setMode(mode);
}
/**
* Set the flag indicating how this dialog behaves when the <code>open()</code> method is called.
* Valid values are defined by the LAUNCH_CONFIGURATION_DIALOG... constants in this class.
*/
public void setOpenMode(int mode) {
fOpenMode = mode;
}
protected int getOpenMode() {
return fOpenMode;
}
/**
* Returns the Object to be used as context for this dialog, derived from the specified selection.
* If the specified selection has as its first element an IFile whose extension matches
* <code>ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION</code>, then return
* the launch configuration declared in the IFile. Otherwise, return the first element
* in the specified selection.
*/
protected Object resolveContext(IStructuredSelection selection) {
// Empty selection means no context
if ((selection == null) || (selection.isEmpty())) {
return null;
}
// If first element is a launch config file, create a launch configuration from it
// and make this the context, otherwise just return the first element
Object firstSelected = selection.getFirstElement();
if (firstSelected instanceof IFile) {
IFile file = (IFile) firstSelected;
if (ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION.equals(file.getFileExtension())) {
return getLaunchManager().getLaunchConfiguration(file);
}
}
return firstSelected;
}
/**
* A launch configuration dialog overrides this method
* to create a custom set of buttons in the button bar.
* This dialog has 'Launch' and 'Cancel'
* buttons.
*
* @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(Composite)
*/
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, ID_LAUNCH_BUTTON, getLaunchButtonText(), true);
createButton(parent, ID_CLOSE_BUTTON, LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Close_1"), false); //$NON-NLS-1$
}
/**
* Handle the 'save and launch' & 'launch' buttons here, all others are handled
* in <code>Dialog</code>
*
* @see Dialog#buttonPressed(int)
*/
protected void buttonPressed(int buttonId) {
if (buttonId == ID_LAUNCH_BUTTON) {
handleLaunchPressed();
} else if (buttonId == ID_CLOSE_BUTTON) {
handleClosePressed();
} else {
super.buttonPressed(buttonId);
}
}
/**
* Returns the appropriate text for the launch button - run or debug.
*/
protected String getLaunchButtonText() {
if (getMode() == ILaunchManager.DEBUG_MODE) {
return LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Deb&ug_4"); //$NON-NLS-1$
} else {
return LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.R&un_5"); //$NON-NLS-1$
}
}
/**
* @see Dialog#createContents(Composite)
*/
protected Control createContents(Composite parent) {
Control contents = super.createContents(parent);
initializeBounds();
initializeSashForm();
createContextMenu(getTreeViewer().getControl());
getLaunchManager().addLaunchConfigurationListener(this);
ensureSelectionAreaWidth();
doInitialTreeSelection();
return contents;
}
/**
* Initialize the relative weights (widths) of the 2 sides of the sash.
*/
protected void initializeSashForm() {
int[] sashWeights = DEFAULT_SASH_WEIGHTS;
String sashWeightString = getPreferenceStore().getString(IDebugPreferenceConstants.PREF_LAUNCH_CONFIGURATION_DIALOG_SASH_WEIGHTS);
if (sashWeightString.length() > 0) {
Point sashWeightPoint = parseCoordinates(sashWeightString);
if (sashWeightPoint != null) {
sashWeights[0] = sashWeightPoint.x;
sashWeights[1] = sashWeightPoint.y;
}
}
getSashForm().setWeights(sashWeights);
}
/**
* Check if the selection area is currently wide enough so that both the 'New' &
* 'Delete' buttons are shown without truncation. If so, do nothing. Otherwise,
* increase the width of this dialog's Shell just enough so that both buttons
* are shown cleanly.
*/
protected void ensureSelectionAreaWidth() {
Button newButton = getButtonActionNew().getButton();
Button deleteButton = getButtonActionDelete().getButton();
int requiredWidth = newButton.getBounds().width + deleteButton.getBounds().width;
int marginWidth = ((GridLayout)getSelectionArea().getLayout()).marginWidth;
int horizontalSpacing = ((GridLayout)getSelectionArea().getLayout()).horizontalSpacing;
requiredWidth += (2 * marginWidth) + horizontalSpacing;
int currentWidth = getSelectionArea().getBounds().width;
if (requiredWidth > currentWidth) {
int[] newSashWeights = new int[2];
newSashWeights[0] = requiredWidth;
newSashWeights[1] = getEditArea().getBounds().width;
Shell shell= getShell();
Point shellSize= shell.getSize();
setShellSize(shellSize.x + (requiredWidth - currentWidth), shellSize.y);
getSashForm().setWeights(newSashWeights);
}
}
/**
* Creates a pop-up menu on the specified control.
*/
protected void createContextMenu(Control menuControl) {
MenuManager menuMgr= new MenuManager("#PopUp"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager mgr) {
fillContextMenu(mgr);
}
});
Menu menu= menuMgr.createContextMenu(menuControl);
menuControl.setMenu(menu);
}
/**
* Fill the specified context menu with the basic launch configuration
* management actions - New, Duplicate & Delete.
*/
protected void fillContextMenu(IMenuManager menu) {
if (getButtonActionNew().isEnabled()) {
menu.add(getButtonActionNew());
}
if (getButtonActionDuplicate().isEnabled()) {
menu.add(getButtonActionDuplicate());
}
if (getButtonActionDelete().isEnabled()) {
menu.add(getButtonActionDelete());
}
}
/**
* Set the initial selection in the tree.
*/
protected void doInitialTreeSelection() {
getTreeViewer().setSelection(getInitialSelection());
}
/**
* Write out this dialog's Shell size, location & sash weights to the preference store.
*/
protected void persistShellGeometry() {
Point shellLocation = getShell().getLocation();
Point shellSize = getShell().getSize();
int[] sashWeights = getSashForm().getWeights();
String locationString = serializeCoords(shellLocation);
String sizeString = serializeCoords(shellSize);
String sashWeightString = serializeCoords(new Point(sashWeights[0], sashWeights[1]));
getPreferenceStore().setValue(IDebugPreferenceConstants.PREF_LAUNCH_CONFIGURATION_DIALOG_LOCATION, locationString);
getPreferenceStore().setValue(IDebugPreferenceConstants.PREF_LAUNCH_CONFIGURATION_DIALOG_SIZE, sizeString);
getPreferenceStore().setValue(IDebugPreferenceConstants.PREF_LAUNCH_CONFIGURATION_DIALOG_SASH_WEIGHTS, sashWeightString);
}
/**
* @see Window#close()
*/
public boolean close() {
getLaunchManager().removeLaunchConfigurationListener(this);
persistShellGeometry();
return super.close();
}
/**
* Determine the first configuration for this dialog. If single-click launching is
* enabled, launch the configuration WITHOUT realizing the dialog. If single-click
* launching was successful, this method returns
* <code>ILaunchConfigurationDialog.SINGLE_CLICK_LAUNCHED</code>. Otherwise, open the
* dialog in the specified mode.
*
* @see Window#open()
*/
public int open() {
int mode = getOpenMode();
if (mode == LAUNCH_CONFIGURATION_DIALOG_LAUNCH_LAST) {
return doLastLaunchedConfig(true);
} else if (mode == LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_LAST_LAUNCHED) {
return doLastLaunchedConfig(false);
} else if (mode == LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_NEW_CONFIG_OF_TYPE) {
return openDialogOnNewConfigOfSpecifiedType();
} else if (mode == LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_SELECTION) {
return openDialogOnSelection();
}
return super.open();
}
/**
* Retrieve the last launched configuration in the workspace. If <code>launch</code>
* is <code>true</code>, launch this configuration without showing the dialog, otherwise
* just set the initial selection in the dialog to the last launched configuration.
*/
protected int doLastLaunchedConfig(boolean launch) {
ILaunchConfiguration lastLaunchedConfig = getLastLaunchedWorkbenchConfiguration();
if (launch) {
try {
if (lastLaunchedConfig != null) {
if (lastLaunchedConfig.supportsMode(getMode())) {
fUnderlyingConfig = lastLaunchedConfig;
doLaunch(lastLaunchedConfig);
} else {
// If we're trying to launch, but the last launched config doesn't
// support the current mode of the dialog, show an error dialog
String configName = lastLaunchedConfig.getName();
String title = LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Cannot_relaunch_1"); //$NON-NLS-1$
String message = MessageFormat.format(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Cannot_relaunch_[{1}]_because_it_does_not_support_{2}_mode_2"), new String[] {configName, getMode()}); //$NON-NLS-1$
MessageDialog.openError(getShell(), title, message);
}
return ILaunchConfigurationDialog.LAUNCHED_BEFORE_OPENING;
}
} catch(CoreException e) {
DebugUIPlugin.errorDialog(DebugUIPlugin.getShell(), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Launch_Configuration_Error_6"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Exception_occurred_processing_launch_configuration._See_log_for_more_information_7"), e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
if (lastLaunchedConfig != null) {
setInitialSelection(new StructuredSelection(lastLaunchedConfig));
}
return super.open();
}
/**
* Realize this dialog so that a new configuration of the type that was specified via
* <code>setInitialConfigType()</code> is selected.
*/
protected int openDialogOnNewConfigOfSpecifiedType() {
ILaunchConfigurationType configType = getInitialConfigType();
ILaunchConfiguration config = null;
if (configType != null) {
config = createConfigOfType(configType);
}
if (config != null) {
setInitialSelection(new StructuredSelection(config));
}
return super.open();
}
/**
* Open this dialog with the selection set to the value specified by
* <code>setInitialSelection()</code>.
*/
protected int openDialogOnSelection() {
// Nothing special is required, the dialog will open and whatever was specified
// via setInitialSelection() will be selected in the tree
return super.open();
}
/**
* Return the last launched configuration in the workspace.
*/
protected ILaunchConfiguration getLastLaunchedWorkbenchConfiguration() {
LaunchConfigurationHistoryElement historyElement = DebugUIPlugin.getLaunchConfigurationManager().getLastLaunch();
if (historyElement != null) {
return historyElement.getLaunchConfiguration();
}
return null;
}
/**
* @see org.eclipse.jface.dialogs.Dialog#createDialogArea(Composite)
*/
protected Control createDialogArea(Composite parent) {
GridData gd;
Composite dialogComp = (Composite)super.createDialogArea(parent);
Composite topComp = new Composite(dialogComp, SWT.NONE);
gd = new GridData(GridData.FILL_BOTH);
topComp.setLayoutData(gd);
GridLayout topLayout = new GridLayout();
topLayout.numColumns = 2;
topLayout.marginHeight = 5;
topLayout.marginWidth = 0;
topComp.setLayout(topLayout);
// Set the things that TitleAreaDialog takes care of
setTitle(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Create,_manage,_and_run_launch_configurations_8")); //$NON-NLS-1$
setMessage(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Ready_to_launch_2")); //$NON-NLS-1$
setModeLabelState();
// Create the SashForm that contains the selection area on the left,
// and the edit area on the right
setSashForm(new SashForm(topComp, SWT.NONE));
getSashForm().setOrientation(SWT.HORIZONTAL);
gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = 2;
getSashForm().setLayoutData(gd);
// Build the launch configuration selection area and put it into the composite.
Composite launchConfigSelectionArea = createLaunchConfigurationSelectionArea(getSashForm());
gd = new GridData(GridData.FILL_VERTICAL);
launchConfigSelectionArea.setLayoutData(gd);
// Build the launch configuration edit area and put it into the composite.
Composite editAreaComp = createLaunchConfigurationEditArea(getSashForm());
gd = new GridData(GridData.FILL_BOTH);
editAreaComp.setLayoutData(gd);
// Build the separator line that demarcates the button bar
Label separator = new Label(topComp, SWT.HORIZONTAL | SWT.SEPARATOR);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
separator.setLayoutData(gd);
dialogComp.layout(true);
return dialogComp;
}
/**
* Create and return a launch configuration of the specified type.
* This method is intended to be called before the UI has been realized, such as in
* the case of single-click launching or creating a config for an initial configuration
* type.
*/
protected ILaunchConfiguration createConfigOfType(ILaunchConfigurationType configType) {
ILaunchConfigurationWorkingCopy workingCopy = null;
try {
workingCopy = configType.newInstance(null, getLaunchManager().generateUniqueLaunchConfigurationNameFrom(DEFAULT_NEW_CONFIG_NAME));
} catch (CoreException ce) {
DebugUIPlugin.log(ce);
return null;
}
ILaunchConfiguration config = null;
try {
ILaunchConfigurationTabGroup group= createGroup(configType);
group.setDefaults(workingCopy);
group.dispose();
// Assign a name to the config if it doesn't already have one
if (workingCopy.getName().trim().length() == 0) {
IResource res = getResourceContext();
String name = ""; //$NON-NLS-1$
if (res != null) {
name = res.getName();
}
name = generateName(name);
workingCopy.rename(name);
}
config = workingCopy.doSave();
} catch (CoreException e) {
DebugUIPlugin.log(e);
return null;
}
return config;
}
/**
* Returns tab group for the given type of launch configuration.
* Tabs are initialized to be contained in this dialog.
*
* @exception CoreException if unable to instantiate a tab group
*/
protected ILaunchConfigurationTabGroup createGroup(final ILaunchConfigurationType configType) throws CoreException {
// Use a final Object array to store the tab group and any exception that
// results from the Runnable
final Object[] finalArray = new Object[2];
Runnable runnable = new Runnable() {
public void run() {
ILaunchConfigurationTabGroup tabGroup = null;
try {
tabGroup = LaunchConfigurationPresentationManager.getDefault().getTabGroup(configType);
finalArray[0] = tabGroup;
} catch (CoreException ce) {
finalArray[1] = ce;
return;
}
tabGroup.createTabs(LaunchConfigurationDialog.this, getMode());
ILaunchConfigurationTab[] tabs = tabGroup.getTabs();
for (int i = 0; i < tabs.length; i++) {
tabs[i].setLaunchConfigurationDialog(LaunchConfigurationDialog.this);
}
}
};
// Creating the tabs can result in plugin loading, so we show the busy cursor
BusyIndicator.showWhile(getDisplay(), runnable);
// Re-throw any CoreException if there was one
if (finalArray[1] != null) {
throw (CoreException)finalArray[1];
}
// Otherwise return the tab group
return (ILaunchConfigurationTabGroup)finalArray[0];
}
/**
* Returns the selected IResource context from the workbench,
* or <code>null</code> if there was no context in the workbench.
*/
protected IResource getResourceContext() {
if (fResourceContext == null) {
Object workbenchSelection = getContext();
if (workbenchSelection instanceof IResource) {
fResourceContext = (IResource)workbenchSelection;
} else if (workbenchSelection instanceof IAdaptable) {
fResourceContext = (IResource) ((IAdaptable)workbenchSelection).getAdapter(IResource.class);
}
}
return fResourceContext;
}
/**
* Set the title area image based on the mode this dialog was initialized with
*/
protected void setModeLabelState() {
Image image;
if (getMode().equals(ILaunchManager.DEBUG_MODE)) {
image = DebugUITools.getImage(IDebugUIConstants.IMG_WIZBAN_DEBUG);
} else {
image = DebugUITools.getImage(IDebugUIConstants.IMG_WIZBAN_RUN);
}
setTitleImage(image);
}
/**
* Convenience method to set the selection on the configuration tree.
*/
protected void setTreeViewerSelection(ISelection selection) {
getTreeViewer().setSelection(selection);
}
private void setLastSavedName(String lastSavedName) {
this.fLastSavedName = lastSavedName;
}
private String getLastSavedName() {
return fLastSavedName;
}
/**
* Update buttons and message.
*/
protected void refreshStatus() {
updateButtons();
updateMessage();
}
/**
* Verify the attributes common to all launch configuration.
* Indicate failure by throwing a <code>CoreException</code>.
*/
protected void verifyStandardAttributes() throws CoreException {
verifyName();
}
/**
* Verify that the launch configuration name is valid.
*/
protected void verifyName() throws CoreException {
String currentName = getNameTextWidget().getText().trim();
// If there is no name, complain
if (currentName.length() < 1) {
throw new CoreException(new Status(IStatus.ERROR,
DebugUIPlugin.getUniqueIdentifier(),
0,
LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Name_required_for_launch_configuration_11"), //$NON-NLS-1$
null));
}
// If the name hasn't changed from the last saved name, do nothing
if (currentName.equals(getLastSavedName())) {
return;
}
// See if name contains any 'illegal' characters
IStatus status = ResourcesPlugin.getWorkspace().validateName(currentName, IResource.FILE);
if (status.getCode() != IStatus.OK) {
throw new CoreException(new Status(IStatus.ERROR,
DebugUIPlugin.getDefault().getDescriptor().getUniqueIdentifier(),
0,
status.getMessage(),
null));
}
// Otherwise, if there's already a config with the same name, complain
if (getLaunchManager().isExistingLaunchConfigurationName(currentName)) {
throw new CoreException(new Status(IStatus.ERROR,
DebugUIPlugin.getDefault().getDescriptor().getUniqueIdentifier(),
0,
LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Launch_configuration_already_exists_with_this_name_12"), //$NON-NLS-1$
null));
}
}
/**
* If the name is valid, rename the current launch configuration. Otherwise, show an
* appropriate error message.
*/
protected void updateConfigFromName() {
if (getLaunchConfiguration() != null) {
try {
verifyName();
} catch (CoreException ce) {
refreshStatus();
return;
}
getLaunchConfiguration().rename(getNameTextWidget().getText().trim());
refreshStatus();
}
}
protected Display getDisplay() {
Shell shell = getShell();
if (shell != null) {
return shell.getDisplay();
} else {
return Display.getDefault();
}
}
/**
* Creates the launch configuration selection area of the dialog.
* This area displays a tree of launch configurations that the user
* may select, and allows users to create new configurations, and
* delete and duplicate existing configurations.
*
* @return the composite used for launch configuration selection area
*/
protected Composite createLaunchConfigurationSelectionArea(Composite parent) {
Composite comp = new Composite(parent, SWT.NONE);
setSelectionArea(comp);
GridLayout layout = new GridLayout();
layout.numColumns = 3;
layout.marginHeight = 0;
layout.marginWidth = 5;
comp.setLayout(layout);
Label treeLabel = new Label(comp, SWT.NONE);
treeLabel.setText(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Launch_Con&figurations__1")); //$NON-NLS-1$
GridData gd = new GridData();
gd.horizontalSpan = 3;
treeLabel.setLayoutData(gd);
TreeViewer tree = new TreeViewer(comp);
gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = 3;
// Set width hint to 0 to force tree to only be as wide as the combined
// width of the 'New' & 'Delete' buttons. Otherwise tree wants to be much wider.
gd.widthHint = 0;
tree.getControl().setLayoutData(gd);
tree.setContentProvider(new LaunchConfigurationContentProvider());
tree.setLabelProvider(DebugUITools.newDebugModelPresentation());
tree.setSorter(new WorkbenchViewerSorter());
setTreeViewer(tree);
tree.addSelectionChangedListener(this);
tree.setInput(ResourcesPlugin.getWorkspace().getRoot());
tree.expandAll();
tree.addDoubleClickListener(this);
tree.getControl().addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
handleKeyPressed(e);
}
});
Button newButton = SWTUtil.createPushButton(comp, LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Ne&w_13"), null); //$NON-NLS-1$
setButtonActionNew(new ButtonActionNew(newButton.getText(), newButton));
Button deleteButton = SWTUtil.createPushButton(comp, LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Dele&te_14"), null); //$NON-NLS-1$
setButtonActionDelete(new ButtonActionDelete(deleteButton.getText(), deleteButton));
setButtonActionDuplicate(new ButtonActionDuplicate(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Duplicate_1"), null)); //$NON-NLS-1$
return comp;
}
/**
* Creates the launch configuration edit area of the dialog.
* This area displays the name of the launch configuration
* currently being edited, as well as a tab folder of tabs
* that are applicable to the launch configuration.
*
* @return the composite used for launch configuration editing
*/
protected Composite createLaunchConfigurationEditArea(Composite parent) {
Composite outerComp = new Composite(parent, SWT.NONE);
GridLayout outerCompLayout = new GridLayout();
outerCompLayout.numColumns = 1;
outerCompLayout.marginHeight = 0;
outerCompLayout.marginWidth = 0;
outerComp.setLayout(outerCompLayout);
Composite comp = new Composite(outerComp, SWT.NONE);
setEditArea(comp);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
layout.marginHeight = 0;
layout.marginWidth = 5;
comp.setLayout(layout);
GridData gd = new GridData(GridData.FILL_BOTH);
comp.setLayoutData(gd);
Label nameLabel = new Label(comp, SWT.HORIZONTAL | SWT.LEFT);
nameLabel.setText(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.&Name__16")); //$NON-NLS-1$
gd = new GridData(GridData.BEGINNING);
nameLabel.setLayoutData(gd);
Text nameText = new Text(comp, SWT.SINGLE | SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL);
nameText.setLayoutData(gd);
setNameTextWidget(nameText);
getNameTextWidget().addModifyListener(
new ModifyListener() {
public void modifyText(ModifyEvent e) {
updateConfigFromName();
}
}
);
Label spacer = new Label(comp, SWT.NONE);
gd = new GridData();
gd.horizontalSpan = 2;
spacer.setLayoutData(gd);
fTabComposite = new Composite(comp, SWT.NONE);
GridLayout outerTabCompositeLayout = new GridLayout();
outerTabCompositeLayout.marginHeight = 0;
outerTabCompositeLayout.marginWidth = 0;
fTabComposite.setLayout(outerTabCompositeLayout);
gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = 2;
fTabComposite.setLayoutData(gd);
TabFolder tabFolder = new TabFolder(fTabComposite, SWT.NONE);
setTabFolder(tabFolder);
gd = new GridData(GridData.FILL_BOTH);
tabFolder.setLayoutData(gd);
getTabFolder().addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent evt) {
handleTabSelected();
}
});
Composite buttonComp = new Composite(comp, SWT.NONE);
GridLayout buttonCompLayout = new GridLayout();
buttonCompLayout.numColumns = 2;
buttonComp.setLayout(buttonCompLayout);
gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
gd.horizontalSpan = 2;
buttonComp.setLayoutData(gd);
setApplyButton(new Button(buttonComp, SWT.PUSH));
getApplyButton().setText(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.&Apply_17")); //$NON-NLS-1$
gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
getApplyButton().setLayoutData(gd);
SWTUtil.setButtonDimensionHint(getApplyButton());
getApplyButton().addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent evt) {
handleApplyPressed();
}
});
setRevertButton(new Button(buttonComp, SWT.PUSH));
getRevertButton().setText(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Revert_2")); //$NON-NLS-1$
gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
getRevertButton().setLayoutData(gd);
SWTUtil.setButtonDimensionHint(getRevertButton());
getRevertButton().addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent evt) {
handleRevertPressed();
}
});
return outerComp;
}
/**
* @see Dialog#createButtonBar(Composite)
*/
protected Control createButtonBar(Composite parent) {
Composite composite= new Composite(parent, SWT.NULL);
GridLayout layout= new GridLayout();
layout.numColumns= 2;
layout.marginHeight= 0;
layout.marginWidth= 0;
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout pmLayout = new GridLayout();
pmLayout.numColumns = 3;
setProgressMonitorPart(new ProgressMonitorPart(composite, pmLayout, PROGRESS_INDICATOR_HEIGHT));
Button cancelButton = createButton(getProgressMonitorPart(), ID_CANCEL_BUTTON, LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Cancel_3"), true); //$NON-NLS-1$
setProgressMonitorCancelButton(cancelButton);
getProgressMonitorCancelButton().addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent evt) {
setCancelButtonPressed(true);
}
});
getProgressMonitorPart().setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
getProgressMonitorPart().setVisible(false);
return super.createButtonBar(composite);
}
/**
* Sets the title for the dialog, and establishes the help context.
*
* @see org.eclipse.jface.window.Window#configureShell(Shell);
*/
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.setText(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Launch_Configurations_18")); //$NON-NLS-1$
WorkbenchHelp.setHelp(
shell,
IDebugHelpContextIds.LAUNCH_CONFIGURATION_DIALOG);
}
/**
* @see Window#getInitialLocation(Point)
*/
protected Point getInitialLocation(Point initialSize) {
String locationString = getPreferenceStore().getString(IDebugPreferenceConstants.PREF_LAUNCH_CONFIGURATION_DIALOG_LOCATION);
if (locationString.length() > 0) {
Point locationPoint = parseCoordinates(locationString);
if (locationPoint != null) {
return locationPoint;
}
}
return super.getInitialLocation(initialSize);
}
/**
* @see Window#getInitialSize()
*/
protected Point getInitialSize() {
String sizeString = getPreferenceStore().getString(IDebugPreferenceConstants.PREF_LAUNCH_CONFIGURATION_DIALOG_SIZE);
if (sizeString.length() > 0) {
Point sizePoint = parseCoordinates(sizeString);
if (sizePoint != null) {
return sizePoint;
}
}
return DEFAULT_INITIAL_DIALOG_SIZE;
}
/**
* Given a coordinate String of the form "123x456" return a Point object whose
* X value is 123 and Y value is 456. Return <code>null</code> if the String
* is not in the specified form.
*/
protected Point parseCoordinates(String coordString) {
int byIndex = coordString.indexOf('x');
if (byIndex < 0) {
return null;
}
try {
int x = Integer.parseInt(coordString.substring(0, byIndex));
int y = Integer.parseInt(coordString.substring(byIndex + 1));
return new Point(x, y);
} catch (NumberFormatException nfe) {
return null;
}
}
/**
* Given a Point object, return a String of the form "XCoordxYCoord".
*/
protected String serializeCoords(Point coords) {
StringBuffer buffer = new StringBuffer();
buffer.append(coords.x);
buffer.append('x');
buffer.append(coords.y);
return buffer.toString();
}
private void setSashForm(SashForm sashForm) {
fSashForm = sashForm;
}
protected SashForm getSashForm() {
return fSashForm;
}
/**
* Sets the tree viewer used to display launch configurations.
*
* @param viewer the tree viewer used to display launch
* configurations
*/
private void setTreeViewer(TreeViewer viewer) {
fConfigTree = viewer;
}
/**
* Returns the tree viewer used to display launch configurations.
*
* @param the tree viewer used to display launch configurations
*/
protected TreeViewer getTreeViewer() {
return fConfigTree;
}
protected IStructuredSelection getTreeViewerSelection() {
return (IStructuredSelection)getTreeViewer().getSelection();
}
protected Object getTreeViewerFirstSelectedElement() {
IStructuredSelection selection = getTreeViewerSelection();
if (selection == null) {
return null;
}
return selection.getFirstElement();
}
/**
* Content provider for launch configuration tree.
*/
class LaunchConfigurationContentProvider implements ITreeContentProvider {
/**
* Actual launch configurations have no children. Launch configuration types have
* all configurations of that type as children, minus any configurations that are
* marked as private.
*
* @see ITreeContentProvider#getChildren(Object)
*/
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof ILaunchConfiguration) {
return EMPTY_ARRAY;
} else if (parentElement instanceof ILaunchConfigurationType) {
try {
ILaunchConfigurationType type = (ILaunchConfigurationType)parentElement;
ILaunchConfiguration[] allConfigs = getLaunchManager().getLaunchConfigurations(type);
ArrayList filteredConfigs = new ArrayList(allConfigs.length);
for (int i = 0; i < allConfigs.length; i++) {
ILaunchConfiguration config = allConfigs[i];
if (config.getAttribute(IDebugUIConstants.ATTR_PRIVATE, false)) {
continue;
}
filteredConfigs.add(config);
}
return filteredConfigs.toArray();
} catch (CoreException e) {
DebugUIPlugin.errorDialog(getShell(), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Error_19"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.An_exception_occurred_while_retrieving_launch_configurations_20"), e); //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
return getLaunchManager().getLaunchConfigurationTypes();
}
return EMPTY_ARRAY;
}
/**
* @see ITreeContentProvider#getParent(Object)
*/
public Object getParent(Object element) {
if (element instanceof ILaunchConfiguration) {
if (!((ILaunchConfiguration)element).exists()) {
return null;
}
try {
return ((ILaunchConfiguration)element).getType();
} catch (CoreException e) {
DebugUIPlugin.errorDialog(getShell(), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Error_19"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.An_exception_occurred_while_retrieving_launch_configurations_20"), e); //$NON-NLS-1$ //$NON-NLS-2$
}
} else if (element instanceof ILaunchConfigurationType) {
return ResourcesPlugin.getWorkspace().getRoot();
}
return null;
}
/**
* @see ITreeContentProvider#hasChildren(Object)
*/
public boolean hasChildren(Object element) {
if (element instanceof ILaunchConfiguration) {
return false;
} else {
return getChildren(element).length > 0;
}
}
/**
* Return only the launch configuration types that support the current mode AND
* are marked as 'public'.
*
* @see IStructuredContentProvider#getElements(Object)
*/
public Object[] getElements(Object inputElement) {
ILaunchConfigurationType[] allTypes = getLaunchManager().getLaunchConfigurationTypes();
ArrayList list = new ArrayList(allTypes.length);
String mode = getMode();
for (int i = 0; i < allTypes.length; i++) {
ILaunchConfigurationType configType = allTypes[i];
if (configType.supportsMode(mode) && configType.isPublic()) {
list.add(configType);
}
}
return list.toArray();
}
/**
* @see IContentProvider#dispose()
*/
public void dispose() {
}
/**
* @see IContentProvider#inputChanged(Viewer, Object, Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
/**
* Returns the launch manager.
*
* @return the launch manager
*/
protected ILaunchManager getLaunchManager() {
return DebugPlugin.getDefault().getLaunchManager();
}
/**
* Returns whether this dialog is currently open
*/
protected boolean isVisible() {
return getTreeViewer() != null;
}
/**
* Notification that selection has changed in the launch configuration tree.
* <p>
* If the currently displayed configuration is not saved,
* prompt for saving before moving on to the new selection.
* </p>
*
* @param event selection changed event
*/
public void selectionChanged(SelectionChangedEvent event) {
// Ignore selectionChange events that occur while saving
if (ignoreSelectionChanges()) {
return;
}
// Get the new selection
IStructuredSelection selection = (IStructuredSelection)event.getSelection();
if (selection.isEmpty()) {
getEditArea().setVisible(false);
setWorkingCopy(null);
setSelectedTreeObject(null);
updateButtons();
return;
}
// Get details of the new selection
Object firstSelectedElement = selection.getFirstElement();
boolean singleSelection = selection.size() == 1;
boolean configSelected = firstSelectedElement instanceof ILaunchConfiguration;
// If selection is the same, don't bother
Object lastSelectedTreeObj = getSelectedTreeObject();
if (singleSelection && (lastSelectedTreeObj != null) && lastSelectedTreeObj.equals(firstSelectedElement)) {
getEditArea().setVisible(lastSelectedTreeObj instanceof ILaunchConfiguration);
return;
}
// Take care of any unsaved changes. If the user aborts, reset selection
// to whatever it was previously selected
boolean canReplaceConfig = canDiscardCurrentConfig();
if (!canReplaceConfig) {
StructuredSelection prevSelection;
if (lastSelectedTreeObj == null) {
prevSelection = StructuredSelection.EMPTY;
} else {
prevSelection = new StructuredSelection(lastSelectedTreeObj);
}
setTreeViewerSelection(prevSelection);
return;
}
// If a config is selected, update the edit area for it, if a config type is
// selected, clear the edit area
if (singleSelection && configSelected) {
ILaunchConfiguration config = (ILaunchConfiguration) firstSelectedElement;
setLastSavedName(config.getName());
setLaunchConfiguration(config, false);
} else if (singleSelection && firstSelectedElement instanceof ILaunchConfigurationType) {
if (canReplaceConfig) {
clearLaunchConfiguration();
getEditArea().setVisible(false);
disposeExistingTabs();
}
} else {
// multi-selection
clearLaunchConfiguration();
getEditArea().setVisible(false);
}
updateButtons();
if (singleSelection) {
setSelectedTreeObject(firstSelectedElement);
} else {
setSelectedTreeObject(null);
}
}
protected void setProgressMonitorPart(ProgressMonitorPart part) {
fProgressMonitorPart = part;
}
protected ProgressMonitorPart getProgressMonitorPart() {
return fProgressMonitorPart;
}
protected void setProgressMonitorCancelButton(Button button) {
fProgressMonitorCancelButton = button;
}
protected Button getProgressMonitorCancelButton() {
return fProgressMonitorCancelButton;
}
/**
* Sets the configuration to display/edit.
* Updates the tab folder to contain the appropriate pages.
* Sets all configuration-related state appropriately.
*
* @param config the launch configuration to display/edit
* @param init whether to initialize the config with default values
*/
protected void setLaunchConfiguration(ILaunchConfiguration config, boolean init) {
try {
// turn on initializing flag to ignore message updates
setInitializingTabs(true);
getEditArea().setVisible(true);
showTabsForConfigType(config.getType());
if (config.isWorkingCopy()) {
setWorkingCopy((ILaunchConfigurationWorkingCopy)config);
} else {
setWorkingCopy(config.getWorkingCopy());
}
fUnderlyingConfig = getLaunchConfiguration().getOriginal();
// update the name field before to avoid verify error
getNameTextWidget().setText(config.getName());
// Set the defaults for all tabs before any are initialized
// so that every tab can see ALL the default values
if (init) {
getTabGroup().setDefaults(getLaunchConfiguration());
}
// update the tabs with the new working copy
getTabGroup().initializeFrom(getLaunchConfiguration());
// update the name field after in case client changed it
getNameTextWidget().setText(config.getName());
// turn off initializing flag to update message
setInitializingTabs(false);
refreshStatus();
} catch (CoreException ce) {
DebugUIPlugin.errorDialog(getShell(), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Error_19"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Exception_occurred_setting_launch_configuration_24"), ce); //$NON-NLS-1$ //$NON-NLS-2$
clearLaunchConfiguration();
return;
}
}
/**
* Clears the configuration being shown/edited.
* Resets all configuration-related state.
*/
protected void clearLaunchConfiguration() {
setWorkingCopy(null);
fUnderlyingConfig = null;
setLastSavedName(null);
getNameTextWidget().setText(""); //$NON-NLS-1$
refreshStatus();
}
/**
* Populate the tabs in the configuration edit area to be appropriate to the current
* launch configuration type.
*/
protected void showTabsForConfigType(ILaunchConfigurationType configType) {
// Don't do any work if the current tabs are for the current config type
if (getTabType() != null && getTabType().equals(configType)) {
return;
}
// Avoid flicker
getEditArea().setVisible(false);
// Dispose the current tabs
disposeExistingTabs();
// Build the new tabs
ILaunchConfigurationTabGroup group = null;
try {
group = createGroup(configType);
} catch (CoreException ce) {
DebugUIPlugin.errorDialog(getShell(), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Error_19"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Exception_occurred_creating_launch_configuration_tabs_27"),ce); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
// Create the Control for each tab, and determine the maximum tab dimensions
PixelConverter pixelConverter = new PixelConverter(getTabFolder());
int runningTabWidth = 0;
ILaunchConfigurationTab[] tabs = group.getTabs();
Point contentSize = new Point(0, 0);
for (int i = 0; i < tabs.length; i++) {
TabItem tab = new TabItem(getTabFolder(), SWT.NONE);
String name = tabs[i].getName();
if (name == null) {
name = LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.unspecified_28"); //$NON-NLS-1$
}
tab.setText(name);
Image image = tabs[i].getImage();
tab.setImage(image);
runningTabWidth += pixelConverter.convertWidthInCharsToPixels(name.length() + 5);
if (image != null) {
runningTabWidth += image.getBounds().width;
}
tabs[i].createControl(tab.getParent());
Control control = tabs[i].getControl();
if (control != null) {
tab.setControl(control);
Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
if (size.x > contentSize.x) {
contentSize.x = size.x;
}
if (size.y > contentSize.y) {
contentSize.y = size.y;
}
}
}
// Determine if more space is needed to show all tab labels across the top of the
// tab folder. If so, only increase size of dialog to some percent of the available
// screen real estate.
if (runningTabWidth > contentSize.x) {
int maxAllowedWidth = (int) (getDisplay().getBounds().width * MAX_DIALOG_WIDTH_PERCENT);
int otherWidth = getSashForm().SASH_WIDTH + getSelectionArea().getBounds().width;
int totalWidth = runningTabWidth + otherWidth;
if (totalWidth > maxAllowedWidth) {
contentSize.x = maxAllowedWidth - otherWidth;
} else {
contentSize.x = runningTabWidth;
}
}
// Adjust the maximum tab dimensions to account for the extra space required for the tab labels
Rectangle tabFolderBoundingBox = getTabFolder().computeTrim(0, 0, contentSize.x, contentSize.y);
contentSize.x = tabFolderBoundingBox.width;
contentSize.y = tabFolderBoundingBox.height;
// Force recalculation of sizes
getTabFolder().layout(true);
// Calculate difference between required space for tab folder and current size,
// then increase size of this dialog's Shell by that amount
Rectangle rect = fTabComposite.getClientArea();
Point containerSize= new Point(rect.width, rect.height);
int hdiff= contentSize.x - containerSize.x;
int vdiff= contentSize.y - containerSize.y;
// Only increase size of dialog, never shrink it
if (hdiff > 0 || vdiff > 0) {
int[] newSashWeights = null;
if (hdiff > 0) {
newSashWeights = calculateNewSashWeights(hdiff);
}
hdiff= Math.max(0, hdiff);
vdiff= Math.max(0, vdiff);
Shell shell= getShell();
Point shellSize= shell.getSize();
setShellSize(shellSize.x + hdiff, shellSize.y + vdiff);
// Adjust the sash weights so that all of the increase in width
// is given to the tab area
if (newSashWeights != null) {
getSashForm().setWeights(newSashWeights);
}
}
setTabGroup(group);
setTabType(configType);
getEditArea().setVisible(true);
}
/**
* Calculate & return a 2 element integer array that specifies the relative
* weights of the selection area and the edit area, based on the specified
* increase in width of the owning shell. The point of this method is calculate
* sash weights such that when the shell gets wider, all of the increase in width
* is given to the edit area (tab folder), and the selection area (tree) stays
* the same width.
*/
protected int[] calculateNewSashWeights(int widthIncrease) {
int[] newWeights = new int[2];
newWeights[0] = getSelectionArea().getBounds().width;
newWeights[1] = getEditArea().getBounds().width + widthIncrease;
return newWeights;
}
/**
* Increase the size of this dialog's <code>Shell</code> by the specified amounts.
* Do not increase the size of the Shell beyond the bounds of the Display.
*/
private void setShellSize(int width, int height) {
Rectangle bounds = getShell().getDisplay().getBounds();
getShell().setSize(Math.min(width, bounds.width), Math.min(height, bounds.height));
}
protected void disposeExistingTabs() {
setDisposingTabs(true);
TabItem[] oldTabs = getTabFolder().getItems();
for (int i = 0; i < oldTabs.length; i++) {
oldTabs[i].dispose();
}
if (getTabGroup() != null) {
getTabGroup().dispose();
}
setTabGroup(null);
setTabType(null);
setDisposingTabs(false);
}
/**
* Sets the current launch configuration that is being
* displayed/edited.
*/
protected void setWorkingCopy(ILaunchConfigurationWorkingCopy workingCopy) {
fWorkingCopy = workingCopy;
}
protected boolean isWorkingCopyDirty() {
ILaunchConfigurationWorkingCopy workingCopy = getLaunchConfiguration();
if (workingCopy == null) {
return false;
}
// Working copy hasn't been saved
if (workingCopy.getOriginal() == null) {
return true;
}
// Name has changed. Normally, this would be caught in the 'contentsEqual'
// check below, however there are some circumstances where this fails, such as
// when the name is invalid
if (isNameDirty()) {
return true;
}
updateWorkingCopyFromPages();
ILaunchConfiguration original = workingCopy.getOriginal();
return !original.contentsEqual(workingCopy);
}
/**
* Return <code>true</code> if the name has been modified since the last time it was saved.
*/
protected boolean isNameDirty() {
String currentName = getNameTextWidget().getText().trim();
return !currentName.equals(getLastSavedName());
}
protected void setContext(Object context) {
fContext = context;
}
protected Object getContext() {
return fContext;
}
protected void setMode(String mode) {
fMode = mode;
}
/**
* @see ILaunchConfigurationDialog#getMode()
*/
public String getMode() {
return fMode;
}
/**
* Sets the text widget used to display the name
* of the configuration being displayed/edited
*
* @param widget the text widget used to display the name
* of the configuration being displayed/edited
*/
private void setNameTextWidget(Text widget) {
fNameText = widget;
}
/**
* Returns the text widget used to display the name
* of the configuration being displayed/edited
*
* @return the text widget used to display the name
* of the configuration being displayed/edited
*/
protected Text getNameTextWidget() {
return fNameText;
}
/**
* Sets the 'apply' button.
*
* @param button the 'apply' button.
*/
private void setApplyButton(Button button) {
fApplyButton = button;
}
/**
* Returns the 'apply' button
*
* @return the 'apply' button
*/
protected Button getApplyButton() {
return fApplyButton;
}
/**
* Sets the 'revert' button.
*
* @param button the 'revert' button.
*/
private void setRevertButton(Button button) {
fRevertButton = button;
}
/**
* Returns the 'revert' button
*
* @return the 'revert' button
*/
protected Button getRevertButton() {
return fRevertButton;
}
private void setDisposingTabs(boolean disposing) {
fDisposingTabs = disposing;
}
private boolean isDisposingTabs() {
return fDisposingTabs;
}
/**
* Sets the tab folder
*
* @param folder the tab folder
*/
private void setTabFolder(TabFolder folder) {
fTabFolder = folder;
}
/**
* Returns the tab folder
*
* @return the tab folder
*/
protected TabFolder getTabFolder() {
return fTabFolder;
}
/**
* Sets the current tab group being displayed
*
* @param group the current tab group being displayed
*/
private void setTabGroup(ILaunchConfigurationTabGroup group) {
fTabGroup = group;
}
/**
* Returns the current tab group
*
* @return the current tab group, or <code>null</code> if none
*/
public ILaunchConfigurationTabGroup getTabGroup() {
return fTabGroup;
}
/**
* @see ILaunchConfigurationDialog#getTabs()
*/
public ILaunchConfigurationTab[] getTabs() {
if (getTabGroup() == null) {
return null;
} else {
return getTabGroup().getTabs();
}
}
/**
* @see ILaunchConfigurationListener#launchConfigurationAdded(ILaunchConfiguration)
*/
public void launchConfigurationAdded(ILaunchConfiguration configuration) {
setIgnoreSelectionChanges(true);
try {
setWorkingCopy(configuration.getWorkingCopy());
fUnderlyingConfig = configuration;
} catch (CoreException e) {
DebugUIPlugin.log(e);
}
getTreeViewer().refresh();
updateButtons();
setIgnoreSelectionChanges(false);
}
/**
* @see ILaunchConfigurationListener#launchConfigurationChanged(ILaunchConfiguration)
*/
public void launchConfigurationChanged(ILaunchConfiguration configuration) {
}
/**
* @see ILaunchConfigurationListener#launchConfigurationRemoved(ILaunchConfiguration)
*/
public void launchConfigurationRemoved(ILaunchConfiguration configuration) {
getTreeViewer().remove(configuration);
}
protected void setIgnoreSelectionChanges(boolean ignore) {
fIgnoreSelectionChanges = ignore;
}
protected boolean ignoreSelectionChanges() {
return fIgnoreSelectionChanges;
}
/**
* Return whether the current configuration can be discarded. This involves determining
* if it is dirty, and if it is, asking the user what to do.
*/
protected boolean canDiscardCurrentConfig() {
// If there is no working copy, there's no problem, return true
ILaunchConfigurationWorkingCopy workingCopy = getLaunchConfiguration();
if (workingCopy == null) {
return true;
}
if (isWorkingCopyDirty()) {
return showUnsavedChangesDialog();
} else {
return true;
}
}
/**
* Show the user a dialog appropriate to whether the unsaved changes in the current config
* can be saved or not. Return <code>true</code> if the user indicated that they wish to replace
* the current config, either by saving changes or by discarding the, return <code>false</code>
* otherwise.
*/
protected boolean showUnsavedChangesDialog() {
if (canSaveConfig()) {
return showSaveChangesDialog();
} else {
return showDiscardChangesDialog();
}
}
/**
* Create and return a dialog that asks the user whether they want to save
* unsaved changes. Return <code>true </code> if they chose to save changes,
* <code>false</code> otherwise.
*/
protected boolean showSaveChangesDialog() {
StringBuffer buffer = new StringBuffer(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.The_configuration___29")); //$NON-NLS-1$
buffer.append(getLaunchConfiguration().getName());
buffer.append(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.__has_unsaved_changes.__Do_you_wish_to_save_them__30")); //$NON-NLS-1$
MessageDialog dialog = new MessageDialog(getShell(),
LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Save_changes__31"), //$NON-NLS-1$
null,
buffer.toString(),
MessageDialog.QUESTION,
new String[] {LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Yes_32"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.No_33"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Cancel_34")}, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0);
// If user clicked 'Cancel' or closed dialog, return false
int selectedButton = dialog.open();
if ((selectedButton < 0) || (selectedButton == 2)) {
return false;
}
// If they hit 'Yes', save the working copy
if (selectedButton == 0) {
saveConfig();
}
return true;
}
/**
* Create and return a dialog that asks the user whether they want to discard
* unsaved changes. Return <code>true</code> if they chose to discard changes,
* <code>false</code> otherwise.
*/
protected boolean showDiscardChangesDialog() {
StringBuffer buffer = new StringBuffer(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.The_configuration___35")); //$NON-NLS-1$
buffer.append(getNameTextWidget().getText());
buffer.append(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.__has_unsaved_changes_that_CANNOT_be_saved_because_of_the_following_error_36")); //$NON-NLS-1$
buffer.append(fCantSaveErrorMessage);
buffer.append(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Do_you_wish_to_discard_changes_37")); //$NON-NLS-1$
MessageDialog dialog = new MessageDialog(getShell(),
LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Discard_changes__38"), //$NON-NLS-1$
null,
buffer.toString(),
MessageDialog.QUESTION,
new String[] {LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Yes_32"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.No_33")}, //$NON-NLS-1$ //$NON-NLS-2$
1);
// If user clicked 'Yes', return true
int selectedButton = dialog.open();
if (selectedButton == 0) {
return true;
}
return false;
}
/**
* Return <code>true</code> if the current configuration can be saved, <code>false</code>
* otherwise. Note this is NOT the same thing as the config simply being valid. It is
* possible to save a config that does not validate. This method determines whether the
* config can be saved without causing a serious error. For example, a shared config that
* has no specified location would cause this method to return <code>false</code>.
*/
protected boolean canSaveConfig() {
fCantSaveErrorMessage = null;
// First make sure that name doesn't prevent saving the config
try {
verifyName();
} catch (CoreException ce) {
fCantSaveErrorMessage = ce.getStatus().getMessage();
return false;
}
// Next, make sure none of the tabs object to saving the config
ILaunchConfigurationTab[] tabs = getTabs();
if (tabs == null) {
fCantSaveErrorMessage = LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.No_tabs_found_41"); //$NON-NLS-1$
return false;
}
for (int i = 0; i < tabs.length; i++) {
if (!tabs[i].canSave()) {
fCantSaveErrorMessage = tabs[i].getErrorMessage();
return false;
}
}
return true;
}
/**
* Notification the 'New' action has been activated.
*/
protected void handleNewAction() {
// Take care of any unsaved changes
if (!canDiscardCurrentConfig()) {
return;
}
// The 'New' action should only be enabled if a single config type is selected
Object selectedElement = getTreeViewerFirstSelectedElement();
if (!(selectedElement instanceof ILaunchConfigurationType)) {
return;
}
// Construct a new config of the selected type and select the result in the tree
ILaunchConfigurationType configType = (ILaunchConfigurationType) selectedElement;
constructNewConfig(configType);
getTreeViewer().setSelection(new StructuredSelection(fUnderlyingConfig));
}
/**
* Notification the 'Duplicate' action has been activated.
*/
protected void handleDuplicateAction() {
// Take care of any unsaved changes
if (!canDiscardCurrentConfig()) {
return;
}
// The 'Duplicate' action should only be enabled if a single config is selected
Object selectedElement = getTreeViewerFirstSelectedElement();
if (!(selectedElement instanceof ILaunchConfiguration)) {
return;
}
// Duplicate the selected config and select the dupe in the tree
ILaunchConfiguration copyFromConfig = (ILaunchConfiguration) selectedElement;
String newName = getLaunchManager().generateUniqueLaunchConfigurationNameFrom(copyFromConfig.getName());
try {
ILaunchConfigurationWorkingCopy newWorkingCopy = copyFromConfig.copy(newName);
setLaunchConfiguration(newWorkingCopy, false);
doSave();
getTreeViewer().setSelection(new StructuredSelection(fUnderlyingConfig));
} catch (CoreException ce) {
DebugUIPlugin.log(ce);
}
}
/**
* Create a new configuration of the specified type and select it in the tree.
*/
protected void doHandleNewConfiguration(ILaunchConfigurationType configType) {
constructNewConfig(configType);
getTreeViewer().setSelection(new StructuredSelection(fUnderlyingConfig));
}
/**
* Make a copy of the specified configuration and select it in the tree.
*/
protected void doHandleCopyConfiguration(ILaunchConfiguration copyFromConfig) {
String newName = getLaunchManager().generateUniqueLaunchConfigurationNameFrom(copyFromConfig.getName());
try {
ILaunchConfigurationWorkingCopy newWorkingCopy = copyFromConfig.copy(newName);
setLaunchConfiguration(newWorkingCopy, false);
doSave();
getTreeViewer().setSelection(new StructuredSelection(fUnderlyingConfig));
} catch (CoreException ce) {
DebugUIPlugin.log(ce);
}
}
/**
* If a config type is selected, create a new config of that type initialized to
* fWorkbenchSelection. If a config is selected, create of new config of the
* same type as the selected config.
* protected void constructNewConfig() {
*/
protected void constructNewConfig(ILaunchConfigurationType configType) {
try {
ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, getLaunchManager().generateUniqueLaunchConfigurationNameFrom(DEFAULT_NEW_CONFIG_NAME));
setLastSavedName(null);
setLaunchConfiguration(wc, true);
doSave();
} catch (CoreException ce) {
DebugUIPlugin.errorDialog(getShell(), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Error_19"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Exception_creating_new_launch_configuration_45"), ce); //$NON-NLS-1$ //$NON-NLS-2$
clearLaunchConfiguration();
return;
}
}
/**
* Notification the 'Delete' action has been activated
*/
protected void handleDeleteAction() {
IStructuredSelection selection = getTreeViewerSelection();
// The 'Delete' button is disabled if the selection contains anything other than configurations (no types)
ILaunchConfiguration firstSelectedConfig = (ILaunchConfiguration) selection.getFirstElement();
ILaunchConfigurationType firstSelectedConfigType = null;
try {
firstSelectedConfigType = firstSelectedConfig.getType();
} catch (CoreException ce) {
DebugUIPlugin.log(ce);
}
// Initialize data used to set the selection after deletion
int typeIndex= -1; // The index of the deleted configuration's type
int configIndex= -1; // The index of the deleted configuration
TreeItem[] items= getTreeViewer().getTree().getItems();
TreeItem typeItem;
for (int i= 0, numTypes= items.length; i < numTypes; i++) {
typeItem= items[i];
if (typeItem.getData() == firstSelectedConfigType) {
typeIndex= i;
TreeItem[] configs= typeItem.getItems();
for (int j= 0, numConfigs= configs.length; j < numConfigs; j++) {
if (configs[j].getData() == firstSelectedConfig) {
configIndex= j;
break;
}
}
}
}
// Make the user confirm the deletion
String dialogMessage = selection.size() > 1 ? LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Do_you_wish_to_delete_the_selected_launch_configurations__1") : LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Do_you_wish_to_delete_the_selected_launch_configuration__2"); //$NON-NLS-1$ //$NON-NLS-2$
boolean ok = MessageDialog.openQuestion(this.getShell(), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Confirm_Launch_Configuration_Deletion_3"), dialogMessage); //$NON-NLS-1$
if (!ok) {
return;
}
Iterator iterator = selection.iterator();
while (iterator.hasNext()) {
clearLaunchConfiguration();
Object selectedElement = iterator.next();
if (selectedElement instanceof ILaunchConfiguration) {
try {
((ILaunchConfiguration)selectedElement).delete();
} catch (CoreException ce) {
DebugUIPlugin.log(ce);
}
}
}
IStructuredSelection newSelection= null;
if (typeIndex != -1 && configIndex != -1) {
// Reset selection to the next config
TreeItem[] configItems= getTreeViewer().getTree().getItems()[typeIndex].getItems();
int numItems= configItems.length;
if (numItems > configIndex) { // Select the item at the same index as the deleted
newSelection= new StructuredSelection(configItems[configIndex].getData());
} else if (numItems > 0) { // Deleted the last item(s). Select the last item
newSelection= new StructuredSelection(configItems[numItems - 1].getData());
}
}
if (newSelection == null) {
// Reset selection to the config type of the first selected configuration
newSelection = new StructuredSelection(firstSelectedConfigType);
}
getTreeViewer().setSelection(newSelection);
}
/**
* Notification the 'Close' button has been pressed.
*/
protected void handleClosePressed() {
if (canDiscardCurrentConfig()) {
disposeExistingTabs();
cancelPressed();
}
}
/**
* Notification that the 'Apply' button has been pressed
*/
protected void handleApplyPressed() {
saveConfig();
getTreeViewer().setSelection(new StructuredSelection(fUnderlyingConfig));
}
/**
* Notification that the 'Revert' button has been pressed
*/
protected void handleRevertPressed() {
setLaunchConfiguration(getLaunchConfiguration().getOriginal(), false);
}
protected void saveConfig() {
try {
// trim name
Text widget = getNameTextWidget();
widget.setText(widget.getText().trim());
doSave();
} catch (CoreException e) {
DebugUIPlugin.errorDialog(getShell(), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Launch_Configuration_Error_46"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Exception_occurred_while_saving_launch_configuration_47"), e); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
updateButtons();
}
/**
* Notification that a tab has been selected
*
* Disallow tab changing when the current tab is invalid.
* Update the config from the tab being left, and refresh
* the tab being entered.
*/
protected void handleTabSelected() {
if (isDisposingTabs()) {
return;
}
ILaunchConfigurationTab[] tabs = getTabs();
if (fCurrentTabIndex == getTabFolder().getSelectionIndex() || tabs == null || tabs.length == 0 || fCurrentTabIndex > (tabs.length - 1)) {
return;
}
if (fCurrentTabIndex != -1) {
ILaunchConfigurationTab tab = tabs[fCurrentTabIndex];
ILaunchConfigurationWorkingCopy wc = getLaunchConfiguration();
if (wc != null) {
// apply changes when leaving a tab
tab.performApply(getLaunchConfiguration());
// re-initialize a tab when entering it
getActiveTab().initializeFrom(wc);
}
}
fCurrentTabIndex = getTabFolder().getSelectionIndex();
refreshStatus();
}
/**
* Iterate over the pages to update the working copy
*/
protected void updateWorkingCopyFromPages() {
ILaunchConfigurationWorkingCopy workingCopy = getLaunchConfiguration();
if (getTabGroup() != null) {
getTabGroup().performApply(workingCopy);
}
}
/**
* Do the save
*/
protected void doSave() throws CoreException {
ILaunchConfigurationWorkingCopy workingCopy = getLaunchConfiguration();
updateWorkingCopyFromPages();
if (isWorkingCopyDirty()) {
fUnderlyingConfig = workingCopy.doSave();
setWorkingCopy(fUnderlyingConfig.getWorkingCopy());
setLastSavedName(fUnderlyingConfig.getName());
}
}
/**
* Notification the 'launch' button has been pressed.
* Save and launch.
*/
protected void handleLaunchPressed() {
int result = CANCEL;
try {
doSave();
result = doLaunch(getLaunchConfiguration());
} catch (CoreException e) {
DebugUIPlugin.errorDialog(getShell(), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Launch_Configuration_Error_6"), LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Exception_occurred_while_launching_configuration._See_log_for_more_information_49"), e); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
if (result == OK) {
if (fUnderlyingConfig != null) {
try {
getPreferenceStore().setValue(IDebugPreferenceConstants.PREF_LAST_LAUNCH_CONFIGURATION_SELECTION, fUnderlyingConfig.getMemento());
} catch (CoreException e) {
DebugUIPlugin.log(e);
}
}
disposeExistingTabs();
close();
} else {
getShell().setFocus();
}
}
/**
* Save the working copy if necessary, then launch the underlying configuration.
*
* @return one of CANCEL or OK
*/
protected int doLaunch(ILaunchConfiguration config) throws CoreException {
if (!DebugUITools.saveAndBuildBeforeLaunch()) {
return CANCEL;
}
// If the configuration is a working copy and is dirty or doesn't yet exist, save it
if (config instanceof ILaunchConfigurationWorkingCopy) {
ILaunchConfigurationWorkingCopy workingCopy = (ILaunchConfigurationWorkingCopy) config;
if (isWorkingCopyDirty() || !workingCopy.exists()) {
fUnderlyingConfig = workingCopy.doSave();
}
}
// liftoff
ILaunch launch = launchWithProgress();
// If the launch was cancelled, get out. Otherwise, notify the tabs of the successful launch.
if (cancelButtonPressed()) {
launch.terminate();
return CANCEL;
} else if (launch != null) {
ILaunchConfigurationTabGroup group = getTabGroup();
boolean disposeTabs = false;
if (group == null) {
// when launching without realizing this dialog, the tabs
// may not exist - create and then dispose so we can notify them of a launch
disposeTabs = true;
group = createGroup(config.getType());
}
group.launched(launch);
if (disposeTabs) {
group.dispose();
}
}
return OK;
}
/**
* @return the resulting launch, or <code>null</code> if cancelled.
* @exception CoreException if an exception occurrs launching
*/
private ILaunch launchWithProgress() throws CoreException {
final ILaunch[] launchResult = new ILaunch[1];
// Do the launch
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException {
try {
launchResult[0] = fUnderlyingConfig.launch(getMode(), monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
}
};
try {
run(true, true, runnable);
} catch (InterruptedException e) {
return null;
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof CoreException) {
throw (CoreException)t;
} else {
IStatus status = new Status(IStatus.ERROR, IDebugUIConstants.PLUGIN_ID, DebugException.INTERNAL_ERROR, LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Exception_occurred_while_launching_50"), t); //$NON-NLS-1$
throw new CoreException(status);
}
} finally {
//remove any "error" launch
ILaunchManager manager= DebugPlugin.getDefault().getLaunchManager();
ILaunch[] launches= manager.getLaunches();
for (int i = 0; i < launches.length; i++) {
ILaunch iLaunch = launches[i];
if (!iLaunch.hasChildren()) {
manager.removeLaunch(iLaunch);
}
}
}
return launchResult[0];
}
protected IPreferenceStore getPreferenceStore() {
return DebugUIPlugin.getDefault().getPreferenceStore();
}
/***************************************************************************************
*
* ProgressMonitor & IRunnableContext related methods
*
***************************************************************************************/
/**
* @see IRunnableContext#run(boolean, boolean, IRunnableWithProgress)
*/
public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException {
if (isVisible()) {
// The operation can only be canceled if it is executed in a separate thread.
// Otherwise the UI is blocked anyway.
Object state = aboutToStart();
fActiveRunningOperations++;
try {
ModalContext.run(runnable, fork, fProgressMonitorPart, getShell().getDisplay());
} finally {
fActiveRunningOperations--;
stopped(state);
}
} else {
ProgressMonitorDialog dialog = new ProgressMonitorDialog(DebugUIPlugin.getShell());
dialog.run(fork, cancelable, runnable);
}
}
/**
* About to start a long running operation triggered through
* the dialog. Shows the progress monitor and disables the dialog's
* buttons and controls.
*
* @return the saved UI state
*/
private Object aboutToStart() {
Map savedState = null;
if (getShell() != null) {
// Save focus control
Control focusControl = getShell().getDisplay().getFocusControl();
if (focusControl != null && focusControl.getShell() != getShell()) {
focusControl = null;
}
// Set the busy cursor to all shells.
Display d = getShell().getDisplay();
waitCursor = new Cursor(d, SWT.CURSOR_WAIT);
setDisplayCursor(waitCursor);
// Set the arrow cursor to the cancel component.
arrowCursor= new Cursor(d, SWT.CURSOR_ARROW);
getProgressMonitorCancelButton().setCursor(arrowCursor);
// Deactivate shell
savedState = saveUIState();
if (focusControl != null) {
savedState.put(FOCUS_CONTROL, focusControl);
}
// Attach the progress monitor part to the cancel button
getProgressMonitorCancelButton().setEnabled(true);
setCancelButtonPressed(false);
getProgressMonitorPart().attachToCancelComponent(getProgressMonitorCancelButton());
getProgressMonitorPart().setVisible(true);
getProgressMonitorCancelButton().setFocus();
}
return savedState;
}
/**
* A long running operation triggered through the dialog
* was stopped either by user input or by normal end.
* Hides the progress monitor and restores the enable state
* of the dialog's buttons and controls.
*
* @param savedState the saved UI state as returned by <code>aboutToStart</code>
* @see #aboutToStart
*/
private void stopped(Object savedState) {
if (getShell() != null) {
getProgressMonitorPart().setVisible(false);
getProgressMonitorPart().removeFromCancelComponent(getProgressMonitorCancelButton());
Map state = (Map)savedState;
restoreUIState(state);
setDisplayCursor(null);
waitCursor.dispose();
waitCursor = null;
arrowCursor.dispose();
arrowCursor = null;
Control focusControl = (Control)state.get(FOCUS_CONTROL);
if (focusControl != null) {
focusControl.setFocus();
}
}
}
/**
* Captures and returns the enabled/disabled state of the wizard dialog's
* buttons and the tree of controls for the currently showing page. All
* these controls are disabled in the process, with the possible excepton of
* the Cancel button.
*
* @return a map containing the saved state suitable for restoring later
* with <code>restoreUIState</code>
* @see #restoreUIState
*/
private Map saveUIState() {
Map savedState= new HashMap(10);
saveEnableStateAndSet(getButtonActionNew().getButton(), savedState, "new", false);//$NON-NLS-1$
saveEnableStateAndSet(getButtonActionDelete().getButton(), savedState, "delete", false);//$NON-NLS-1$
saveEnableStateAndSet(getApplyButton(), savedState, "apply", false);//$NON-NLS-1$
saveEnableStateAndSet(getRevertButton(), savedState, "revert", false);//$NON-NLS-1$
saveEnableStateAndSet(getButton(ID_LAUNCH_BUTTON), savedState, "launch", false);//$NON-NLS-1$
saveEnableStateAndSet(getButton(ID_CLOSE_BUTTON), savedState, "close", false);//$NON-NLS-1$
savedState.put("editarea", ControlEnableState.disable(getEditArea()));//$NON-NLS-1$
savedState.put("tree", ControlEnableState.disable(getTreeViewer().getControl()));//$NON-NLS-1$
return savedState;
}
/**
* Saves the enabled/disabled state of the given control in the
* given map, which must be modifiable.
*
* @param w the control, or <code>null</code> if none
* @param h the map (key type: <code>String</code>, element type:
* <code>Boolean</code>)
* @param key the key
* @param enabled <code>true</code> to enable the control,
* and <code>false</code> to disable it
* @see #restoreEnableStateAndSet
*/
private void saveEnableStateAndSet(Control w, Map h, String key, boolean enabled) {
if (w != null) {
h.put(key, new Boolean(w.isEnabled()));
w.setEnabled(enabled);
}
}
/**
* Restores the enabled/disabled state of the wizard dialog's
* buttons and the tree of controls for the currently showing page.
*
* @param state a map containing the saved state as returned by
* <code>saveUIState</code>
* @see #saveUIState
*/
private void restoreUIState(Map state) {
restoreEnableState(getButtonActionNew().getButton(), state, "new");//$NON-NLS-1$
restoreEnableState(getButtonActionDelete().getButton(), state, "delete");//$NON-NLS-1$
restoreEnableState(getApplyButton(), state, "apply");//$NON-NLS-1$
restoreEnableState(getRevertButton(), state, "revert");//$NON-NLS-1$
restoreEnableState(getButton(ID_LAUNCH_BUTTON), state, "launch");//$NON-NLS-1$
restoreEnableState(getButton(ID_CLOSE_BUTTON), state, "close");//$NON-NLS-1$
ControlEnableState tabState = (ControlEnableState) state.get("editarea");//$NON-NLS-1$
tabState.restore();
ControlEnableState treeState = (ControlEnableState) state.get("tree");//$NON-NLS-1$
treeState.restore();
}
/**
* Restores the enabled/disabled state of the given control.
*
* @param w the control
* @param h the map (key type: <code>String</code>, element type:
* <code>Boolean</code>)
* @param key the key
* @see #saveEnableStateAndSet
*/
private void restoreEnableState(Control w, Map h, String key) {
if (w != null) {
Boolean b = (Boolean) h.get(key);
if (b != null)
w.setEnabled(b.booleanValue());
}
}
protected void setCancelButtonPressed(boolean pressed) {
fCancelButtonPressed = pressed;
}
protected boolean cancelButtonPressed() {
return fCancelButtonPressed;
}
/**
* Sets the given cursor for all shells currently active
* for this window's display.
*
* @param cursor the cursor
*/
private void setDisplayCursor(Cursor cursor) {
Shell[] shells = getShell().getDisplay().getShells();
for (int i = 0; i < shells.length; i++)
shells[i].setCursor(cursor);
}
/**
* Checks whether it is alright to close this dialog
* and performed standard cancel processing. If there is a
* long running operation in progress, this method posts an
* alert message saying that the dialog cannot be closed.
*
* @return <code>true</code> if it is alright to close this dialog, and
* <code>false</code> if it is not
*/
private boolean okToClose() {
if (fActiveRunningOperations > 0) {
synchronized (this) {
fWindowClosingDialog = createDialogClosingDialog();
}
fWindowClosingDialog.open();
synchronized (this) {
fWindowClosingDialog = null;
}
return false;
}
return true;
}
/**
* Creates and return a new wizard closing dialog without opening it.
*/
private MessageDialog createDialogClosingDialog() {
MessageDialog result= new MessageDialog(
getShell(),
JFaceResources.getString("WizardClosingDialog.title"),//$NON-NLS-1$
null,
JFaceResources.getString("WizardClosingDialog.message"),//$NON-NLS-1$
MessageDialog.QUESTION,
new String[] {IDialogConstants.OK_LABEL},
0 );
return result;
}
/**
* @see ILaunchConfigurationDialog#canLaunch()
*/
public boolean canLaunch() {
try {
verifyStandardAttributes();
} catch (CoreException e) {
return false;
}
ILaunchConfigurationTab[] tabs = getTabs();
if (tabs == null) {
return false;
}
for (int i = 0; i < tabs.length; i++) {
if (!tabs[i].isValid(getLaunchConfiguration())) {
return false;
}
}
return true;
}
protected ILaunchConfigurationWorkingCopy getLaunchConfiguration() {
return fWorkingCopy;
}
/**
* @see ILaunchConfigurationDialog#updateButtons()
*/
public void updateButtons() {
if (isInitializingTabs()) {
return;
}
// Get the current selection
IStructuredSelection sel = (IStructuredSelection)getTreeViewer().getSelection();
boolean singleSelection = sel.size() == 1;
boolean firstItemLaunchConfig = sel.getFirstElement() instanceof ILaunchConfiguration;
boolean firstItemLaunchConfigType = sel.getFirstElement() instanceof ILaunchConfigurationType;
// New action
getButtonActionNew().setEnabled(singleSelection && firstItemLaunchConfigType);
// Duplicate action
getButtonActionDuplicate().setEnabled(singleSelection && firstItemLaunchConfig);
// Delete action
if (sel.isEmpty()) {
getButtonActionDelete().setEnabled(false);
} else {
Iterator iter = sel.iterator();
boolean enable = true;
while (iter.hasNext()) {
if (iter.next() instanceof ILaunchConfigurationType) {
enable = false;
break;
}
}
getButtonActionDelete().setEnabled(enable);
}
// Apply & Launch buttons
if (sel.isEmpty()) {
getApplyButton().setEnabled(false);
getButton(ID_LAUNCH_BUTTON).setEnabled(false);
} else {
boolean canLaunch = canLaunch();
getApplyButton().setEnabled(canLaunch);
getButton(ID_LAUNCH_BUTTON).setEnabled(canLaunch);
}
// Revert button
if (sel.isEmpty() || sel.size() > 1) {
getRevertButton().setEnabled(false);
} else {
if (firstItemLaunchConfig && isWorkingCopyDirty()) {
getRevertButton().setEnabled(true);
} else {
getRevertButton().setEnabled(false);
}
}
}
/**
* @see ILaunchConfigurationDialog#getActiveTab()
*/
public ILaunchConfigurationTab getActiveTab() {
TabFolder folder = getTabFolder();
ILaunchConfigurationTab[] tabs = getTabs();
if (folder != null && tabs != null) {
int pageIndex = folder.getSelectionIndex();
if (pageIndex >= 0) {
return tabs[pageIndex];
}
}
return null;
}
/**
* Returns the currently active TabItem
*
* @return launch configuration tab item
*/
protected TabItem getActiveTabItem() {
TabFolder folder = getTabFolder();
TabItem tabItem = null;
int selectedIndex = folder.getSelectionIndex();
if (selectedIndex >= 0) {
tabItem = folder.getItem(selectedIndex);
}
return tabItem;
}
/**
* @see ILaunchConfigurationDialog#updateMessage()
*/
public void updateMessage() {
if (isInitializingTabs()) {
return;
}
// If there is no current working copy, show a default informational message and clear the error message
if (getLaunchConfiguration() == null) {
setErrorMessage(null);
setMessage(LaunchConfigurationsMessages.getString("LaunchConfigurationDialog.Select_a_type_of_configuration_to_create,_and_press___new__51")); //$NON-NLS-1$
return;
}
try {
verifyStandardAttributes();
} catch (CoreException ce) {
setErrorMessage(ce.getMessage());
return;
}
// Get the active tab. If there isn't one, clear the informational & error messages
ILaunchConfigurationTab activeTab = getActiveTab();
if (activeTab == null) {
setMessage(null);
setErrorMessage(null);
return;
}
// Always set the informational (non-error) message based on the active tab
setMessage(activeTab.getMessage());
// The bias is to show the active page's error message, but if there isn't one,
// show the error message for one of the other tabs that has an error. Set the icon
// for all tabs according to whether they contain errors.
String errorMessage = checkTabForError(activeTab);
boolean errorOnActiveTab = errorMessage != null;
setTabIcon(getActiveTabItem(), errorOnActiveTab, activeTab);
ILaunchConfigurationTab[] allTabs = getTabs();
for (int i = 0; i < allTabs.length; i++) {
if (getTabFolder().getSelectionIndex() == i) {
continue;
}
String tabError = checkTabForError(allTabs[i]);
TabItem tabItem = getTabFolder().getItem(i);
boolean errorOnTab = tabError != null;
setTabIcon(tabItem, errorOnTab, allTabs[i]);
if (errorOnTab && !errorOnActiveTab) {
errorMessage = '[' + removeAmpersandsFrom(tabItem.getText()) + "]: " + tabError; //$NON-NLS-1$
}
}
setErrorMessage(errorMessage);
}
/**
* Force the tab to update it's error state and return any error message.
*/
protected String checkTabForError(ILaunchConfigurationTab tab) {
tab.isValid(getLaunchConfiguration());
return tab.getErrorMessage();
}
/**
* Set the specified tab item's icon to an error icon if <code>error</code> is true,
* or a transparent icon of the same size otherwise.
*/
protected void setTabIcon(TabItem tabItem, boolean error, ILaunchConfigurationTab tab) {
Image image = null;
if (error) {
image = LaunchConfigurationManager.getDefault().getErrorTabImage(tab);
} else {
image = tab.getImage();
}
tabItem.setImage(image);
}
/**
* Return a copy of the specified string
*/
protected String removeAmpersandsFrom(String string) {
String newString = new String(string);
int index = newString.indexOf('&');
while (index != -1) {
newString = string.substring(0, index) + newString.substring(index + 1, newString.length());
index = newString.indexOf('&');
}
return newString;
}
/**
* Returns the launch configuration selection area control.
*
* @return control
*/
protected Composite getSelectionArea() {
return fSelectionArea;
}
/**
* Sets the launch configuration selection area control.
*
* @param editArea control
*/
private void setSelectionArea(Composite selectionArea) {
fSelectionArea = selectionArea;
}
/**
* Returns the launch configuration edit area control.
*
* @return control
*/
protected Composite getEditArea() {
return fEditArea;
}
/**
* Sets the launch configuration edit area control.
*
* @param editArea control
*/
private void setEditArea(Composite editArea) {
fEditArea = editArea;
}
/**
* Returns the type that tabs are currently displayed
* for, or <code>null</code> if none.
*
* @return launch configuration type or <code>null</code>
*/
protected ILaunchConfigurationType getTabType() {
return fTabType;
}
/**
* Sets the type that tabs are currently displayed
* for, or <code>null</code> if none.
*
* @param tabType launch configuration type
*/
private void setTabType(ILaunchConfigurationType tabType) {
fTabType = tabType;
}
protected Object getSelectedTreeObject() {
return fSelectedTreeObject;
}
protected void setSelectedTreeObject(Object obj) {
fSelectedTreeObject = obj;
}
/**
* @see ILaunchConfigurationDialog#setName(String)
*/
public void setName(String name) {
if (isVisible()) {
if (name == null) {
name = ""; //$NON-NLS-1$
}
fNameText.setText(name.trim());
refreshStatus();
}
}
/**
* @see ILaunchConfigurationDialog#generateName(String)
*/
public String generateName(String name) {
if (name == null) {
name = ""; //$NON-NLS-1$
}
return getLaunchManager().generateUniqueLaunchConfigurationNameFrom(name);
}
/**
* @see IDoubleClickListener#doubleClick(DoubleClickEvent)
*/
public void doubleClick(DoubleClickEvent event) {
ISelection selection = event.getSelection();
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
Object firstSelected = structuredSelection.getFirstElement();
if (firstSelected instanceof ILaunchConfigurationType) {
if (getButtonActionNew().isEnabled()) {
getButtonActionNew().run();
}
} else if (firstSelected instanceof ILaunchConfiguration) {
if (canLaunch()) {
handleLaunchPressed();
}
}
}
}
/**
* Sets whether this dialog is initializing pages
* and should not bother to refresh status (butttons
* and message).
*/
private void setInitializingTabs(boolean init) {
fInitializingTabs = init;
}
/**
* Returns whether this dialog is initializing pages
* and should not bother to refresh status (butttons
* and message).
*/
protected boolean isInitializingTabs() {
return fInitializingTabs;
}
/**
* Returns the initial launch configuration type, or <code>null</code> if none has been set.
*/
protected ILaunchConfigurationType getInitialConfigType() {
return fInitialConfigType;
}
/**
* Sets the initial launch configuration type to be used when this dialog is opened.
*/
public void setInitialConfigType(ILaunchConfigurationType configType) {
fInitialConfigType = configType;
}
/**
* Returns the initial selection shown in this dialog when opened in
* <code>LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_SELECTION</code> mode.
*/
protected IStructuredSelection getInitialSelection() {
return fInitialSelection;
}
/**
* Sets the initial selection for the dialog when opened in
* <code>LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_SELECTION</code> mode.
*/
public void setInitialSelection(IStructuredSelection selection) {
fInitialSelection = selection;
}
/**
* Handles key events in tree viewer. Specifically
* when the delete key is pressed.
*/
protected void handleKeyPressed(KeyEvent event) {
if (event.character == SWT.DEL && event.stateMask == 0) {
if (getButtonActionDelete().isEnabled()) {
getButtonActionDelete().run();
}
}
}
protected void setButtonActionNew(ButtonAction action) {
fButtonActionNew = action;
}
protected ButtonAction getButtonActionNew() {
return fButtonActionNew;
}
protected void setButtonActionDuplicate(ButtonAction action) {
fButtonActionDuplicate = action;
}
protected ButtonAction getButtonActionDuplicate() {
return fButtonActionDuplicate;
}
protected void setButtonActionDelete(ButtonAction action) {
fButtonActionDelete = action;
}
protected ButtonAction getButtonActionDelete() {
return fButtonActionDelete;
}
/**
* Extension of <code>Action</code> that manages a <code>Button</code>
* widget. This allows common handling for actions that must appear in
* a pop-up menu and also as a (non-toolbar) button in the UI.
*/
private abstract class ButtonAction extends Action {
protected Button fButton;
/**
* Construct a ButtonAction handler. All details of the specified
* <code>Button</code>'s layout and appearance should be handled
* external to this class.
*/
public ButtonAction(String text, Button button) {
super(text);
fButton = button;
if (fButton != null) {
fButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent evt) {
ButtonAction.this.run();
}
});
}
}
public Button getButton() {
return fButton;
}
/**
* @see IAction#setEnabled(boolean)
*/
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (fButton != null) {
fButton.setEnabled(enabled);
}
}
}
/**
* Handler for creating a new configuration.
*/
private class ButtonActionNew extends ButtonAction {
public ButtonActionNew(String text, Button button) {
super(text, button);
}
public void run() {
handleNewAction();
}
}
/**
* Handler for duplicating a configuration.
*/
private class ButtonActionDuplicate extends ButtonAction {
public ButtonActionDuplicate(String text, Button button) {
super(text, button);
}
public void run() {
handleDuplicateAction();
}
}
/**
* Handler for deleting a configuration.
*/
private class ButtonActionDelete extends ButtonAction {
public ButtonActionDelete(String text, Button button) {
super(text, button);
}
public void run() {
handleDeleteAction();
}
}
}