/******************************************************************************* * Copyright (c) 2015, 2017 Red Hat Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat - Initial Contribution *******************************************************************************/ package org.eclipse.linuxtools.internal.docker.ui.wizards; import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLaunchConfigurationConstants.CPU_PRIORITY; import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLaunchConfigurationConstants.DATA_VOLUMES; import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLaunchConfigurationConstants.ENABLE_LIMITS; import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLaunchConfigurationConstants.ENV_VARIABLES; import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLaunchConfigurationConstants.LABELS; import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLaunchConfigurationConstants.MEMORY_LIMIT; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.UpdateValueStrategy; import org.eclipse.core.databinding.beans.BeanProperties; import org.eclipse.core.databinding.beans.IBeanValueProperty; import org.eclipse.core.databinding.observable.IChangeListener; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.map.IObservableMap; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.databinding.property.Properties; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider; import org.eclipse.jface.databinding.viewers.ViewerSupport; import org.eclipse.jface.databinding.viewers.ViewersObservables; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.linuxtools.docker.core.DockerException; import org.eclipse.linuxtools.docker.core.IDockerConnection; import org.eclipse.linuxtools.docker.core.IDockerImage; import org.eclipse.linuxtools.docker.core.IDockerImageInfo; import org.eclipse.linuxtools.docker.ui.Activator; import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; import org.eclipse.linuxtools.internal.docker.ui.jobs.FindImageInfoRunnable; import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumesVariablesModel.MountType; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; 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.Scale; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; /** * A {@link WizardPage} to let the user select the CPU and memory allocation for * the container, as well as the volumes to mount. * * @author xcoulon * */ public class ImageRunResourceVolumesVariablesPage extends WizardPage { private final int COLUMNS = 2; private final DataBindingContext dbc = new DataBindingContext(); private final ImageRunResourceVolumesVariablesModel model; private final ILaunchConfiguration lastLaunchConfiguration; /** * Default constructor. * * @param selectedImage * the {@link IDockerImage} to run * @throws DockerException * if obtaining info from the given {@link IDockerConnection} * failed * */ public ImageRunResourceVolumesVariablesPage( final IDockerConnection connection) throws DockerException { super("ImageSelectionPage2", //$NON-NLS-1$ WizardMessages.getString("ImageRunResourceVolVarPage.title"), //$NON-NLS-1$ SWTImagesFactory.DESC_BANNER_REPOSITORY); setPageComplete(true); this.model = new ImageRunResourceVolumesVariablesModel(connection); this.lastLaunchConfiguration = null; } /** * Default constructor. * * @param selectedImage * the {@link IDockerImage} to run * @param lastLaunchConfiguration * the last {@link ILaunchConfiguration} used to run this * {@link IDockerImage} or <code>null</code> if none exists. * @throws DockerException * if obtaining info from the given {@link IDockerConnection} * failed * @throws CoreException * if reading attributes from {@link ILaunchConfiguration} * failed * */ public ImageRunResourceVolumesVariablesPage(final IDockerImage image, final ILaunchConfiguration lastLaunchConfiguration) throws DockerException { super("ImageSelectionPage2", //$NON-NLS-1$ WizardMessages.getString("ImageRunResourceVolVarPage.title"), //$NON-NLS-1$ SWTImagesFactory.DESC_BANNER_REPOSITORY); setPageComplete(true); this.model = new ImageRunResourceVolumesVariablesModel( image); this.lastLaunchConfiguration = lastLaunchConfiguration; } public ImageRunResourceVolumesVariablesModel getModel() { return model; } @Override public void createControl(Composite parent) { final ScrolledComposite scrollTop = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL); scrollTop.setExpandVertical(true); scrollTop.setExpandHorizontal(true); final Composite container = new Composite(scrollTop, SWT.NONE); GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) .applyTo(container); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) .applyTo(container); createVolumeSettingsContainer(container); // createSectionSeparator(container, true); createEnvironmentVariablesContainer(container); createLabelVariablesContainer(container); createSectionSeparator(container, true); createResourceSettingsContainer(container); setDefaultValues(); scrollTop.setContent(container); Point point = container.computeSize(SWT.DEFAULT, SWT.DEFAULT); scrollTop.setSize(point); scrollTop.setMinSize(point); // TODO: Workaround https://bugs.eclipse.org/bugs/show_bug.cgi?id=487160 setControl(scrollTop); } private void createSectionSeparator(final Composite container, final boolean separator) { final int SECTION_INDENT = 10; GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .span(COLUMNS, 1).grab(true, false) .indent(SWT.DEFAULT, SECTION_INDENT) .applyTo(new Label(container, separator ? (SWT.SEPARATOR | SWT.HORIZONTAL) : SWT.NONE)); } private void createResourceSettingsContainer(final Composite parent) { final Composite container = new Composite(parent, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) .span(COLUMNS, 1).grab(true, false).applyTo(container); GridLayoutFactory.fillDefaults().spacing(10, 2).applyTo(container); final Button enableResourceLimitationButton = new Button(container, SWT.CHECK); enableResourceLimitationButton.setText(WizardMessages.getString( "ImageRunResourceVolVarPage.enableLimitationButton")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .applyTo(enableResourceLimitationButton); final int COLUMNS = 5; final int INDENT = 20; final Composite subContainer = new Composite(container, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) .indent(INDENT, 0).span(COLUMNS, 1).grab(true, false) .applyTo(subContainer); GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) .spacing(10, 2).applyTo(subContainer); // specify CPU limitation final Label cpuPriorityLabel = new Label(subContainer, SWT.NONE); cpuPriorityLabel.setText(WizardMessages .getString("ImageRunResourceVolVarPage.cpuPriorityLabel")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).applyTo(cpuPriorityLabel); final Button lowCPULimitationButton = new Button(subContainer, SWT.RADIO); bindButton(lowCPULimitationButton, ImageRunResourceVolumesVariablesModel.CPU_LOW); lowCPULimitationButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.lowButton")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .applyTo(lowCPULimitationButton); final Button mediumCPULimitationButton = new Button(subContainer, SWT.RADIO); mediumCPULimitationButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.mediumButton")); //$NON-NLS-1$ bindButton(mediumCPULimitationButton, ImageRunResourceVolumesVariablesModel.CPU_MEDIUM); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .applyTo(mediumCPULimitationButton); final Button highCPULimitationButton = new Button(subContainer, SWT.RADIO); highCPULimitationButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.highButton")); //$NON-NLS-1$ bindButton(highCPULimitationButton, ImageRunResourceVolumesVariablesModel.CPU_HIGH); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1) .applyTo(highCPULimitationButton); // Memory limitation final Label memoryLimitLabel = new Label(subContainer, SWT.NONE); memoryLimitLabel.setText(WizardMessages .getString("ImageRunResourceVolVarPage.memoryLimit")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).applyTo(memoryLimitLabel); final Scale memoryLimitSpinner = new Scale(subContainer, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).span(2, 1).applyTo(memoryLimitSpinner); memoryLimitSpinner.setBackground( Display.getDefault().getSystemColor(SWT.COLOR_TRANSPARENT)); memoryLimitSpinner.setMinimum(0); memoryLimitSpinner.setMaximum(this.model.getTotalMemory()); memoryLimitSpinner.setPageIncrement(64); dbc.bindValue(WidgetProperties.selection().observe(memoryLimitSpinner), BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.MEMORY_LIMIT) .observe(model)); final Text memoryLimitValueText = new Text(subContainer, SWT.BORDER); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).hint(50, SWT.DEFAULT) .applyTo(memoryLimitValueText); dbc.bindValue( WidgetProperties.text(SWT.Modify).observe(memoryLimitValueText), BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.MEMORY_LIMIT) .observe(model)); final Label memoryLimitValueLabel = new Label(subContainer, SWT.NONE); memoryLimitValueLabel.setText("MB"); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(false, false).applyTo(memoryLimitValueLabel); // enable/disable controls final IObservableValue enableResourceLimitationsObservable = BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.ENABLE_RESOURCE_LIMITATIONS) .observe(model); dbc.bindValue( WidgetProperties.selection() .observe(enableResourceLimitationButton), enableResourceLimitationsObservable); enableResourceLimitationsObservable .addChangeListener(onEnableResourceLimitation(subContainer)); toggleResourceLimitationControls(subContainer); } /** * Binds the given <code>cpuShares</code> value to the given {@link Button} * when it is selected. * * @param button * the {@link Button} to bind * @param cpuShares * the <code>cpuShares</code> to bind to the {@link Button} * @return */ private Binding bindButton(final Button button, final long cpuShares) { return dbc.bindValue(WidgetProperties.selection().observe(button), BeanProperties .value(ImageRunResourceVolumesVariablesModel.class, ImageRunResourceVolumesVariablesModel.CPU_SHARE_WEIGHT) .observe(model), new UpdateValueStrategy() { @Override public Object convert(Object value) { if (value.equals(Boolean.TRUE)) { return cpuShares; } return 0l; } }, new UpdateValueStrategy() { @Override public Object convert(final Object value) { return value.equals(cpuShares); } }); } private IChangeListener onEnableResourceLimitation( final Composite container) { return event -> toggleResourceLimitationControls(container); } private void toggleResourceLimitationControls(Composite container) { for (Control childControl : container.getChildren()) { if (model.isEnableResourceLimitations()) { childControl.setEnabled(true); } else { childControl.setEnabled(false); } } } private void createVolumeSettingsContainer(final Composite container) { final Label volumesLabel = new Label(container, SWT.NONE); volumesLabel.setText(WizardMessages .getString("ImageRunResourceVolVarPage.dataVolumesLabel")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(true, false).span(COLUMNS, 1).applyTo(volumesLabel); final CheckboxTableViewer dataVolumesTableViewer = createVolumesTable( container); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).hint(200, 100) .applyTo(dataVolumesTableViewer.getTable()); // buttons final Composite buttonsContainers = new Composite(container, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(false, false).applyTo(buttonsContainers); GridLayoutFactory.fillDefaults().numColumns(1).margins(0, 0) .spacing(SWT.DEFAULT, 0).applyTo(buttonsContainers); final Button addButton = new Button(buttonsContainers, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).applyTo(addButton); addButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.addButton")); //$NON-NLS-1$ addButton.addSelectionListener(onAddDataVolume(dataVolumesTableViewer)); final Button editButton = new Button(buttonsContainers, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).applyTo(editButton); editButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.editButton")); //$NON-NLS-1$ editButton .addSelectionListener(onEditDataVolume(dataVolumesTableViewer)); editButton.setEnabled(false); final Button removeButton = new Button(buttonsContainers, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).applyTo(removeButton); removeButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.removeButton")); //$NON-NLS-1$ removeButton.addSelectionListener( onRemoveDataVolumes(dataVolumesTableViewer)); removeButton.setEnabled(false); // update table content when selected image changes bind(dataVolumesTableViewer, model.getDataVolumes(), BeanProperties.values(DataVolumeModel.class, DataVolumeModel.CONTAINER_PATH, DataVolumeModel.MOUNT, DataVolumeModel.READ_ONLY_VOLUME)); dbc.bindSet( ViewersObservables.observeCheckedElements( dataVolumesTableViewer, DataVolumeModel.class), BeanProperties .set(ImageRunResourceVolumesVariablesModel.SELECTED_DATA_VOLUMES) .observe(model)); // disable the edit and removeButton if the table is empty dataVolumesTableViewer.addSelectionChangedListener( onSelectionChanged(editButton, removeButton)); } private void setDefaultValues() { try { // skip if a previous launch configuration was provided final IDockerImage selectedImage = model.getSelectedImage(); if (selectedImage == null) { return; } final IDockerImageInfo selectedImageInfo = findImageInfo( selectedImage); // using a map filled with entries (key==value) from default volumes // that can be overridden by values from last launch config final Map<String, DataVolumeModel> volumes = new HashMap<>(); final Set<DataVolumeModel> selectedVolumes = new HashSet<>(); if (selectedImageInfo != null && selectedImageInfo.config() != null) { for (String volume : selectedImageInfo.config().volumes()) { volumes.put(volume, new DataVolumeModel(volume)); } } if (lastLaunchConfiguration != null) { // volumes: final List<String> launchConfigVolumes = lastLaunchConfiguration .getAttribute(DATA_VOLUMES, Collections.<String> emptyList()); for (String containerVolume : launchConfigVolumes) { final DataVolumeModel volume = DataVolumeModel .parseString(containerVolume); if (volume != null) { volumes.put(volume.getContainerPath(), volume); selectedVolumes.add(volume); } } // environment variables model.setEnvironmentVariables( lastLaunchConfiguration.getAttribute(ENV_VARIABLES, Collections.<String> emptyList())); // labels Map<String, String> labels = lastLaunchConfiguration .getAttribute(LABELS, (Map<String, String>) null); if (labels != null) { model.setLabelVariables(labels); } // resource limitations model.setEnableResourceLimitations(lastLaunchConfiguration .getAttribute(ENABLE_LIMITS, false)); // CPU shares model.setCpuShareWeight(Long.parseLong(lastLaunchConfiguration .getAttribute(CPU_PRIORITY, Long.toString( ImageRunResourceVolumesVariablesModel.CPU_MEDIUM)))); // retrieve memory limit stored in MB final long memoryLimit = Long.parseLong(lastLaunchConfiguration .getAttribute(MEMORY_LIMIT, Long.toString( ImageRunResourceVolumesVariablesModel.DEFAULT_MEMORY))); // make sure memory limit is not higher than maxMemory model.setMemoryLimit( Math.min(model.getTotalMemory(), memoryLimit)); } model.setDataVolumes(volumes.values()); model.setSelectedDataVolumes(selectedVolumes); } catch (CoreException | InvocationTargetException | InterruptedException e) { Activator.log(e); } } private IDockerImageInfo findImageInfo(final IDockerImage selectedImage) throws InvocationTargetException, InterruptedException { final FindImageInfoRunnable findImageInfoRunnable = new FindImageInfoRunnable( selectedImage); getContainer().run(true, true, findImageInfoRunnable); final IDockerImageInfo selectedImageInfo = findImageInfoRunnable .getResult(); return selectedImageInfo; } /** * Same as * {@link ViewerSupport#bind(StructuredViewer, IObservableList, org.eclipse.core.databinding.property.value.IValueProperty[]) * but with a custom LabelProvider, DataVolumesLabelProvider * * @param viewer * @param input * @param labelProperties */ private void bind(final StructuredViewer viewer, final IObservableList input, final IBeanValueProperty[] labelProperties) { final ObservableListContentProvider contentProvider = new ObservableListContentProvider(); if (viewer.getInput() != null) { viewer.setInput(null); } viewer.setContentProvider(contentProvider); viewer.setLabelProvider( new DataVolumesLabelProvider(Properties.observeEach( contentProvider.getKnownElements(), labelProperties))); if (input != null) { viewer.setInput(input); } } private ISelectionChangedListener onSelectionChanged( final Button... targetButtons) { return e -> { if (e.getSelection().isEmpty()) { setControlsEnabled(targetButtons, false); } else { setControlsEnabled(targetButtons, true); } }; } private SelectionListener onAddDataVolume( final CheckboxTableViewer dataVolumesTableViewer) { return new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final ContainerDataVolumeDialog dialog = new ContainerDataVolumeDialog( getShell(), model.getConnection()); dialog.create(); if (dialog.open() == IDialogConstants.OK_ID) { final DataVolumeModel dataVolume = dialog.getDataVolume(); dataVolume.setSelected(true); model.getDataVolumes().add(dataVolume); model.getSelectedDataVolumes().add(dataVolume); dataVolumesTableViewer.setChecked(dataVolume, true); } } }; } private SelectionListener onEditDataVolume( final CheckboxTableViewer dataVolumesTableViewer) { return new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final IStructuredSelection selection = (IStructuredSelection) dataVolumesTableViewer .getSelection(); if (selection.isEmpty()) { return; } final DataVolumeModel selectedDataVolume = (DataVolumeModel) selection .getFirstElement(); final ContainerDataVolumeDialog dialog = new ContainerDataVolumeDialog( getShell(), model.getConnection(), selectedDataVolume); dialog.create(); if (dialog.open() == IDialogConstants.OK_ID) { final DataVolumeModel dialogDataVolume = dialog .getDataVolume(); selectedDataVolume.setContainerMount( dialogDataVolume.getContainerMount()); selectedDataVolume .setMountType(dialogDataVolume.getMountType()); selectedDataVolume.setHostPathMount( dialogDataVolume.getHostPathMount()); selectedDataVolume.setContainerMount( dialogDataVolume.getContainerMount()); selectedDataVolume .setReadOnly(dialogDataVolume.isReadOnly()); model.getSelectedDataVolumes().add(selectedDataVolume); dataVolumesTableViewer.setChecked(selectedDataVolume, true); } } }; } private SelectionListener onRemoveDataVolumes( final TableViewer dataVolumesTableViewer) { return new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final IStructuredSelection selection = dataVolumesTableViewer .getStructuredSelection(); for (@SuppressWarnings("unchecked") Iterator<DataVolumeModel> iterator = selection .iterator(); iterator.hasNext();) { final DataVolumeModel volume = iterator.next(); model.removeDataVolume(volume); model.getSelectedDataVolumes().remove(volume); } } }; } private CheckboxTableViewer createVolumesTable(final Composite container) { final Table table = new Table(container, SWT.CHECK | SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL); final CheckboxTableViewer tableViewer = new CheckboxTableViewer(table); table.setHeaderVisible(true); table.setLinesVisible(true); dbc.bindSet( ViewersObservables.observeCheckedElements(tableViewer, DataVolumeModel.class), BeanProperties .set(ImageRunResourceVolumesVariablesModel.SELECTED_DATA_VOLUMES) .observe(model)); addTableViewerColum(tableViewer, WizardMessages.getString( "ImageRunResourceVolVarPage.containerPathColumn"), //$NON-NLS-1$ 150); addTableViewerColum(tableViewer, WizardMessages .getString("ImageRunResourceVolVarPage.mountColumn"), //$NON-NLS-1$ 150); addTableViewerColum(tableViewer, WizardMessages .getString("ImageRunResourceVolVarPage.readonlyColumn"), //$NON-NLS-1$ 60); return tableViewer; } private TableViewerColumn addTableViewerColum(final TableViewer tableViewer, final String title, final int width) { final TableViewerColumn viewerColumn = new TableViewerColumn( tableViewer, SWT.NONE); final TableColumn column = viewerColumn.getColumn(); if (title != null) { column.setText(title); } column.setWidth(width); return viewerColumn; } private void createLabelVariablesContainer(final Composite container) { final Label labelVarLabel = new Label(container, SWT.NONE); labelVarLabel.setText(WizardMessages .getString("ImageRunResourceVolVarPage.labelVarLabel")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(true, false).span(COLUMNS, 1).applyTo(labelVarLabel); final TableViewer labelVariablesTableViewer = createEnvironmentVariablesTable( container); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).hint(200, 100) .applyTo(labelVariablesTableViewer.getTable()); // buttons final Composite buttonsContainers = new Composite(container, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(false, false).applyTo(buttonsContainers); GridLayoutFactory.fillDefaults().numColumns(1).margins(0, 0) .spacing(SWT.DEFAULT, 0).applyTo(buttonsContainers); final Button addButton = new Button(buttonsContainers, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).applyTo(addButton); addButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.addButton")); //$NON-NLS-1$ addButton.setEnabled(true); addButton.addSelectionListener(onAddLabelVariable()); final Button editButton = new Button(buttonsContainers, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).applyTo(editButton); editButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.editButton")); //$NON-NLS-1$ editButton.setEnabled(true); editButton.addSelectionListener( onEditLabelVariable(labelVariablesTableViewer)); editButton.setEnabled(false); final Button removeButton = new Button(buttonsContainers, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).applyTo(removeButton); removeButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.removeButton")); //$NON-NLS-1$ removeButton.addSelectionListener( onRemoveLabelVariables(labelVariablesTableViewer)); removeButton.setEnabled(false); // update table content when selected image changes ViewerSupport.bind(labelVariablesTableViewer, model.getLabelVariables(), BeanProperties.values(LabelVariableModel.class, LabelVariableModel.NAME, LabelVariableModel.VALUE)); // disable the edit and removeButton if the table is empty labelVariablesTableViewer.addSelectionChangedListener( onSelectionChanged(editButton, removeButton)); } private TableViewer createLabelVariablesTable(Composite container) { final Table table = new Table(container, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL); final TableViewer tableViewer = new TableViewer(table); table.setHeaderVisible(true); table.setLinesVisible(true); addTableViewerColum(tableViewer, WizardMessages .getString("ImageRunResourceVolVarPage.nameColumn"), //$NON-NLS-1$ 200); addTableViewerColum(tableViewer, WizardMessages .getString("ImageRunResourceVolVarPage.valueColumn"), //$NON-NLS-1$ 200); return tableViewer; } private SelectionListener onAddLabelVariable() { return new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final ContainerLabelVariableDialog dialog = new ContainerLabelVariableDialog( getShell()); dialog.create(); if (dialog.open() == IDialogConstants.OK_ID) { model.getLabelVariables().add(dialog.getLabelVariable()); } } }; } private SelectionListener onEditLabelVariable( final TableViewer LabelVariablesTableViewer) { return new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final LabelVariableModel selectedVariable = (LabelVariableModel) LabelVariablesTableViewer .getStructuredSelection().getFirstElement(); final ContainerLabelVariableDialog dialog = new ContainerLabelVariableDialog( getShell(), selectedVariable); dialog.create(); if (dialog.open() == IDialogConstants.OK_ID) { selectedVariable .setName(dialog.getLabelVariable().getName()); selectedVariable .setValue(dialog.getLabelVariable().getValue()); LabelVariablesTableViewer.refresh(); } } }; } private SelectionListener onRemoveLabelVariables( final TableViewer linksTableViewer) { return new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final IStructuredSelection selection = linksTableViewer .getStructuredSelection(); for (@SuppressWarnings("unchecked") Iterator<LabelVariableModel> iterator = selection .iterator(); iterator.hasNext();) { model.removeLabelVariable(iterator.next()); } } }; } private void createEnvironmentVariablesContainer( final Composite container) { final Label envVarLabel = new Label(container, SWT.NONE); envVarLabel.setText(WizardMessages .getString("ImageRunResourceVolVarPage.envVarLabel")); //$NON-NLS-1$ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(true, false).span(COLUMNS, 1).applyTo(envVarLabel); final TableViewer environmentVariablesTableViewer = createEnvironmentVariablesTable( container); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).hint(200, 100) .applyTo(environmentVariablesTableViewer.getTable()); // buttons final Composite buttonsContainers = new Composite(container, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(false, false).applyTo(buttonsContainers); GridLayoutFactory.fillDefaults().numColumns(1).margins(0, 0) .spacing(SWT.DEFAULT, 0).applyTo(buttonsContainers); final Button addButton = new Button(buttonsContainers, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).applyTo(addButton); addButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.addButton")); //$NON-NLS-1$ addButton.setEnabled(true); addButton.addSelectionListener(onAddEnvironmentVariable()); final Button editButton = new Button(buttonsContainers, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).applyTo(editButton); editButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.editButton")); //$NON-NLS-1$ editButton.setEnabled(true); editButton.addSelectionListener( onEditEnvironmentVariable(environmentVariablesTableViewer)); editButton.setEnabled(false); final Button removeButton = new Button(buttonsContainers, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) .grab(true, false).applyTo(removeButton); removeButton.setText(WizardMessages .getString("ImageRunResourceVolVarPage.removeButton")); //$NON-NLS-1$ removeButton.addSelectionListener( onRemoveEnvironmentVariables(environmentVariablesTableViewer)); removeButton.setEnabled(false); // update table content when selected image changes ViewerSupport.bind(environmentVariablesTableViewer, model.getEnvironmentVariables(), BeanProperties.values(EnvironmentVariableModel.class, EnvironmentVariableModel.NAME, EnvironmentVariableModel.VALUE)); // disable the edit and removeButton if the table is empty environmentVariablesTableViewer.addSelectionChangedListener( onSelectionChanged(editButton, removeButton)); } private TableViewer createEnvironmentVariablesTable(Composite container) { final Table table = new Table(container, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL); final TableViewer tableViewer = new TableViewer(table); table.setHeaderVisible(true); table.setLinesVisible(true); addTableViewerColum(tableViewer, WizardMessages .getString("ImageRunResourceVolVarPage.nameColumn"), //$NON-NLS-1$ 200); addTableViewerColum(tableViewer, WizardMessages .getString("ImageRunResourceVolVarPage.valueColumn"), //$NON-NLS-1$ 200); return tableViewer; } private SelectionListener onAddEnvironmentVariable() { return new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final ContainerEnvironmentVariableDialog dialog = new ContainerEnvironmentVariableDialog( getShell()); dialog.create(); if (dialog.open() == IDialogConstants.OK_ID) { model.getEnvironmentVariables() .add(dialog.getEnvironmentVariable()); } } }; } private SelectionListener onEditEnvironmentVariable( final TableViewer environmentVariablesTableViewer) { return new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final EnvironmentVariableModel selectedVariable = (EnvironmentVariableModel) environmentVariablesTableViewer .getStructuredSelection().getFirstElement(); final ContainerEnvironmentVariableDialog dialog = new ContainerEnvironmentVariableDialog( getShell(), selectedVariable); dialog.create(); if (dialog.open() == IDialogConstants.OK_ID) { selectedVariable.setName( dialog.getEnvironmentVariable().getName()); selectedVariable.setValue( dialog.getEnvironmentVariable().getValue()); environmentVariablesTableViewer.refresh(); } } }; } private SelectionListener onRemoveEnvironmentVariables( final TableViewer linksTableViewer) { return new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final IStructuredSelection selection = linksTableViewer .getStructuredSelection(); for (@SuppressWarnings("unchecked") Iterator<EnvironmentVariableModel> iterator = selection .iterator(); iterator.hasNext();) { model.removeEnvironmentVariable(iterator.next()); } } }; } private static void setControlsEnabled(final Control[] controls, final boolean enabled) { for (Control control : controls) { control.setEnabled(enabled); } } private static final class DataVolumesLabelProvider extends ObservableMapLabelProvider { private Image CONTAINER_IMAGE = SWTImagesFactory.DESC_CONTAINER .createImage(); private Image FOLDER_CLOSED_IMAGE = SWTImagesFactory.DESC_FOLDER_CLOSED .createImage(); private Image FILE_IMAGE = SWTImagesFactory.DESC_FILE.createImage(); public DataVolumesLabelProvider(final IObservableMap[] attributeMaps) { super(attributeMaps); } @Override public void dispose() { CONTAINER_IMAGE.dispose(); FOLDER_CLOSED_IMAGE.dispose(); FILE_IMAGE.dispose(); super.dispose(); } @Override public Image getColumnImage(Object element, int columnIndex) { final DataVolumeModel dataVolume = ((DataVolumeModel) element); if (dataVolume.getMountType() != null && columnIndex == 1) { switch (dataVolume.getMountType()) { case CONTAINER: return CONTAINER_IMAGE; case HOST_FILE_SYSTEM: final File hostFile = new File(dataVolume.getMount()); if (!hostFile.exists() || hostFile.isDirectory()) { return FOLDER_CLOSED_IMAGE; } else { return FILE_IMAGE; } default: return null; } } return null; } @Override public String getColumnText(Object element, int columnIndex) { final DataVolumeModel dataVolume = ((DataVolumeModel) element); switch (columnIndex) { case 0: return dataVolume.getContainerPath(); case 1: return dataVolume.getMount(); case 2: if (dataVolume.getMountType() != MountType.HOST_FILE_SYSTEM) { return null; } else if (dataVolume.isReadOnly()) { return WizardMessages .getString("ImageRunResourceVolVarPage.true"); //$NON-NLS-1$ } return WizardMessages .getString("ImageRunResourceVolVarPage.false"); //$NON-NLS-1$ default: return null; } } } }