Skip to content

Content of file SelectLocationPage.java

/*******************************************************************************
 * Copyright (c) 2011-2015 EclipseSource Muenchen GmbH and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 * Stefan Dirix - initial API and implementation
 ******************************************************************************/
package org.eclipse.emf.ecp.emf2web.ui.wizard;

import java.io.File;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.PojoProperties;
import org.eclipse.core.databinding.conversion.IConverter;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.ui.dialogs.WorkspaceResourceDialog;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecp.emf2web.controller.xtend.GenerationInfo;
import org.eclipse.emf.ecp.emf2web.ui.messages.Messages;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.databinding.wizard.WizardPageSupport;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;

/**
 * A page for a single generated file which's main purpose is to select a location for the file.
 *
 * @author Stefan Dirix
 *
 */
public class SelectLocationPage extends WizardPage {
	private DataBindingContext bindingContext;

	private final GenerationInfo generationInfo;
	private Text locationText;
	private Text generatedText;
	private Button btnWrap;
	private ControlDecoration requiredLocationDecoration;

	private boolean wasAlreadyVisible;

	/**
	 * Constructor.
	 *
	 * @param generationInfo The {@link GenerationInfo} for which this page is responsible.
	 */
	public SelectLocationPage(GenerationInfo generationInfo) {
		super("wizardPage"); //$NON-NLS-1$
		this.generationInfo = generationInfo;

		wasAlreadyVisible = false;

		setTitleAndDescription();
	}

	/**
	 * Sets title and description of this page according to the {@link GenerationInfo}.
	 */
	protected void setTitleAndDescription() {
		if (GenerationInfo.MODEL_TYPE.equals(generationInfo.getType())) {
			setTitle(Messages.getString("SelectLocationPage.Title_ModelType")); //$NON-NLS-1$
			setDescription(Messages.getString("SelectLocationPage.Description_ModelType")); //$NON-NLS-1$
		} else if (GenerationInfo.VIEW_TYPE.equals(generationInfo.getType())) {
			setTitle(Messages.getString("SelectLocationPage.Title_ViewType")); //$NON-NLS-1$
			setDescription(Messages.getString("SelectLocationPage.Description_ViewType")); //$NON-NLS-1$
		} else if (GenerationInfo.MODEL_AND_VIEW_TYPE.equals(generationInfo.getType())) {
			setTitle(Messages.getString("SelectLocationPage.Title_ModelAndViewType")); //$NON-NLS-1$
			setDescription(Messages.getString("SelectLocationPage.Description_ModelAndViewType")); //$NON-NLS-1$
		} else {
			setTitle(Messages.getString("SelectLocationPage.Title_OtherType") + generationInfo.getNameProposal()); //$NON-NLS-1$
			setDescription(Messages.getString("SelectLocationPage.Description_OtherType")); //$NON-NLS-1$
		}
	}

	/**
	 * Returns the linked {@link GenerationInfo}.
	 *
	 * @return The {@link GenerationInfo}.
	 */
	public GenerationInfo getGenerationInfo() {
		return generationInfo;
	}

	/**
	 * Returns the bindingContext of this page.
	 *
	 * @return The {@link DataBindingContext}.
	 */
	public DataBindingContext getBindingContext() {
		return bindingContext;
	}

