Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerDataVolumeDialog.java')
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerDataVolumeDialog.java398
1 files changed, 398 insertions, 0 deletions
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerDataVolumeDialog.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerDataVolumeDialog.java
new file mode 100644
index 0000000000..4740f59514
--- /dev/null
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerDataVolumeDialog.java
@@ -0,0 +1,398 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Red Hat.
+ * 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 java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+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.observable.ChangeEvent;
+import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.databinding.swt.ISWTObservableValue;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.fieldassist.ComboContentAdapter;
+import org.eclipse.jface.fieldassist.ContentProposal;
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.IContentProposal;
+import org.eclipse.jface.fieldassist.IContentProposalProvider;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.linuxtools.docker.core.IDockerConnection;
+import org.eclipse.linuxtools.docker.core.IDockerContainer;
+import org.eclipse.linuxtools.docker.core.IDockerContainerInfo;
+import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory;
+import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumesVariablesModel.MountType;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+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.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @author xcoulon
+ *
+ */
+public class ContainerDataVolumeDialog extends Dialog {
+
+ private final DataVolumeModel model;
+
+ private final DataBindingContext dbc = new DataBindingContext();
+
+ private final List<String> containerNames;
+
+ private final IDockerConnection connection;
+
+ protected ContainerDataVolumeDialog(final Shell parentShell,
+ final IDockerConnection connection,
+ final DataVolumeModel selectedDataVolume) {
+ super(parentShell);
+ this.connection = connection;
+ this.model = new DataVolumeModel(selectedDataVolume);
+ this.containerNames = WizardUtils.getContainerNames(connection);
+ }
+
+ protected ContainerDataVolumeDialog(final Shell parentShell,
+ final IDockerConnection connection) {
+ super(parentShell);
+ this.connection = connection;
+ this.model = new DataVolumeModel();
+ this.containerNames = WizardUtils.getContainerNames(connection);
+ }
+
+ public DataVolumeModel getDataVolume() {
+ return model;
+ }
+
+ @Override
+ protected void configureShell(final Shell shell) {
+ super.configureShell(shell);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ shell.setText("Data Volume");
+ }
+
+ @Override
+ protected Point getInitialSize() {
+ return new Point(450, super.getInitialSize().y);
+ }
+
+ @Override
+ protected Control createDialogArea(final Composite parent) {
+ final Composite container = new Composite(parent, SWT.NONE);
+ final int COLUMNS = 3;
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1)
+ .grab(true, true).applyTo(container);
+ GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(COLUMNS)
+ .applyTo(container);
+ final Label explanationLabel = new Label(container, SWT.NONE);
+ explanationLabel.setText("Specify the Data Volume to mount:"); //$NON-NLS-1$
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .span(COLUMNS, 1).grab(true, false).applyTo(explanationLabel);
+
+ // No mount
+ final Button noMountButton = new Button(container, SWT.RADIO);
+ noMountButton.setText("No external mount");
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .span(COLUMNS, 1).grab(true, false).applyTo(noMountButton);
+ bindButton(noMountButton, MountType.NONE);
+ // File System mount
+ final Button fileSystemMountButton = new Button(container, SWT.RADIO);
+ fileSystemMountButton.setText("Mount a host directory or host file");
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .span(COLUMNS, 1).grab(true, false)
+ .applyTo(fileSystemMountButton);
+ final Label hostPathLabel = new Label(container, SWT.NONE);
+ hostPathLabel.setText("Path:"); //$NON-NLS-1$
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .indent(20, SWT.DEFAULT).grab(false, false)
+ .applyTo(hostPathLabel);
+ final Text hostPathText = new Text(container, SWT.BORDER);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .grab(true, false).applyTo(hostPathText);
+ final IObservableValue hostPathObservable = BeanProperties
+ .value(DataVolumeModel.class, DataVolumeModel.HOST_PATH_MOUNT)
+ .observe(model);
+ dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(hostPathText),
+ hostPathObservable);
+
+ final Button hostPathBrowseButton = new Button(container, SWT.NONE);
+ hostPathBrowseButton.setText("Browse...");
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .grab(false, false).applyTo(hostPathBrowseButton);
+ hostPathBrowseButton.addSelectionListener(onHostPathBrowse());
+ // optional read-only access
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .grab(false, false).applyTo(new Label(container, SWT.NONE));
+ final Button readOnlyButton = new Button(container, SWT.CHECK);
+ readOnlyButton.setText("Read-only access"); //$NON-NLS-1$
+ readOnlyButton.setToolTipText(
+ "Specify if the mounted host directory or path is read-only"); //$NON-NLS-1$
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .span(COLUMNS - 1, 1).grab(true, false).applyTo(readOnlyButton);
+ final ISWTObservableValue readOnlyButtonObservable = WidgetProperties
+ .selection().observe(readOnlyButton);
+ dbc.bindValue(readOnlyButtonObservable,
+ BeanProperties
+ .value(DataVolumeModel.class,
+ DataVolumeModel.READ_ONLY_VOLUME)
+ .observe(model));
+ bindButton(fileSystemMountButton, MountType.HOST_FILE_SYSTEM,
+ hostPathText, hostPathBrowseButton, readOnlyButton);
+
+ // Container mount
+ final Button containerMountButton = new Button(container, SWT.RADIO);
+ containerMountButton.setText("Mount a data volume container");
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .span(COLUMNS, 1).grab(true, false)
+ .applyTo(containerMountButton);
+ final Label containerSelectionLabel = new Label(container, SWT.NONE);
+ containerSelectionLabel.setText("Container:"); //$NON-NLS-1$
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .indent(20, SWT.DEFAULT).applyTo(containerSelectionLabel);
+ final Combo containerSelectionCombo = new Combo(container, SWT.BORDER);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .grab(true, false).span(1, 1).applyTo(containerSelectionCombo);
+ new ControlDecoration(containerSelectionCombo, SWT.TOP | SWT.LEFT);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .grab(false, false).applyTo(new Label(container, SWT.NONE));
+ bindButton(containerMountButton, MountType.CONTAINER,
+ containerSelectionCombo);
+ final ComboViewer containerSelectionComboViewer = new ComboViewer(
+ containerSelectionCombo);
+ containerSelectionComboViewer
+ .setContentProvider(new ArrayContentProvider());
+ containerSelectionComboViewer.setInput(this.containerNames);
+ final IObservableValue selectedContainerObservable = BeanProperties
+ .value(DataVolumeModel.class, DataVolumeModel.CONTAINER_MOUNT)
+ .observe(model);
+ dbc.bindValue(
+ WidgetProperties.selection().observe(containerSelectionCombo),
+ selectedContainerObservable);
+ new ContentProposalAdapter(containerSelectionCombo,
+ new ComboContentAdapter() {
+ @Override
+ public void insertControlContents(Control control,
+ String text, int cursorPosition) {
+ final Combo combo = (Combo) control;
+ final Point selection = combo.getSelection();
+ combo.setText(text);
+ selection.x = text.length();
+ selection.y = selection.x;
+ combo.setSelection(selection);
+ }
+ }, getContainerNameContentProposalProvider(
+ containerSelectionCombo),
+ null, null);
+
+ // error message
+ final Composite errorContainer = new Composite(container, SWT.NONE);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL)
+ .span(COLUMNS, 1).grab(true, true).applyTo(errorContainer);
+ GridLayoutFactory.fillDefaults().margins(6, 6).numColumns(2)
+ .applyTo(errorContainer);
+
+ final Label errorMessageIcon = new Label(errorContainer, SWT.NONE);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .hint(20, SWT.DEFAULT)
+ .applyTo(errorMessageIcon);
+ final Label errorMessageLabel = new Label(errorContainer, SWT.NONE);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .grab(true, false)
+ .applyTo(errorMessageLabel);
+ setupValidationSupport(errorMessageIcon, errorMessageLabel);
+ return container;
+ }
+
+ private void setupValidationSupport(final Label errorMessageIcon,
+ final Label errorMessageLabel) {
+ for (@SuppressWarnings("unchecked")
+ Iterator<Binding> iterator = dbc.getBindings().iterator(); iterator
+ .hasNext();) {
+ final Binding binding = iterator.next();
+ binding.getModel().addChangeListener(onDataVolumeSettingsChanged(
+ errorMessageIcon, errorMessageLabel));
+
+ }
+ }
+
+ /**
+ * Binds the given {@link MountType} to the given {@link Button} when it is
+ * selected, and set the enablement of the associated {@link Control} at the
+ * same time (ie: the {@link Control} are only enabled when the given
+ * {@link Button} is selected.
+ *
+ * @param button
+ * the {@link Button} to bind
+ * @param mountType
+ * the {@link MountType} to bind to the {@link Button}
+ * @param controls
+ * the {@link Control}s to enable or disable when the Button is
+ * selected/unselected.
+ * @return
+ */
+ private Binding bindButton(final Button button, final MountType mountType,
+ final Control... controls) {
+ return dbc.bindValue(WidgetProperties.selection().observe(button),
+ BeanProperties.value(DataVolumeModel.class,
+ DataVolumeModel.MOUNT_TYPE).observe(model),
+ new UpdateValueStrategy() {
+ @Override
+ public Object convert(Object value) {
+ if (value.equals(Boolean.TRUE)) {
+ setEnabled(controls, true);
+ return mountType;
+ }
+ setEnabled(controls, false);
+ return null;
+ }
+
+ private void setEnabled(final Control[] controls,
+ final boolean enabled) {
+ for (Control control : controls) {
+ control.setEnabled(enabled);
+ }
+ }
+ }, new UpdateValueStrategy() {
+ @Override
+ public Object convert(final Object value) {
+ if (mountType.equals(value)) {
+ button.setEnabled(true);
+ }
+ return mountType.equals(value);
+ }
+ });
+ }
+
+ private SelectionListener onHostPathBrowse() {
+ return new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ final FileDialog fileDialog = new FileDialog(getShell());
+ final String selectedPath = fileDialog.open();
+ if (selectedPath != null) {
+ model.setHostPathMount(selectedPath);
+ }
+ }
+ };
+ }
+
+ /**
+ * Creates an {@link IContentProposalProvider} to propose
+ * {@link IDockerContainer} names based on the current text.
+ *
+ * @param items
+ * @return
+ */
+ private IContentProposalProvider getContainerNameContentProposalProvider(
+ final Combo containerSelectionCombo) {
+ return new IContentProposalProvider() {
+
+ @Override
+ public IContentProposal[] getProposals(final String contents,
+ final int position) {
+ final List<IContentProposal> proposals = new ArrayList<IContentProposal>();
+ for (String containerName : containerSelectionCombo
+ .getItems()) {
+ if (containerName.contains(contents)) {
+ proposals.add(new ContentProposal(containerName,
+ containerName, containerName, position));
+ }
+ }
+ return proposals.toArray(new IContentProposal[0]);
+ }
+ };
+ }
+
+ private IChangeListener onDataVolumeSettingsChanged(
+ final Label errorMessageIcon, final Label errorMessageLabel) {
+
+ return new IChangeListener() {
+
+ @Override
+ public void handleChange(ChangeEvent event) {
+ final IStatus status = validateInput(errorMessageLabel);
+ if (status.isOK()) {
+ errorMessageIcon.setVisible(false);
+ errorMessageLabel.setVisible(false);
+ setOkButtonEnabled(true);
+ } else if (status.matches(IStatus.WARNING)) {
+ errorMessageIcon.setVisible(true);
+ errorMessageIcon.setImage(
+ SWTImagesFactory.DESC_WARNING.createImage());
+ errorMessageLabel.setVisible(true);
+ errorMessageLabel.setText(status.getMessage());
+ setOkButtonEnabled(true);
+ } else if (status.matches(IStatus.ERROR)) {
+ errorMessageIcon.setVisible(true);
+ errorMessageIcon.setImage(
+ SWTImagesFactory.DESC_ERROR.createImage());
+ errorMessageLabel.setVisible(true);
+ errorMessageLabel.setText(status.getMessage());
+ setOkButtonEnabled(true);
+ }
+ }
+ };
+ }
+
+ private IStatus validateInput(final Label errorMessageLabel) {
+ final MountType mountType = model.getMountType();
+ final String hostPath = model.getHostPathMount();
+ if (mountType == MountType.HOST_FILE_SYSTEM
+ && (hostPath == null || hostPath.isEmpty())) {
+ return ValidationStatus.ok();
+ } else if (mountType == MountType.HOST_FILE_SYSTEM
+ && !new File(hostPath).exists()) {
+ return ValidationStatus
+ .warning("The specified path does not exist on the host."); //$NON-NLS-1$
+ } else if (mountType == MountType.CONTAINER) {
+ final IDockerContainer container = WizardUtils
+ .getContainer(connection, model.getContainerMount());
+ if (container == null) {
+ return ValidationStatus.error("");
+ }
+ final IDockerContainerInfo selectedContainerInfo = container.info();
+ if (!selectedContainerInfo.volumes()
+ .containsKey(model.getContainerPath())) {
+ return ValidationStatus
+ .warning("The selected container does not define a "
+ + model.getContainerPath() + " volume."); //$NON-NLS-1$
+ }
+ }
+ return ValidationStatus.ok();
+ }
+
+ private void setOkButtonEnabled(final boolean enabled) {
+ getButton(IDialogConstants.OK_ID).setEnabled(enabled);
+ }
+
+}

Back to the top