diff options
author | Jeff Johnston | 2015-11-19 19:33:27 +0000 |
---|---|---|
committer | Jeff Johnston | 2015-11-27 20:29:07 +0000 |
commit | 973a63e7cf4f298667cb06c5aa76982bf27a71bc (patch) | |
tree | de4f09f76495df318916f1c9e413c5dafff9c84e | |
parent | a3ab852e583f4174ff460aa4cac114104896d68e (diff) | |
download | org.eclipse.linuxtools-973a63e7cf4f298667cb06c5aa76982bf27a71bc.tar.gz org.eclipse.linuxtools-973a63e7cf4f298667cb06c5aa76982bf27a71bc.tar.xz org.eclipse.linuxtools-973a63e7cf4f298667cb06c5aa76982bf27a71bc.zip |
Bug 471662 - Refactor the run image wizard into a launcher
- fill in the RunDockerImageLaunchConfigurationDelegate
- create main, ports, links, volumes, and environment tabs using
existing Run Image wizard models and a tab group to group them
- add launch extensions to Docker UI plug-in
- change some existing wizard model classes to add toString() methods
and create methods that take an output string
Change-Id: I2aefcde43e9b3f239fd89b13db7ec22fd319b9bc
Reviewed-on: https://git.eclipse.org/r/60825
Reviewed-by: Xavier Coulon <xcoulon@redhat.com>
Tested-by: Hudson CI
Reviewed-by: Jeff Johnston <jjohnstn@redhat.com>
28 files changed, 3178 insertions, 32 deletions
diff --git a/containers/org.eclipse.linuxtools.docker.ui/icons/environment_co.gif b/containers/org.eclipse.linuxtools.docker.ui/icons/environment_co.gif Binary files differnew file mode 100644 index 0000000000..716df436f9 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/icons/environment_co.gif diff --git a/containers/org.eclipse.linuxtools.docker.ui/icons/links_obj.gif b/containers/org.eclipse.linuxtools.docker.ui/icons/links_obj.gif Binary files differnew file mode 100644 index 0000000000..6123b270e8 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/icons/links_obj.gif diff --git a/containers/org.eclipse.linuxtools.docker.ui/icons/main_tab.gif b/containers/org.eclipse.linuxtools.docker.ui/icons/main_tab.gif Binary files differnew file mode 100644 index 0000000000..0193dbeab7 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/icons/main_tab.gif diff --git a/containers/org.eclipse.linuxtools.docker.ui/icons/ports_tab.gif b/containers/org.eclipse.linuxtools.docker.ui/icons/ports_tab.gif Binary files differnew file mode 100644 index 0000000000..68d40f7e2d --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/icons/ports_tab.gif diff --git a/containers/org.eclipse.linuxtools.docker.ui/icons/volumes.gif b/containers/org.eclipse.linuxtools.docker.ui/icons/volumes.gif Binary files differnew file mode 100644 index 0000000000..c13bea1ca4 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/icons/volumes.gif diff --git a/containers/org.eclipse.linuxtools.docker.ui/plugin.xml b/containers/org.eclipse.linuxtools.docker.ui/plugin.xml index 49e7208b77..1d40098d8a 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/plugin.xml +++ b/containers/org.eclipse.linuxtools.docker.ui/plugin.xml @@ -1455,4 +1455,12 @@ </contextualLaunch> </shortcut> </extension> + <extension + point="org.eclipse.debug.ui.launchConfigurationTabGroups"> + <launchConfigurationTabGroup + class="org.eclipse.linuxtools.internal.docker.ui.launch.RunImageLaunchConfigurationTabGroup" + id="org.eclipse.linuxtools.docker.ui.runLaunchConfigurationTabGroup" + type="org.eclipse.linuxtools.docker.ui.runDockerImageLaunchConfigurationType"> + </launchConfigurationTabGroup> + </extension> </plugin> diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/SWTImagesFactory.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/SWTImagesFactory.java index 1f7d7b89e8..b500320a20 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/SWTImagesFactory.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/SWTImagesFactory.java @@ -57,16 +57,21 @@ public class SWTImagesFactory { + "docker_small.gif"; //$NON-NLS-1$ public static final String IMG_WIZARD = NAME_PREFIX + "banner-repository.gif"; //$NON-NLS-1$ + public static final String IMG_ENV = NAME_PREFIX + "environment_co.gif"; //$NON-NLS-1$ public static final String IMG_FILTER = NAME_PREFIX + "filter_ps.gif"; //$NON-NLS-1$ public static final String IMG_KILL = NAME_PREFIX + "kill.gif"; //$NON-NLS-1$ public static final String IMG_KILLD = NAME_PREFIX + "killd.gif"; //$NON-NLS-1$ + public static final String IMG_LINKS = NAME_PREFIX + "links_obj.gif"; //$NON-NLS-1$ + public static final String IMG_MAIN_TAB = NAME_PREFIX + "main_tab.gif"; //$NON-NLS-1$ public static final String IMG_PULL = NAME_PREFIX + "pull.gif"; //$NON-NLS-1$ public static final String IMG_PUSH = NAME_PREFIX + "push.gif"; //$NON-NLS-1$ public static final String IMG_BUILD = NAME_PREFIX + "build_exec.png"; //$NON-NLS-1$ public static final String IMG_PAUSE = NAME_PREFIX + "suspend.gif"; //$NON-NLS-1$ public static final String IMG_PAUSE_D = NAME_PREFIX + "suspendd.gif"; //$NON-NLS-1$ + public static final String IMG_PORTS_TAB = NAME_PREFIX + "ports_tab.gif"; //$NON-NLS-1$ public static final String IMG_REMOVE = NAME_PREFIX + "delete.gif"; //$NON-NLS-1$ public static final String IMG_REMOVE_D = NAME_PREFIX + "delete_d.gif"; //$NON-NLS-1$ + public static final String IMG_RESOURCE = NAME_PREFIX + "resource_obj.gif"; //$NON-NLS-1$ public static final String IMG_RESUME = NAME_PREFIX + "resume.gif"; //$NON-NLS-1$ public static final String IMG_RESUME_D = NAME_PREFIX + "resumed.gif"; //$NON-NLS-1$ public static final String IMG_START = NAME_PREFIX + "running.gif"; //$NON-NLS-1$ @@ -100,6 +105,7 @@ public class SWTImagesFactory { public static final String IMG_RESOLVED = NAME_PREFIX + "resolved.gif"; //$NON-NLS-1$ public static final String IMG_BANNER_REPOSITORY = NAME_PREFIX + "banner-repository.gif"; //$NON-NLS-1$ + public static final String IMG_VOLUMES = NAME_PREFIX + "volumes.gif"; //$NON-NLS-1$ public static final String IMG_WARNING = NAME_PREFIX + "warning_obj.gif"; //$NON-NLS-1$ public static final String IMG_ERROR = NAME_PREFIX + "error_obj.gif"; //$NON-NLS-1$ @@ -107,6 +113,7 @@ public class SWTImagesFactory { IMG_CONNECTION); public static final ImageDescriptor DESC_CREATE_CONTAINER = createManaged( "", IMG_CREATE_CONTAINER); + public static final ImageDescriptor DESC_ENV = createManaged("", IMG_ENV); public static final ImageDescriptor DESC_FOLDER = createManaged("", IMG_FOLDER); public static final ImageDescriptor DESC_FOLDER_CLOSED = createManaged("", @@ -121,6 +128,8 @@ public class SWTImagesFactory { public static final ImageDescriptor DESC_KILL = createManaged("", IMG_KILL); public static final ImageDescriptor DESC_KILLD = createManaged("", IMG_KILLD); + public static final ImageDescriptor DESC_LINKS = createManaged("", + IMG_LINKS); public static final ImageDescriptor DESC_DOCKER_LARGE = createManaged("", IMG_DOCKER_LARGE); public static final ImageDescriptor DESC_DOCKER_SMALL = createManaged("", @@ -129,6 +138,8 @@ public class SWTImagesFactory { IMG_WIZARD); public static final ImageDescriptor DESC_FILTER = createManaged("", IMG_FILTER); + public static final ImageDescriptor DESC_MAIN_TAB = createManaged("", + IMG_MAIN_TAB); public static final ImageDescriptor DESC_PULL = createManaged("", IMG_PULL); public static final ImageDescriptor DESC_PUSH = createManaged("", IMG_PUSH); public static final ImageDescriptor DESC_BUILD = createManaged("", @@ -137,10 +148,14 @@ public class SWTImagesFactory { IMG_PAUSE); public static final ImageDescriptor DESC_PAUSE_D = createManaged("", IMG_PAUSE_D); + public static final ImageDescriptor DESC_PORTS_TAB = createManaged("", + IMG_PORTS_TAB); public static final ImageDescriptor DESC_REMOVE = createManaged("", IMG_REMOVE); public static final ImageDescriptor DESC_REMOVE_D = createManaged("", IMG_REMOVE_D); + public static final ImageDescriptor DESC_RESOURCE = createManaged("", + IMG_RESOURCE); public static final ImageDescriptor DESC_RESUME = createManaged("", IMG_RESUME); public static final ImageDescriptor DESC_RESUME_D = createManaged("", @@ -186,6 +201,8 @@ public class SWTImagesFactory { IMG_RESOLVED); public static final ImageDescriptor DESC_BANNER_REPOSITORY = createManaged( "", IMG_BANNER_REPOSITORY); + public static final ImageDescriptor DESC_VOLUMES = createManaged("", + IMG_VOLUMES); public static final ImageDescriptor DESC_WARNING = createManaged("", IMG_WARNING); public static final ImageDescriptor DESC_ERROR = createManaged("", diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RunImageCommandHandler.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RunImageCommandHandler.java index f4c151caa5..3366b39b0e 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RunImageCommandHandler.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RunImageCommandHandler.java @@ -81,7 +81,7 @@ public class RunImageCommandHandler extends AbstractHandler { return null; } - private void runImage(final IDockerConnection connection, + public static void runImage(final IDockerConnection connection, final IDockerContainerConfig containerConfig, final IDockerHostConfig hostConfig, final String containerName, final boolean removeWhenExits) { diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/IRunDockerImageLaunchConfigurationConstants.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/IRunDockerImageLaunchConfigurationConstants.java index 08690ba432..421ce39d8d 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/IRunDockerImageLaunchConfigurationConstants.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/IRunDockerImageLaunchConfigurationConstants.java @@ -28,7 +28,7 @@ public interface IRunDockerImageLaunchConfigurationConstants { public static final String PUBLISH_ALL_PORTS = "publishAllPorts"; //$NON-NLS-1$ - public static final String PUBLISH_PORTS = "publishPorts"; //$NON-NLS-1$ + public static final String PUBLISHED_PORTS = "publishedPorts"; //$NON-NLS-1$ public static final String LINKS = "links"; //$NON-NLS-1$ @@ -40,10 +40,18 @@ public interface IRunDockerImageLaunchConfigurationConstants { public static final String DATA_VOLUME = "volumes"; //$NON-NLS-1$ + public static final String VOLUMES_FROM = "volumesFrom"; //$NON-NLS-1$ + + public static final String BINDS = "binds"; //$NON-NLS-1$ + public static final String ENV_VARIABLES = "envVariables"; //$NON-NLS-1$ + public static final String ENABLE_LIMITS = "enableLimits"; //$NON-NLS-1$ + public static final String CPU_PRIORITY = "cpuPriority"; //$NON-NLS-1$ public static final String MEMORY_LIMIT = "memoryLimit"; //$NON-NLS-1$ + public static final String CONNECTION_NAME = "connectionName"; //$NON-NLS-1$ + } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchConfigurationUtils.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchConfigurationUtils.java index d6bfe12699..da431b0487 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchConfigurationUtils.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchConfigurationUtils.java @@ -15,16 +15,24 @@ import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLa import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLaunchConfigurationConstants.CONTAINER_NAME; import static org.eclipse.linuxtools.internal.docker.ui.launch.IRunDockerImageLaunchConfigurationConstants.IMAGE_NAME; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.layout.PixelConverter; import org.eclipse.linuxtools.docker.core.IDockerContainer; import org.eclipse.linuxtools.docker.ui.Activator; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Button; /** * Utility class to manage {@link ILaunchConfiguration} @@ -75,6 +83,15 @@ public class LaunchConfigurationUtils { return null; } + public static int getButtonWidthHint(Button button) { + /* button.setFont(JFaceResources.getDialogFont()); */ + PixelConverter converter = new PixelConverter(button); + int widthHint = converter + .convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH); + return Math.max(widthHint, + button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x); + } + public static ILaunchConfiguration getLaunchConfiguration( final ILaunchConfigurationType type, final String name) throws CoreException { @@ -89,4 +106,26 @@ public class LaunchConfigurationUtils { return null; } + public static String convertToUnixPath(String path) { + String unixPath = path; + + if (Platform.OS_WIN32.equals(Platform.getOS())) { + // replace backslashes with slashes + unixPath = unixPath.replaceAll("\\\\", "/"); + + // replace "C:/" with "/c/" + Matcher m = Pattern.compile("([a-zA-Z]):/").matcher(unixPath); + if (m.find()) { + StringBuffer b = new StringBuffer(); + b.append('/'); + m.appendReplacement(b, m.group(1).toLowerCase()); + b.append('/'); + m.appendTail(b); + unixPath = b.toString(); + } + } + + return unixPath; + } + } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchMessages.properties b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchMessages.properties index 0ee5026d15..0f26bfc90a 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchMessages.properties +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/LaunchMessages.properties @@ -40,5 +40,14 @@ ImageBuildShortcutChooseConnection.msg=Choose the Docker Connection to use MissingConnectionError.msg=No Docker connection named ''{0}'' exists. RunDockerImageLaunchConfiguration.creation.failure=Failed to save launch configuration for the image to run +RunDockerImageLaunchConfiguration.load.failure=Failed to load launch configuration + +RunMainTab.name=Main +RunMainTabSelectConnection.tooltip=Select the Docker Connection to use +RunVolumesTab.name=Volumes +RunPortsTab.name=Ports +RunLinksTab.name=Links +RunResourcesTab.name=Resources +RunEnvTab.name=Environment NoConnectionError.msg=No Docker connection exists
\ No newline at end of file diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunDockerImageLaunchConfigurationDelegate.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunDockerImageLaunchConfigurationDelegate.java index 22649da1f0..49801052b4 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunDockerImageLaunchConfigurationDelegate.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunDockerImageLaunchConfigurationDelegate.java @@ -11,10 +11,37 @@ package org.eclipse.linuxtools.internal.docker.ui.launch; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.model.ILaunchConfigurationDelegate; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugModelPresentation; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.linuxtools.docker.core.DockerConnectionManager; +import org.eclipse.linuxtools.docker.core.IDockerConnection; +import org.eclipse.linuxtools.docker.core.IDockerContainerConfig; +import org.eclipse.linuxtools.docker.core.IDockerHostConfig; +import org.eclipse.linuxtools.docker.core.IDockerPortBinding; +import org.eclipse.linuxtools.docker.ui.Activator; +import org.eclipse.linuxtools.internal.docker.core.DockerContainerConfig; +import org.eclipse.linuxtools.internal.docker.core.DockerContainerConfig.Builder; +import org.eclipse.linuxtools.internal.docker.core.DockerHostConfig; +import org.eclipse.linuxtools.internal.docker.core.DockerPortBinding; +import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.commands.RunImageCommandHandler; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.dialogs.ElementListSelectionDialog; /** * Launch configuration delegate for running Docker Images @@ -22,11 +49,273 @@ import org.eclipse.debug.core.model.ILaunchConfigurationDelegate; public class RunDockerImageLaunchConfigurationDelegate implements ILaunchConfigurationDelegate { + private static final String LaunchShortcut_Connection_Selection = "ImageBuildShortcutConnectionSelection.title"; //$NON-NLS-1$ + private static final String LaunchShortcut_Choose_Connection = "ImageBuildShortcutChooseConnection.msg"; //$NON-NLS-1$ + @Override public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) { - // TODO Auto-generated method stub + try { + ILaunchConfiguration config = launch.getLaunchConfiguration(); + final IDockerContainerConfig containerConfig = getDockerContainerConfig( + config); + final IDockerHostConfig hostConfig = getDockerHostConfig(config); + final IDockerConnection connection = getDockerConnection(config); + if (connection == null) + return; + RunImageCommandHandler.runImage(connection, containerConfig, + hostConfig, + config.getAttribute( + IRunDockerImageLaunchConfigurationConstants.CONTAINER_NAME, + (String) null), + config.getAttribute( + IRunDockerImageLaunchConfigurationConstants.AUTO_REMOVE, + false)); + } catch (CoreException e) { + Activator.log(e); + } + } + + public IDockerHostConfig getDockerHostConfig(ILaunchConfiguration config) + throws CoreException { + + final DockerHostConfig.Builder hostConfigBuilder = new DockerHostConfig.Builder(); + if (config.getAttribute( + IRunDockerImageLaunchConfigurationConstants.PUBLISH_ALL_PORTS, + false)) { + hostConfigBuilder.publishAllPorts(true); + } else { + final Map<String, List<IDockerPortBinding>> portBindings = new HashMap<>(); + Map<String, String> ports = config.getAttribute( + IRunDockerImageLaunchConfigurationConstants.PUBLISHED_PORTS, + new HashMap<String, String>()); + for (Map.Entry<String, String> entry : ports.entrySet()) { + String key = entry.getKey(); + String entryValue = entry.getValue(); + + String[] portPairs = entryValue.split("\\s*,\\s*"); //$NON-NLS-1$ + + for (int i = 0; i < portPairs.length; i += 2) { + DockerPortBinding portBinding = new DockerPortBinding( + portPairs[i], portPairs[i + 1]); + portBindings.put(key, + Arrays.<IDockerPortBinding> asList(portBinding)); + } + } + hostConfigBuilder.portBindings(portBindings); + } + // container links + final List<String> links = config.getAttribute( + IRunDockerImageLaunchConfigurationConstants.LINKS, + new ArrayList<String>()); + hostConfigBuilder.links(links); + + // data volumes + + List<String> volumesFromList = config.getAttribute(IRunDockerImageLaunchConfigurationConstants.VOLUMES_FROM, new ArrayList<String>()); + hostConfigBuilder.volumesFrom(volumesFromList); + + final List<String> binds = new ArrayList<>(); + + List<String> bindsList = config.getAttribute(IRunDockerImageLaunchConfigurationConstants.BINDS, new ArrayList<String>()); + + for (String bindsListEntry : bindsList) { + String[] bindsEntryParms = bindsListEntry.split(":"); //$NON-NLS-1$ + String bind = LaunchConfigurationUtils.convertToUnixPath( + bindsEntryParms[0]) + ':' + + bindsEntryParms[1] + ':' + 'Z'; + if (bindsEntryParms[2].equals("true")) { + bind += ",ro"; //$NON-NLS-1$ + } + binds.add(bind); + + } + hostConfigBuilder.binds(binds); + + return hostConfigBuilder.build(); + } + + public IDockerContainerConfig getDockerContainerConfig( + ILaunchConfiguration lconfig) throws CoreException { + + String commandAsString = lconfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.COMMAND, ""); //$NON-NLS-1$ + List<String> command = getCmdList(commandAsString); + String entrypoint = lconfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.ENTRYPOINT, ""); //$NON-NLS-1$ + String imageName = lconfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.IMAGE_NAME, ""); //$NON-NLS-1$ + boolean useTTY = lconfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.ALLOCATE_PSEUDO_CONSOLE, + false); + boolean interactive = lconfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.INTERACTIVE, false); + + final Builder config = new DockerContainerConfig.Builder().cmd(command) + .entryPoint(entrypoint).image(imageName).tty(useTTY) + .openStdin(interactive); + boolean limits_enabled = lconfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.ENABLE_LIMITS, + false); + if (limits_enabled) { + int memory = lconfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.MEMORY_LIMIT, + 0); + int cpuShares = lconfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.CPU_PRIORITY, + 0); + config.memory(Long.valueOf(memory) * 1048576); + config.cpuShares(Long.valueOf(cpuShares)); + } + // environment variables + final List<String> environmentVariables = lconfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.ENV_VARIABLES, + new ArrayList<String>()); + config.env(environmentVariables); + return config.build(); + } + + private IDockerConnection getDockerConnection(ILaunchConfiguration config) + throws CoreException { + String configName = config.getAttribute( + IRunDockerImageLaunchConfigurationConstants.CONNECTION_NAME, + ""); //$NON-NLS-1$ + IDockerConnection connection = DockerConnectionManager.getInstance() + .findConnection(configName); + if (connection == null) { + connection = chooseConnection( + DockerConnectionManager.getInstance().getConnections()); + } + return connection; + } + + // Create a proper command list after handling quotation. + private List<String> getCmdList(String s) { + ArrayList<String> list = new ArrayList<>(); + int length = s.length(); + boolean insideQuote1 = false; // single-quote + boolean insideQuote2 = false; // double-quote + boolean escaped = false; + StringBuffer buffer = new StringBuffer(); + // Parse the string and break it up into chunks that are + // separated by white-space or are quoted. Ignore characters + // that have been escaped, including the escape character. + for (int i = 0; i < length; ++i) { + char c = s.charAt(i); + if (escaped) { + buffer.append(c); + escaped = false; + } + switch (c) { + case '\'': + if (!insideQuote2) + insideQuote1 = insideQuote1 ^ true; + else + buffer.append(c); + break; + case '\"': + if (!insideQuote1) + insideQuote2 = insideQuote2 ^ true; + else + buffer.append(c); + break; + case '\\': + escaped = true; + break; + case ' ': + case '\t': + case '\r': + case '\n': + if (insideQuote1 || insideQuote2) + buffer.append(c); + else { + String item = buffer.toString(); + buffer.setLength(0); + if (item.length() > 0) + list.add(item); + } + break; + default: + buffer.append(c); + break; + } + } + // add last item of string that will be in the buffer + String item = buffer.toString(); + if (item.length() > 0) + list.add(item); + return list; + } + + private class ConnectionSelectionLabelProvider implements ILabelProvider { + @Override + public void removeListener(ILabelProviderListener listener) { + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return false; + } + + @Override + public void dispose() { + } + + @Override + public void addListener(ILabelProviderListener listener) { + } + + @Override + public String getText(Object element) { + return element.toString(); + } + + @Override + public Image getImage(Object element) { + return SWTImagesFactory.DESC_REPOSITORY_MIDDLE.createImage(); + } + } + + /** + * Show a selection dialog that allows the user to choose one of the + * connections to use to build the Image. + * + * @param connections + * Array of connections. + * @return The chosen connection, or <code>null</code> if the user cancelled + * the dialog. + */ + protected IDockerConnection chooseConnection( + final IDockerConnection[] connections) { + IDebugModelPresentation labelProvider = DebugUITools + .newDebugModelPresentation(); + ElementListSelectionDialog dialog = new ElementListSelectionDialog( + getActiveWorkbenchShell(), + new ConnectionSelectionLabelProvider() { + + }); + + dialog.setElements(connections); + dialog.setTitle( + LaunchMessages.getString(LaunchShortcut_Connection_Selection)); + dialog.setMessage( + LaunchMessages.getString(LaunchShortcut_Choose_Connection)); + dialog.setMultipleSelection(false); + int result = dialog.open(); + labelProvider.dispose(); + if (result == IStatus.OK) { + return (IDockerConnection) dialog.getFirstResult(); + } + return null; + } + /** + * Get the active Workbench shell. + * + * @return active shell as returned by the plug-in + */ + protected Shell getActiveWorkbenchShell() { + return Activator.getActiveWorkbenchShell(); } } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageEnvironmentTab.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageEnvironmentTab.java new file mode 100644 index 0000000000..d5fce1e7e7 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageEnvironmentTab.java @@ -0,0 +1,317 @@ +/******************************************************************************* + * 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.launch; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.databinding.beans.BeanProperties; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; +import org.eclipse.jface.databinding.viewers.ViewerSupport; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.linuxtools.docker.ui.Activator; +import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ContainerEnvironmentVariableDialog; +import org.eclipse.linuxtools.internal.docker.ui.wizards.EnvironmentVariableModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumesVariablesModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.WizardMessages; +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.Image; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + +public class RunImageEnvironmentTab extends AbstractLaunchConfigurationTab { + + private static final String TAB_NAME = "RunEnvTab.name"; //$NON-NLS-1$ + + private static final int COLUMNS = 3; + + private ImageRunResourceVolumesVariablesModel model = null; + + public RunImageEnvironmentTab(ImageRunResourceVolumesVariablesModel model) { + this.model = model; + } + + @Override + public void createControl(Composite parent) { + final Composite container = new Composite(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1) + .grab(true, false).applyTo(container); + GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) + .applyTo(container); + if (model == null) { + setErrorMessage(LaunchMessages.getString("NoConnectionError.msg")); + } else { + setErrorMessage(null); + createEnvironmentVariablesContainer(container); + } + setControl(container); + } + + private void createEnvironmentVariablesContainer( + final Composite container) { + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(3, 1) + .applyTo(new Label(container, SWT.NONE)); + 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(environmentVariablesTableViewer)); + 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, + new String[] { EnvironmentVariableModel.NAME, + EnvironmentVariableModel.VALUE })); + + // disable the edit and removeButton if the table is empty + environmentVariablesTableViewer.addSelectionChangedListener( + onSelectionChanged(editButton, removeButton)); + } + + private ISelectionChangedListener onSelectionChanged( + final Button... targetButtons) { + return new ISelectionChangedListener() { + + @Override + public void selectionChanged(final SelectionChangedEvent e) { + if (e.getSelection().isEmpty()) { + setControlsEnabled(targetButtons, false); + } else { + setControlsEnabled(targetButtons, true); + } + updateLaunchConfigurationDialog(); + } + + }; + } + + private TableViewerColumn addTableViewerColumn( + 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 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); + addTableViewerColumn(tableViewer, + WizardMessages + .getString("ImageRunResourceVolVarPage.nameColumn"), //$NON-NLS-1$ + 200); + addTableViewerColumn(tableViewer, + WizardMessages + .getString("ImageRunResourceVolVarPage.valueColumn"), //$NON-NLS-1$ + 200); + tableViewer.setContentProvider(new ObservableListContentProvider()); + return tableViewer; + } + + private SelectionListener onAddEnvironmentVariable( + final TableViewer environmentVariablesTableViewer) { + 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()); + environmentVariablesTableViewer + .add(dialog.getEnvironmentVariable()); + environmentVariablesTableViewer.refresh(); + updateLaunchConfigurationDialog(); + } + } + }; + } + + 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(); + } + updateLaunchConfigurationDialog(); + } + }; + } + + private SelectionListener onRemoveEnvironmentVariables( + final TableViewer environmentVariablesTableViewer) { + return new SelectionAdapter() { + + @Override + public void widgetSelected(final SelectionEvent e) { + final IStructuredSelection selection = environmentVariablesTableViewer + .getStructuredSelection(); + for (@SuppressWarnings("unchecked") + Iterator<EnvironmentVariableModel> iterator = selection + .iterator(); iterator.hasNext();) { + EnvironmentVariableModel m = iterator.next(); + model.removeEnvironmentVariable(m); + environmentVariablesTableViewer.remove(m); + environmentVariablesTableViewer.refresh(); + } + updateLaunchConfigurationDialog(); + } + }; + } + + private static void setControlsEnabled(final Control[] controls, + final boolean enabled) { + for (Control control : controls) { + control.setEnabled(enabled); + } + } + + @Override + public Image getImage() { + return SWTImagesFactory.get(SWTImagesFactory.IMG_ENV); + } + + @Override + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + } + + @Override + public void initializeFrom(ILaunchConfiguration configuration) { + try { + model.removeEnvironmentVariables(); + final List<String> environmentVariables = configuration + .getAttribute( + IRunDockerImageLaunchConfigurationConstants.ENV_VARIABLES, + new ArrayList<String>()); + for (String environmenVariable : environmentVariables) { + model.addEnvironmentVariable(EnvironmentVariableModel + .createEnvironmentVariableModel(environmenVariable)); + } + } catch (CoreException e) { + Activator.logErrorMessage( + LaunchMessages.getString( + "RunDockerImageLaunchConfiguration.load.failure"), //$NON-NLS-1$ + e); + } + // update the underlying launch config working copy on model + // changes. + model.addPropertyChangeListener( + new LaunchConfigurationChangeListener()); + + } + + private class LaunchConfigurationChangeListener + implements PropertyChangeListener { + + @Override + public void propertyChange(final PropertyChangeEvent evt) { + updateLaunchConfigurationDialog(); + } + } + + @Override + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + ArrayList<String> envList = new ArrayList<>(); + for (Object o : model.getEnvironmentVariables()) { + EnvironmentVariableModel m = (EnvironmentVariableModel) o; + envList.add(m.toString()); + } + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.ENV_VARIABLES, + envList); + } + + @Override + public String getName() { + return LaunchMessages.getString(TAB_NAME); + } + +} diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageLaunchConfigurationTabGroup.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageLaunchConfigurationTabGroup.java new file mode 100644 index 0000000000..50f095f606 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageLaunchConfigurationTabGroup.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * 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.launch; + +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup; +import org.eclipse.debug.ui.ILaunchConfigurationDialog; +import org.eclipse.linuxtools.docker.core.DockerConnectionManager; +import org.eclipse.linuxtools.docker.core.DockerException; +import org.eclipse.linuxtools.docker.core.IDockerConnection; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumesVariablesModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunSelectionModel; + +public class RunImageLaunchConfigurationTabGroup + extends AbstractLaunchConfigurationTabGroup { + + private ImageRunSelectionModel runSelectionModel; + private ImageRunResourceVolumesVariablesModel runVolumesModel; + + public RunImageLaunchConfigurationTabGroup() { + } + + public ImageRunSelectionModel getRunSelectionModel() { + return runSelectionModel; + } + + public ImageRunResourceVolumesVariablesModel getRunVolumesModel() { + return runVolumesModel; + } + + @Override + public void createTabs(ILaunchConfigurationDialog dialog, String mode) { + IDockerConnection[] connections = DockerConnectionManager.getInstance() + .getConnections(); + runSelectionModel = null; + runVolumesModel = null; + if (connections != null && connections.length > 0) { + runSelectionModel = new ImageRunSelectionModel(connections[0]); + try { + runVolumesModel = new ImageRunResourceVolumesVariablesModel( + connections[0]); + } catch (DockerException e) { + // do nothing + } + } + setTabs(new AbstractLaunchConfigurationTab[] { + new RunImageMainTab(runSelectionModel, runVolumesModel), + new RunImageVolumesTab(runVolumesModel), + new RunImagePortsTab(runSelectionModel), + new RunImageLinksTab(runSelectionModel), + new RunImageEnvironmentTab(runVolumesModel), + new RunImageResourcesTab(runVolumesModel) }); + } + +} diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageLinksTab.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageLinksTab.java new file mode 100644 index 0000000000..850798e51b --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageLinksTab.java @@ -0,0 +1,300 @@ +/******************************************************************************* + * 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.launch; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.databinding.beans.BeanProperties; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; +import org.eclipse.jface.databinding.viewers.ViewerSupport; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ContainerLinkDialog; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunSelectionModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunSelectionModel.ContainerLinkModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.WizardMessages; +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.Image; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + +public class RunImageLinksTab extends AbstractLaunchConfigurationTab { + + private static final String TAB_NAME = "RunLinksTab.name"; //$NON-NLS-1$ + + private static final int COLUMNS = 3; + + private ImageRunSelectionModel model = null; + + public RunImageLinksTab(ImageRunSelectionModel model) { + this.model = model; + } + + @Override + public void createControl(Composite parent) { + final Composite container = new Composite(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1) + .grab(true, false).applyTo(container); + GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) + .applyTo(container); + if (model == null) { + setErrorMessage(LaunchMessages.getString("NoConnectionError.msg")); + } else { + setErrorMessage(null); + createLinkSettingsSection(container); + } + setControl(container); + } + + private TableViewerColumn createTableViewerColumn( + 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 createLinkSettingsSection(final Composite container) { + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(3, 1) + .applyTo(new Label(container, SWT.NONE)); + final Label linksLabel = new Label(container, SWT.NONE); + linksLabel.setText( + WizardMessages.getString("ImageRunSelectionPage.links")); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(COLUMNS, 1).applyTo(linksLabel); + final TableViewer linksTableViewer = createLinksTable(container); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).grab(true, true) + .hint(200, 100).applyTo(linksTableViewer.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("ImageRunSelectionPage.addButton")); //$NON-NLS-1$ + addButton.addSelectionListener(onAddLink()); + final Button editButton = new Button(buttonsContainers, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) + .grab(true, false).applyTo(editButton); + editButton.setText( + WizardMessages.getString("ImageRunSelectionPage.editButton")); //$NON-NLS-1$ + editButton.setEnabled(false); + editButton.addSelectionListener(onEditLink(linksTableViewer)); + final Button removeButton = new Button(buttonsContainers, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) + .grab(true, false).applyTo(removeButton); + removeButton.setText( + WizardMessages.getString("ImageRunSelectionPage.remove")); //$NON-NLS-1$ + removeButton.addSelectionListener(onRemoveLinks(linksTableViewer)); + removeButton.setEnabled(false); + ViewerSupport + .bind(linksTableViewer, model.getLinks(), + BeanProperties.values(ContainerLinkModel.class, + new String[] { + ContainerLinkModel.CONTAINER_NAME, + ContainerLinkModel.CONTAINER_ALIAS })); + // disable the edit and removeButton if the table is empty + linksTableViewer.addSelectionChangedListener( + onSelectionChanged(editButton, removeButton)); + + } + + private ISelectionChangedListener onSelectionChanged( + final Button... targetButtons) { + return new ISelectionChangedListener() { + + @Override + public void selectionChanged(final SelectionChangedEvent e) { + if (e.getSelection().isEmpty()) { + setControlsEnabled(targetButtons, false); + } else { + setControlsEnabled(targetButtons, true); + } + updateLaunchConfigurationDialog(); + } + }; + } + + private TableViewer createLinksTable(final 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); + createTableViewerColumn(tableViewer, + WizardMessages + .getString("ImageRunSelectionPage.containerNameColumn"), //$NON-NLS-1$ + 200); + createTableViewerColumn(tableViewer, + WizardMessages.getString("ImageRunSelectionPage.aliasColumn"), //$NON-NLS-1$ + 150); + tableViewer.setContentProvider(new ObservableListContentProvider()); + return tableViewer; + } + + private SelectionListener onAddLink() { + return new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + final ContainerLinkDialog dialog = new ContainerLinkDialog( + getShell(), model.getSelectedConnection()); + dialog.create(); + if (dialog.open() == IDialogConstants.OK_ID) { + model.addLink(dialog.getContainerName(), + dialog.getContainerAlias()); + } + updateLaunchConfigurationDialog(); + } + }; + } + + private SelectionListener onEditLink(final TableViewer linksTableViewer) { + return new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + final IStructuredSelection selection = linksTableViewer + .getStructuredSelection(); + + final ContainerLinkModel selectedContainerLink = (ContainerLinkModel) selection + .getFirstElement(); + final ContainerLinkDialog dialog = new ContainerLinkDialog( + getShell(), model.getSelectedConnection(), + selectedContainerLink); + dialog.create(); + if (dialog.open() == IDialogConstants.OK_ID) { + selectedContainerLink + .setContainerName(dialog.getContainerName()); + selectedContainerLink + .setContainerAlias(dialog.getContainerAlias()); + linksTableViewer.refresh(); + updateLaunchConfigurationDialog(); + } + } + }; + } + + private SelectionListener onRemoveLinks( + final TableViewer linksTableViewer) { + return new SelectionAdapter() { + + @Override + public void widgetSelected(final SelectionEvent e) { + final IStructuredSelection selection = linksTableViewer + .getStructuredSelection(); + for (@SuppressWarnings("unchecked") + Iterator<ContainerLinkModel> iterator = selection + .iterator(); iterator.hasNext();) { + model.removeLink(iterator.next()); + } + updateLaunchConfigurationDialog(); + } + }; + } + + private static void setControlsEnabled(final Control[] controls, + final boolean enabled) { + for (Control control : controls) { + control.setEnabled(enabled); + } + } + + @Override + public Image getImage() { + return SWTImagesFactory.get(SWTImagesFactory.IMG_CONTAINER_LINK); + } + + @Override + public void setDefaults( + final ILaunchConfigurationWorkingCopy configuration) { + } + + @Override + public void initializeFrom(final ILaunchConfiguration configuration) { + try { + // model needs to be recycled + model.removeLinks(); + final List<String> containerLinks = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.LINKS, + new ArrayList<String>()); + for (String containerLink : containerLinks) { + model.addLink(ImageRunSelectionModel.ContainerLinkModel + .createContainerLinkModel(containerLink)); + } + } catch (CoreException e) { + // do nothing + } + // update the underlying launch config working copy on model + // changes. + model.addPropertyChangeListener( + new LaunchConfigurationChangeListener()); + } + + @Override + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + ArrayList<String> linksList = new ArrayList<>(); + for (Object o : model.getLinks()) { + ImageRunSelectionModel.ContainerLinkModel m = (ImageRunSelectionModel.ContainerLinkModel) o; + linksList.add(m.toString()); + } + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.LINKS, linksList); + } + + @Override + public String getName() { + return LaunchMessages.getString(TAB_NAME); + } + + private class LaunchConfigurationChangeListener + implements PropertyChangeListener { + + @Override + public void propertyChange(final PropertyChangeEvent evt) { + updateLaunchConfigurationDialog(); + } + } + +} diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageMainTab.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageMainTab.java new file mode 100644 index 0000000000..3a83d56f5e --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageMainTab.java @@ -0,0 +1,633 @@ +/******************************************************************************* + * 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.launch; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.databinding.DataBindingContext; +import org.eclipse.core.databinding.beans.BeanProperties; +import org.eclipse.core.databinding.observable.list.IObservableList; +import org.eclipse.core.databinding.observable.list.WritableList; +import org.eclipse.core.databinding.observable.value.IObservableValue; +import org.eclipse.core.databinding.observable.value.IValueChangeListener; +import org.eclipse.core.databinding.observable.value.ValueChangeEvent; +import org.eclipse.core.databinding.validation.MultiValidator; +import org.eclipse.core.databinding.validation.ValidationStatus; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.databinding.swt.WidgetProperties; +import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +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.DockerConnectionManager; +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.docker.ui.wizards.ImageSearch; +import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.commands.CommandUtils; +import org.eclipse.linuxtools.internal.docker.ui.utils.IRunnableWithResult; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumesVariablesModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunSelectionModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunSelectionModel.ExposedPortModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.WizardMessages; +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.Image; +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.Label; +import org.eclipse.swt.widgets.Text; + +public class RunImageMainTab extends AbstractLaunchConfigurationTab { + + private static final String TAB_NAME = "RunMainTab.name"; //$NON-NLS-1$ + // private static final String ERROR_PULLING_IMAGE = "ImagePullError.msg"; + // //$NON-NLS-1$ + + private static final int COLUMNS = 3; + + private final DataBindingContext dbc = new DataBindingContext(); + private final ImageRunSelectionModel model; + private final ImageRunResourceVolumesVariablesModel volumesModel; + + public RunImageMainTab(ImageRunSelectionModel model, + ImageRunResourceVolumesVariablesModel volumesModel) { + this.model = model; + this.volumesModel = volumesModel; + } + + public ImageRunSelectionModel getModel() { + return model; + } + + private class ImageSelectionValidator extends MultiValidator { + + private final IObservableValue imageSelectionObservable; + + ImageSelectionValidator( + final IObservableValue imageSelectionObservable) { + this.imageSelectionObservable = imageSelectionObservable; + } + + @Override + protected IStatus validate() { + final String selectedImageName = (String) imageSelectionObservable + .getValue(); + if (selectedImageName.isEmpty()) { + model.setSelectedImageNeedsPulling(false); + return ValidationStatus.error(WizardMessages + .getString("ImageRunSelectionPage.specifyImageMsg")); //$NON-NLS-1$ + } + if (model.getSelectedImage() != null) { + model.setSelectedImageNeedsPulling(false); + return ValidationStatus.ok(); + } + model.setSelectedImageNeedsPulling(true); + return ValidationStatus.warning(WizardMessages.getFormattedString( + "ImageRunSelectionPage.imageNotFoundMessage", //$NON-NLS-1$ + selectedImageName)); + } + + @Override + public IObservableList getTargets() { + WritableList targets = new WritableList(); + targets.add(imageSelectionObservable); + return targets; + } + } + + @Override + public void createControl(Composite parent) { + final Composite container = new Composite(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1) + .grab(true, false).applyTo(container); + GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) + .applyTo(container); + if (model == null) { + setErrorMessage(LaunchMessages.getString("NoConnectionError.msg")); + return; + } else { + setErrorMessage(null); + setDefaultValues(); + createImageSettingsSection(container); + createSectionSeparator(container, true); + createRunOptionsSection(container); + final IObservableValue connectionSelectionObservable = BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.SELECTED_CONNECTION_NAME) + .observe(model); + connectionSelectionObservable + .addValueChangeListener(onConnectionSelectionChange()); + final IObservableValue imageSelectionObservable = BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.SELECTED_IMAGE_NAME) + .observe(model); + imageSelectionObservable + .addValueChangeListener(onImageSelectionChange()); + final ImageSelectionValidator imageSelectionValidator = new ImageSelectionValidator( + imageSelectionObservable); + dbc.addValidationStatusProvider(imageSelectionValidator); + } + setControl(container); + } + + private void setDefaultValues() { + final IDockerImage selectedImage = model.getSelectedImage(); + if (selectedImage == null) { + return; + } + findImageInfo(selectedImage); + } + + 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)); + } + + /** + * Creates the {@link Composite} container that will display widgets to + * select an {@link IDockerImage}, name it and specify the command to run. + * + * @param container + * the parent {@link Composite} + */ + private void createImageSettingsSection(final Composite container) { + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(3, 1) + .applyTo(new Label(container, SWT.NONE)); + final Label connectionSelectionLabel = new Label(container, SWT.NONE); + connectionSelectionLabel + .setText(WizardMessages.getString("Connection.label")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).applyTo(connectionSelectionLabel); + final Combo connectionSelectionCombo = new Combo(container, SWT.BORDER); + connectionSelectionCombo.setToolTipText( + LaunchMessages.getString("RunMainTabSelectConnection.tooltip")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).span(1, 1).applyTo(connectionSelectionCombo); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(1, 1) + .applyTo(new Label(container, SWT.NONE)); + new ControlDecoration(connectionSelectionCombo, SWT.TOP | SWT.LEFT); + final ComboViewer connectionSelectionComboViewer = new ComboViewer( + connectionSelectionCombo); + connectionSelectionComboViewer + .setContentProvider(new ArrayContentProvider()); + connectionSelectionComboViewer.setInput(getConnectionNames()); + dbc.bindValue( + WidgetProperties.selection().observe(connectionSelectionCombo), + BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.SELECTED_CONNECTION_NAME) + .observe(model)); + // Image selection name + final Label imageSelectionLabel = new Label(container, SWT.NONE); + imageSelectionLabel.setText(WizardMessages.getString("Image.label")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).applyTo(imageSelectionLabel); + final Combo imageSelectionCombo = new Combo(container, SWT.BORDER); + final ComboViewer imageSelectionComboViewer = new ComboViewer( + imageSelectionCombo); + imageSelectionCombo.setToolTipText(WizardMessages + .getString("ImageRunSelectionPage.selectTooltip")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).span(1, 1).applyTo(imageSelectionCombo); + new ControlDecoration(imageSelectionCombo, SWT.TOP | SWT.LEFT); + new ContentProposalAdapter(imageSelectionCombo, + 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); + } + }, getImageNameContentProposalProvider(imageSelectionCombo), + null, null); + // image search + final Button searchImageButton = new Button(container, SWT.NONE); + searchImageButton.setText( + WizardMessages.getString("ImageRunSelectionPage.search")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(1, 1) + // .hint(LaunchConfigurationUtils + // .getButtonWidthHint(searchImageButton), SWT.DEFAULT) + .applyTo(searchImageButton); + searchImageButton.addSelectionListener(onSearchImage()); + imageSelectionComboViewer + .setContentProvider(new ObservableListContentProvider()); + dbc.bindList(WidgetProperties.items().observe(imageSelectionCombo), + BeanProperties + .list(ImageRunSelectionModel.class, + ImageRunSelectionModel.IMAGE_NAMES) + .observe(model)); + dbc.bindValue(WidgetProperties.selection().observe(imageSelectionCombo), + BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.SELECTED_IMAGE_NAME) + .observe(model)); + // Container name (optional) + final Label containerNameLabel = new Label(container, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).applyTo(imageSelectionLabel); + containerNameLabel.setText("Name:"); //$NON-NLS-1$ + final Text containerNameText = new Text(container, SWT.BORDER); + containerNameText.setToolTipText(WizardMessages + .getString("ImageRunSelectionPage.containerTooltip")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).span(1, 1).applyTo(containerNameText); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(1, 1) + .applyTo(new Label(container, SWT.NONE)); + dbc.bindValue( + WidgetProperties.text(SWT.Modify).observe(containerNameText), + BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.CONTAINER_NAME) + .observe(model)); + // EntryPoint (optional) + final Label entrypointLabel = new Label(container, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).applyTo(imageSelectionLabel); + entrypointLabel.setText( + WizardMessages.getString("ImageRunSelectionPage.entrypoint")); //$NON-NLS-1$ + // TODO: include SWT.SEARCH | SWT.ICON_SEARCH to support value reset + final Text entrypointText = new Text(container, SWT.BORDER); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).span(1, 1).applyTo(entrypointText); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(1, 1) + .applyTo(new Label(container, SWT.NONE)); + dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(entrypointText), + BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.ENTRYPOINT) + .observe(model)); + + // Command (optional) + final Label commandLabel = new Label(container, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).applyTo(imageSelectionLabel); + commandLabel.setText( + WizardMessages.getString("ImageRunSelectionPage.command")); //$NON-NLS-1$ + final Text commandText = new Text(container, SWT.BORDER); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).span(1, 1).applyTo(commandText); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(1, 1) + .applyTo(new Label(container, SWT.NONE)); + dbc.bindValue(WidgetProperties.text(SWT.Modify).observe(commandText), + BeanProperties.value(ImageRunSelectionModel.class, + ImageRunSelectionModel.COMMAND).observe(model)); + } + + private String[] getConnectionNames() { + IDockerConnection[] connections = DockerConnectionManager.getInstance().getConnections(); + ArrayList<String> connectionNames = new ArrayList<>(); + for (IDockerConnection connection : connections) { + connectionNames.add(connection.getName()); + } + return connectionNames.toArray(new String[] {}); + } + + /** + * Creates an {@link IContentProposalProvider} to propose + * {@link IDockerImage} names based on the current text. + * + * @param items + * @return + */ + private IContentProposalProvider getImageNameContentProposalProvider( + final Combo imageSelectionCombo) { + return new IContentProposalProvider() { + + @Override + public IContentProposal[] getProposals(final String contents, + final int position) { + final List<IContentProposal> proposals = new ArrayList<>(); + for (String imageName : imageSelectionCombo.getItems()) { + if (imageName.contains(contents)) { + proposals.add(new ContentProposal(imageName, imageName, + imageName, position)); + } + } + return proposals.toArray(new IContentProposal[0]); + } + }; + } + + private IValueChangeListener onImageSelectionChange() { + return new IValueChangeListener() { + + @Override + public void handleValueChange(final ValueChangeEvent event) { + final IDockerImage selectedImage = model.getSelectedImage(); + // skip if the selected image does not exist in the local Docker + // host + if (selectedImage == null) { + model.setExposedPorts(new WritableList()); + return; + } + findImageInfo(selectedImage); + volumesModel.setSelectedImage(selectedImage); + } + }; + } + + private IValueChangeListener onConnectionSelectionChange() { + return new IValueChangeListener() { + + @Override + public void handleValueChange(final ValueChangeEvent event) { + IDockerImage selectedImage = model.getSelectedImage(); + // skip if the selected image does not exist in the local Docker + // host + if (selectedImage == null) { + List<String> imageNames = model.getImageNames(); + if (imageNames.size() > 0) { + model.setSelectedImageName(imageNames.get(0)); + selectedImage = model.getSelectedImage(); + } else { + model.setExposedPorts(new WritableList()); + return; + } + } + findImageInfo(selectedImage); + volumesModel.setSelectedImage(selectedImage); + } + }; + } + + private static final class FindImageInfoRunnable + implements IRunnableWithResult<IDockerImageInfo> { + private final IDockerImage selectedImage; + private IDockerImageInfo selectedImageInfo; + + private FindImageInfoRunnable(IDockerImage selectedImage) { + this.selectedImage = selectedImage; + } + + @Override + public void run(final IProgressMonitor monitor) { + selectedImageInfo = selectedImage.getConnection() + .getImageInfo(selectedImage.id()); + } + + @Override + public IDockerImageInfo getResult() { + return selectedImageInfo; + } + } + + private void findImageInfo(final IDockerImage selectedImage) { + try { + final FindImageInfoRunnable findImageInfoRunnable = new FindImageInfoRunnable( + selectedImage); + ProgressMonitorDialog dialog = new ProgressMonitorDialog( + this.getShell()); + dialog.run(true, true, findImageInfoRunnable); + final IDockerImageInfo selectedImageInfo = findImageInfoRunnable + .getResult(); + final Set<String> exposedPortInfos = selectedImageInfo.config() + .exposedPorts(); + final WritableList availablePorts = new WritableList(); + if (exposedPortInfos != null) { + for (String exposedPortInfo : exposedPortInfos) { + final String privatePort = exposedPortInfo.substring(0, + exposedPortInfo.indexOf('/')); + final String type = exposedPortInfo + .substring(exposedPortInfo.indexOf('/')); // $NON-NLS-1$ + final ExposedPortModel exposedPort = new ExposedPortModel( + privatePort, type, "", privatePort); + availablePorts.add(exposedPort); // $NON-NLS-1$ + } + } + model.setExposedPorts(availablePorts); + model.setCommand(selectedImageInfo.config().cmd()); + model.setEntrypoint(selectedImageInfo.config().entrypoint()); + + } catch (InvocationTargetException | InterruptedException e) { + Activator.log(e); + } + } + + private void createRunOptionsSection(final Composite container) { + // interactive/show in console mode + final Button interactiveButton = new Button(container, SWT.CHECK); + interactiveButton.setText( + WizardMessages.getString("ImageRunSelectionPage.openStdin")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .span(COLUMNS, 1).grab(true, false).applyTo(interactiveButton); + dbc.bindValue(WidgetProperties.selection().observe(interactiveButton), + BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.INTERACTIVE_MODE) + .observe(model)); + // allocate pseudo-TTY + final Button allocatePseudoTTY = new Button(container, SWT.CHECK); + allocatePseudoTTY + .setText(WizardMessages.getString("ImageRunSelectionPage.tty")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .span(COLUMNS, 1).grab(true, false).applyTo(allocatePseudoTTY); + dbc.bindValue(WidgetProperties.selection().observe(allocatePseudoTTY), + BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.ALLOCATE_PSEUDO_TTY) + .observe(model)); + + // remove when exits + final Button removeWhenExitsButton = new Button(container, SWT.CHECK); + removeWhenExitsButton.setText( + WizardMessages.getString("ImageRunSelectionPage.autoRemove")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .span(COLUMNS, 1).grab(true, false) + .applyTo(removeWhenExitsButton); + dbc.bindValue( + WidgetProperties.selection().observe(removeWhenExitsButton), + BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.REMOVE_WHEN_EXITS) + .observe(model)); + } + + private SelectionListener onSearchImage() { + return new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + final ImageSearch imageSearchWizard = new ImageSearch( + RunImageMainTab.this.model.getSelectedConnection(), + RunImageMainTab.this.model.getSelectedImageName()); + final boolean completed = CommandUtils + .openWizard(imageSearchWizard, getShell()); + if (completed) { + model.setSelectedImageName( + imageSearchWizard.getSelectedImage()); + } + } + }; + } + + @Override + public Image getImage() { + return SWTImagesFactory.get(SWTImagesFactory.IMG_MAIN_TAB); + } + + @Override + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + + } + + @Override + public void initializeFrom(ILaunchConfiguration configuration) { + final IDockerConnection[] connections = DockerConnectionManager + .getInstance() + .getConnections(); + try { + String connectionName = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.CONNECTION_NAME, + connections[0].getName()); + model.setSelectedConnectionName(connectionName); + String imageName = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.IMAGE_NAME, ""); //$NON-NLS-1$ + model.setSelectedImageName(imageName); + String command = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.COMMAND, ""); //$NON-NLS-1$ + model.setCommand(command); + String entryPoint = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.ENTRYPOINT, ""); //$NON-NLS-1$ + model.setEntrypoint(entryPoint); + String containerName = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.CONTAINER_NAME, + ""); //$NON-NLS-1$ + model.setContainerName(containerName); + boolean removeContainer = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.AUTO_REMOVE, + false); + model.setRemoveWhenExits(removeContainer); + boolean interactive = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.INTERACTIVE, + false); + model.setInteractiveMode(interactive); + boolean useTTY = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.ALLOCATE_PSEUDO_CONSOLE, + false); + model.setAllocatePseudoTTY(useTTY); + } catch (CoreException e) { + Activator.logErrorMessage( + LaunchMessages.getString( + "RunDockerImageLaunchConfiguration.load.failure"), //$NON-NLS-1$ + e); + } + // update the underlying launch config working copy on model + // changes. + model.addPropertyChangeListener( + new LaunchConfigurationChangeListener()); + + } + + @Override + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.CONNECTION_NAME, + model.getSelectedConnectionName()); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.IMAGE_NAME, + model.getSelectedImageName()); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.COMMAND, + model.getCommand()); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.ENTRYPOINT, + "".equals(model.getEntrypoint()) ? null //$NON-NLS-1$ + : model.getEntrypoint()); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.CONTAINER_NAME, + "".equals(model.getContainerName()) ? null //$NON-NLS-1$ + : model.getContainerName()); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.ALLOCATE_PSEUDO_CONSOLE, + model.isAllocatePseudoTTY()); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.AUTO_REMOVE, + model.isRemoveWhenExits()); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.INTERACTIVE, + model.isInteractiveMode()); + } + + @Override + public boolean isValid(ILaunchConfiguration launchConfig) { + try { + if (launchConfig.getAttribute( + IRunDockerImageLaunchConfigurationConstants.CONNECTION_NAME, + "").isEmpty()) { + return false; + } + } catch (CoreException e) { + Activator.log(e); + } + return super.isValid(launchConfig); + } + + private class LaunchConfigurationChangeListener + implements PropertyChangeListener { + + @Override + public void propertyChange(final PropertyChangeEvent evt) { + updateLaunchConfigurationDialog(); + } + } + + @Override + public void dispose() { + super.dispose(); + } + + @Override + public String getName() { + return LaunchMessages.getString(TAB_NAME); + } + +} diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImagePortsTab.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImagePortsTab.java new file mode 100644 index 0000000000..3a721db448 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImagePortsTab.java @@ -0,0 +1,428 @@ +/******************************************************************************* + * 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.launch; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.databinding.DataBindingContext; +import org.eclipse.core.databinding.beans.BeanProperties; +import org.eclipse.core.databinding.observable.value.IValueChangeListener; +import org.eclipse.core.databinding.observable.value.ValueChangeEvent; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.databinding.swt.WidgetProperties; +import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; +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.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.linuxtools.docker.ui.Activator; +import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ContainerPortDialog; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunSelectionModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunSelectionModel.ExposedPortModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.WizardMessages; +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.Image; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + +public class RunImagePortsTab extends AbstractLaunchConfigurationTab + implements PropertyChangeListener { + + private static final String TAB_NAME = "RunPortsTab.name"; //$NON-NLS-1$ + + private static final int INDENT = 30; + + private static final int COLUMNS = 3; + + private final DataBindingContext dbc = new DataBindingContext(); + + private final ImageRunSelectionModel model; + + public RunImagePortsTab(ImageRunSelectionModel model) { + this.model = model; + } + + @Override + public void createControl(Composite parent) { + final Composite container = new Composite(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1) + .grab(true, false).applyTo(container); + GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) + .applyTo(container); + if (model == null) { + setErrorMessage(LaunchMessages.getString("NoConnectionError.msg")); + } else { + setErrorMessage(null); + createPortSettingsSection(container); + } + setControl(container); + } + + private void createPortSettingsSection(final Composite container) { + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(3, 1) + .applyTo(new Label(container, SWT.NONE)); + final Button publishAllPortsButton = new Button(container, SWT.CHECK); + publishAllPortsButton.setText(WizardMessages + .getString("ImageRunSelectionPage.publishAllPorts")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .span(COLUMNS, 1).grab(true, false) + .applyTo(publishAllPortsButton); + dbc.bindValue( + WidgetProperties.selection().observe(publishAllPortsButton), + BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.PUBLISH_ALL_PORTS) + .observe(model)); + // specify ports + final Label portSettingsLabel = new Label(container, SWT.NONE); + portSettingsLabel.setText( + WizardMessages.getString("ImageRunSelectionPage.portSettings")); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(true, false).span(COLUMNS, 1).indent(INDENT, 0) + .applyTo(portSettingsLabel); + final CheckboxTableViewer exposedPortsTableViewer = createPortSettingsTable( + container); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) + .grab(true, false).span(COLUMNS - 1, 1).indent(INDENT, 0) + .hint(200, 70).applyTo(exposedPortsTableViewer.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("ImageRunSelectionPage.add")); //$NON-NLS-1$ + addButton.addSelectionListener(onAddPort(exposedPortsTableViewer)); + final Button editButton = new Button(buttonsContainers, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) + .grab(true, false).applyTo(editButton); + editButton.setText( + WizardMessages.getString("ImageRunSelectionPage.editButton")); //$NON-NLS-1$ + editButton.setEnabled(false); + editButton.addSelectionListener(onEditPort(exposedPortsTableViewer)); + final Button removeButton = new Button(buttonsContainers, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP) + .grab(true, false).applyTo(removeButton); + removeButton.setText( + WizardMessages.getString("ImageRunSelectionPage.remove")); //$NON-NLS-1$ + removeButton + .addSelectionListener(onRemovePorts(exposedPortsTableViewer)); + BeanProperties + .value(ImageRunSelectionModel.class, + ImageRunSelectionModel.PUBLISH_ALL_PORTS) + .observe(model) + .addValueChangeListener(onPublishAllPortsChange( + exposedPortsTableViewer.getTable(), addButton, + removeButton)); + ViewerSupport.bind(exposedPortsTableViewer, model.getExposedPorts(), + BeanProperties.values(ExposedPortModel.class, + new String[] { ExposedPortModel.CONTAINER_PORT, + ExposedPortModel.PORT_TYPE, + ExposedPortModel.HOST_ADDRESS, + ExposedPortModel.HOST_PORT })); + dbc.bindSet( + ViewersObservables.observeCheckedElements( + exposedPortsTableViewer, ExposedPortModel.class), + BeanProperties.set(ImageRunSelectionModel.SELECTED_PORTS) + .observe(model)); + + // disable the edit and removeButton if the table is empty + exposedPortsTableViewer.addSelectionChangedListener( + onSelectionChanged(editButton, removeButton)); + exposedPortsTableViewer.addCheckStateListener(onCheckStateChanged()); + + togglePortMappingControls(exposedPortsTableViewer.getTable(), addButton, + removeButton); + } + + private static void setControlsEnabled(final Control[] controls, + final boolean enabled) { + for (Control control : controls) { + control.setEnabled(enabled); + } + } + + private ISelectionChangedListener onSelectionChanged( + final Button... targetButtons) { + return new ISelectionChangedListener() { + + @Override + public void selectionChanged(final SelectionChangedEvent e) { + if (e.getSelection().isEmpty()) { + setControlsEnabled(targetButtons, false); + } else { + setControlsEnabled(targetButtons, true); + } + } + }; + } + + private ICheckStateListener onCheckStateChanged() { + return new ICheckStateListener() { + + @Override + public void checkStateChanged(final CheckStateChangedEvent e) { + ImageRunSelectionModel.ExposedPortModel element = (ImageRunSelectionModel.ExposedPortModel) e + .getElement(); + if (e.getChecked()) { + model.getSelectedPorts().add(element); + element.setSelected(true); + } else { + model.getSelectedPorts().remove(element); + element.setSelected(false); + } + updateLaunchConfigurationDialog(); + } + }; + } + + private CheckboxTableViewer createPortSettingsTable( + final Composite container) { + final Table table = new Table(container, SWT.BORDER | SWT.FULL_SELECTION + | SWT.V_SCROLL | SWT.H_SCROLL | SWT.CHECK); + final CheckboxTableViewer tableViewer = new CheckboxTableViewer(table); + table.setHeaderVisible(true); + table.setLinesVisible(true); + createTableViewerColumn(tableViewer, + WizardMessages + .getString("ImageRunSelectionPage.containerPortColumn"), //$NON-NLS-1$ + 100); + createTableViewerColumn(tableViewer, + WizardMessages.getString("ImageRunSelectionPage.typeColumn"), //$NON-NLS-1$ + 50); + createTableViewerColumn(tableViewer, + WizardMessages + .getString("ImageRunSelectionPage.hostAddressColumn"), //$NON-NLS-1$ + 100); + createTableViewerColumn(tableViewer, + WizardMessages + .getString("ImageRunSelectionPage.hostPortColumn"), //$NON-NLS-1$ + 100); + tableViewer.setContentProvider(new ObservableListContentProvider()); + return tableViewer; + } + + private TableViewerColumn createTableViewerColumn( + 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 IValueChangeListener onPublishAllPortsChange( + final Control... controls) { + return new IValueChangeListener() { + + @Override + public void handleValueChange(final ValueChangeEvent event) { + togglePortMappingControls(controls); + } + }; + } + + private SelectionListener onAddPort( + final CheckboxTableViewer exposedPortsTableViewer) { + return new SelectionAdapter() { + @Override + public void widgetSelected(final SelectionEvent e) { + final ContainerPortDialog dialog = new ContainerPortDialog( + getShell()); + dialog.create(); + if (dialog.open() == IDialogConstants.OK_ID) { + final ExposedPortModel port = dialog.getPort(); + model.addAvailablePort(port); + model.getSelectedPorts().add(port); + port.setSelected(true); + exposedPortsTableViewer.setChecked(port, true); + updateLaunchConfigurationDialog(); + } + } + }; + } + + private SelectionListener onEditPort( + final CheckboxTableViewer exposedPortsTableViewer) { + return new SelectionAdapter() { + @Override + public void widgetSelected(final SelectionEvent e) { + final IStructuredSelection selection = exposedPortsTableViewer + .getStructuredSelection(); + final ExposedPortModel selectedContainerPort = (ExposedPortModel) selection + .getFirstElement(); + final ContainerPortDialog dialog = new ContainerPortDialog( + getShell(), selectedContainerPort); + dialog.create(); + if (dialog.open() == IDialogConstants.OK_ID) { + final ExposedPortModel configuredPort = dialog.getPort(); + selectedContainerPort.setContainerPort( + configuredPort.getContainerPort()); + selectedContainerPort + .setHostAddress(configuredPort.getHostAddress()); + selectedContainerPort + .setHostPort(configuredPort.getHostPort()); + } + updateLaunchConfigurationDialog(); + } + }; + } + + private SelectionListener onRemovePorts( + final TableViewer portsTableViewer) { + return new SelectionAdapter() { + + @Override + public void widgetSelected(final SelectionEvent e) { + final IStructuredSelection selection = portsTableViewer + .getStructuredSelection(); + for (@SuppressWarnings("unchecked") + Iterator<ExposedPortModel> iterator = selection + .iterator(); iterator.hasNext();) { + final ExposedPortModel port = iterator.next(); + model.removeAvailablePort(port); + model.getSelectedPorts().remove(port); + } + updateLaunchConfigurationDialog(); + } + }; + } + + private void togglePortMappingControls(final Control... controls) { + for (Control control : controls) { + if (model.isPublishAllPorts()) { + control.setEnabled(false); + } else { + control.setEnabled(true); + } + updateLaunchConfigurationDialog(); + } + } + + @Override + public Image getImage() { + return SWTImagesFactory.get(SWTImagesFactory.IMG_CONTAINER_PORT); + } + + @Override + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + + } + + @Override + public void initializeFrom(ILaunchConfiguration configuration) { + try { + // recycle the model + model.removeExposedPorts(); + final boolean publishAllPorts = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.PUBLISH_ALL_PORTS, + true); + model.setPublishAllPorts(publishAllPorts); + final List<String> publishedPorts = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.PUBLISHED_PORTS, + new ArrayList<String>()); + final Set<ExposedPortModel> selectedPorts = new HashSet<>(); + for (String port : publishedPorts) { + final ImageRunSelectionModel.ExposedPortModel exposedPort = ImageRunSelectionModel.ExposedPortModel + .createPortModel(port); + model.addExposedPort(exposedPort); + if (exposedPort.getSelected()) { + selectedPorts.add(exposedPort); + } + } + // select ports + model.setSelectedPorts(selectedPorts); + + // update the underlying launch config working copy on model + // changes. + model.addPropertyChangeListener( + new LaunchConfigurationChangeListener()); + } catch (CoreException e) { + Activator.logErrorMessage( + LaunchMessages.getString( + "RunDockerImageLaunchConfiguration.load.failure"), //$NON-NLS-1$ + e); + } + + } + + @Override + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.PUBLISH_ALL_PORTS, + model.isPublishAllPorts()); + List<String> portsList = new ArrayList<>(); + for (Object o : model.getExposedPorts().toArray()) { + ImageRunSelectionModel.ExposedPortModel m = (ImageRunSelectionModel.ExposedPortModel) o; + portsList.add(m.toString()); + } + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.PUBLISHED_PORTS, + portsList); + } + + @Override + public String getName() { + return LaunchMessages.getString(TAB_NAME); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + // TODO Auto-generated method stub + + } + + private class LaunchConfigurationChangeListener + implements PropertyChangeListener { + + @Override + public void propertyChange(final PropertyChangeEvent evt) { + updateLaunchConfigurationDialog(); + } + } + +} diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageResourcesTab.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageResourcesTab.java new file mode 100644 index 0000000000..292b45a40e --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageResourcesTab.java @@ -0,0 +1,297 @@ +/******************************************************************************* + * 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.launch; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import org.eclipse.core.databinding.DataBindingContext; +import org.eclipse.core.databinding.beans.BeanProperties; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.databinding.swt.WidgetProperties; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.linuxtools.docker.ui.Activator; +import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumesVariablesModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.WizardMessages; +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.Image; +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.Text; + +public class RunImageResourcesTab extends AbstractLaunchConfigurationTab { + + private static final String TAB_NAME = "RunResourcesTab.name"; //$NON-NLS-1$ + + private static final int COLUMNS = 2; + + private final DataBindingContext dbc = new DataBindingContext(); + private ImageRunResourceVolumesVariablesModel model = null; + + private Composite container; + + public RunImageResourcesTab(ImageRunResourceVolumesVariablesModel model) { + this.model = model; + } + + @Override + public void createControl(Composite parent) { + final Composite container = new Composite(parent, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(1, 1) + .grab(true, false).applyTo(container); + GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) + .applyTo(container); + if (model == null) { + setErrorMessage(LaunchMessages.getString("NoConnectionError.msg")); + } else { + setErrorMessage(null); + createResourceSettingsContainer(container); + } + setControl(container); + } + + 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); + dbc.bindValue( + WidgetProperties.selection() + .observe(enableResourceLimitationButton), + BeanProperties + .value(ImageRunResourceVolumesVariablesModel.class, + ImageRunResourceVolumesVariablesModel.ENABLE_RESOURCE_LIMITATIONS) + .observe(model)); + final int COLUMNS = 5; + final int INDENT = 20; + final Composite subContainer = new Composite(container, SWT.NONE); + setContainer(subContainer); + 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); + lowCPULimitationButton.setText(WizardMessages + .getString("ImageRunResourceVolVarPage.lowButton")); //$NON-NLS-1$ + lowCPULimitationButton.addSelectionListener( + onCpuShareWeighting(ImageRunResourceVolumesVariablesModel.LOW)); + 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$ + mediumCPULimitationButton.addSelectionListener(onCpuShareWeighting( + ImageRunResourceVolumesVariablesModel.MEDIUM)); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .applyTo(mediumCPULimitationButton); + final Button highCPULimitationButton = new Button(subContainer, + SWT.RADIO); + mediumCPULimitationButton.setSelection(true); + highCPULimitationButton.setText(WizardMessages + .getString("ImageRunResourceVolVarPage.highButton")); //$NON-NLS-1$ + highCPULimitationButton.addSelectionListener(onCpuShareWeighting( + ImageRunResourceVolumesVariablesModel.HIGH)); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1) + .applyTo(highCPULimitationButton); + dbc.bindValue( + WidgetProperties.selection() + .observe(enableResourceLimitationButton), + BeanProperties + .value(ImageRunResourceVolumesVariablesModel.class, + ImageRunResourceVolumesVariablesModel.ENABLE_RESOURCE_LIMITATIONS) + .observe(model)); + + // 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); + int maxMemory = this.model.getTotalMemory(); + memoryLimitSpinner.setMaximum(this.model.getTotalMemory()); + memoryLimitSpinner.setSelection(Math.min(512, maxMemory)); + 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)); + dbc.bindValue(WidgetProperties.selection().observe(memoryLimitSpinner), + 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 + enableResourceLimitationButton + .addSelectionListener(onEnableResourceLimitation(subContainer)); + toggleResourceLimitationControls(subContainer); + + } + + private void setContainer(final Composite container) { + this.container = container; + } + + private Composite getContainer() { + return container; + } + + private SelectionListener onCpuShareWeighting(final int cpuShareWeigth) { + return new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + model.setCpuShareWeight(cpuShareWeigth); + } + }; + } + + private SelectionListener onEnableResourceLimitation( + final Composite container) { + return new SelectionAdapter() { + @Override + public void widgetSelected(final SelectionEvent e) { + toggleResourceLimitationControls(container); + } + + }; + } + + private void toggleResourceLimitationControls(Composite container) { + for (Control childControl : container.getChildren()) { + if (model.isEnableResourceLimitations()) { + childControl.setEnabled(true); + } else { + childControl.setEnabled(false); + } + updateLaunchConfigurationDialog(); + } + } + + + @Override + public Image getImage() { + return SWTImagesFactory.get(SWTImagesFactory.IMG_RESOURCE); + } + + @Override + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + // TODO Auto-generated method stub + + } + + @Override + public void initializeFrom(ILaunchConfiguration configuration) { + try { + boolean enableLimits = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.ENABLE_LIMITS, + false); + model.setEnableResourceLimitations(enableLimits); + + int cpuShareWeight = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.CPU_PRIORITY, + 1024); + model.setCpuShareWeight(cpuShareWeight); + + int maxMemory = this.model.getTotalMemory(); + int memoryLimit = Math.min(512, maxMemory); + memoryLimit = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.MEMORY_LIMIT, + memoryLimit); + model.setMemoryLimit(memoryLimit); + toggleResourceLimitationControls(getContainer()); + } catch (CoreException e) { + Activator.logErrorMessage( + LaunchMessages.getString( + "RunDockerImageLaunchConfiguration.load.failure"), //$NON-NLS-1$ + e); + } + model.addPropertyChangeListener( + new LaunchConfigurationChangeListener()); + } + + @Override + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.ENABLE_LIMITS, + model.isEnableResourceLimitations()); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.MEMORY_LIMIT, + model.getMemoryLimit()); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.CPU_PRIORITY, + model.getCpuShareWeight()); + } + + @Override + public String getName() { + return LaunchMessages.getString(TAB_NAME); + } + + private class LaunchConfigurationChangeListener + implements PropertyChangeListener { + + @Override + public void propertyChange(final PropertyChangeEvent evt) { + updateLaunchConfigurationDialog(); + } + } + +} diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageVolumesTab.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageVolumesTab.java new file mode 100644 index 0000000000..067514cf43 --- /dev/null +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/RunImageVolumesTab.java @@ -0,0 +1,549 @@ +/******************************************************************************* + * 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.launch; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.databinding.DataBindingContext; +import org.eclipse.core.databinding.beans.BeanProperties; +import org.eclipse.core.databinding.beans.IBeanValueProperty; +import org.eclipse.core.databinding.observable.list.IObservableList; +import org.eclipse.core.databinding.observable.list.WritableList; +import org.eclipse.core.databinding.observable.map.IObservableMap; +import org.eclipse.core.databinding.observable.set.IObservableSet; +import org.eclipse.core.databinding.property.Properties; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Platform; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +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.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.linuxtools.docker.ui.Activator; +import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ContainerDataVolumeDialog; +import org.eclipse.linuxtools.internal.docker.ui.wizards.DataVolumeModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumesVariablesModel; +import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumesVariablesModel.MountType; +import org.eclipse.linuxtools.internal.docker.ui.wizards.WizardMessages; +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.Image; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + +public class RunImageVolumesTab extends AbstractLaunchConfigurationTab { + + private static final String TAB_NAME = "RunVolumesTab.name"; //$NON-NLS-1$ + + private static final int COLUMNS = 3; + + private final DataBindingContext dbc = new DataBindingContext(); + private ImageRunResourceVolumesVariablesModel model = null; + + public RunImageVolumesTab(ImageRunResourceVolumesVariablesModel model) { + this.model = model; + } + + public ImageRunResourceVolumesVariablesModel getModel() { + return model; + } + + @Override + public void createControl(Composite parent) { + final Composite container = new Composite(parent, SWT.NONE); + GridLayoutFactory.fillDefaults().numColumns(COLUMNS).margins(6, 6) + .applyTo(container); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL) + .applyTo(container); + if (model == null) { + setErrorMessage(LaunchMessages.getString("NoConnectionError.msg")); + } else { + setErrorMessage(null); + createVolumeSettingsContainer(container); + } + setControl(container); + } + + private void createVolumeSettingsContainer(final Composite container) { + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) + .grab(false, false).span(3, 1) + .applyTo(new Label(container, SWT.NONE)); + 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()); + // update table content when selected image changes + bind(dataVolumesTableViewer, model.getDataVolumes(), + BeanProperties.values(DataVolumeModel.class, + new String[] { DataVolumeModel.CONTAINER_PATH, + DataVolumeModel.MOUNT, + DataVolumeModel.READ_ONLY_VOLUME })); + final IObservableSet selectedVolumesObservable = BeanProperties + .set(ImageRunResourceVolumesVariablesModel.SELECTED_DATA_VOLUMES) + .observe(model); + dbc.bindSet( + ViewersObservables.observeCheckedElements( + dataVolumesTableViewer, DataVolumeModel.class), + selectedVolumesObservable); + dataVolumesTableViewer.addCheckStateListener(onCheckStateChanged()); + + // initializes the checkboxes selection upon loading the model. + // remove ? + // selectedVolumesObservable.addChangeListener(new + // IChangeListener() { + // + // @Override + // public void handleChange(ChangeEvent event) { + // final IObservableSet observable = (IObservableSet) event + // .getObservable(); + // for (Iterator<?> iterator = observable.iterator(); iterator + // .hasNext();) { + // final DataVolumeModel volume = (DataVolumeModel) iterator + // .next(); + // dataVolumesTableViewer.setChecked(volume, true); + // } + // updateLaunchConfigurationDialog(); + // } + // }); + + // 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); + // disable the edit and removeButton if the table is empty + dataVolumesTableViewer.addSelectionChangedListener( + onSelectionChanged(editButton, removeButton)); + + } + + private ICheckStateListener onCheckStateChanged() { + return new ICheckStateListener() { + + @Override + public void checkStateChanged(final CheckStateChangedEvent e) { + DataVolumeModel element = (DataVolumeModel) e.getElement(); + if (e.getChecked()) { + model.getSelectedDataVolumes().add(element); + element.setSelected(true); + } else { + model.getSelectedDataVolumes().remove(element); + element.setSelected(false); + } + updateLaunchConfigurationDialog(); + } + }; + } + + /** + * 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 new ISelectionChangedListener() { + + @Override + public void selectionChanged(final SelectionChangedEvent e) { + if (e.getSelection().isEmpty()) { + setControlsEnabled(targetButtons, false); + updateLaunchConfigurationDialog(); + } else { + setControlsEnabled(targetButtons, true); + updateLaunchConfigurationDialog(); + } + } + + }; + } + + 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) { + model.getDataVolumes().add(dialog.getDataVolume()); + model.getSelectedDataVolumes().add(dialog.getDataVolume()); + dialog.getDataVolume().setSelected(true); + dataVolumesTableViewer.setChecked(dialog.getDataVolume(), + true); + updateLaunchConfigurationDialog(); + } + } + }; + } + + 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); + updateLaunchConfigurationDialog(); + } + } + }; + } + + 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); + } + updateLaunchConfigurationDialog(); + } + }; + } + + 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); + addTableViewerColumn(tableViewer, + WizardMessages.getString( + "ImageRunResourceVolVarPage.containerPathColumn"), //$NON-NLS-1$ + 150); + addTableViewerColumn(tableViewer, + WizardMessages + .getString("ImageRunResourceVolVarPage.mountColumn"), //$NON-NLS-1$ + 150); + addTableViewerColumn(tableViewer, + WizardMessages + .getString("ImageRunResourceVolVarPage.readonlyColumn"), //$NON-NLS-1$ + 60); + return tableViewer; + } + + private TableViewerColumn addTableViewerColumn( + 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 static void setControlsEnabled(final Control[] controls, + final boolean enabled) { + for (Control control : controls) { + control.setEnabled(enabled); + } + } + + private static final class DataVolumesLabelProvider + extends ObservableMapLabelProvider { + + public DataVolumesLabelProvider(final IObservableMap[] attributeMaps) { + super(attributeMaps); + } + + @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 SWTImagesFactory.DESC_CONTAINER.createImage(); + case HOST_FILE_SYSTEM: + final File hostFile = new File(dataVolume.getMount()); + if (!hostFile.exists() || hostFile.isDirectory()) { + return SWTImagesFactory.DESC_FOLDER_CLOSED + .createImage(); + } else { + return SWTImagesFactory.DESC_FILE.createImage(); + } + 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; + } + } + } + + @Override + public Image getImage() { + return SWTImagesFactory.get(SWTImagesFactory.IMG_CONTAINER_VOLUME); + } + + @Override + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + } + + @Override + public void initializeFrom(ILaunchConfiguration configuration) { + final WritableList volumes = new WritableList(); + try { + final List<String> volumesList = configuration.getAttribute( + IRunDockerImageLaunchConfigurationConstants.DATA_VOLUME, + new ArrayList<String>()); + final Set<DataVolumeModel> selectedVolumes = new HashSet<>(); + for (String volume : volumesList) { + DataVolumeModel volumeModel = DataVolumeModel + .createDataVolumeModel(volume); + volumes.add(volumeModel); + if (volumeModel.getSelected()) { + selectedVolumes.add(volumeModel); + } + } + model.setDataVolumes(volumes); + model.setSelectedDataVolumes(selectedVolumes); + + } catch (CoreException e) { + Activator.logErrorMessage( + LaunchMessages.getString( + "RunDockerImageLaunchConfiguration.load.failure"), //$NON-NLS-1$ + e); + } + // update the underlying launch config working copy on model + // changes. + model.addPropertyChangeListener( + new LaunchConfigurationChangeListener()); + } + + @Override + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + WritableList volumes = model.getDataVolumes(); + Set<DataVolumeModel> selectedVolumes = model.getSelectedDataVolumes(); + + ArrayList<String> binds = new ArrayList<>(); + ArrayList<String> volumesFrom = new ArrayList<>(); + ArrayList<String> volumesList = new ArrayList<>(); + Set<String> selectedVolumesSet = new TreeSet<>(); + + for (@SuppressWarnings("unchecked") + Iterator<DataVolumeModel> iterator = volumes.iterator(); iterator + .hasNext();) { + DataVolumeModel volume = iterator.next(); + StringBuffer buffer = new StringBuffer(); + volumesList.add(volume.toString()); + switch (volume.getMountType()) { + case HOST_FILE_SYSTEM: + buffer.append(volume.getHostPathMount() + "," + + volume.getHostPathMount() + "," + + volume.isReadOnly()); + if (selectedVolumes.contains(volume)) { + selectedVolumesSet.add(volume.toString()); + String bind = convertToUnixPath(volume.getHostPathMount()) + + ':' + volume.getContainerPath() + ':' + 'Z'; + if (volume.isReadOnly()) { + bind += ",ro"; //$NON-NLS-1$ + } + binds.add(bind); + } + break; + case CONTAINER: + if (selectedVolumes.contains(volume)) { + selectedVolumesSet.add(volume.toString()); + volumesFrom.add(volume.getContainerMount()); + } + break; + default: + break; + } + } + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.BINDS, binds); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.VOLUMES_FROM, + volumesFrom); + configuration.setAttribute( + IRunDockerImageLaunchConfigurationConstants.DATA_VOLUME, + volumesList); + } + + private String convertToUnixPath(String path) { + String unixPath = path; + + if (Platform.OS_WIN32.equals(Platform.getOS())) { + // replace backslashes with slashes + unixPath = unixPath.replaceAll("\\\\", "/"); + + // replace "C:/" with "/c/" + Matcher m = Pattern.compile("([a-zA-Z]):/").matcher(unixPath); + if (m.find()) { + StringBuffer b = new StringBuffer(); + b.append('/'); + m.appendReplacement(b, m.group(1).toLowerCase()); + b.append('/'); + m.appendTail(b); + unixPath = b.toString(); + } + } + + return unixPath; + } + + @Override + public String getName() { + return LaunchMessages.getString(TAB_NAME); + } + + private class LaunchConfigurationChangeListener + implements PropertyChangeListener { + + @Override + public void propertyChange(final PropertyChangeEvent evt) { + updateLaunchConfigurationDialog(); + } + } + +} 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 index 6573415476..5874c09852 100644 --- 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 @@ -74,7 +74,7 @@ public class ContainerDataVolumeDialog extends Dialog { private final IDockerConnection connection; - protected ContainerDataVolumeDialog(final Shell parentShell, + public ContainerDataVolumeDialog(final Shell parentShell, final IDockerConnection connection, final DataVolumeModel selectedDataVolume) { super(parentShell); @@ -83,7 +83,7 @@ public class ContainerDataVolumeDialog extends Dialog { this.containerNames = WizardUtils.getContainerNames(connection); } - protected ContainerDataVolumeDialog(final Shell parentShell, + public ContainerDataVolumeDialog(final Shell parentShell, final IDockerConnection connection) { super(parentShell); this.connection = connection; diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerEnvironmentVariableDialog.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerEnvironmentVariableDialog.java index cf2b61d6d5..e05c0af222 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerEnvironmentVariableDialog.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerEnvironmentVariableDialog.java @@ -40,7 +40,7 @@ public class ContainerEnvironmentVariableDialog extends Dialog { private final DataBindingContext dbc = new DataBindingContext(); - protected ContainerEnvironmentVariableDialog(final Shell parentShell) { + public ContainerEnvironmentVariableDialog(final Shell parentShell) { super(parentShell); this.model = new EnvironmentVariableModel(); } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerLinkDialog.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerLinkDialog.java index 8a9e2e3526..08fe996552 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerLinkDialog.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerLinkDialog.java @@ -56,7 +56,7 @@ public class ContainerLinkDialog extends Dialog { private final DataBindingContext dbc = new DataBindingContext(); - protected ContainerLinkDialog(final Shell shell, + public ContainerLinkDialog(final Shell shell, final IDockerConnection connection) { super(shell); this.connection = connection; diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerPortDialog.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerPortDialog.java index 01acccdf79..85009b59e6 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerPortDialog.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ContainerPortDialog.java @@ -44,7 +44,7 @@ public class ContainerPortDialog extends Dialog { private final DataBindingContext dbc = new DataBindingContext(); - protected ContainerPortDialog(final Shell parentShell) { + public ContainerPortDialog(final Shell parentShell) { super(parentShell); this.model = new ContainerPortDialogModel(); } diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/DataVolumeModel.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/DataVolumeModel.java index 9cc4a14021..57e27530d9 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/DataVolumeModel.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/DataVolumeModel.java @@ -22,6 +22,8 @@ import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageRunResourceVolumes public class DataVolumeModel extends BaseDatabindingModel implements Comparable<DataVolumeModel> { + private static final String SEPARATOR = ":"; //$NON-NLS-1$ + public static final String CONTAINER_PATH = "containerPath"; //$NON-NLS-1$ public static final String MOUNT_TYPE = "mountType"; //$NON-NLS-1$ @@ -34,6 +36,8 @@ public class DataVolumeModel extends BaseDatabindingModel public static final String CONTAINER_MOUNT = "containerMount"; //$NON-NLS-1$ + public static final String SELECTED = "selected"; //$NON-NLS-1$ + private final String id = UUID.randomUUID().toString(); private String containerPath; @@ -48,6 +52,8 @@ public class DataVolumeModel extends BaseDatabindingModel private boolean readOnly = false; + private boolean selected; + public DataVolumeModel() { } @@ -76,6 +82,35 @@ public class DataVolumeModel extends BaseDatabindingModel } } + /** + * Create a DataVolumeModel from a toString() output. + * + * @param fromString + * @return DataVolumeModel + */ + public static DataVolumeModel createDataVolumeModel( + final String fromString) { + final DataVolumeModel model = new DataVolumeModel(); + final String[] items = fromString.split(SEPARATOR); // $NON-NLS-1$ + model.containerPath = items[0]; + model.mountType = MountType.valueOf(items[1]); + switch (model.mountType) { + case CONTAINER: + model.setContainerMount(items[2]); + model.setSelected(Boolean.valueOf(items[3])); + break; + case HOST_FILE_SYSTEM: + model.setHostPathMount(items[2]); + model.setReadOnly(Boolean.valueOf(items[3])); + model.setSelected(Boolean.valueOf(items[4])); + break; + case NONE: + model.setSelected(Boolean.valueOf(items[2])); + break; + } + return model; + } + public String getContainerPath() { return this.containerPath; } @@ -145,11 +180,40 @@ public class DataVolumeModel extends BaseDatabindingModel } } + public boolean getSelected() { + return selected; + } + + public void setSelected(final boolean selected) { + firePropertyChange(SELECTED, this.selected, this.selected = selected); + } + @Override public int compareTo(final DataVolumeModel other) { return this.getContainerPath().compareTo(other.getContainerPath()); } + // FIXME we should have a dedicated method to serialize the bean + @Override + public String toString() { + final StringBuffer buffer = new StringBuffer(); + buffer.append( + this.containerPath + SEPARATOR + getMountType() + SEPARATOR); + switch (getMountType()) { + case CONTAINER: + buffer.append(getContainerMount()); + break; + case HOST_FILE_SYSTEM: + buffer.append(getHostPathMount() + SEPARATOR); // $NON-NLS-1$ + buffer.append(isReadOnly()); + break; + case NONE: + break; + } + buffer.append(SEPARATOR).append(this.selected); + return buffer.toString(); + } + @Override public int hashCode() { final int prime = 31; diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/EnvironmentVariableModel.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/EnvironmentVariableModel.java index 4a354f7296..22a922479e 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/EnvironmentVariableModel.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/EnvironmentVariableModel.java @@ -44,6 +44,12 @@ public class EnvironmentVariableModel extends BaseDatabindingModel { this.value = variable.getValue(); } + public static EnvironmentVariableModel createEnvironmentVariableModel( + String fromString) { + String[] s = fromString.split("="); //$NON-NLS-1$ + return new EnvironmentVariableModel(s[0], s[1]); + } + public String getName() { return name; } @@ -61,6 +67,11 @@ public class EnvironmentVariableModel extends BaseDatabindingModel { } @Override + public String toString() { + return name + "=" + value; //$NON-NLS-1$ + } + + @Override public int hashCode() { final int prime = 31; int result = 1; diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunResourceVolumesVariablesModel.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunResourceVolumesVariablesModel.java index cd61b0847f..24aeb9154f 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunResourceVolumesVariablesModel.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunResourceVolumesVariablesModel.java @@ -141,8 +141,17 @@ public class ImageRunResourceVolumesVariablesModel public void setEnvironmentVariables( final WritableList environmentVariables) { + firePropertyChange(ENVIRONMENT_VARIABLES, this.environmentVariables, + this.environmentVariables = environmentVariables); + } + + public void addEnvironmentVariable( + final EnvironmentVariableModel variable) { + this.environmentVariables.add(variable); + } + + public void removeEnvironmentVariables() { this.environmentVariables.clear(); - this.environmentVariables.addAll(environmentVariables); } public void removeEnvironmentVariable( diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunSelectionModel.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunSelectionModel.java index 173dd2a48a..69c2fb50b1 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunSelectionModel.java +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageRunSelectionModel.java @@ -13,7 +13,6 @@ package org.eclipse.linuxtools.internal.docker.ui.wizards; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -21,6 +20,7 @@ import java.util.UUID; import org.eclipse.core.databinding.observable.list.WritableList; import org.eclipse.core.runtime.Assert; +import org.eclipse.linuxtools.docker.core.DockerConnectionManager; import org.eclipse.linuxtools.docker.core.IDockerConnection; import org.eclipse.linuxtools.docker.core.IDockerImage; import org.eclipse.linuxtools.internal.docker.ui.databinding.BaseDatabindingModel; @@ -33,6 +33,10 @@ import org.eclipse.linuxtools.internal.docker.ui.databinding.BaseDatabindingMode */ public class ImageRunSelectionModel extends BaseDatabindingModel { + public static final String CONNECTION_NAMES = "connectionNames"; //$NON-NLS-1$ + + public static final String SELECTED_CONNECTION_NAME = "selectedConnectionName"; //$NON-NLS-1$ + public static final String SELECTED_IMAGE_NAME = "selectedImageName"; //$NON-NLS-1$ public static final String SELECTED_IMAGE = "selectedImage"; //$NON-NLS-1$ @@ -61,7 +65,11 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { public static final String REMOVE_WHEN_EXITS = "removeWhenExits"; //$NON-NLS-1$ - private final IDockerConnection selectedConnection; + private String selectedConnectionName; + + private List<String> connectionNames; + + private Map<String, IDockerConnection> connections; private String selectedImageName; @@ -79,11 +87,11 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { private boolean publishAllPorts = true; - private WritableList exposedPorts = new WritableList(); + private final WritableList exposedPorts = new WritableList(); - private Set<ExposedPortModel> selectedPorts = new HashSet<>(); + private Set<ExposedPortModel> selectedPorts; - private WritableList links = new WritableList(); + private final WritableList links = new WritableList(); private boolean interactiveMode = false; @@ -93,20 +101,34 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { public ImageRunSelectionModel( final IDockerConnection selectedConnection) { - this.selectedConnection = selectedConnection; + refreshConnectionNames(); + setSelectedConnectionName(selectedConnection.getName()); refreshImageNames(); } + public void refreshConnectionNames() { + this.connectionNames = new ArrayList<>(); + this.connections = new HashMap<>(); + for (IDockerConnection connection : DockerConnectionManager + .getInstance().getConnections()) { + String name = connection.getName(); + connections.put(name, connection); + connectionNames.add(name); + } + } + public void refreshImageNames() { this.imageNames = new ArrayList<>(); this.images = new HashMap<>(); - for (IDockerImage image : this.selectedConnection.getImages()) { - if (!image.isIntermediateImage() && !image.isDangling()) { - for (String tag : image.tags()) { - final String imageName = ImageRunSelectionModel - .getImageName(image.repo(), tag); - images.put(imageName, image); - imageNames.add(imageName); + if (getSelectedConnection() != null) { + for (IDockerImage image : getSelectedConnection().getImages()) { + if (!image.isIntermediateImage() && !image.isDangling()) { + for (String tag : image.tags()) { + final String imageName = ImageRunSelectionModel + .getImageName(image.repo(), tag); + images.put(imageName, image); + imageNames.add(imageName); + } } } } @@ -134,6 +156,30 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { this.publishAllPorts = publishAllPorts); } + public List<String> getConnectionNames() { + return connectionNames; + } + + public void setConnectionNames(final List<String> connectionNames) { + firePropertyChange(CONNECTION_NAMES, this.connectionNames, + this.connectionNames = connectionNames); + } + + public String getSelectedConnectionName() { + return selectedConnectionName; + } + + public void setSelectedConnectionName(final String selectedConnectionName) { + firePropertyChange(SELECTED_CONNECTION_NAME, + this.selectedConnectionName, + this.selectedConnectionName = selectedConnectionName); + refreshImageNames(); + } + + public IDockerConnection getSelectedConnection() { + return this.connections.get(selectedConnectionName); + } + public List<String> getImageNames() { return imageNames; } @@ -143,10 +189,6 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { this.imageNames = imageNames); } - public IDockerConnection getSelectedConnection() { - return selectedConnection; - } - public String getSelectedImageName() { return selectedImageName; } @@ -238,8 +280,22 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { this.exposedPorts.addAll(ports); } + public void removeExposedPorts() { + this.exposedPorts.clear(); + } + + public void addExposedPort(final ExposedPortModel exposedPort) { + if (!this.exposedPorts.contains(exposedPort)) { + this.exposedPorts.add(exposedPort); + } + } + + public void removeExposedPort(final ExposedPortModel exposedPort) { + this.exposedPorts.remove(exposedPort); + } + public Set<ExposedPortModel> getSelectedPorts() { - return selectedPorts; + return this.selectedPorts; } public void setSelectedPorts(final Set<ExposedPortModel> ports) { @@ -253,7 +309,11 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { public void addLink(final String containerName, final String containerAlias) { - links.add(new ContainerLinkModel(containerName, containerAlias)); + addLink(new ContainerLinkModel(containerName, containerAlias)); + } + + public void addLink(final ContainerLinkModel containerLink) { + links.add(containerLink); } public void addLink(final int index, final String containerName, @@ -265,8 +325,13 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { links.remove(link); } + public void removeLinks() { + this.links.clear(); + } + public void setLinks(final WritableList links) { - firePropertyChange(LINKS, this.links, this.links = links); + this.links.clear(); + this.links.addAll(links); } public static String getImageName(final String repo, final String tag) { @@ -303,6 +368,8 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { public static class ExposedPortModel extends BaseDatabindingModel implements Comparable<ExposedPortModel> { + private static final String SEPARATOR = ":"; //$NON-NLS-1$ + public static final String SELECTED = "selected"; //$NON-NLS-1$ public static final String CONTAINER_PORT = "containerPort"; //$NON-NLS-1$ @@ -344,12 +411,26 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { this.hostAddress = hostAddress; } + /** + * Create an ExposedPortModel from its toString output + * + * @param fromString + * @return ExposedPortModel + */ + static public ExposedPortModel createPortModel(String fromString) { + String[] s = fromString.split(SEPARATOR); + ExposedPortModel model = new ExposedPortModel(s[0], s[1], s[2], + s[3]); + model.selected = Boolean.valueOf(s[4]); + return model; + } + public String getContainerPort() { return containerPort; } public void setContainerPort(final String containerPort) { - firePropertyChange(SELECTED, this.containerPort, + firePropertyChange(CONTAINER_PORT, this.containerPort, this.containerPort = containerPort); } @@ -358,7 +439,7 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { } public void setPortType(final String type) { - firePropertyChange(SELECTED, this.portType, this.portType = type); + firePropertyChange(PORT_TYPE, this.portType, this.portType = type); } public boolean getSelected() { @@ -418,9 +499,21 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { return this.containerPort.compareTo(other.containerPort); } + // FIXME we should have a dedicated method to serialize the bean + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(containerPort + SEPARATOR + portType + + SEPARATOR + hostAddress + SEPARATOR + hostPort + + SEPARATOR + selected); + return buffer.toString(); + } + } - public class ContainerLinkModel extends BaseDatabindingModel { + public static class ContainerLinkModel extends BaseDatabindingModel { + + private static final String CONTAINER_SEPARATOR = ":"; //$NON-NLS-1$ public static final String CONTAINER_NAME = "containerName"; //$NON-NLS-1$ @@ -442,6 +535,12 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { this.containerAlias = alias; } + public static ContainerLinkModel createContainerLinkModel( + final String fromString) { + String[] s = fromString.split(CONTAINER_SEPARATOR); + return new ContainerLinkModel(s[0], s[1]); + } + public String getContainerName() { return containerName; } @@ -460,6 +559,11 @@ public class ImageRunSelectionModel extends BaseDatabindingModel { } @Override + public String toString() { + return containerName + CONTAINER_SEPARATOR + containerAlias; + } + + @Override public int hashCode() { final int prime = 31; int result = 1; diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties index 6e69e92a97..4e68b667e6 100644 --- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties +++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties @@ -65,6 +65,7 @@ NetworkDisabled.label=Network Disabled Privileged.label=Privileged PublishAll.label=Publish All Ports NetworkMode.label=Network Mode +Connection.label=Connection: Name.label=Name: Author.label=Author: |