blob: 405867a5edec98d208c2854c7d3650f95d1d106c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Wahlbrink <sw@wahlbrink.eu> - Bug 471829
* Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes
*******************************************************************************/
package org.eclipse.debug.ui;
import static org.eclipse.swt.accessibility.AccessibleListener.getNameAdapter;
import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.debug.internal.ui.SWTFactory;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationManager;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationsMessages;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchGroupExtension;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchHistory;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
import org.eclipse.ui.ide.IDEEncoding;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.views.navigator.ResourceComparator;
import org.osgi.framework.FrameworkUtil;
/**
* Launch configuration tab used to specify the location a launch configuration
* is stored in, whether it should appear in the favorites list, and perspective
* switching behavior for an associated launch.
* <p>
* Clients may call {@link #setHelpContextId(String)} on this tab prior to control
* creation to alter the default context help associated with this tab.
* </p>
* <p>
* Clients may instantiate this class.
* </p>
* @since 2.0
* @noextend This class is not intended to be subclassed by clients.
*/
public class CommonTab extends AbstractLaunchConfigurationTab {
/**
* Constant representing the id of the {@link IDialogSettings} location for the {@link ContainerSelectionDialog} used
* on this tab
*
* @since 3.6
*/
private static final String SHARED_LAUNCH_CONFIGURATON_DIALOG = IDebugUIConstants.PLUGIN_ID
+ ".SHARED_LAUNCH_CONFIGURATON_DIALOG"; //$NON-NLS-1$
private static final String WORKSPACE_SELECTION_DIALOG = IDebugUIConstants.PLUGIN_ID
+ ".WORKSPACE_SELECTION_DIALOG"; //$NON-NLS-1$
/**
* This attribute exists solely for the purpose of making sure that invalid shared locations
* can be revertible. This attribute is not saveable and will never appear in a saved
* launch configuration.
* @since 3.3
*/
private static final String BAD_CONTAINER = "bad_container_name"; //$NON-NLS-1$
// Local/shared UI widgets
private Composite fIoComposit;
private Button fLocalRadioButton;
private Button fSharedRadioButton;
private Text fSharedLocationText;
private Button fSharedLocationButton;
private Button fLaunchInBackgroundButton;
private Button fTerminateDescendantsButton;
private Button fDefaultEncodingButton;
private Button fAltEncodingButton;
private Combo fEncodingCombo;
private Button fConsoleOutput;
private Button fFileOutput;
private Button fFileBrowse;
private Text fFileText;
private Button fVariables;
private Button fAppend;
private Button fMergeOutput;
private Button fWorkspaceBrowse;
private Button fInputFileCheckButton;
private Text fInputFileLocationText;
private Button fInputFileBrowse;
private Button fInputVariables;
private Button fInputWorkspaceBrowse;
/**
* Check box list for specifying favorites
*/
private CheckboxTableViewer fFavoritesTable;
/**
* Modify listener that simply updates the owning launch configuration dialog.
*/
private ModifyListener fBasicModifyListener = evt -> scheduleUpdateJob();
/**
* Constructs a new tab with default context help.
*/
public CommonTab() {
super();
setHelpContextId(IDebugHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_COMMON_TAB);
}
@Override
public void createControl(Composite parent) {
Composite comp = new Composite(parent, SWT.NONE);
setControl(comp);
PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), getHelpContextId());
comp.setLayout(new GridLayout(2, true));
comp.setFont(parent.getFont());
createSharedConfigComponent(comp);
createFavoritesComponent(comp);
createEncodingComponent(comp);
createOutputCaptureComponent(comp);
createLaunchInBackgroundComponent(comp);
createTerminateDescendantsButtonComponent(comp);
}
/**
* Returns the {@link IDialogSettings} for the given id
*
* @param id the id of the dialog settings to get
* @return the {@link IDialogSettings} to pass into the {@link ContainerSelectionDialog}
* @since 3.6
*/
IDialogSettings getDialogBoundsSettings(String id) {
IDialogSettings settings = PlatformUI.getDialogSettingsProvider(FrameworkUtil.getBundle(CommonTab.class))
.getDialogSettings();
IDialogSettings section = settings.getSection(id);
if (section == null) {
section = settings.addNewSection(id);
}
return section;
}
/**
* Creates the favorites control
* @param parent the parent composite to add this one to
* @since 3.2
*/
private void createFavoritesComponent(Composite parent) {
Group favComp = SWTFactory.createGroup(parent, LaunchConfigurationsMessages.CommonTab_Display_in_favorites_menu__10, 1, 1, GridData.FILL_BOTH);
fFavoritesTable = CheckboxTableViewer.newCheckList(favComp, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
Control table = fFavoritesTable.getControl();
GridData gd = new GridData(GridData.FILL_BOTH);
table.setLayoutData(gd);
table.setFont(parent.getFont());
fFavoritesTable.setContentProvider(new FavoritesContentProvider());
fFavoritesTable.setLabelProvider(new FavoritesLabelProvider());
fFavoritesTable.addCheckStateListener(event -> updateLaunchConfigurationDialog());
}
/**
* Creates the shared config component
* @param parent the parent composite to add this component to
* @since 3.2
*/
private void createSharedConfigComponent(Composite parent) {
Group group = SWTFactory.createGroup(parent, LaunchConfigurationsMessages.CommonTab_0, 3, 2, GridData.FILL_HORIZONTAL);
Composite comp = SWTFactory.createComposite(group, parent.getFont(), 3, 3, GridData.FILL_BOTH, 0, 0);
fLocalRadioButton = createRadioButton(comp, LaunchConfigurationsMessages.CommonTab_L_ocal_3);
GridData gd = new GridData();
gd.horizontalSpan = 3;
fLocalRadioButton.setLayoutData(gd);
fSharedRadioButton = createRadioButton(comp, LaunchConfigurationsMessages.CommonTab_S_hared_4);
fSharedRadioButton.addSelectionListener(widgetSelectedAdapter(e -> handleSharedRadioButtonSelected()));
fSharedLocationText = SWTFactory.createSingleText(comp, 1);
fSharedLocationText.getAccessible().addAccessibleListener(
getNameAdapter(e -> e.result = LaunchConfigurationsMessages.CommonTab_S_hared_4));
fSharedLocationText.addModifyListener(fBasicModifyListener);
fSharedLocationButton = createPushButton(comp, LaunchConfigurationsMessages.CommonTab__Browse_6, null);
fSharedLocationButton.addSelectionListener(widgetSelectedAdapter(e -> handleSharedLocationButtonSelected()));
fLocalRadioButton.setSelection(true);
setSharedEnabled(false);
}
/**
* Creates the component set for the capture output composite
* @param parent the parent to add this component to
*/
private void createOutputCaptureComponent(Composite parent) {
Group group = SWTFactory.createGroup(parent, LaunchConfigurationsMessages.CommonTab_4, 5, 2, GridData.FILL_HORIZONTAL);
createInputCaptureComponent(group);
Composite comp = SWTFactory.createComposite(group, group.getFont(), 5, 5, GridData.FILL_BOTH, 0, 0);
fIoComposit = comp;
fFileOutput = createCheckButton(comp, LaunchConfigurationsMessages.CommonTab_6);
fFileOutput.setLayoutData(new GridData(SWT.BEGINNING, SWT.NORMAL, false, false));
fFileOutput.addSelectionListener(widgetSelectedAdapter(e -> {
enableOuputCaptureWidgets(fFileOutput.getSelection());
updateLaunchConfigurationDialog();
}));
fFileText = SWTFactory.createSingleText(comp, 4);
fFileText.getAccessible()
.addAccessibleListener(getNameAdapter(e -> e.result = LaunchConfigurationsMessages.CommonTab_6));
fFileText.addModifyListener(fBasicModifyListener);
Composite bcomp = SWTFactory.createComposite(comp, 3, 5, GridData.HORIZONTAL_ALIGN_END);
GridLayout ld = (GridLayout)bcomp.getLayout();
ld.marginHeight = 1;
ld.marginWidth = 0;
fWorkspaceBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_12, null);
fWorkspaceBrowse.addSelectionListener(widgetSelectedAdapter(e -> {
ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(),
new WorkbenchContentProvider());
dialog.setTitle(LaunchConfigurationsMessages.CommonTab_13);
dialog.setMessage(LaunchConfigurationsMessages.CommonTab_14);
dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
dialog.setComparator(new ResourceComparator(ResourceComparator.NAME));
dialog.setDialogBoundsSettings(getDialogBoundsSettings(WORKSPACE_SELECTION_DIALOG),
Dialog.DIALOG_PERSISTSIZE);
if (dialog.open() == IDialogConstants.OK_ID) {
IResource resource = (IResource) dialog.getFirstResult();
if (resource != null) {
String arg = resource.getFullPath().toString();
String fileLoc = VariablesPlugin.getDefault().getStringVariableManager()
.generateVariableExpression("workspace_loc", arg); //$NON-NLS-1$
fFileText.setText(fileLoc);
}
}
}));
fFileBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_7, null);
fFileBrowse.addSelectionListener(widgetSelectedAdapter(e -> {
String filePath = fFileText.getText();
FileDialog dialog = new FileDialog(getShell(), SWT.SAVE | SWT.SHEET);
filePath = dialog.open();
if (filePath != null) {
fFileText.setText(filePath);
}
}));
fVariables = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_9, null);
fVariables.addSelectionListener(widgetSelectedAdapter(e -> {
StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell());
dialog.open();
String variable = dialog.getVariableExpression();
if (variable != null) {
fFileText.insert(variable);
}
}));
fAppend = createCheckButton(comp, LaunchConfigurationsMessages.CommonTab_11);
GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, false);
gd.horizontalSpan = 5;
fAppend.setLayoutData(gd);
fAppend.addSelectionListener(widgetSelectedAdapter(e -> updateLaunchConfigurationDialog()));
}
private void createInputCaptureComponent(Composite parent){
Composite comp1 = SWTFactory.createComposite(parent, parent.getFont(), 5, 5, GridData.FILL_BOTH, 0, 0);
fConsoleOutput = createCheckButton(comp1, LaunchConfigurationsMessages.CommonTab_5);
fConsoleOutput.addSelectionListener(widgetSelectedAdapter(e -> updateLaunchConfigurationDialog()));
Composite comp = SWTFactory.createComposite(comp1, comp1.getFont(), 5, 5, GridData.FILL_BOTH, 0, 0);
fInputFileCheckButton = createCheckButton(comp, LaunchConfigurationsMessages.CommonTab_17);
GridData gd = new GridData(SWT.BEGINNING, SWT.NORMAL, false, false);
gd.horizontalSpan = 3;
fInputFileCheckButton.setLayoutData(gd);
fInputFileCheckButton.addSelectionListener(widgetSelectedAdapter(e -> {
handleInputFileButtonSelected();
updateLaunchConfigurationDialog();
}));
fInputFileLocationText = SWTFactory.createSingleText(comp, 2);
fInputFileLocationText.getAccessible()
.addAccessibleListener(getNameAdapter(e -> e.result = LaunchConfigurationsMessages.CommonTab_17));
fInputFileLocationText.addModifyListener(fBasicModifyListener);
Composite bcomp = SWTFactory.createComposite(comp, 3, 5, GridData.HORIZONTAL_ALIGN_END);
GridLayout ld = (GridLayout) bcomp.getLayout();
ld.marginHeight = 1;
ld.marginWidth = 0;
fInputWorkspaceBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_16, null);
fInputWorkspaceBrowse.addSelectionListener(widgetSelectedAdapter(e -> {
ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(),
new WorkbenchContentProvider());
dialog.setTitle(LaunchConfigurationsMessages.CommonTab_13);
dialog.setValidator(selection -> {
if (selection.length == 0) {
return new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), 0,
IInternalDebugCoreConstants.EMPTY_STRING, null);
}
for (Object f : selection) {
if (!(f instanceof IFile)) {
return new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), 0,
IInternalDebugCoreConstants.EMPTY_STRING, null);
}
}
return new Status(IStatus.OK, DebugUIPlugin.getUniqueIdentifier(), 0,
IInternalDebugCoreConstants.EMPTY_STRING, null);
});
dialog.setMessage(LaunchConfigurationsMessages.CommonTab_18);
dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
dialog.setComparator(new ResourceComparator(ResourceComparator.NAME));
dialog.setDialogBoundsSettings(getDialogBoundsSettings(WORKSPACE_SELECTION_DIALOG),
Dialog.DIALOG_PERSISTSIZE);
if (dialog.open() == IDialogConstants.OK_ID) {
IResource resource = (IResource) dialog.getFirstResult();
if (resource != null) {
String arg = resource.getFullPath().toString();
String fileLoc = VariablesPlugin.getDefault().getStringVariableManager()
.generateVariableExpression("workspace_loc", arg); //$NON-NLS-1$
fInputFileLocationText.setText(fileLoc);
}
}
}));
fInputFileBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_19, null);
fInputFileBrowse.addSelectionListener(widgetSelectedAdapter(e -> {
String filePath = fInputFileLocationText.getText();
FileDialog dialog = new FileDialog(getShell(), SWT.OK | SWT.SHEET);
filePath = dialog.open();
if (filePath != null) {
fInputFileLocationText.setText(filePath);
}
}));
fInputVariables = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_20, null);
fInputVariables.addSelectionListener(widgetSelectedAdapter(e -> {
StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell());
dialog.open();
String variable = dialog.getVariableExpression();
if (variable != null) {
fInputFileLocationText.insert(variable);
}
}));
setInputFileEnabled(false);
}
/**
* Enables or disables the output capture widgets based on the the specified enablement
* @param enable if the output capture widgets should be enabled or not
* @since 3.2
*/
private void enableOuputCaptureWidgets(boolean enable) {
fFileText.setEnabled(enable);
fFileBrowse.setEnabled(enable);
fWorkspaceBrowse.setEnabled(enable);
fVariables.setEnabled(enable);
fAppend.setEnabled(enable);
}
/**
* Returns the default encoding for the specified config
* @param config the configuration to get the encoding for
* @return the default encoding
*
* @since 3.4
*/
private String getDefaultEncoding(ILaunchConfiguration config) {
try {
IResource[] resources = config.getMappedResources();
if(resources != null && resources.length > 0) {
IResource res = resources[0];
if(res instanceof IFile) {
return ((IFile)res).getCharset();
}
else if(res instanceof IContainer) {
return ((IContainer)res).getDefaultCharset();
}
}
}
catch(CoreException ce) {
DebugUIPlugin.log(ce);
}
return ResourcesPlugin.getEncoding();
}
/**
* Creates the encoding component
* @param parent the parent to add this composite to
*/
private void createEncodingComponent(Composite parent) {
Group group = SWTFactory.createGroup(parent, LaunchConfigurationsMessages.CommonTab_1, 2, 1, GridData.FILL_BOTH);
fDefaultEncodingButton = createRadioButton(group, IInternalDebugCoreConstants.EMPTY_STRING);
GridData gd = new GridData(SWT.BEGINNING, SWT.NORMAL, true, false);
gd.horizontalSpan = 2;
fDefaultEncodingButton.setLayoutData(gd);
fAltEncodingButton = createRadioButton(group, LaunchConfigurationsMessages.CommonTab_3);
fAltEncodingButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
fEncodingCombo = new Combo(group, SWT.NONE);
fEncodingCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
fEncodingCombo.setFont(parent.getFont());
List<String> allEncodings = IDEEncoding.getIDEEncodings();
String[] encodingArray = allEncodings.toArray(new String[0]);
fEncodingCombo.setItems(encodingArray);
if (encodingArray.length > 0) {
fEncodingCombo.select(0);
}
fEncodingCombo.getAccessible()
.addAccessibleListener(getNameAdapter(e -> e.result = LaunchConfigurationsMessages.CommonTab_3));
SelectionListener listener = widgetSelectedAdapter(e -> {
if (e.getSource() instanceof Button) {
Button button = (Button) e.getSource();
if (button.getSelection()) {
updateLaunchConfigurationDialog();
fEncodingCombo.setEnabled(fAltEncodingButton.getSelection());
}
} else {
updateLaunchConfigurationDialog();
}
});
fAltEncodingButton.addSelectionListener(listener);
fDefaultEncodingButton.addSelectionListener(listener);
fEncodingCombo.addSelectionListener(listener);
fEncodingCombo.addKeyListener(KeyListener.keyReleasedAdapter(e -> scheduleUpdateJob()));
}
/**
* Returns whether or not the given encoding is valid.
*
* @param enc
* the encoding to validate
* @return <code>true</code> if the encoding is valid, <code>false</code>
* otherwise
*/
private boolean isValidEncoding(String enc) {
try {
return Charset.isSupported(enc);
} catch (IllegalCharsetNameException e) {
// This is a valid exception
return false;
}
}
/**
* Creates the controls needed to edit the launch in background
* attribute of an external tool
*
* @param parent the composite to create the controls in
*/
protected void createLaunchInBackgroundComponent(Composite parent) {
fLaunchInBackgroundButton = createCheckButton(parent, LaunchConfigurationsMessages.CommonTab_10);
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
data.horizontalSpan = 2;
fLaunchInBackgroundButton.setLayoutData(data);
fLaunchInBackgroundButton.setFont(parent.getFont());
fLaunchInBackgroundButton.addSelectionListener(widgetSelectedAdapter(e -> updateLaunchConfigurationDialog()));
}
/**
* Creates the controls needed to edit the terminate descendants attribute of an
* external tool
*
* @param parent the composite to create the controls in
*/
private void createTerminateDescendantsButtonComponent(Composite parent) {
fTerminateDescendantsButton = createCheckButton(parent,
LaunchConfigurationsMessages.CommonTab_AttributeLabel_TerminateDescendants);
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
data.horizontalSpan = 2;
fTerminateDescendantsButton.setLayoutData(data);
fTerminateDescendantsButton.setFont(parent.getFont());
fTerminateDescendantsButton.addSelectionListener(widgetSelectedAdapter(e -> updateLaunchConfigurationDialog()));
}
/**
* handles the shared radio button being selected
*/
private void handleSharedRadioButtonSelected() {
setSharedEnabled(isShared());
updateLaunchConfigurationDialog();
}
/**
* handles the input file being selected
*/
private void handleInputFileButtonSelected() {
setInputFileEnabled(isInputFile());
updateLaunchConfigurationDialog();
}
/**
* Sets the widgets for specifying that a launch configuration is to be shared to the enable value
* @param enable the enabled value for
*/
private void setSharedEnabled(boolean enable) {
fSharedLocationText.setEnabled(enable);
fSharedLocationButton.setEnabled(enable);
}
private void setInputFileEnabled(boolean enable) {
fInputFileLocationText.setEnabled(enable);
fInputFileBrowse.setEnabled(enable);
fInputWorkspaceBrowse.setEnabled(enable);
fInputVariables.setEnabled(enable);
}
private String getDefaultSharedConfigLocation(ILaunchConfiguration config) {
String path = IInternalDebugCoreConstants.EMPTY_STRING;
try {
IResource[] mappedResources = config.getMappedResources();
if(mappedResources != null) {
IProject proj;
for (IResource resource : mappedResources) {
proj = resource.getProject();
if(proj != null && proj.isAccessible()) {
return proj.getFullPath().toOSString();
}
}
}
}
catch (CoreException e) {DebugUIPlugin.log(e);}
return path;
}
/**
* if the shared radio button is selected, indicating that the launch configuration is to be shared
* @return true if the radio button is selected, false otherwise
*/
private boolean isShared() {
return fSharedRadioButton.getSelection();
}
/**
* if the input file button is selected, indicating that the launch will
* take input file as stdin
*
* @return true if the check button is selected, false otherwise
*/
private boolean isInputFile() {
return fInputFileCheckButton.getSelection();
}
/**
* Handles the shared location button being selected
*/
private void handleSharedLocationButtonSelected() {
String currentContainerString = fSharedLocationText.getText();
IContainer currentContainer = getContainer(currentContainerString);
ContainerSelectionDialog dialog = new ContainerSelectionDialog(getShell(),
currentContainer,
false,
LaunchConfigurationsMessages.CommonTab_Select_a_location_for_the_launch_configuration_13);
dialog.showClosedProjects(false);
dialog.setDialogBoundsSettings(getDialogBoundsSettings(SHARED_LAUNCH_CONFIGURATON_DIALOG), Dialog.DIALOG_PERSISTSIZE);
dialog.open();
Object[] results = dialog.getResult();
if ((results != null) && (results.length > 0) && (results[0] instanceof IPath)) {
IPath path = (IPath)results[0];
String containerName = path.toOSString();
fSharedLocationText.setText(containerName);
}
}
/**
* gets the container form the specified path
* @param path the path to get the container from
* @return the container for the specified path or null if one cannot be determined
*/
private IContainer getContainer(String path) {
Path containerPath = new Path(path);
return (IContainer) getWorkspaceRoot().findMember(containerPath);
}
@Override
public void initializeFrom(ILaunchConfiguration configuration) {
boolean isShared = !configuration.isLocal();
fSharedRadioButton.setSelection(isShared);
fLocalRadioButton.setSelection(!isShared);
setSharedEnabled(isShared);
fSharedLocationText.setText(getDefaultSharedConfigLocation(configuration));
if(isShared) {
String containerName = IInternalDebugCoreConstants.EMPTY_STRING;
IFile file = configuration.getFile();
if (file != null) {
IContainer parent = file.getParent();
if (parent != null) {
containerName = parent.getFullPath().toOSString();
}
}
fSharedLocationText.setText(containerName);
}
updateFavoritesFromConfig(configuration);
updateLaunchInBackground(configuration);
updateEncoding(configuration);
updateConsoleOutput(configuration);
boolean terminateDescendants = getAttribute(configuration, DebugPlugin.ATTR_TERMINATE_DESCENDANTS, true);
fTerminateDescendantsButton.setSelection(terminateDescendants);
}
/**
* Updates the console output form the local configuration
* @param configuration the local configuration
*/
private void updateConsoleOutput(ILaunchConfiguration configuration) {
boolean outputToConsole = getAttribute(configuration, IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, true);
String stdinFromFile = getAttribute(configuration, IDebugUIConstants.ATTR_CAPTURE_STDIN_FILE, (String) null);
String outputFile = getAttribute(configuration, IDebugUIConstants.ATTR_CAPTURE_IN_FILE, (String) null);
boolean append = getAttribute(configuration, IDebugUIConstants.ATTR_APPEND_TO_FILE, false);
boolean mergeOutput = getAttribute(configuration, DebugPlugin.ATTR_MERGE_OUTPUT, false);
boolean supportsMergeOutput = false;
try {
supportsMergeOutput = configuration.getType().supportsOutputMerging();
} catch (CoreException e) {
}
fConsoleOutput.setSelection(outputToConsole);
fAppend.setSelection(append);
if (supportsMergeOutput) {
fMergeOutput = createCheckButton(fIoComposit, LaunchConfigurationsMessages.CommonTab_21);
GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, false);
gd.horizontalSpan = 5;
fMergeOutput.setLayoutData(gd);
fMergeOutput.addSelectionListener(widgetSelectedAdapter(e -> updateLaunchConfigurationDialog()));
fMergeOutput.setSelection(mergeOutput);
}
else if (fMergeOutput != null) {
fMergeOutput.dispose();
fMergeOutput = null;
}
boolean haveOutputFile= outputFile != null;
if (haveOutputFile) {
fFileText.setText(outputFile);
}
fFileOutput.setSelection(haveOutputFile);
enableOuputCaptureWidgets(haveOutputFile);
boolean haveInputFile = stdinFromFile != null;
if (haveInputFile) {
fInputFileLocationText.setText(stdinFromFile);
}
fInputFileCheckButton.setSelection(haveInputFile);
setInputFileEnabled(haveInputFile);
}
/**
* Updates the launch on background check button
* @param configuration the local launch configuration
*/
protected void updateLaunchInBackground(ILaunchConfiguration configuration) {
fLaunchInBackgroundButton.setSelection(isLaunchInBackground(configuration));
}
/**
* Updates the encoding
* @param configuration the local configuration
*/
private void updateEncoding(ILaunchConfiguration configuration) {
String encoding = getAttribute(configuration, DebugPlugin.ATTR_CONSOLE_ENCODING, (String) null);
String defaultEncoding = getDefaultEncoding(configuration);
fDefaultEncodingButton.setText(MessageFormat.format(LaunchConfigurationsMessages.CommonTab_2, defaultEncoding));
fDefaultEncodingButton.pack();
if (encoding != null) {
fAltEncodingButton.setSelection(true);
fDefaultEncodingButton.setSelection(false);
fEncodingCombo.setText(encoding);
fEncodingCombo.setEnabled(true);
} else {
fDefaultEncodingButton.setSelection(true);
fAltEncodingButton.setSelection(false);
fEncodingCombo.setEnabled(false);
}
}
/**
* Returns whether the given configuration should be launched in the background.
*
* @param configuration the configuration
* @return whether the configuration is configured to launch in the background
*/
public static boolean isLaunchInBackground(ILaunchConfiguration configuration) {
return getAttribute(configuration, IDebugUIConstants.ATTR_LAUNCH_IN_BACKGROUND, true);
}
/**
* Updates the favorites selections from the local configuration
* @param config the local configuration
*/
@SuppressWarnings("deprecation")
private void updateFavoritesFromConfig(ILaunchConfiguration config) {
fFavoritesTable.setInput(config);
fFavoritesTable.setCheckedElements(new Object[]{});
List<String> groups = getAttribute(config, IDebugUIConstants.ATTR_FAVORITE_GROUPS, new ArrayList<>());
if (groups.isEmpty()) {
// check old attributes for backwards compatible
if (getAttribute(config, IDebugUIConstants.ATTR_DEBUG_FAVORITE, false)) {
groups.add(IDebugUIConstants.ID_DEBUG_LAUNCH_GROUP);
}
if (getAttribute(config, IDebugUIConstants.ATTR_RUN_FAVORITE, false)) {
groups.add(IDebugUIConstants.ID_RUN_LAUNCH_GROUP);
}
}
if (!groups.isEmpty()) {
List<LaunchGroupExtension> list = new ArrayList<>();
for (String id : groups) {
LaunchGroupExtension extension = getLaunchConfigurationManager().getLaunchGroup(id);
if (extension != null) {
list.add(extension);
}
}
fFavoritesTable.setCheckedElements(list.toArray());
}
}
/**
* Updates the configuration form the local shared config working copy
* @param config the local shared config working copy
*/
private void updateConfigFromLocalShared(ILaunchConfigurationWorkingCopy config) {
if (isShared()) {
String containerPathString = fSharedLocationText.getText();
IContainer container = getContainer(containerPathString);
if(container == null) {
//we need to force an attribute to allow the invalid container path to be revertable
config.setAttribute(BAD_CONTAINER, containerPathString);
}
else {
config.setContainer(container);
}
} else {
config.setContainer(null);
}
}
/**
* Convenience accessor
* @return the singleton {@link LaunchConfigurationManager}
*/
protected LaunchConfigurationManager getLaunchConfigurationManager() {
return DebugUIPlugin.getDefault().getLaunchConfigurationManager();
}
/**
* Update the favorite settings.
*
* NOTE: set to <code>null</code> instead of <code>false</code> for backwards compatibility
* when comparing if content is equal, since 'false' is default
* and will be missing for older configurations.
* @param config the configuration to update
*/
@SuppressWarnings("deprecation")
private void updateConfigFromFavorites(ILaunchConfigurationWorkingCopy config) {
Object[] checked = fFavoritesTable.getCheckedElements();
boolean debug = getAttribute(config, IDebugUIConstants.ATTR_DEBUG_FAVORITE, false);
boolean run = getAttribute(config, IDebugUIConstants.ATTR_RUN_FAVORITE, false);
if (debug || run) {
// old attributes
List<LaunchGroupExtension> groups = new ArrayList<>();
int num = 0;
if (debug) {
groups.add(getLaunchConfigurationManager().getLaunchGroup(IDebugUIConstants.ID_DEBUG_LAUNCH_GROUP));
num++;
}
if (run) {
num++;
groups.add(getLaunchConfigurationManager().getLaunchGroup(IDebugUIConstants.ID_RUN_LAUNCH_GROUP));
}
// see if there are any changes
if (num == checked.length) {
boolean different = false;
for (Object checked1 : checked) {
if (!groups.contains(checked1)) {
different = true;
break;
}
}
if (!different) {
return;
}
}
}
config.setAttribute(IDebugUIConstants.ATTR_DEBUG_FAVORITE, (String) null);
config.setAttribute(IDebugUIConstants.ATTR_RUN_FAVORITE, (String) null);
List<String> groups = null;
for (Object c : checked) {
LaunchGroupExtension group = (LaunchGroupExtension) c;
if (groups == null) {
groups = new ArrayList<>();
}
groups.add(group.getIdentifier());
}
config.setAttribute(IDebugUIConstants.ATTR_FAVORITE_GROUPS, groups);
}
private static boolean getAttribute(ILaunchConfiguration config, String attribute, boolean defaultValue) {
try {
return config.getAttribute(attribute, defaultValue);
} catch (CoreException ce) {
DebugUIPlugin.log(ce);
return defaultValue;
}
}
private static String getAttribute(ILaunchConfiguration config, String attribute, String defaultValue) {
try {
return config.getAttribute(attribute, defaultValue);
} catch (CoreException ce) {
DebugUIPlugin.log(ce);
return defaultValue;
}
}
private static List<String> getAttribute(ILaunchConfiguration config, String attribute, List<String> defaultValue) {
try {
return config.getAttribute(attribute, defaultValue);
} catch (CoreException ce) {
DebugUIPlugin.log(ce);
return defaultValue;
}
}
/**
* Convenience method for getting the workspace root.
* @return the singleton {@link IWorkspaceRoot}
*/
private IWorkspaceRoot getWorkspaceRoot() {
return ResourcesPlugin.getWorkspace().getRoot();
}
@Override
public boolean isValid(ILaunchConfiguration config) {
setMessage(null);
setErrorMessage(null);
return validateLocalShared() && validateRedirectFile() && validateEncoding() && validateStdinFile();
}
/**
* validates the encoding selection
* @return true if the validate encoding is allowable, false otherwise
*/
private boolean validateEncoding() {
if (fAltEncodingButton.getSelection() && fEncodingCombo.getSelectionIndex() == -1
&& !isValidEncoding(fEncodingCombo.getText().trim())) {
setErrorMessage(LaunchConfigurationsMessages.CommonTab_15);
return false;
}
return true;
}
/**
* Validates if the redirect file is valid
* @return true if the filename is not zero, false otherwise
*/
private boolean validateRedirectFile() {
if(fFileOutput.getSelection()) {
int len = fFileText.getText().trim().length();
if (len == 0) {
setErrorMessage(LaunchConfigurationsMessages.CommonTab_8);
return false;
}
}
return true;
}
/**
* validates the local shared config file location
* @return true if the local shared file exists, false otherwise
*/
private boolean validateLocalShared() {
if (isShared()) {
String path = fSharedLocationText.getText().trim();
IContainer container = getContainer(path);
if (container == null || container.equals(ResourcesPlugin.getWorkspace().getRoot())) {
setErrorMessage(LaunchConfigurationsMessages.CommonTab_Invalid_shared_configuration_location_14);
return false;
} else if (!container.getProject().isOpen()) {
setErrorMessage(LaunchConfigurationsMessages.CommonTab_Cannot_save_launch_configuration_in_a_closed_project__1);
return false;
}
}
return true;
}
/**
* validates the stdin file location
*
* @return true if the stdin file exists, false otherwise
*/
private boolean validateStdinFile() {
if (isInputFile()) {
int len = fInputFileLocationText.getText().trim().length();
if (len == 0) {
setErrorMessage(LaunchConfigurationsMessages.CommonTab_Invalid_stdin_file_location_15);
return false;
}
}
return true;
}
@Override
public void setDefaults(ILaunchConfigurationWorkingCopy config) {
config.setContainer(null);
setAttribute(IDebugUIConstants.ATTR_LAUNCH_IN_BACKGROUND, config, true, true);
}
@Override
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
updateConfigFromLocalShared(configuration);
updateConfigFromFavorites(configuration);
boolean launchInBackground = fLaunchInBackgroundButton.getSelection();
setAttribute(IDebugUIConstants.ATTR_LAUNCH_IN_BACKGROUND, configuration, launchInBackground, true);
boolean terminateDescendants = fTerminateDescendantsButton.getSelection();
setAttribute(DebugPlugin.ATTR_TERMINATE_DESCENDANTS, configuration, terminateDescendants, true);
String encoding = null;
if(fAltEncodingButton.getSelection()) {
encoding = fEncodingCombo.getText().trim();
}
configuration.setAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING, encoding);
boolean captureOutput = false;
if (fConsoleOutput.getSelection()) {
captureOutput = true;
configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, (String) null);
} else {
configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, false);
}
if (fInputFileCheckButton.getSelection()) {
configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_STDIN_FILE, fInputFileLocationText.getText());
} else {
configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_STDIN_FILE, (String) null);
}
if (fFileOutput.getSelection()) {
captureOutput = true;
String file = fFileText.getText();
configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_FILE, file);
if(fAppend.getSelection()) {
configuration.setAttribute(IDebugUIConstants.ATTR_APPEND_TO_FILE, true);
} else {
configuration.setAttribute(IDebugUIConstants.ATTR_APPEND_TO_FILE, (String)null);
}
} else {
configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_FILE, (String)null);
}
if (fMergeOutput != null) {
if (fMergeOutput.getSelection()) {
configuration.setAttribute(DebugPlugin.ATTR_MERGE_OUTPUT, true);
} else {
configuration.setAttribute(DebugPlugin.ATTR_MERGE_OUTPUT, (String) null);
}
}
if (!captureOutput) {
configuration.setAttribute(DebugPlugin.ATTR_CAPTURE_OUTPUT, false);
} else {
configuration.setAttribute(DebugPlugin.ATTR_CAPTURE_OUTPUT, (String)null);
}
}
@Override
public String getName() {
return LaunchConfigurationsMessages.CommonTab__Common_15;
}
/**
* @since 3.3
*/
@Override
public String getId() {
return "org.eclipse.debug.ui.commonTab"; //$NON-NLS-1$
}
@Override
public boolean canSave() {
return validateLocalShared();
}
@Override
public Image getImage() {
return DebugUITools.getImage(IInternalDebugUIConstants.IMG_OBJS_COMMON_TAB);
}
@Override
public void activated(ILaunchConfigurationWorkingCopy workingCopy) {}
@Override
public void deactivated(ILaunchConfigurationWorkingCopy workingCopy) {}
/**
* @since 3.13
*/
@Override
protected void initializeAttributes() {
super.initializeAttributes();
getAttributesLabelsForPrototype().put(DebugPlugin.ATTR_CONSOLE_ENCODING, LaunchConfigurationsMessages.CommonTab_AttributeLabel_ConsoleEncoding);
getAttributesLabelsForPrototype().put(DebugPlugin.ATTR_CAPTURE_OUTPUT, LaunchConfigurationsMessages.CommonTab_AttributeLabel_CaptureOutput);
getAttributesLabelsForPrototype().put(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, LaunchConfigurationsMessages.CommonTab_AttributeLabel_CaptureInConsole);
getAttributesLabelsForPrototype().put(IDebugUIConstants.ATTR_CAPTURE_STDIN_FILE, LaunchConfigurationsMessages.CommonTab_AttributeLabel_CaptureStdInFile);
getAttributesLabelsForPrototype().put(IDebugUIConstants.ATTR_CAPTURE_IN_FILE, LaunchConfigurationsMessages.CommonTab_AttributeLabel_CaptureInFile);
getAttributesLabelsForPrototype().put(IDebugUIConstants.ATTR_APPEND_TO_FILE, LaunchConfigurationsMessages.CommonTab_AttributeLabel_AppendToFile);
getAttributesLabelsForPrototype().put(IDebugUIConstants.ATTR_LAUNCH_IN_BACKGROUND, LaunchConfigurationsMessages.CommonTab_AttributeLabel_LaunchInBackground);
getAttributesLabelsForPrototype().put(IDebugUIConstants.ATTR_FAVORITE_GROUPS, LaunchConfigurationsMessages.CommonTab_AttributeLabel_FavoriteGroups);
getAttributesLabelsForPrototype().put(DebugPlugin.ATTR_TERMINATE_DESCENDANTS, LaunchConfigurationsMessages.CommonTab_AttributeLabel_TerminateDescendants);
}
/**
* Content provider for the favorites table
*/
class FavoritesContentProvider implements IStructuredContentProvider {
@Override
public Object[] getElements(Object inputElement) {
ILaunchGroup[] groups = DebugUITools.getLaunchGroups();
List<ILaunchGroup> possibleGroups = new ArrayList<>();
ILaunchConfiguration configuration = (ILaunchConfiguration)inputElement;
for (ILaunchGroup extension : groups) {
LaunchHistory history = getLaunchConfigurationManager().getLaunchHistory(extension.getIdentifier());
if (history != null && history.accepts(configuration)) {
possibleGroups.add(extension);
}
}
return possibleGroups.toArray();
}
@Override
public void dispose() {}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
}
/**
* Provides the labels for the favorites table
*
*/
class FavoritesLabelProvider implements ITableLabelProvider {
private Map<Object, Image> fImages = new HashMap<>();
@Override
public Image getColumnImage(Object element, int columnIndex) {
return fImages.computeIfAbsent(element, e -> {
ImageDescriptor descriptor = ((LaunchGroupExtension) e).getImageDescriptor();
return descriptor != null ? descriptor.createImage() : null;
});
}
@Override
public String getColumnText(Object element, int columnIndex) {
String label = ((LaunchGroupExtension)element).getLabel();
return DebugUIPlugin.removeAccelerators(label);
}
@Override
public void addListener(ILabelProviderListener listener) {}
@Override
public void dispose() {
for (Image image : fImages.values()) {
image.dispose();
}
}
@Override
public boolean isLabelProperty(Object element, String property) {return false;}
@Override
public void removeListener(ILabelProviderListener listener) {}
}
}