	@Override
	public void createControl(Composite parent) {
		final Composite container = new Composite(parent, SWT.NULL);

		setControl(container);
		container.setLayout(new GridLayout(3, false));

		final Label lblLocation = new Label(container, SWT.NONE);
		lblLocation.setText(Messages.getString("SelectLocationPage.LocationLabel")); //$NON-NLS-1$
		new Label(container, SWT.NONE);
		new Label(container, SWT.NONE);

		locationText = new Text(container, SWT.BORDER);
		locationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));

		requiredLocationDecoration = new ControlDecoration(locationText, SWT.LEFT | SWT.TOP);
		final FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault()
			.getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
		requiredLocationDecoration.setImage(fieldDecoration.getImage());
		requiredLocationDecoration.setDescriptionText(Messages.getString("SelectLocationPage.RequiredDecorationText")); //$NON-NLS-1$
		requiredLocationDecoration.hide();

		final Button browseWorkspaceButton = new Button(container, SWT.NONE);
		browseWorkspaceButton.addSelectionListener(new BrowseWorkspaceButtonSelectionListener());
		browseWorkspaceButton.setText(Messages.getString("SelectLocationPage.BrowseWorkspaceButtonLabel")); //$NON-NLS-1$

		final Button browseFilesystemButton = new Button(container, SWT.NONE);
		browseFilesystemButton.addSelectionListener(new BrowseFilesystemButtonSelectionListener());
		browseFilesystemButton.setText(Messages.getString("SelectLocationPage.BrowseFilesystemButtonLabel")); //$NON-NLS-1$
		new Label(container, SWT.NONE);

		if (generationInfo.getWrapper() != null) {
			final Group grpWrapper = new Group(container, SWT.NONE);
			grpWrapper.setLayout(new GridLayout(1, false));
			grpWrapper.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
			grpWrapper.setText(Messages.getString("SelectLocationPage.OptionalSettingsGroupText")); //$NON-NLS-1$

			btnWrap = new Button(grpWrapper, SWT.CHECK);
			btnWrap.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
			final String buttonText = Messages.getString("SelectLocationPage.WrapButtonText") //$NON-NLS-1$
				+ ' ' + generationInfo.getWrapper().getName();
			btnWrap.setText(buttonText);
		}

		final Group grpPreview = new Group(container, SWT.NONE);
		grpPreview.setLayout(new FillLayout(SWT.HORIZONTAL));
		grpPreview.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
		grpPreview.setText(Messages.getString("SelectLocationPage.ContentGroupText")); //$NON-NLS-1$

		generatedText = new Text(grpPreview, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
		bindingContext = initDataBindings();

		WizardPageSupport.create(this, bindingContext);
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.jface.dialogs.DialogPage#setVisible(boolean)
	 */
	@Override
	public void setVisible(boolean visible) {
		super.setVisible(visible);
		if (visible && !wasAlreadyVisible) {
			wasAlreadyVisible = true;
		}
	}

	/**
	 * Indicates if this page was already shown to the user.
	 *
	 * @return
	 * 		{@code true} if this page was already shown to the user, {@code false} if this page was never shown to
	 *         the user.
	 */
	public boolean wasAlreadyVisible() {
		return wasAlreadyVisible;
	}

	/**
	 * Selection Listener for the Browse Workspace button opening a WorkspaceResourceDialog.
	 */
	private class BrowseWorkspaceButtonSelectionListener extends SelectionAdapter {
		@Override
		public void widgetSelected(final SelectionEvent e) {
			final WorkspaceResourceDialog dialog = new WorkspaceResourceDialog(getShell(), new WorkbenchLabelProvider(),
				new WorkbenchContentProvider());
			dialog.setAllowMultiple(false);
			dialog.setTitle(Messages.getString("SelectLocationPage.SelectLocationDialogTitle")); //$NON-NLS-1$
			dialog.setShowNewFolderControl(true);
			dialog.setShowFileControl(true);

			// preselect if file exists in workspace
			if (generationInfo.getLocation() != null && generationInfo.getLocation().isPlatform()) {
				final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
				final IResource resource = root
					.findMember(generationInfo.getLocation().trimSegments(1).toPlatformString(true));
				if (resource != null && resource.isAccessible()) {
					dialog.setInitialSelection(resource);
					final int segment = generationInfo.getLocation().segmentCount() > 0
						? generationInfo.getLocation().segmentCount() - 1
						: 0;
					dialog.setFileText(generationInfo.getLocation().segment(segment));
				}
			}

			dialog.loadContents();

			if (dialog.open() == Window.OK) {
				final IFile file = dialog.getFile();
				final URI newLocation = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
				setNewLocation(newLocation);
			}
		}
	}

	/**
	 * Selection Listener for the Browse Filesystem button opening a FileDialog.
	 */
	private class BrowseFilesystemButtonSelectionListener extends SelectionAdapter {
		@Override
		public void widgetSelected(final SelectionEvent e) {
			final FileDialog fileDialog = new FileDialog(getShell(), SWT.SINGLE | SWT.SAVE);
			// preselect if proposal is not in workspace
			if (generationInfo.getLocation() != null && !generationInfo.getLocation().isPlatform()) {
				final File file = new File(generationInfo.getLocation().toFileString());
				final File parent = file.getParentFile();
				if (parent != null && parent.exists()) {
					fileDialog.setFilterPath(parent.getAbsolutePath());
				}
				fileDialog.setFileName(file.getName());
			}
			final String result = fileDialog.open();
			if (result != null) {
				final URI newLocation = URI.createFileURI(result);
				setNewLocation(newLocation);
			}
		}
	}

	/**
	 * Handles the propagation of a new location.
	 *
	 * @param location
	 *            The new location for the generated file.
	 */
	private void setNewLocation(URI location) {
		generationInfo.setLocation(location);
		bindingContext.updateTargets();
		requiredLocationDecoration.hide();
	}

	/**
	 * Validates the given location.
	 */
	private class LocationValidator implements IValidator {
		@Override
		public IStatus validate(Object value) {
			if (value == null) {
				requiredLocationDecoration.show();
				return ValidationStatus.error(Messages.getString("SelectLocationPage.LocationError")); //$NON-NLS-1$
			}
			if (URI.class.isInstance(value)) {
				final URI uri = URI.class.cast(value);
				if (uri.isPlatform()) {
					final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
					final IResource resource = root.findMember(uri.toPlatformString(true));
					if (IContainer.class.isInstance(resource)) {
						requiredLocationDecoration.show();
						return ValidationStatus.error(Messages.getString("SelectLocationPage.LocationDirectoryError")); //$NON-NLS-1$
					}
				} else {
					if (uri.toFileString() == null) {
						requiredLocationDecoration.show();
						return ValidationStatus.error(Messages.getString("SelectLocationPage.LocationValidError")); //$NON-NLS-1$
					}
					final File file = new File(uri.toFileString());
					if (file.isDirectory()) {
						requiredLocationDecoration.show();
						return ValidationStatus.error(Messages.getString("SelectLocationPage.LocationDirectoryError")); //$NON-NLS-1$
					}
				}
			}
			requiredLocationDecoration.hide();
			return ValidationStatus.ok();
		}
	}

	/**
	 * Converts a manually entered string to an {@link URI}.
	 */
	private class StringToURIConverter implements IConverter {
		@Override
		public Object getToType() {
			return URI.class;
		}

		@Override
		public Object getFromType() {
			return String.class;
		}

		@Override
		public Object convert(Object fromObject) {
			if (fromObject == null || "".equals(fromObject)) { //$NON-NLS-1$
				return null;
			}
			final String path = (String) fromObject;
			if (path.startsWith("platform:") || path.startsWith("file:")) { //$NON-NLS-1$ //$NON-NLS-2$
				return URI.createURI(path, false);
			}
			return URI.createFileURI(path);
		}
	}

	/**
	 * Converts an URI to a String.
	 */
	private class URItoStringConverter implements IConverter {
		@Override
		public Object getToType() {
			return String.class;
		}

		@Override
		public Object getFromType() {
			return URI.class;
		}

		@Override
		public Object convert(Object fromObject) {
			if (fromObject == null) {
				return ""; //$NON-NLS-1$
			}
			final URI path = (URI) fromObject;
			if (path.isFile()) {
				return path.toFileString();
			}
			return path.toString();
		}
	}

	/**
	 * Creates and initializes the used data bindings.
	 *
	 * @return The initialized {@link DataBindingContext}.
	 */
	protected DataBindingContext initDataBindings() {
		final DataBindingContext bindingContext = new DataBindingContext();

		final IObservableValue observeTextLocationTextObserveWidget = WidgetProperties.text(SWT.Modify)
			.observe(locationText);
		final IObservableValue locationGenerationInfoObserveValue = PojoProperties.value("location") //$NON-NLS-1$
			.observe(generationInfo);
		bindingContext.bindValue(
			observeTextLocationTextObserveWidget, locationGenerationInfoObserveValue, new UpdateValueStrategy()
				.setConverter(new StringToURIConverter()).setAfterConvertValidator(new LocationValidator()),
			new UpdateValueStrategy().setConverter(new URItoStringConverter()));
final IObservableValue observeTextGeneratedTextObserveWidget = WidgetProperties.text(SWT.Modify) .observe(generatedText); final IObservableValue generatedStringGenerationInfoObserveValue = PojoProperties.value("generatedString") //$NON-NLS-1$ .observe(generationInfo); bindingContext.bindValue(observeTextGeneratedTextObserveWidget, generatedStringGenerationInfoObserveValue, null, null); if (generationInfo.getWrapper() != null) { final IObservableValue observeSelectionBtnWrapObserveWidget = WidgetProperties.selection().observe(btnWrap); final IObservableValue wrapGenerationInfoObserveValue = PojoProperties.value("wrap") //$NON-NLS-1$ .observe(generationInfo); bindingContext.bindValue(observeSelectionBtnWrapObserveWidget, wrapGenerationInfoObserveValue, null, null); } return bindingContext; } }