Java tutorial
/******************************************************************************* * 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.importapp; 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.MultiValidator; import org.eclipse.core.databinding.validation.ValidationStatus; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport; import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.wizard.IWizard; 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.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.DirectoryDialog; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.jboss.tools.common.ui.databinding.InvertingBooleanConverter; import org.jboss.tools.common.ui.databinding.ValueBindingBuilder; import org.jboss.tools.openshift.common.core.utils.FileUtils; import org.jboss.tools.openshift.internal.common.ui.utils.UIUtils; import org.jboss.tools.openshift.internal.common.ui.wizard.AbstractOpenShiftWizardPage; /** * @author Andre Dietisheim * @author Rob Stryker * @author Xavier Coulon * */ public class GitCloningWizardPage extends AbstractOpenShiftWizardPage { private IGitCloningPageModel model; private Button useDefaultRepoPathButton; private Button skipCloneOnlyImportButton; private RepoPathValidationStatusProvider repoPathValidator; public GitCloningWizardPage(IWizard wizard, IGitCloningPageModel model) { super(getTitle(model), "Configure the cloning settings by specifying the clone destination", "Cloning settings", wizard); this.model = model; } private static String getTitle(IGitCloningPageModel model) { String name = (model == null) ? null : model.getApplicationName(); return (name == null) ? "Import an existing OpenShift application" : "Import the '" + name + "' OpenShift application"; } @Override protected void doCreateControls(Composite parent, DataBindingContext dbc) { GridLayoutFactory.fillDefaults().applyTo(parent); Composite cloneGroup = createCloneGroup(parent, dbc); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).applyTo(cloneGroup); Composite filler = new Composite(parent, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(filler); } private Composite createCloneGroup(Composite parent, DataBindingContext dbc) { Group cloneGroup = new Group(parent, SWT.NONE); cloneGroup.setText("Cloning settings"); cloneGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); GridLayoutFactory.fillDefaults().numColumns(3).equalWidth(false).margins(10, 10).applyTo(cloneGroup); Composite composite = new Composite(cloneGroup, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(composite); GridLayoutFactory.fillDefaults().numColumns(3).margins(15, 15).applyTo(composite); // Repo Path Management useDefaultRepoPathButton = new Button(composite, SWT.CHECK); useDefaultRepoPathButton.setText("Use default clone destination"); useDefaultRepoPathButton.setToolTipText("Uncheck if you want to use a custom location to clone to"); GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).span(3, 1).applyTo(useDefaultRepoPathButton); Label labelForRepoPath = new Label(composite, SWT.NONE); labelForRepoPath.setText("Git Clone Location:"); GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).grab(false, false).indent(10, 0) .applyTo(labelForRepoPath); final Text repoPathText = new Text(composite, SWT.BORDER); GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).align(SWT.FILL, SWT.CENTER).grab(true, false) .applyTo(repoPathText); final IObservableValue repoPathObservable = WidgetProperties.text(SWT.Modify).observe(repoPathText); final IObservableValue repoPathModelObservable = BeanProperties .value(IGitCloningPageModel.PROPERTY_REPOSITORY_PATH).observe(model); ValueBindingBuilder.bind(repoPathObservable).to(repoPathModelObservable).in(dbc); Button browseRepoPathButton = new Button(composite, SWT.PUSH); browseRepoPathButton.setText("Browse..."); GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).hint(100, SWT.DEFAULT) .applyTo(browseRepoPathButton); browseRepoPathButton.addSelectionListener(onRepoPath()); final IObservableValue isDefaultRepoObservable = WidgetProperties.selection() .observe(useDefaultRepoPathButton); final IObservableValue useDefaultRepoModelObservable = BeanProperties .value(IGitCloningPageModel.PROPERTY_USE_DEFAULT_REPOSITORY_PATH).observe(model); ValueBindingBuilder.bind(isDefaultRepoObservable).to(useDefaultRepoModelObservable).in(dbc); ValueBindingBuilder.bind(WidgetProperties.enabled().observe(repoPathText)) .notUpdating(useDefaultRepoModelObservable).converting(new InvertingBooleanConverter()).in(dbc); ValueBindingBuilder.bind(WidgetProperties.enabled().observe(browseRepoPathButton)) .notUpdating(useDefaultRepoModelObservable).converting(new InvertingBooleanConverter()).in(dbc); // move focus to the project location text control when not choosing the // 'Use default location' option. UIUtils.focusOnSelection(useDefaultRepoPathButton, repoPathText); // Skip clone skipCloneOnlyImportButton = new Button(composite, SWT.CHECK); skipCloneOnlyImportButton.setSelection(false); skipCloneOnlyImportButton.setText("Reuse existing repository"); GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).span(3, 1).applyTo(skipCloneOnlyImportButton); final IObservableValue skipCloneObservable = WidgetProperties.selection() .observe(skipCloneOnlyImportButton); final IObservableValue skipCloneModelObservable = BeanProperties .value(IGitCloningPageModel.PROPERTY_SKIP_CLONE_ONLY_IMPORT).observe(model); skipCloneOnlyImportButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { model.setSkipClone(skipCloneOnlyImportButton.getSelection()); } }); IObservableValue projectNameObservable = BeanProperties.value(IGitCloningPageModel.PROPERTY_PROJECT_NAME) .observe(model); this.repoPathValidator = new RepoPathValidationStatusProvider(repoPathObservable, projectNameObservable, skipCloneObservable); dbc.addValidationStatusProvider(repoPathValidator); ControlDecorationSupport.create(repoPathValidator, SWT.LEFT | SWT.TOP); return cloneGroup; } private SelectionListener onRepoPath() { return new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { DirectoryDialog dialog = new DirectoryDialog(getShell()); dialog.setText("Git clone location"); dialog.setMessage("Choose the location for git clone..."); dialog.setFilterPath(model.getRepositoryPath()); String repositoryPath = dialog.open(); if (repositoryPath != null) { model.setRepositoryPath(repositoryPath); } } }; } @Override protected void onPageActivated(DataBindingContext dbc) { repoPathValidator.forceRevalidate(); } /** * A multivalidator for the repo path. Validates the repo path on behalf of * the selection to use the default repo path and the repo path value. */ class RepoPathValidationStatusProvider extends MultiValidator { private final IObservableValue repoPathObservable; private final IObservableValue projectNameObservable; private final IObservableValue skipCloneObservable; public RepoPathValidationStatusProvider(IObservableValue repoPathObservable, IObservableValue projectNameObservable, IObservableValue skipCloneObservable) { this.repoPathObservable = repoPathObservable; this.projectNameObservable = projectNameObservable; this.skipCloneObservable = skipCloneObservable; } @Override protected IStatus validate() { final String repoPath = (String) repoPathObservable.getValue(); final String projectName = (String) projectNameObservable.getValue(); final Boolean skipClone = (Boolean) skipCloneObservable.getValue(); final IPath repoResourcePath = new Path(repoPath); if (repoResourcePath.isEmpty() || !repoResourcePath.isAbsolute()) { return ValidationStatus.cancel("You need to provide an absolute path that we'll clone to."); } if (!FileUtils.canWrite(repoResourcePath.toOSString())) { return ValidationStatus .error(NLS.bind("The location {0} is not writeable.", repoResourcePath.toOSString())); } final IPath projectPath = projectName != null ? repoResourcePath.append(new Path(projectName)) : null; if (skipClone) { if (projectPath == null || !projectPath.toFile().exists()) { return ValidationStatus.error(NLS.bind( "The location \"{0}\" does not contain a folder named \"{1}\"\n" + "Please clone the repository or browse to a location containing the repository.", repoResourcePath.toOSString(), projectName)); } } else { if (projectPath != null && projectPath.toFile().exists()) { skipCloneOnlyImportButton.setEnabled(true); skipCloneOnlyImportButton.setVisible(true); return ValidationStatus.error(NLS.bind( "The location \"{0}\" already contains a folder named \"{1}\"\n" + "Please choose a different destination, or select 'Reuse existing repository'.", repoResourcePath.toOSString(), projectName)); } else { skipCloneOnlyImportButton.setEnabled(false); skipCloneOnlyImportButton.setVisible(false); } } return ValidationStatus.ok(); } public void forceRevalidate() { revalidate(); } } @Override public void setVisible(boolean visible) { if (visible) { setTitle(getTitle(model)); } super.setVisible(visible); } }