blob: aa9e32b1e6fe502a63b1c2a25bf8cc1eeb866737 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2019 Keith Seitz 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:
* Keith Seitz (keiths@redhat.com) - initial implementation
* IBM Corporation - integration and code cleanup
* Jan Opacki (jan.opacki@gmail.com) bug 307139
* Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes
* Jens Reimann (jreimann@redhat.com) - add copy & paste support
* Andrew Obuchowicz (aobuchow@redhat.com) - Bug 548344
*******************************************************************************/
package org.eclipse.debug.ui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.internal.ui.AbstractDebugCheckboxSelectionDialog;
import org.eclipse.debug.internal.ui.DebugPluginImages;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.MultipleInputDialog;
import org.eclipse.debug.internal.ui.SWTFactory;
import org.eclipse.debug.internal.ui.TextGetSetEditingSupport;
import org.eclipse.debug.internal.ui.launchConfigurations.EnvironmentVariable;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationsMessages;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.bindings.keys.SWTKeySupport;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewerEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TableViewerEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.PlatformUI;
import com.ibm.icu.text.MessageFormat;
/**
* Launch configuration tab for configuring the environment passed into
* Runtime.exec(...) when a config is launched.
* <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>
* This class may be instantiated.
* </p>
*
* @since 3.0
* @noextend This class is not intended to be sub-classed by clients.
*/
public class EnvironmentTab extends AbstractLaunchConfigurationTab {
protected TableViewer environmentTable;
protected String[] envTableColumnHeaders = { LaunchConfigurationsMessages.EnvironmentTab_Variable_1,
LaunchConfigurationsMessages.EnvironmentTab_Value_2, };
private static final String NAME_LABEL = LaunchConfigurationsMessages.EnvironmentTab_8;
private static final String VALUE_LABEL = LaunchConfigurationsMessages.EnvironmentTab_9;
protected static final String P_VARIABLE = "variable"; //$NON-NLS-1$
protected static final String P_VALUE = "value"; //$NON-NLS-1$
protected Button envAddButton;
protected Button envEditButton;
protected Button envRemoveButton;
/**
* @since 3.14
*/
protected Button envCopyButton;
/**
* @since 3.14
*/
protected Button envPasteButton;
protected Button appendEnvironment;
protected Button replaceEnvironment;
protected Button envSelectButton;
private KeyStroke copyKeyStroke;
private KeyStroke pasteKeyStroke;
/**
* Content provider for the environment table
*/
protected class EnvironmentVariableContentProvider implements IStructuredContentProvider {
@Override
public Object[] getElements(Object inputElement) {
EnvironmentVariable[] elements = new EnvironmentVariable[0];
ILaunchConfiguration config = (ILaunchConfiguration) inputElement;
Map<String, String> m;
try {
m = config.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, (Map<String, String>) null);
} catch (CoreException e) {
DebugUIPlugin.log(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), IStatus.ERROR,
"Error reading configuration", e)); //$NON-NLS-1$
return elements;
}
if (m != null && !m.isEmpty()) {
elements = new EnvironmentVariable[m.size()];
String[] varNames = new String[m.size()];
m.keySet().toArray(varNames);
for (int i = 0; i < m.size(); i++) {
elements[i] = new EnvironmentVariable(varNames[i], m.get(varNames[i]));
}
}
return elements;
}
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
if (newInput == null) {
return;
}
if (viewer instanceof TableViewer) {
TableViewer tableViewer = (TableViewer) viewer;
if (tableViewer.getTable().isDisposed()) {
return;
}
tableViewer.setComparator(new ViewerComparator() {
@Override
public int compare(Viewer iviewer, Object e1, Object e2) {
if (e1 == null) {
return -1;
} else if (e2 == null) {
return 1;
} else {
return ((EnvironmentVariable) e1).getName()
.compareToIgnoreCase(((EnvironmentVariable) e2).getName());
}
}
});
}
}
}
/**
* Label provider for the environment table
*/
public class EnvironmentVariableLabelProvider extends LabelProvider implements ITableLabelProvider {
@Override
public String getColumnText(Object element, int columnIndex) {
String result = null;
if (element != null) {
EnvironmentVariable var = (EnvironmentVariable) element;
switch (columnIndex) {
case 0: // variable
result = var.getName();
break;
case 1: // value
result = var.getValue();
break;
default:
break;
}
}
return result;
}
@Override
public Image getColumnImage(Object element, int columnIndex) {
if (columnIndex == 0) {
return DebugPluginImages.getImage(IDebugUIConstants.IMG_OBJS_ENV_VAR);
}
return null;
}
}
/**
* Constructs a new tab with default context help.
*/
public EnvironmentTab() {
super();
setHelpContextId(IDebugHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_ENVIRONMENT_TAB);
try {
this.copyKeyStroke = KeyStroke.getInstance("M1+C"); //$NON-NLS-1$
} catch (ParseException e) {
}
try {
this.pasteKeyStroke = KeyStroke.getInstance("M1+V"); //$NON-NLS-1$
} catch (ParseException e) {
}
}
@Override
public void createControl(Composite parent) {
// Create main composite
Composite mainComposite = SWTFactory.createComposite(parent, 2, 1, GridData.FILL_HORIZONTAL);
setControl(mainComposite);
PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), getHelpContextId());
createEnvironmentTable(mainComposite);
createTableButtons(mainComposite);
createAppendReplace(mainComposite);
Dialog.applyDialogFont(mainComposite);
}
/**
* Creates and configures the widgets which allow the user to choose whether the
* specified environment should be appended to the native environment or if it
* should completely replace it.
*
* @param parent the composite in which the widgets should be created
*/
protected void createAppendReplace(Composite parent) {
Composite comp = SWTFactory.createComposite(parent, 1, 2, GridData.FILL_HORIZONTAL);
appendEnvironment = createRadioButton(comp, LaunchConfigurationsMessages.EnvironmentTab_16);
appendEnvironment.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateLaunchConfigurationDialog();
}
});
replaceEnvironment = createRadioButton(comp, LaunchConfigurationsMessages.EnvironmentTab_17);
}
/**
* Updates the enablement of the append/replace widgets. The widgets should
* disable when there are no environment variables specified.
*/
protected void updateAppendReplace() {
boolean enable = environmentTable.getTable().getItemCount() > 0;
appendEnvironment.setEnabled(enable);
replaceEnvironment.setEnabled(enable);
}
/**
* Creates and configures the table that displayed the key/value pairs that
* comprise the environment.
*
* @param parent the composite in which the table should be created
*/
protected void createEnvironmentTable(Composite parent) {
Font font = parent.getFont();
// Create label, add it to the parent to align the right side buttons with the
// top of the table
SWTFactory.createLabel(parent, LaunchConfigurationsMessages.EnvironmentTab_Environment_variables_to_set__3, 2);
// Create table composite
Composite tableComposite = SWTFactory.createComposite(parent, font, 1, 1, GridData.FILL_BOTH, 0, 0);
// Create table
environmentTable = new TableViewer(tableComposite,
SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION);
Table table = environmentTable.getTable();
table.setLayoutData(new GridData(GridData.FILL_BOTH));
table.setHeaderVisible(true);
table.setLinesVisible(true);
table.setFont(font);
environmentTable.setContentProvider(new EnvironmentVariableContentProvider());
environmentTable.setLabelProvider(new EnvironmentVariableLabelProvider());
environmentTable.setColumnProperties(new String[] { P_VARIABLE, P_VALUE });
environmentTable.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
handleTableSelectionChanged(event);
}
});
// Setup right-click context menu
Menu menuTable = new Menu(table);
table.setMenu(menuTable);
// Create add environment variable menu item
MenuItem miAdd = new MenuItem(menuTable, SWT.NONE);
miAdd.setText(LaunchConfigurationsMessages.EnvironmentTab_Add_4);
miAdd.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvAddButtonSelected();
}
});
// Create copy environment variable menu item
MenuItem miCopy = new MenuItem(menuTable, SWT.NONE);
miCopy.setText(LaunchConfigurationsMessages.EnvironmentTab_Copy);
miCopy.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvCopyButtonSelected();
}
});
// Create paste environment variable menu item
MenuItem miPaste = new MenuItem(menuTable, SWT.NONE);
miPaste.setText(LaunchConfigurationsMessages.EnvironmentTab_Paste);
miPaste.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvPasteButtonSelected();
}
});
// Create remove environment variable menu item
MenuItem miRemove = new MenuItem(menuTable, SWT.NONE);
miRemove.setText(LaunchConfigurationsMessages.EnvironmentTab_Remove_6);
miRemove.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvRemoveButtonSelected();
}
});
environmentTable.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = environmentTable.getStructuredSelection();
if (selection.size() == 1) {
miRemove.setText(LaunchConfigurationsMessages.EnvironmentTab_Remove_6);
} else if (selection.size() > 1) {
miRemove.setText(LaunchConfigurationsMessages.EnvironmentTab_Remove_All);
}
}
});
// Disable certain context menu item's if no table item is selected
table.addListener(SWT.MenuDetect, new Listener() {
@Override
public void handleEvent(Event event) {
if (table.getSelectionCount() <= 0) {
miRemove.setEnabled(false);
miCopy.setEnabled(false);
} else {
miRemove.setEnabled(true);
miCopy.setEnabled(true);
}
}
});
// Setup and create Columns
ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(environmentTable) {
@Override
protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
|| event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION
|| event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
}
};
int feature = ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
| ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION;
TableViewerEditor.create(environmentTable, actSupport, feature);
// Setup environment variable name column
final TableViewerColumn tcv1 = new TableViewerColumn(environmentTable, SWT.NONE, 0);
tcv1.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
return ((EnvironmentVariable) element).getName();
}
});
TableColumn tc1 = tcv1.getColumn();
tc1.setText(envTableColumnHeaders[0]);
tcv1.setEditingSupport(new TextGetSetEditingSupport<>(tcv1.getViewer(), EnvironmentVariable::getName,
(EnvironmentVariable envVar, String value) -> {
// Trim environment variable names
String newName = value.trim();
if (newName != null && !newName.isEmpty()) {
if (!newName.equals(envVar.getName())) {
if (canRenameVariable(newName)) {
envVar.setName(newName);
updateAppendReplace();
updateLaunchConfigurationDialog();
}
}
}
}));
// Setup environment variable value column
final TableViewerColumn tcv2 = new TableViewerColumn(environmentTable, SWT.NONE, 1);
tcv2.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
return ((EnvironmentVariable) element).getValue();
}
});
TableColumn tc2 = tcv2.getColumn();
tc2.setText(envTableColumnHeaders[1]);
tcv2.setEditingSupport(
new TextGetSetEditingSupport<>(tcv2.getViewer(), EnvironmentVariable::getValue, (envVar, value) -> {
// Don't trim environment variable values
envVar.setValue(value);
updateAppendReplace();
updateLaunchConfigurationDialog();
}));
// Create table column layout
TableColumnLayout tableColumnLayout = new TableColumnLayout(true);
PixelConverter pixelConverter = new PixelConverter(font);
tableColumnLayout.setColumnData(tc1, new ColumnWeightData(1, pixelConverter.convertWidthInCharsToPixels(20)));
tableColumnLayout.setColumnData(tc2, new ColumnWeightData(2, pixelConverter.convertWidthInCharsToPixels(20)));
tableComposite.setLayout(tableColumnLayout);
environmentTable.getTable().addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
KeyStroke current = computeKeyStroke(e);
if (current.equals(copyKeyStroke)) {
handleEnvCopyButtonSelected();
} else if (current.equals(pasteKeyStroke)) {
handleEnvPasteButtonSelected();
}
}
});
}
/**
* Responds to a selection changed event in the environment table
*
* @param event the selection change event
*/
protected void handleTableSelectionChanged(SelectionChangedEvent event) {
int size = event.getStructuredSelection().size();
envEditButton.setEnabled(size == 1);
envRemoveButton.setEnabled(size > 0);
envCopyButton.setEnabled(size > 0);
}
/**
* Creates the add/edit/remove buttons for the environment table
*
* @param parent the composite in which the buttons should be created
*/
protected void createTableButtons(Composite parent) {
// Create button composite
Composite buttonComposite = SWTFactory.createComposite(parent, parent.getFont(), 1, 1,
GridData.VERTICAL_ALIGN_BEGINNING | GridData.HORIZONTAL_ALIGN_END, 0, 0);
// Create buttons
envAddButton = createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_Add_4, null);
envAddButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvAddButtonSelected();
}
});
envSelectButton = createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_18, null);
envSelectButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvSelectButtonSelected();
}
});
envEditButton = createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_Edit_5, null);
envEditButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvEditButtonSelected();
}
});
envEditButton.setEnabled(false);
envRemoveButton = createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_Remove_6, null);
envRemoveButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvRemoveButtonSelected();
}
});
envRemoveButton.setEnabled(false);
envCopyButton = createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_Copy, null);
envCopyButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvCopyButtonSelected();
}
});
envCopyButton.setEnabled(false);
envPasteButton = createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_Paste, null);
envPasteButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleEnvPasteButtonSelected();
}
});
envPasteButton.setEnabled(true);
}
/**
* Adds a new environment variable to the table.
*/
protected void handleEnvAddButtonSelected() {
MultipleInputDialog dialog = new MultipleInputDialog(getShell(),
LaunchConfigurationsMessages.EnvironmentTab_22);
dialog.addTextField(NAME_LABEL, null, false);
dialog.addVariablesField(VALUE_LABEL, null, true);
if (dialog.open() != Window.OK) {
return;
}
String name = dialog.getStringValue(NAME_LABEL);
String value = dialog.getStringValue(VALUE_LABEL);
if (name != null && value != null && name.length() > 0 && value.length() > 0) {
// Trim the environment variable name but *NOT* the value
addVariable(new EnvironmentVariable(name.trim(), value));
updateAppendReplace();
}
}
/**
* Returns whether the environment variable can be renamed to the given variable
* name. If the name is already used for another variable, the user decides with
* a dialog whether to overwrite the existing variable
*
* @param newVariableName the chosen name to give to the variable
* @return whether the new name should be used or not
*/
private boolean canRenameVariable(String newVariableName) {
TableItem[] items = environmentTable.getTable().getItems();
for (int i = 0; i < items.length; i++) {
EnvironmentVariable existingVariable = (EnvironmentVariable) items[i].getData();
if (existingVariable.getName().equals(newVariableName)) {
boolean overWrite = MessageDialog.openQuestion(getShell(),
LaunchConfigurationsMessages.EnvironmentTab_12,
MessageFormat.format(LaunchConfigurationsMessages.EnvironmentTab_13,
new Object[] { newVariableName }));
if (!overWrite) {
return false;
}
environmentTable.remove(existingVariable);
return true;
}
}
return true;
}
/**
* Attempts to add the given variable. Returns whether the variable
* was added or not (as when the user answers not to overwrite an
* existing variable).
* @param variable the variable to add
* @return whether the variable was added
*/
protected boolean addVariable(EnvironmentVariable variable) {
String name = variable.getName();
TableItem[] items = environmentTable.getTable().getItems();
for (int i = 0; i < items.length; i++) {
EnvironmentVariable existingVariable = (EnvironmentVariable) items[i].getData();
if (existingVariable.getName().equals(name)) {
boolean overWrite = MessageDialog.openQuestion(getShell(),
LaunchConfigurationsMessages.EnvironmentTab_12,
MessageFormat.format(LaunchConfigurationsMessages.EnvironmentTab_13, new Object[] { name })); //
if (!overWrite) {
return false;
}
environmentTable.remove(existingVariable);
break;
}
}
environmentTable.add(variable);
updateLaunchConfigurationDialog();
return true;
}
/**
* Attempts to add the given variables. Returns the number of variables added
* (as when the user answers not to overwrite an existing variable).
*
* @param variables the variables to add
* @return the number of variables added
* @since 3.14
*/
protected int addVariables(List<EnvironmentVariable> variables) {
if (variables.isEmpty()) {
return 0;
}
List<EnvironmentVariable> remove = new LinkedList<>();
List<EnvironmentVariable> conflicting = new LinkedList<>();
Map<String, String> requested = variables.stream()
.collect(Collectors.toMap(EnvironmentVariable::getName, EnvironmentVariable::getValue));
for (TableItem item : environmentTable.getTable().getItems()) {
EnvironmentVariable existingVariable = (EnvironmentVariable) item.getData();
String name = existingVariable.getName();
String currentValue = requested.get(name);
if (currentValue != null) {
remove.add(existingVariable);
if (!currentValue.equals(existingVariable.getValue())) {
conflicting.add(existingVariable);
}
}
}
if (!conflicting.isEmpty()) {
String names = conflicting.stream().map(EnvironmentVariable::getName).collect(Collectors.joining(", ")); //$NON-NLS-1$
boolean overWrite = MessageDialog.openQuestion(getShell(),
LaunchConfigurationsMessages.EnvironmentTab_Paste_Overwrite_Title,
MessageFormat.format(LaunchConfigurationsMessages.EnvironmentTab_Paste_Overwrite_Message,
new Object[] { names })); //
if (!overWrite) {
return 0;
}
}
remove.forEach(environmentTable::remove);
variables.forEach(environmentTable::add);
updateLaunchConfigurationDialog();
return variables.size();
}
/**
* Displays a dialog that allows user to select native environment variables to
* add to the table.
*/
private void handleEnvSelectButtonSelected() {
// get Environment Variables from the OS
Map<String, EnvironmentVariable> envVariables = getNativeEnvironment();
// get Environment Variables from the table
TableItem[] items = environmentTable.getTable().getItems();
for (int i = 0; i < items.length; i++) {
EnvironmentVariable var = (EnvironmentVariable) items[i].getData();
envVariables.remove(var.getName());
}
NativeEnvironmentSelectionDialog dialog = new NativeEnvironmentSelectionDialog(getShell(), envVariables);
dialog.setTitle(LaunchConfigurationsMessages.EnvironmentTab_20);
int button = dialog.open();
if (button == Window.OK) {
Object[] selected = dialog.getResult();
for (int i = 0; i < selected.length; i++) {
environmentTable.add(selected[i]);
}
}
updateAppendReplace();
updateLaunchConfigurationDialog();
}
/**
* Gets native environment variable from the LaunchManager. Creates
* EnvironmentVariable objects.
*
* @return Map of name - EnvironmentVariable pairs based on native environment.
*/
private Map<String, EnvironmentVariable> getNativeEnvironment() {
Map<String, String> stringVars = DebugPlugin.getDefault().getLaunchManager()
.getNativeEnvironmentCasePreserved();
HashMap<String, EnvironmentVariable> vars = new HashMap<>();
for (Entry<String, String> entry : stringVars.entrySet()) {
vars.put(entry.getKey(), new EnvironmentVariable(entry.getKey(), entry.getValue()));
}
return vars;
}
/**
* Creates an editor for the value of the selected environment variable.
*/
private void handleEnvEditButtonSelected() {
IStructuredSelection sel = environmentTable.getStructuredSelection();
EnvironmentVariable var = (EnvironmentVariable) sel.getFirstElement();
if (var == null) {
return;
}
String originalName = var.getName();
String value = var.getValue();
MultipleInputDialog dialog = new MultipleInputDialog(getShell(),
LaunchConfigurationsMessages.EnvironmentTab_11);
dialog.addTextField(NAME_LABEL, originalName, false);
if (value != null && value.contains(System.getProperty("line.separator"))) { //$NON-NLS-1$
dialog.addMultilinedVariablesField(VALUE_LABEL, value, true);
} else {
dialog.addVariablesField(VALUE_LABEL, value, true);
}
if (dialog.open() != Window.OK) {
return;
}
String name = dialog.getStringValue(NAME_LABEL);
value = dialog.getStringValue(VALUE_LABEL);
if (!originalName.equals(name)) {
// Trim the environment variable name but *NOT* the value
if (addVariable(new EnvironmentVariable(name.trim(), value))) {
environmentTable.remove(var);
}
} else {
var.setValue(value);
environmentTable.update(var, null);
updateLaunchConfigurationDialog();
}
}
/**
* Removes the selected environment variable from the table.
*/
private void handleEnvRemoveButtonSelected() {
IStructuredSelection sel = environmentTable.getStructuredSelection();
try {
environmentTable.getControl().setRedraw(false);
for (Iterator<?> i = sel.iterator(); i.hasNext();) {
EnvironmentVariable var = (EnvironmentVariable) i.next();
environmentTable.remove(var);
}
} finally {
environmentTable.getControl().setRedraw(true);
}
updateAppendReplace();
updateLaunchConfigurationDialog();
}
/**
* Copy the currently selected table entries to the clipboard.
*/
private void handleEnvCopyButtonSelected() {
Iterable<?> iterable = () -> environmentTable.getStructuredSelection().iterator();
String data = StreamSupport.stream(iterable.spliterator(), false).filter(o -> o instanceof EnvironmentVariable)
.map(EnvironmentVariable.class::cast).map(var -> String.format("%s=%s", var.getName(), var.getValue())) //$NON-NLS-1$
.collect(Collectors.joining(System.lineSeparator()));
Clipboard clipboard = new Clipboard(getShell().getDisplay());
try {
clipboard.setContents(new Object[] { data }, new Transfer[] { TextTransfer.getInstance() });
} finally {
clipboard.dispose();
}
}
/**
* Extract the content from the clipboard and add the new content.
*/
private void handleEnvPasteButtonSelected() {
Clipboard clipboard = new Clipboard(getShell().getDisplay());
try {
List<EnvironmentVariable> variables = convertEnvironmentVariablesFromData(
clipboard.getContents(TextTransfer.getInstance()));
addVariables(variables);
updateAppendReplace();
} finally {
clipboard.dispose();
}
}
/**
* Convert the clipboard data to a list of {@link EnvironmentVariable}s. <br>
* Only entries containing an equals sign ({@code =} will be considered.
*
* @param data The clipboard data. May be {@code null}, which will result in an
* empty list.
* @return The resulting and valid {@link EnvironmentVariable}s in an
* unmodifiable list.
*/
private static List<EnvironmentVariable> convertEnvironmentVariablesFromData(Object data) {
if (!(data instanceof String)) {
return Collections.emptyList();
}
String entries[] = ((String) data).split("\\R"); //$NON-NLS-1$
List<EnvironmentVariable> result = new ArrayList<>(entries.length);
for (String entry : entries) {
int idx = entry.indexOf('=');
if (idx < 1) {
continue;
}
// the name is trimmed ...
String name = entry.substring(0, idx).trim();
// .. but the value is *not* trimmed
String value = entry.substring(idx + 1);
result.add(new EnvironmentVariable(name, value));
}
return Collections.unmodifiableList(result);
}
/**
* Updates the environment table for the given launch configuration
*
* @param configuration the configuration to use as input for the backing table
*/
protected void updateEnvironment(ILaunchConfiguration configuration) {
environmentTable.setInput(configuration);
}
@Override
public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
configuration.removeAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES);
}
@Override
public void initializeFrom(ILaunchConfiguration configuration) {
boolean append = true;
try {
append = configuration.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
} catch (CoreException e) {
DebugUIPlugin.log(e.getStatus());
}
if (append) {
appendEnvironment.setSelection(true);
replaceEnvironment.setSelection(false);
} else {
replaceEnvironment.setSelection(true);
appendEnvironment.setSelection(false);
}
updateEnvironment(configuration);
updateAppendReplace();
}
/**
* Stores the environment in the given configuration
*
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
*/
@Override
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
// Convert the table's items into a Map so that this can be saved in the
// configuration's attributes.
TableItem[] items = environmentTable.getTable().getItems();
Map<String, String> map = new HashMap<>(items.length);
for (int i = 0; i < items.length; i++) {
EnvironmentVariable var = (EnvironmentVariable) items[i].getData();
map.put(var.getName(), var.getValue());
}
if (map.isEmpty()) {
configuration.setAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, (Map<String, String>) null);
} else {
configuration.setAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, map);
}
if (appendEnvironment.getSelection()) {
ILaunchConfiguration orig = configuration.getOriginal();
boolean hasTrueValue = false;
if (orig != null) {
try {
hasTrueValue = orig.hasAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES)
&& orig.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
} catch (CoreException e) {
DebugUIPlugin.log(e.getStatus());
}
}
if (hasTrueValue) {
configuration.setAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
} else {
configuration.removeAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES);
}
} else {
configuration.setAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, false);
}
}
@Override
public String getName() {
return LaunchConfigurationsMessages.EnvironmentTab_Environment_7;
}
/**
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getId()
*
* @since 3.3
*/
@Override
public String getId() {
return "org.eclipse.debug.ui.environmentTab"; //$NON-NLS-1$
}
@Override
public Image getImage() {
return DebugPluginImages.getImage(IDebugUIConstants.IMG_OBJS_ENVIRONMENT);
}
@Override
public void activated(ILaunchConfigurationWorkingCopy workingCopy) {
// do nothing when activated
}
@Override
public void deactivated(ILaunchConfigurationWorkingCopy workingCopy) {
// do nothing when deactivated
}
/**
* @since 3.13
*/
@Override
protected void initializeAttributes() {
super.initializeAttributes();
getAttributesLabelsForPrototype().put(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES,
LaunchConfigurationsMessages.EnvironmentTab_AttributeLabel_AppendEnvironmentVariables);
getAttributesLabelsForPrototype().put(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES,
LaunchConfigurationsMessages.EnvironmentTab_AttributeLabel_EnvironmentVariables);
}
private KeyStroke computeKeyStroke(KeyEvent e) {
int accelerator = SWTKeySupport.convertEventToUnmodifiedAccelerator(e);
return SWTKeySupport.convertAcceleratorToKeyStroke(accelerator);
}
/**
* This dialog allows users to select one or more known native environment
* variables from a list.
*/
private class NativeEnvironmentSelectionDialog extends AbstractDebugCheckboxSelectionDialog {
private Object fInput;
public NativeEnvironmentSelectionDialog(Shell parentShell, Object input) {
super(parentShell);
fInput = input;
setShellStyle(getShellStyle() | SWT.RESIZE);
setShowSelectAllButtons(true);
}
@Override
protected String getDialogSettingsId() {
return IDebugUIConstants.PLUGIN_ID + ".ENVIRONMENT_TAB.NATIVE_ENVIROMENT_DIALOG"; //$NON-NLS-1$
}
@Override
protected String getHelpContextId() {
return IDebugHelpContextIds.SELECT_NATIVE_ENVIRONMENT_DIALOG;
}
@Override
protected Object getViewerInput() {
return fInput;
}
@Override
protected String getViewerLabel() {
return LaunchConfigurationsMessages.EnvironmentTab_19;
}
@Override
protected IBaseLabelProvider getLabelProvider() {
return new ILabelProvider() {
@Override
public Image getImage(Object element) {
return DebugPluginImages.getImage(IDebugUIConstants.IMG_OBJS_ENVIRONMENT);
}
@Override
public String getText(Object element) {
EnvironmentVariable var = (EnvironmentVariable) element;
return MessageFormat.format(LaunchConfigurationsMessages.EnvironmentTab_7,
new Object[] { var.getName(), var.getValue() });
}
@Override
public void addListener(ILabelProviderListener listener) {
}
@Override
public void dispose() {
}
@Override
public boolean isLabelProperty(Object element, String property) {
return false;
}
@Override
public void removeListener(ILabelProviderListener listener) {
}
};
}
@Override
protected IContentProvider getContentProvider() {
return new IStructuredContentProvider() {
@Override
public Object[] getElements(Object inputElement) {
EnvironmentVariable[] elements = null;
if (inputElement instanceof HashMap) {
Comparator<Object> comparator = new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
String s1 = (String) o1;
String s2 = (String) o2;
return s1.compareTo(s2);
}
};
TreeMap<Object, Object> envVars = new TreeMap<>(comparator);
envVars.putAll((Map<?, ?>) inputElement);
elements = new EnvironmentVariable[envVars.size()];
int index = 0;
for (Iterator<Object> iterator = envVars.keySet().iterator(); iterator.hasNext(); index++) {
Object key = iterator.next();
elements[index] = (EnvironmentVariable) envVars.get(key);
}
}
return elements;
}
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
};
}
}
}