org.jboss.tools.openshift.internal.ui.wizard.deployimage.DeployImagePage.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.openshift.internal.ui.wizard.deployimage.DeployImagePage.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is 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, Inc. - initial API and implementation
 ******************************************************************************/
package org.jboss.tools.openshift.internal.ui.wizard.deployimage;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.MultiValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.internal.databinding.conversion.ObjectToStringConverter;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.ViewerProperties;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.PageChangingEvent;
import org.eclipse.jface.fieldassist.ContentProposal;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.linuxtools.docker.core.AbstractRegistry;
import org.eclipse.linuxtools.docker.core.IDockerConnection;
import org.eclipse.linuxtools.docker.core.IDockerImage;
import org.eclipse.linuxtools.docker.ui.wizards.ImageSearch;
import org.eclipse.linuxtools.internal.docker.core.RegistryInfo;
import org.eclipse.linuxtools.internal.docker.ui.wizards.NewDockerConnection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.progress.UIJob;
import org.jboss.tools.common.ui.WizardUtils;
import org.jboss.tools.common.ui.databinding.ParametrizableWizardPageSupport;
import org.jboss.tools.common.ui.databinding.ValueBindingBuilder;
import org.jboss.tools.openshift.common.core.connection.IConnection;
import org.jboss.tools.openshift.common.core.utils.UrlUtils;
import org.jboss.tools.openshift.core.connection.Connection;
import org.jboss.tools.openshift.internal.common.core.job.AbstractDelegatingMonitorJob;
import org.jboss.tools.openshift.internal.common.ui.connection.ConnectionColumLabelProvider;
import org.jboss.tools.openshift.internal.common.ui.databinding.IsNotNull2BooleanConverter;
import org.jboss.tools.openshift.internal.common.ui.databinding.RequiredControlDecorationUpdater;
import org.jboss.tools.openshift.internal.common.ui.databinding.TrimmingStringConverter;
import org.jboss.tools.openshift.internal.common.ui.job.UIUpdatingJob;
import org.jboss.tools.openshift.internal.common.ui.utils.UIUtils;
import org.jboss.tools.openshift.internal.common.ui.wizard.AbstractOpenShiftWizardPage;
import org.jboss.tools.openshift.internal.common.ui.wizard.OkCancelButtonWizardDialog;
import org.jboss.tools.openshift.internal.ui.OpenShiftUIActivator;
import org.jboss.tools.openshift.internal.ui.comparators.ProjectViewerComparator;
import org.jboss.tools.openshift.internal.ui.explorer.OpenShiftExplorerLabelProvider;
import org.jboss.tools.openshift.internal.ui.treeitem.ObservableTreeItem2ModelConverter;
import org.jboss.tools.openshift.internal.ui.treeitem.ObservableTreeItemLabelProvider;
import org.jboss.tools.openshift.internal.ui.validator.DockerImageValidator;
import org.jboss.tools.openshift.internal.ui.wizard.common.ResourceNameControl;
import org.jboss.tools.openshift.internal.ui.wizard.project.NewProjectWizard;

import com.openshift.restclient.model.IProject;

/**
 * Page to (mostly) edit the config items for a page
 * 
 * @author jeff.cantrill
 */
public class DeployImagePage extends AbstractOpenShiftWizardPage {

    private static final String MISSING_DOCKER_CONNECTION_MSG = "You must select a Docker connection.";

    static String DEPLOY_IMAGE_PAGE_NAME = "Deployment Config Settings Page";

    private static final String PAGE_DESCRIPTION = "This page allows you to choose an image and the name to be used for the deployed resources.";

    private static final int NUM_COLUMS = 4;

    private final IDeployImagePageModel model;

    ContentProposalAdapter imageNameProposalAdapter;

    protected DeployImagePage(IWizard wizard, IDeployImagePageModel model) {
        super("Deploy an Image", PAGE_DESCRIPTION, DEPLOY_IMAGE_PAGE_NAME, wizard);
        this.model = model;
    }

    @Override
    protected void setupWizardPageSupport(DataBindingContext dbc) {
        ParametrizableWizardPageSupport.create(IStatus.ERROR | IStatus.CANCEL, this, dbc);
    }

