/******************************************************************************* * Copyright (c) 2015 Bruno Medeiros and other Contributors. * 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: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package melnorme.lang.ide.ui.dialogs; import static melnorme.lang.ide.ui.utils.DialogPageUtils.severityToMessageType; import static melnorme.utilbox.core.CoreUtil.list; import static org.eclipse.jface.layout.GridDataFactory.fillDefaults; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.resource.ImageDescriptor; 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.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import melnorme.lang.ide.core.LangCore; import melnorme.lang.ide.core.LangCore_Actual; import melnorme.lang.ide.core.utils.EclipseUtils; import melnorme.lang.ide.core.utils.ProjectValidator; import melnorme.lang.ide.core.utils.ResourceUtils; import melnorme.lang.ide.ui.LangUIPlugin_Actual; import melnorme.lang.ide.ui.utils.WorkbenchUtils; import melnorme.util.swt.SWTFactory; import melnorme.util.swt.SWTFactoryUtil; import melnorme.util.swt.SWTUtil; import melnorme.util.swt.components.CompositeWidget; import melnorme.util.swt.components.fields.DirectoryTextField; import melnorme.util.swt.components.fields.EnablementButtonTextField; import melnorme.util.swt.components.fields.TextFieldWidget; import melnorme.util.swt.components.misc.StatusMessageWidget; import melnorme.utilbox.concurrency.OperationCancellation; import melnorme.utilbox.core.CommonException; import melnorme.utilbox.fields.validation.ValidationSource; import melnorme.utilbox.status.IStatusMessage; import melnorme.utilbox.status.Severity; import melnorme.utilbox.status.StatusException; public abstract class LangProjectWizardFirstPage extends WizardPage { protected final NameGroup nameGroup = createNameGroup(); protected final LocationGroup locationGroup = createLocationGroup(); protected final ProjectValidationGroup projectValidationGroup = createProjectValidationGroup(); protected final PreferencesValidationGroup prefValidationGroup = createPreferencesValidationGroup(); public LangProjectWizardFirstPage() { super(LangProjectWizardFirstPage.class.getSimpleName()); } public LangProjectWizardFirstPage(String pageName, String title, ImageDescriptor titleImage) { super(pageName, title, titleImage); } protected NameGroup createNameGroup() { return new NameGroup(); } protected ProjectValidationGroup createProjectValidationGroup() { return new ProjectValidationGroup(); } protected LocationGroup createLocationGroup() { return new LocationGroup(); } protected PreferencesValidationGroup createPreferencesValidationGroup() { return new PreferencesValidationGroup(); } /* ----------------- ----------------- */ public NameGroup getNameGroup() { return nameGroup; } public LocationGroup getLocationGroup() { return locationGroup; } public ProjectValidationGroup getDetectGroup() { return projectValidationGroup; } public IPath getProjectLocation() { return locationGroup.getProjectLocation(); } @Override public void createControl(Composite parent) { initializeDialogUnits(parent); Composite topControl = new Composite(parent, SWT.NULL); topControl.setLayoutData(new GridData(GridData.FILL_BOTH)); topControl.setLayout(new GridLayout(1, false)); createContents(topControl); setControl(topControl); Dialog.applyDialogFont(topControl); } protected GridDataFactory sectionGDF() { return fillDefaults().grab(true, false); } protected void createContents(Composite parent) { nameGroup.createComponent(parent, sectionGDF().create()); locationGroup.createComponent(parent, sectionGDF().create()); createContents_ValidationGroups(parent); nameGroup.nameField.addChangeListener(this::updateValidationMessage); locationGroup.addChangeListener(this::updateValidationMessage); updateValidationMessage(); } protected void createContents_ValidationGroups(Composite parent) { projectValidationGroup.createComponent(parent, sectionGDF().hint(500, SWT.DEFAULT).create()); prefValidationGroup.createComponent(parent, sectionGDF().hint(500, SWT.DEFAULT).create()); } @Override public void setVisible(boolean visible) { super.setVisible(visible); if (visible) { nameGroup.postSetFocus(); } } public static class NameGroup extends CompositeWidget { protected final TextFieldWidget nameField = new TextFieldWidget(WizardMessages.LangNewProject_NameGroup_label); public NameGroup() { super(true); addChildWidget(nameField); this.layoutColumns = 2; nameField.addFieldValidator2(this::getProjectHandleFor); } public TextFieldWidget nameField() { return nameField; } public String getName() { return nameField.getFieldValue(); } public void validateProjectName() throws StatusException { getProjectHandle2(); } public IProject getProjectHandle2() throws StatusException { return getProjectHandleFor(getName()); } public IProject getProjectHandleFor(String projectName) throws StatusException { return new ProjectValidator().getProjectHandle(projectName); } /* ----------------- ----------------- */ public void postSetFocus() { SWTUtil.post_setFocus(nameField.getFieldControl()); } } /* ----------------- Location ----------------- */ public class LocationGroup extends EnablementButtonTextField { public LocationGroup() { super( WizardMessages.LangNewProject_Location_Directory_label, WizardMessages.LangNewProject_Location_UseDefault_Label, WizardMessages.LangNewProject_Location_Directory_buttonLabel ); nameGroup.nameField.addChangeListener(this::updateDefaultFieldValue); getValidation().addFieldValidation2(true, list(nameGroup.nameField, this), ValidationSource.fromRunnable(this::doValidate)); } protected String getProjectName() { return nameGroup.getName(); } protected boolean isDefaultLocation() { return isUseDefault(); } protected String getLocationString() { return getFieldValue(); } @Override protected String getDefaultFieldValue() { return Platform.getLocation().append(getProjectName()).toOSString(); } /* ----------------- ----------------- */ public IPath getProjectLocation() { String projectName = getProjectName(); if(projectName.isEmpty()) { return null; } if(!Path.EMPTY.isValidPath(getLocationString())) { return null; } return Path.fromOSString(getLocationString()); } public void doValidate() throws StatusException { IProject project = nameGroup.getProjectHandle2(); if(project.exists() && !isDefaultLocation()) { throw new StatusException(Severity.ERROR, WizardMessages.LangNewProject_Location_projectExistsCannotChangeLocation); } IPath projectLocation = getProjectLocation(); if(projectLocation == null) { throw new StatusException(Severity.ERROR, WizardMessages.LangNewProject_Location_invalidLocation); } EclipseUtils.validate( () -> ResourceUtils.getWorkspace().validateProjectLocation(project, projectLocation)); } /* ----------------- ----------------- */ @Override protected Composite doCreateTopLevelControl(Composite parent) { return SWTFactoryUtil.createGroup(parent, WizardMessages.LangNewProject_LocationGroup_label); } @Override public int getPreferredLayoutColumns() { return 3; } @Override protected void createContents_Label(Composite parent) { label = SWTFactory.createLabel(parent, SWT.NONE, labelText); } @Override protected String getNewValueFromButtonSelection() throws OperationCancellation { return DirectoryTextField.openDirectoryDialog(getFieldValue(), button.getShell()); } } public class ProjectValidationGroup extends StatusMessageWidget { @Override public void updateWidgetFromInput() { IProject projectHandle; try { projectHandle = nameGroup.getProjectHandle2(); } catch(CommonException e) { projectHandle = null; } IPath projectLoc = getProjectLocation(); if(projectHandle != null && projectHandle.exists()) { setStatusMessage(Severity.INFO, WizardMessages.LangNewProject_DetectGroup_projectExists); } else if(projectLoc != null && projectLoc.toFile().exists()) { setStatusMessage(Severity.INFO, WizardMessages.LangNewProject_DetectGroup_message); } else { setStatusMessage(null); } } } public class PreferencesValidationGroup extends ProjectValidationGroup { @Override protected void createContents(Composite parent) { super.createContents(parent); hintText.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { openPreferencePage(); } }); } protected void openPreferencePage() { WorkbenchUtils.openPreferencePage(getShell(), LangUIPlugin_Actual.ROOT_PREF_PAGE_ID); updateWidgetFromInput(); } @Override public void updateWidgetFromInput() { try { validatePreferences(); setStatusMessage(null); } catch (CommonException ve) { setPreferencesErrorMessage(ve); } } @SuppressWarnings("unused") protected void setPreferencesErrorMessage(CommonException ve) { setStatusMessage(Severity.WARNING, "The "+ LangCore_Actual.NAME_OF_LANGUAGE + " preferences have not been configured correctly.\n"+ "<a>Click here to configure preferences...</a>"); } } protected void validatePreferences() throws StatusException { LangCore.settings().SDK_LOCATION.getValue(); } protected boolean updateValidationMessage() { IStatusMessage validationStatus = ValidationSource.getValidationStatus(nameGroup, locationGroup); boolean valid; if(validationStatus == null) { setMessage(null); setPageComplete(true); valid = true; } else { Severity severity = validationStatus.getSeverity(); setMessage(validationStatus.getMessage(), severityToMessageType(severity)); setPageComplete(severity != Severity.ERROR); valid = false; } projectValidationGroup.updateWidgetFromInput(); prefValidationGroup.updateWidgetFromInput(); return valid; } }