package melnorme.lang.ide.ui.build; import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull; import java.text.MessageFormat; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelectionChangedListener; 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.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; 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.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.ScrollBar; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import _org.eclipse.debug.internal.ui.MultipleInputDialog; import _org.eclipse.debug.internal.ui.SWTFactory; import melnorme.lang.ide.ui.LangImages; import melnorme.lang.tooling.commands.EnvironmentSettings; import melnorme.util.swt.SWTUtil; import melnorme.util.swt.components.AbstractWidget; import melnorme.util.swt.components.fields.FieldCompositeWidget; import melnorme.util.swt.jface.AbstractContentProvider; class EnvironmentSettingsEditor_Base extends FieldCompositeWidget<EnvironmentSettings> { protected Composite topControl; public EnvironmentSettingsEditor_Base(boolean createInlined) { super(createInlined); } @Override protected void createContents(Composite topControl) { this.topControl = topControl; super.createContents(topControl); } protected Shell getShell() { return topControl.getShell(); } @Override protected void _verifyContract_IDisableableComponent() { // super._verifyContract_IDisableableComponent(); } protected class EnvironmentVariableContentProvider extends AbstractContentProvider { @Override public Object[] getElements(Object inputElement) { return getFieldValue().envVars.map((entry) -> { return new EnvironmentVariable(entry.getKey(), entry.getValue()); }).toArray(); } } } /** * 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 EnvironmentSettingsEditor extends EnvironmentSettingsEditor_Base { protected static final String[] envTableColumnHeaders = { "Variable", "Value", }; private static final String NAME_LABEL= "&Name:"; private static final String VALUE_LABEL= "&Value:"; protected static final String P_VARIABLE = "variable"; //$NON-NLS-1$ protected static final String P_VALUE = "value"; //$NON-NLS-1$ protected TableViewer environmentTable; protected Button envAddButton; protected Button envEditButton; protected Button envRemoveButton; protected Button appendEnvironment; protected Button replaceEnvironment; protected Button envSelectButton; /** * Constructs a new tab with default context help. */ public EnvironmentSettingsEditor() { super(false); field().set(new EnvironmentSettings()); field().addListener((newValue) -> assertNotNull(newValue)); } { layoutColumns = 2; } @Override protected void doSetEnabled(boolean enabled) { super.doSetEnabled(enabled); if(environmentTable == null) { return; } setControlEnabled(environmentTable.getTable(), enabled); setControlEnabled(envAddButton, enabled); setControlEnabled(envEditButton, enabled); setControlEnabled(envRemoveButton, enabled); setControlEnabled(appendEnvironment, enabled); setControlEnabled(replaceEnvironment, enabled); setControlEnabled(envSelectButton, enabled); } @Override protected void createContents(Composite topControl) { super.createContents(topControl); createEnvironmentTable(topControl); createTableButtons(topControl); createAppendReplace(topControl); Dialog.applyDialogFont(topControl); } /** * 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= SWTFactory.createRadioButton(comp, LaunchConfigurationsMessages.EnvironmentTab_16); appendEnvironment.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { field().get().appendEnv = appendEnvironment.getSelection(); notifyFieldChanged(); } }); replaceEnvironment= SWTFactory.createRadioButton(comp, LaunchConfigurationsMessages.EnvironmentTab_17); field().addListener(true, (newValue) -> { if(SWTUtil.isOkToUse(appendEnvironment)) { appendEnvironment.setSelection(newValue.appendEnv); replaceEnvironment.setSelection(!newValue.appendEnv); } }); } /** * 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.setLayout(new GridLayout()); table.setLayoutData(AbstractWidget.gdGrabAll(400, 200)); 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.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()); } } }); environmentTable.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { handleTableSelectionChanged(event); } }); environmentTable.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { if (!environmentTable.getSelection().isEmpty()) { handleEnvEditButtonSelected(); } } }); // Create columns final TableColumn tc1 = new TableColumn(table, SWT.NONE, 0); tc1.setText(envTableColumnHeaders[0]); final TableColumn tc2 = new TableColumn(table, SWT.NONE, 1); tc2.setText(envTableColumnHeaders[1]); final Table tref = table; final Composite comp = tableComposite; tableComposite.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { Rectangle area = comp.getClientArea(); Point size = tref.computeSize(SWT.DEFAULT, SWT.DEFAULT); ScrollBar vBar = tref.getVerticalBar(); int width = area.width - tref.computeTrim(0,0,0,0).width - 2; if (size.y > area.height + tref.getHeaderHeight()) { Point vBarSize = vBar.getSize(); width -= vBarSize.x; } Point oldSize = tref.getSize(); if (oldSize.x > area.width) { tc1.setWidth(width/2-1); tc2.setWidth(width - tc1.getWidth()); tref.setSize(area.width, area.height); } else { tref.setSize(area.width, area.height); tc1.setWidth(width/2-1); tc2.setWidth(width - tc1.getWidth()); } } }); field().addListener(true, (newValue) -> { if(SWTUtil.isOkToUse(environmentTable.getTable())) { environmentTable.setInput(field().get()); environmentTable.refresh(); } }); } /** * 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 LangImages.IMG_ENV_VAR.getImage(); } return null; } } /** * Responds to a selection changed event in the environment table * @param event the selection change event */ protected void handleTableSelectionChanged(SelectionChangedEvent event) { int size = ((IStructuredSelection)event.getSelection()).size(); envEditButton.setEnabled(size == 1); envRemoveButton.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 = SWTFactory.createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_New_4, null); envAddButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { handleEnvAddButtonSelected(); } }); envSelectButton = SWTFactory.createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_18, null); envSelectButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { handleEnvSelectButtonSelected(); } }); envEditButton = SWTFactory.createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_Edit_5, null); envEditButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { handleEnvEditButtonSelected(); } }); envEditButton.setEnabled(false); envRemoveButton = SWTFactory.createPushButton(buttonComposite, LaunchConfigurationsMessages.EnvironmentTab_Remove_6, null); envRemoveButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { handleEnvRemoveButtonSelected(); } }); envRemoveButton.setEnabled(false); } /** * 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) { addVariable(new EnvironmentVariable(name.trim(), value.trim())); } } /** * 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(); if (getFieldValue().envVars.containsKey(name)) { boolean overWrite = MessageDialog.openQuestion(getShell(), LaunchConfigurationsMessages.EnvironmentTab_12, MessageFormat.format(LaunchConfigurationsMessages.EnvironmentTab_13, new Object[] { name })); // if (!overWrite) { return false; } getFieldValue().envVars.remove(name); } getFieldValue().envVars.put(name, variable.getValue()); notifyFieldChanged(); return true; } /** * 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 for (String varName : getFieldValue().envVars.keySet()) { envVariables.remove(varName); } 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++) { EnvironmentVariable envVar = (EnvironmentVariable) selected[i]; getFieldValue().envVars.put(envVar.getName(), envVar.getValue()); } } notifyFieldChanged(); } /** * Gets native environment variable from the LaunchManager. Creates EnvironmentVariable objects. * @return Map of name - EnvironmentVariable pairs based on native environment. */ protected Map<String, EnvironmentVariable> getNativeEnvironment() { Map<String, String> stringVars = DebugPlugin.getDefault().getLaunchManager().getNativeEnvironmentCasePreserved(); HashMap<String, EnvironmentVariable> vars = new HashMap<String, EnvironmentVariable>(); 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= (IStructuredSelection) environmentTable.getSelection(); EnvironmentVariable originalVar= (EnvironmentVariable) sel.getFirstElement(); if (originalVar == null) { return; } String originalName= originalVar.getName(); String value= originalVar.getValue(); MultipleInputDialog dialog= new MultipleInputDialog(getShell(), LaunchConfigurationsMessages.EnvironmentTab_11); dialog.addTextField(NAME_LABEL, originalName, false); if(value != null && value.indexOf(System.getProperty("line.separator")) > -1) { //$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)) { if (addVariable(new EnvironmentVariable(name, value))) { getFieldValue().envVars.remove(originalVar.getName()); notifyFieldChanged(); } } else { getFieldValue().envVars.put(name, value); notifyFieldChanged(); } } /** * Removes the selected environment variable from the table. */ private void handleEnvRemoveButtonSelected() { IStructuredSelection sel = (IStructuredSelection) environmentTable.getSelection(); try { // environmentTable.getControl().setRedraw(false); for (Iterator<?> i = sel.iterator(); i.hasNext();) { EnvironmentVariable var = (EnvironmentVariable) i.next(); getFieldValue().envVars.remove(var.getName()); // environmentTable.remove(var); } } finally { // environmentTable.getControl().setRedraw(true); } notifyFieldChanged(); } protected void notifyFieldChanged() { field().fireFieldValueChanged(); } }