    /**
     * Callback that gets called when this page is going to be deactivated. This
     * is the chance to do a one-time remote call to the selected Docker daemon
     * to check if an image with the given name exists in the local cache or in
     * the remote registry (Docker Hub). This kind of validation is a
     * long-running process, so it should not be performed during the field
     * validation.
     * 
     * @param progress
     *            the direction that the wizard is moving: backwards/forwards
     * @param event
     *            the page changing event that may be use to veto the change
     * @param dbc
     *            the current data binding context
     */
    @Override
    protected void onPageWillGetDeactivated(final Direction progress, final PageChangingEvent event,
            final DataBindingContext dbc) {
        if (imageNameProposalAdapter != null) {
            imageNameProposalAdapter.setEnabled(false);
        }
        if (progress == Direction.BACKWARDS) {
            //Do not block return to change connection.
            return;
        }

        /**
         * Inner class to perform the image search in the selected Docker daemon cache or on the remote registry. 
         */
        class ImageValidatorJob extends Job {

            public ImageValidatorJob(String name) {
                super(name);
            }

            @Override
            protected IStatus run(IProgressMonitor monitor) {
                if (model.initializeContainerInfo()) {
                    return Status.OK_STATUS;
                }
                return Status.CANCEL_STATUS;
            }
        }

        final ImageValidatorJob imageValidator = new ImageValidatorJob("Looking-up the selected Docker image...");
        try {
            final IStatus validatorJobStatus = WizardUtils.runInWizard(imageValidator, getContainer(),
                    getDataBindingContext());
            if (!validatorJobStatus.isOK()) {
                MessageDialog.openError(getShell(), "Error",
                        NLS.bind("No Docker image named {0} could be found.", model.getImageName()));
                event.doit = false;
            }
        } catch (InvocationTargetException | InterruptedException e) {
            final String message = NLS.bind("Failed to look-up metadata for a Docker image named {0}.",
                    model.getImageName());
            MessageDialog.openError(getShell(), "Error", message);
            OpenShiftUIActivator.getDefault().getLogger().logError(message, e);
        }
    }

    @Override
    protected void onPageWillGetActivated(final Direction progress, final PageChangingEvent event,
            final DataBindingContext dbc) {
        if (imageNameProposalAdapter != null) {
            imageNameProposalAdapter.setEnabled(true);
        }
    }

    @Override
    protected void onPageActivated(DataBindingContext dbc) {
        loadResources(dbc);
    }

    private void loadResources(DataBindingContext dbc) {
        Job job = new AbstractDelegatingMonitorJob("Loading projects...") {

            @Override
            protected IStatus doRun(IProgressMonitor monitor) {
                try {
                    model.loadResources();
                    return Status.OK_STATUS;
                } catch (Exception e) {
                    return new Status(Status.ERROR, OpenShiftUIActivator.PLUGIN_ID,
                            NLS.bind("Unable to load the OpenShift projects from connection {0}.",
                                    model.getConnection()),
                            e);
                }
            }
        };
        try {
            WizardUtils.runInWizard(job, getContainer(), dbc);
        } catch (InvocationTargetException | InterruptedException e) {
            // swallowed on purpose
        }
    }

