/*
* Copyright (c) 2015 the original author or authors.
* 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:
* Etienne Studer & Donát Csikós (Gradle Inc.) - initial API and implementation and initial documentation
*/
package org.eclipse.buildship.ui.wizard.project;
import java.util.List;
import com.gradleware.tooling.toolingutils.binding.Property;
import com.gradleware.tooling.toolingutils.binding.ValidationListener;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.PlatformUI;
import org.eclipse.buildship.core.projectimport.ProjectImportConfiguration;
import org.eclipse.buildship.ui.util.font.FontUtils;
import org.eclipse.buildship.ui.util.widget.UiBuilder;
/**
* Common base class for all pages in the {@link ProjectImportWizard}.
*/
public abstract class AbstractWizardPage extends WizardPage {
private final ProjectImportConfiguration configuration;
private final List<Property<?>> observedProperties;
private final String defaultMessage;
private final Font defaultFont;
private final UiBuilder.UiBuilderFactory builderFactory;
/**
* Constructor setting up the main messages and the validation facility for this wizard page.
*
* @param name the name of the page
* @param title the page title
* @param defaultMessage the default message to show when there is no validation error
* @param configuration the data model of the wizard
* @param observedProperties the subset of the properties from the data model that are managed
* on this page
*/
protected AbstractWizardPage(String name, String title, String defaultMessage, ProjectImportConfiguration configuration, final List<Property<?>> observedProperties) {
super(name);
this.configuration = configuration;
this.observedProperties = observedProperties;
this.defaultMessage = defaultMessage;
// set the basic message and the attached image
setTitle(title);
setMessage(defaultMessage);
setImageDescriptor(ImageDescriptor.createFromFile(GradleProjectWizardPage.class, "/icons/full/wizban/wizard.png")); //$NON-NLS-1$
// set up the UI builder
this.defaultFont = FontUtils.getDefaultDialogFont();
this.builderFactory = new UiBuilder.UiBuilderFactory(this.defaultFont);
// create a listener that updates the state and the message if an observed property in the
// model changes
ValidationListener listener = new ValidationListener() {
@Override
public void validationTriggered(Property<?> source, Optional<String> validationErrorMessage) {
// if the modified property is invalid, show its error message, otherwise check if
// any of the other properties of this page is invalid and if so, display the first
// found error message
if (validationErrorMessage.isPresent()) {
setMessage(validationErrorMessage.get(), IMessageProvider.ERROR);
} else {
Optional<String> otherErrorMessage = validateAllObservedProperties();
if (!otherErrorMessage.isPresent()) {
setMessage(AbstractWizardPage.this.defaultMessage);
} else {
setMessage(otherErrorMessage.get(), IMessageProvider.ERROR);
}
}
// we set the page to completed if all its properties are valid
setPageComplete(isPageComplete());
}
private Optional<String> validateAllObservedProperties() {
for (Property<?> property : observedProperties) {
Optional<String> errorMessage = property.validate();
if (errorMessage.isPresent()) {
return errorMessage;
}
}
return Optional.absent();
}
};
// attach the listener to all of the observed properties
for (Property<?> property : observedProperties) {
property.addValidationListener(listener);
}
}
protected ProjectImportConfiguration getConfiguration() {
return this.configuration;
}
protected UiBuilder.UiBuilderFactory getUiBuilderFactory() {
return this.builderFactory;
}
@Override
public final void createControl(Composite parent) {
// align dialog units to the current resolution
initializeDialogUnits(parent);
// create the container control
Composite pageControl = createWizardPageContent(parent);
// assign the created control to the wizard page
setControl(pageControl);
}
private Composite createWizardPageContent(Composite parent) {
// create a scrollable root to handle resizing
ScrolledComposite externalRoot = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
externalRoot.setExpandHorizontal(true);
externalRoot.setExpandVertical(true);
externalRoot.setMinSize(new Point(230, 380));
// add the controls inside the root composite
Composite container = new Composite(externalRoot, SWT.NONE);
createWidgets(container);
// add context information to the bottom of the page if the page defines it
String contextInformation = Strings.emptyToNull(getPageContextInformation());
if (contextInformation != null) {
createWidgetsForContextInformation(container, contextInformation);
}
// also compute the size of the container, otherwise the ScrolledComposite's content is not
// rendered properly
Point containerSize = container.computeSize(SWT.DEFAULT, SWT.DEFAULT);
container.setSize(containerSize);
// set the root's content and return it
externalRoot.setContent(container);
return externalRoot;
}
/**
* Populates the widgets in the wizard page.
*/
protected abstract void createWidgets(Composite root);
private void createWidgetsForContextInformation(Composite root, String contextInformation) {
// create a container box occupying all horizontal space and has a 1-column row layout and a
// 30 pixel margin to not stretch the separator widgets to the edge of the wizard page
Composite contextInformationContainer = new Composite(root, SWT.NONE);
GridLayout contextInformationContainerLayout = new GridLayout(1, false);
contextInformationContainerLayout.marginLeft = contextInformationContainerLayout.marginRight = contextInformationContainerLayout.marginTop = 30;
contextInformationContainerLayout.verticalSpacing = 15;
contextInformationContainer.setLayout(contextInformationContainerLayout);
contextInformationContainer.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1));
// separator widget
Label separator = new Label(contextInformationContainer, SWT.HORIZONTAL | SWT.SEPARATOR);
separator.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
// internal container for flexible resize
Composite textContainer = new Composite(contextInformationContainer, SWT.NONE);
textContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
GridLayout textContainerLayout = new GridLayout(1, false);
textContainerLayout.marginLeft = textContainerLayout.marginRight = 50;
textContainer.setLayout(textContainerLayout);
// text widget aligned to the center having 400 pixels allocated for each line of content
StyledText contextInformationText = new StyledText(textContainer, SWT.WRAP | SWT.MULTI | SWT.CENTER);
contextInformationText.setText(contextInformation);
contextInformationText.setBackground(contextInformationText.getParent().getBackground());
contextInformationText.setEnabled(false);
contextInformationText.setEditable(false);
GridData contextInformationTextLayoutData = new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1);
contextInformationTextLayoutData.widthHint = 400;
contextInformationText.setLayoutData(contextInformationTextLayoutData);
}
/**
* Returns text to display under the widgets. If {@code null} or empty then nothing is displayed.
*
* @return explanation text for for the wizard page
*/
protected abstract String getPageContextInformation();
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
// every time the page becomes visible, set the proper help context, this is required since
// the user could navigate back to the initial Eclipse import page which sets another help
// context
if (visible) {
if (getWizard() instanceof HelpContextIdProvider) {
String helpContextId = ((HelpContextIdProvider) getWizard()).getHelpContextId();
PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), helpContextId);
}
}
}
@Override
public boolean isPageComplete() {
for (Property<?> property : this.observedProperties) {
if (!property.isValid()) {
return false;
}
}
return true;
}
@Override
public void dispose() {
this.defaultFont.dispose();
super.dispose();
}
}