    @Override
    protected void doCreateControls(Composite parent, DataBindingContext dbc) {
        GridLayoutFactory.fillDefaults().numColumns(NUM_COLUMS).margins(10, 10).applyTo(parent);
        createOpenShiftConnectionControl(parent, dbc);
        createProjectControl(parent, dbc);
        createSeparator(parent);
        if (!model.originatedFromDockerExplorer()) {
            createDockerConnectionControl(parent, dbc);
        } else {
            createDockerConnectionInfoControl(parent, dbc);
        }
        createImageNameControls(parent, dbc);
        new ResourceNameControl() {
            @Override
            protected void layoutText(Text resourceNameText) {
                GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).span(NUM_COLUMS - 1, 1)
                        .applyTo(resourceNameText);
            }
        }.doCreateControl(parent, dbc, model);
        createSeparator(parent);
        createPushToRegistrySettings(parent, dbc);
    }

    private void createSeparator(Composite parent) {
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).grab(true, false).span(NUM_COLUMS, 1)
                .applyTo(new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL));
    }

    private SelectionAdapter onBrowseImage() {
        return new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                if (model.getDockerConnection() == null) {
                    MessageDialog.openError(getShell(), "A Docker connection must be selected",
                            MISSING_DOCKER_CONNECTION_MSG);
                    return;
                }
                final ListDockerImagesWizard wizard = new ListDockerImagesWizard(model.getDockerConnection(),
                        model.getImageName());
                final OkCancelButtonWizardDialog wizardDialog = new OkCancelButtonWizardDialog(getShell(), wizard);
                wizardDialog.setPageSize(500, 400);
                if (Window.OK == wizardDialog.open()) {
                    //this bypasses validation
                    model.setImageName(wizard.getSelectedImageName());
                }
            }
        };
    }

    private SelectionAdapter onSearchImage(final Text txtImage) {
        return new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                if (model.getDockerConnection() == null) {
                    MessageDialog.openError(getShell(), "A Docker connection must be selected",
                            MISSING_DOCKER_CONNECTION_MSG);
                    return;
                }
                // FIXME: may need to revisit the call to the constructor once https://bugs.eclipse.org/bugs/show_bug.cgi?id=495285 is addressed
                // there may be no need to to specify the registry info if we want to search on Docker Hub.
                ImageSearch wizard = new ImageSearch(model.getDockerConnection(), txtImage.getText(),
                        new RegistryInfo(AbstractRegistry.DOCKERHUB_REGISTRY, true));
                if (Window.OK == new OkCancelButtonWizardDialog(getShell(), wizard).open()) {
                    //this bypasses validation
                    model.setImageName(wizard.getSelectedImage(), true);
                }
            }
        };
    }

    private void createDockerConnectionControl(Composite parent, DataBindingContext dbc) {
        createDockerConnectionLabel(parent);

        StructuredViewer connectionViewer = new ComboViewer(parent);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).span(NUM_COLUMS - 2, 1)
                .applyTo(connectionViewer.getControl());

        connectionViewer.setContentProvider(new ObservableListContentProvider());
        connectionViewer.setLabelProvider(new ObservableTreeItemLabelProvider() {

            @Override
            public String getText(Object element) {
                return (element instanceof IDockerConnection)
                        ? dockerConnectionToString((IDockerConnection) element)
                        : "";
            }

        });
        connectionViewer
                .setInput(BeanProperties.list(IDeployImagePageModel.PROPERTY_DOCKER_CONNECTIONS).observe(model));

        IObservableValue<IDockerConnection> dockerConnectionObservable = BeanProperties
                .value(IDeployImagePageModel.PROPERTY_DOCKER_CONNECTION).observe(model);
        DockerConnectionStatusProvider validator = new DockerConnectionStatusProvider(dockerConnectionObservable);
        IObservableValue<?> selectedConnectionObservable = ViewerProperties.singleSelection()
                .observe(connectionViewer);
        Binding selectedConnectionBinding = ValueBindingBuilder.bind(selectedConnectionObservable)
                .converting(new ObservableTreeItem2ModelConverter(IDockerConnection.class))
                .validatingAfterConvert(validator)
                .to(BeanProperties.value(IDeployImagePageModel.PROPERTY_DOCKER_CONNECTION).observe(model)).in(dbc);
        ControlDecorationSupport.create(selectedConnectionBinding, SWT.LEFT | SWT.TOP, null,
                new RequiredControlDecorationUpdater(true));

        Button newDockerConnectionButton = new Button(parent, SWT.PUSH);
        newDockerConnectionButton.setText("New...");
        GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).applyTo(newDockerConnectionButton);
        UIUtils.setDefaultButtonWidth(newDockerConnectionButton);
        newDockerConnectionButton.addSelectionListener(onNewDockerConnectionClicked());

        dbc.addValidationStatusProvider(validator);
    }

    private String dockerConnectionToString(IDockerConnection conn) {
        return NLS.bind("{0} ({1})", conn.getName(), conn.getUri());
    }

    private Label createDockerConnectionLabel(Composite parent) {
        Label lblConnection = new Label(parent, SWT.NONE);
        lblConnection.setText("Docker Connection: ");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).applyTo(lblConnection);
        return lblConnection;
    }

    @SuppressWarnings("rawtypes")
    class DockerConnectionStatusProvider extends MultiValidator implements IValidator {
        IObservableValue dockerConnectionObservable;

        DockerConnectionStatusProvider(IObservableValue dockerConnectionObservable) {
            this.dockerConnectionObservable = dockerConnectionObservable;
        }

        @Override
        public IStatus validate(Object value) {
            if (value instanceof IDockerConnection) {
                return ValidationStatus.ok();
            }
            return ValidationStatus.cancel(MISSING_DOCKER_CONNECTION_MSG);
        }

        @Override
        protected IStatus validate() {
            return validate(dockerConnectionObservable.getValue());
        }
    }

    private void createDockerConnectionInfoControl(Composite parent, DataBindingContext dbc) {
        Label lblConnection = createDockerConnectionLabel(parent);
        final Text connectionText = new Text(parent, SWT.READ_ONLY | SWT.NO_FOCUS);
        connectionText.setBackground(lblConnection.getBackground());
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(NUM_COLUMS - 1, 1).grab(true, false)
                .applyTo(connectionText);
        final IObservableValue<String> connnectionTextObservable = WidgetProperties.text(SWT.None)
                .observe(connectionText);
        final IObservableValue<IDockerConnection> connnectionObservable = BeanProperties
                .value(IDeployImagePageModel.PROPERTY_DOCKER_CONNECTION).observe(model);
        ValueBindingBuilder.bind(connnectionTextObservable).notUpdatingParticipant().to(connnectionObservable)
                .converting(new ObjectToStringConverter(IDockerConnection.class) {
                    ConnectionColumLabelProvider labelProvider = new ConnectionColumLabelProvider();

                    @Override
                    public Object convert(Object source) {
                        return (source instanceof IDockerConnection)
                                ? dockerConnectionToString((IDockerConnection) source)
                                : "";
                    }
                }).in(dbc);
    }

    private void createOpenShiftConnectionControl(Composite parent, DataBindingContext dbc) {
        Label lblConnection = new Label(parent, SWT.NONE);
        lblConnection.setText("OpenShift Connection: ");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).applyTo(lblConnection);
        final Text connectionText = new Text(parent, SWT.READ_ONLY | SWT.NO_FOCUS);
        connectionText.setBackground(lblConnection.getBackground());
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(NUM_COLUMS - 1, 1).grab(true, false)
                .applyTo(connectionText);
        final IObservableValue<String> connnectionTextObservable = WidgetProperties.text(SWT.None)
                .observe(connectionText);
        final IObservableValue<IConnection> connnectionObservable = BeanProperties
                .value(IDeployImagePageModel.PROPERTY_CONNECTION).observe(model);
        ValueBindingBuilder.bind(connnectionTextObservable).notUpdatingParticipant().to(connnectionObservable)
                .converting(new ObjectToStringConverter(Connection.class) {
                    ConnectionColumLabelProvider labelProvider = new ConnectionColumLabelProvider();

                    @Override
                    public Object convert(Object source) {
                        return source == null ? "" : labelProvider.getText(source);
                    }
                }).in(dbc);
    }

    private void createProjectControl(Composite parent, DataBindingContext dbc) {
        Label lblProject = new Label(parent, SWT.NONE);
        lblProject.setText("OpenShift Project: ");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).applyTo(lblProject);

        StructuredViewer cmboProject = new ComboViewer(parent);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).hint(SWT.DEFAULT, 30)
                .span(NUM_COLUMS - 2, 1).applyTo(cmboProject.getControl());

        final OpenShiftExplorerLabelProvider labelProvider = new OpenShiftExplorerLabelProvider();
        cmboProject.setContentProvider(new ObservableListContentProvider());
        cmboProject.setLabelProvider(labelProvider);
        cmboProject.setInput(BeanProperties.list(IDeployImagePageModel.PROPERTY_PROJECTS).observe(model));
        ProjectViewerComparator comparator = new ProjectViewerComparator(labelProvider);
        cmboProject.setComparator(comparator);
        model.setProjectsComparator(comparator.asProjectComparator());

        IObservableValue<IProject> projectObservable = BeanProperties.value(IDeployImagePageModel.PROPERTY_PROJECT)
                .observe(model);
        ProjectStatusProvider validator = new ProjectStatusProvider(projectObservable);
        IObservableValue selectedProjectObservable = ViewerProperties.singleSelection().observe(cmboProject);
        Binding selectedProjectBinding = ValueBindingBuilder.bind(selectedProjectObservable)
                .converting(new ObservableTreeItem2ModelConverter(IProject.class)).validatingAfterConvert(validator)
                .to(projectObservable).in(dbc);
        ControlDecorationSupport.create(selectedProjectBinding, SWT.LEFT | SWT.TOP, null,
                new RequiredControlDecorationUpdater(true));

        Button newProjectButton = new Button(parent, SWT.PUSH);
        newProjectButton.setText("New...");
        GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).applyTo(newProjectButton);
        UIUtils.setDefaultButtonWidth(newProjectButton);
        newProjectButton.addSelectionListener(onNewProjectClicked());

        dbc.addValidationStatusProvider(validator);

        cmboProject.getControl().forceFocus();
    }

    @SuppressWarnings("rawtypes")
    class ProjectStatusProvider extends MultiValidator implements IValidator {
        IObservableValue projectObservable;

        ProjectStatusProvider(IObservableValue projectObservable) {
            this.projectObservable = projectObservable;
        }

        @Override
        public IStatus validate(Object value) {
            if (value instanceof IProject) {
                return ValidationStatus.ok();
            }
            return ValidationStatus.cancel("Please choose an OpenShift project.");
        }

        @Override
        protected IStatus validate() {
            return validate(projectObservable.getValue());
        }
    }

    private void createImageNameControls(final Composite parent, final DataBindingContext dbc) {
        //Image
        final Label imageNameLabel = new Label(parent, SWT.NONE);
        imageNameLabel.setText("Image Name: ");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).applyTo(imageNameLabel);
        final Text imageNameText = new Text(parent, SWT.BORDER);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).applyTo(imageNameText);
        final IObservableValue<String> imageNameTextObservable = WidgetProperties.text(SWT.Modify)
                .observeDelayed(500, imageNameText);
        final IObservableValue<String> imageNameObservable = BeanProperties
                .value(IDeployImagePageModel.PROPERTY_IMAGE_NAME).observe(model);
        Binding imageBinding = ValueBindingBuilder.bind(imageNameTextObservable)
                .converting(new TrimmingStringConverter()).validatingAfterConvert(new DockerImageValidator())
                .to(imageNameObservable).in(dbc);
        ControlDecorationSupport.create(imageBinding, SWT.LEFT | SWT.TOP, null,
                new RequiredControlDecorationUpdater(true));

        imageNameProposalAdapter = new ContentProposalAdapter(imageNameText,
                // override the text value before content assist was invoked and
                // move the cursor to the end of the selected value
                new TextContentAdapter() {
                    @Override
                    public void insertControlContents(Control control, String text, int cursorPosition) {
                        final Text imageNameText = (Text) control;
                        final Point selection = imageNameText.getSelection();
                        imageNameText.setText(text);
                        selection.x = text.length();
                        selection.y = selection.x;
                        imageNameText.setSelection(selection);
                    }
                }, getImageNameContentProposalProvider(imageNameText), null, null);

        // List local Docker images
        Button btnDockerBrowse = new Button(parent, SWT.NONE);
        btnDockerBrowse.setText("Browse...");
        btnDockerBrowse.setToolTipText("Look-up an image by browsing the Docker daemon");
        btnDockerBrowse.addSelectionListener(onBrowseImage());
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).applyTo(btnDockerBrowse);
        ValueBindingBuilder.bind(WidgetProperties.enabled().observe(btnDockerBrowse)).notUpdatingParticipant()
                .to(BeanProperties.value(IDeployImagePageModel.PROPERTY_DOCKER_CONNECTION).observe(model))
                .converting(new IsNotNull2BooleanConverter()).in(dbc);

        // search on Docker registry (Docker Hub)
        Button btnDockerSearch = new Button(parent, SWT.NONE);
        btnDockerSearch.setText("Search...");
        btnDockerSearch.setToolTipText("Search an image on the Docker registry");
        btnDockerSearch.addSelectionListener(onSearchImage(imageNameText));
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).applyTo(btnDockerSearch);
        ValueBindingBuilder.bind(WidgetProperties.enabled().observe(btnDockerSearch)).notUpdatingParticipant()
                .to(BeanProperties.value(IDeployImagePageModel.PROPERTY_DOCKER_CONNECTION).observe(model))
                .converting(new IsNotNull2BooleanConverter()).in(dbc);
    }

    @SuppressWarnings("unchecked")
    private void createPushToRegistrySettings(final Composite parent, final DataBindingContext dbc) {
        // checkbox
        final Button pushImageToRegistryButton = new Button(parent, SWT.CHECK);
        pushImageToRegistryButton.setText("Push Image to Registry");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(NUM_COLUMS, 1)
                .applyTo(pushImageToRegistryButton);
        final IObservableValue<Boolean> pushImageToRegistryButtonObservable = BeanProperties
                .value(IDeployImagePageModel.PROPERTY_PUSH_IMAGE_TO_REGISTRY).observe(model);
        ValueBindingBuilder.bind(WidgetProperties.selection().observe(pushImageToRegistryButton))
                .to(pushImageToRegistryButtonObservable).in(dbc);

        // registry location
        final Label registryLocationLabel = new Label(parent, SWT.NONE);
        registryLocationLabel.setText("Image Registry URL:");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).indent(30, 0)
                .applyTo(registryLocationLabel);
        final Text registryLocationText = new Text(parent, SWT.BORDER);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).span(NUM_COLUMS - 1, 1)
                .applyTo(registryLocationText);
        final IObservableValue<String> registryLocationObservable = BeanProperties
                .value(IDeployImagePageModel.PROPERTY_TARGET_REGISTRY_LOCATION).observe(model);
        ValueBindingBuilder.bind(WidgetProperties.text(SWT.Modify).observe(registryLocationText))
                .to(registryLocationObservable).in(dbc);
        ValueBindingBuilder.bind(WidgetProperties.enabled().observe(registryLocationText))
                .to(pushImageToRegistryButtonObservable).in(dbc);

        // username to authenticate on registry
        final Label registryUsernameLabel = new Label(parent, SWT.NONE);
        registryUsernameLabel.setText("Username:");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).indent(30, 0)
                .applyTo(registryUsernameLabel);
        final Text registryUsernameText = new Text(parent, SWT.BORDER);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).span(NUM_COLUMS - 1, 1)
                .applyTo(registryUsernameText);
        final IObservableValue<String> registryUsernameObservable = BeanProperties
                .value(IDeployImagePageModel.PROPERTY_TARGET_REGISTRY_USERNAME).observe(model);
        ValueBindingBuilder.bind(WidgetProperties.text(SWT.Modify).observe(registryUsernameText))
                .to(registryUsernameObservable).in(dbc);
        ValueBindingBuilder.bind(WidgetProperties.enabled().observe(registryUsernameText))
                .to(pushImageToRegistryButtonObservable).in(dbc);

        // password to authenticate on registry
        final Label registryPasswordLabel = new Label(parent, SWT.NONE);
        registryPasswordLabel.setText("Password:");
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).indent(30, 0)
                .applyTo(registryPasswordLabel);
        final Text registryPasswordText = new Text(parent, SWT.BORDER + SWT.PASSWORD);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).span(NUM_COLUMS - 1, 1)
                .applyTo(registryPasswordText);
        final IObservableValue<String> registryPasswordObservable = BeanProperties
                .value(IDeployImagePageModel.PROPERTY_TARGET_REGISTRY_PASSWORD).observe(model);
        ValueBindingBuilder.bind(WidgetProperties.text(SWT.Modify).observe(registryPasswordText))
                .to(registryPasswordObservable).in(dbc);
        ValueBindingBuilder.bind(WidgetProperties.enabled().observe(registryPasswordText))
                .to(pushImageToRegistryButtonObservable).in(dbc);

        // validation
        final PushImageToRegistryStatusProvider validator = new PushImageToRegistryStatusProvider(
                pushImageToRegistryButtonObservable, registryLocationObservable, registryUsernameObservable,
                registryPasswordObservable);
        dbc.addValidationStatusProvider(validator);

    }

    class PushImageToRegistryStatusProvider extends MultiValidator {

        private final IObservableValue<Boolean> pushImageToRegistryObservable;
        private final IObservableValue<String> targetRegistryLocationObservable;
        private final IObservableValue<String> targetRegistryUsernameObservable;
        private final IObservableValue<String> targetRegistryPasswordObservable;

        PushImageToRegistryStatusProvider(final IObservableValue<Boolean> pushImageToRegistryObservable,
                final IObservableValue<String> targetRegistryLocationObservable,
                final IObservableValue<String> targetRegistryUsernameObservable,
                final IObservableValue<String> targetRegistryPasswordObservable) {
            this.pushImageToRegistryObservable = pushImageToRegistryObservable;
            this.targetRegistryLocationObservable = targetRegistryLocationObservable;
            this.targetRegistryUsernameObservable = targetRegistryUsernameObservable;
            this.targetRegistryPasswordObservable = targetRegistryPasswordObservable;
        }

        @Override
        protected IStatus validate() {
            final boolean pushImageToRegistry = pushImageToRegistryObservable.getValue();
            final String targetRegistryLocation = targetRegistryLocationObservable.getValue();
            final String targetRegistryUsername = targetRegistryUsernameObservable.getValue();
            final String targetRegistryPassword = targetRegistryPasswordObservable.getValue();
            if (pushImageToRegistry) {
                if (targetRegistryLocation == null || targetRegistryLocation.isEmpty()) {
                    return ValidationStatus
                            .error("Please specify location of the Docker registry to push the image");
                } else if (!UrlUtils.hasScheme(targetRegistryLocation)) {
                    return ValidationStatus.error("Please provide a valid image registry (HTTP/S) URL.");
                }
                if (targetRegistryUsername == null || targetRegistryUsername.isEmpty()) {
                    return ValidationStatus.info(
                            "The username to authenticate to the target registry is missing. Authentication may fail.");
                }
                if (targetRegistryPassword == null || targetRegistryPassword.isEmpty()) {
                    return ValidationStatus.info(
                            "The password to authenticate to the target registry is missing. Authentication may fail.");
                }
            }
            return Status.OK_STATUS;
        }
    }

    /**
     * Creates an {@link IContentProposalProvider} to propose
     * {@link IDockerImage} names based on the current text.
     * 
     * @param items
     * @return
     */
    private IContentProposalProvider getImageNameContentProposalProvider(final Text imageNameText) {
        return new IContentProposalProvider() {

            @Override
            public IContentProposal[] getProposals(final String input, final int position) {
                return model.getImageNames().stream().filter(name -> name.contains(input))
                        .map(n -> new ContentProposal(n, n, null, position))
                        .toArray(size -> new IContentProposal[size]);
            }
        };
    }

    private SelectionAdapter onNewProjectClicked() {
        return new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                try {
                    // run in job to enforce busy cursor which doesnt work otherwise
                    WizardUtils.runInWizard(new UIJob("Opening projects wizard...") {

                        @Override
                        public IStatus runInUIThread(IProgressMonitor monitor) {
                            NewProjectWizard newProjectWizard = new NewProjectWizard(model.getConnection(),
                                    (List<IProject>) model.getProjects());
                            int result = new OkCancelButtonWizardDialog(getShell(), newProjectWizard).open();
                            // reload projects to reflect changes that happened in
                            // projects wizard
                            if (newProjectWizard.getProject() != null) {
                                model.addProject(newProjectWizard.getProject());
                            }
                            if (Dialog.OK == result) {
                                IProject selectedProject = newProjectWizard.getProject();
                                if (selectedProject != null) {
                                    model.setProject(selectedProject);
                                }
                            }
                            return Status.OK_STATUS;
                        }
                    }, getContainer(), getDataBindingContext());
                } catch (InvocationTargetException | InterruptedException ex) {
                    // swallow intentionnally
                }
            }
        };
    }

    private SelectionAdapter onNewDockerConnectionClicked() {
        return new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                try {
                    // run in job to enforce busy cursor which doesnt work otherwise
                    WizardUtils.runInWizard(new UIUpdatingJob("Opening new Docker connection wizard...") {

                        @Override
                        protected IStatus run(IProgressMonitor monitor) {
                            return Status.OK_STATUS;
                        }

                        @Override
                        protected IStatus updateUI(IProgressMonitor monitor) {
                            NewDockerConnection newDockerConnectionWizard = new NewDockerConnection();
                            int result = new OkCancelButtonWizardDialog(getShell(), newDockerConnectionWizard)
                                    .open();
                            // set docker connection to reflect changes that happened in
                            // docker connection wizard
                            if (Dialog.OK == result) {
                                IDockerConnection dockerConnection = newDockerConnectionWizard
                                        .getDockerConnection();
                                if (dockerConnection != null) {
                                    model.setDockerConnection(dockerConnection);
                                }
                            }
                            return Status.OK_STATUS;
                        }
                    }, getContainer(), getDatabindingContext());
                } catch (InvocationTargetException | InterruptedException ex) {
                    OpenShiftUIActivator.getDefault().getLogger().logError(ex);
                }
            }
        };
    }

}