/*******************************************************************************
* Copyright (c) 2017 Rogue Wave Software Inc. and others.
* 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:
* Rogue Wave Software Inc. - initial implementation
*******************************************************************************/
package org.eclipse.php.phpunit.ui.wizards;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.dltk.core.*;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.php.core.PHPToolkitUtil;
import org.eclipse.php.core.compiler.PHPFlags;
import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
import org.eclipse.php.internal.ui.util.StatusInfo;
import org.eclipse.php.internal.ui.util.StatusUtil;
import org.eclipse.php.internal.ui.wizards.fields.*;
import org.eclipse.php.phpunit.PHPUnitMessages;
import org.eclipse.php.phpunit.PHPUnitPlugin;
import org.eclipse.php.phpunit.model.PHPUnitSearchEngine;
import org.eclipse.php.phpunit.model.PHPUnitValidator;
import org.eclipse.swt.SWT;
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.swt.widgets.Text;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.eclipse.wst.xml.core.internal.document.NodeImpl;
public abstract class PHPUnitWizardPage extends WizardPage {
class ClassNameFieldAdapter implements IDialogFieldListener {
@Override
public void dialogFieldChanged(final DialogField field) {
classNameFieldChanged(field);
}
}
class ContainerFieldAdapter implements IStringButtonAdapter, IDialogFieldListener {
@Override
public void changeControlPressed(final DialogField field) {
containerChangeControlPressed(field);
}
@Override
public void dialogFieldChanged(final DialogField field) {
containerDialogFieldChanged(field);
}
}
class FileNameFieldAdapter implements IDialogFieldListener {
@Override
public void dialogFieldChanged(final DialogField field) {
fileNameFieldChanged(field);
}
}
class SuperClassFieldAdapter implements IStringButtonAdapter, IDialogFieldListener {
@Override
public void changeControlPressed(final DialogField field) {
superClassButtonPressed(field);
}
@Override
public void dialogFieldChanged(final DialogField field) {
superClassFieldChanged(field);
}
}
private final static String DEFAULT_EXTENSION = ".php"; //$NON-NLS-1$
protected boolean fClassNameManual;
protected String fClassNameProposal;
protected IStatus fElementToTestStatus; // status
protected IStatus fClassNameStatus;
protected IStatus fContainerStatus;
protected IStatus fFileNameStatus;
protected StringButtonDialogField fSuperClassDialogField;
protected IStatus fSuperClassStatus;
protected StringDialogField fClassNameDialogField;
private IContainer fContainer;
private IScriptProject fScriptProject;
private PHPUnitSearchEngine fSearchEngine;
private StringButtonDialogField fContainerDialogField;
private StringDialogField fFileNameDialogField;
private boolean fFileNameManual;
private String fFileNameProposal;
private boolean fPageVisible;
private IType fSuperClass;
private Label fSuperClassFileNameLabel;
public PHPUnitWizardPage(final String pageName) {
super(pageName);
fPageVisible = false;
final ContainerFieldAdapter containerAdapter = new ContainerFieldAdapter();
fContainerDialogField = new StringButtonDialogField(containerAdapter);
fContainerDialogField.setDialogFieldListener(containerAdapter);
fContainerDialogField.setLabelText(getContainerLabel());
fContainerDialogField.setButtonLabel(PHPUnitMessages.PHPUnitWizardPage_0);
fContainerStatus = new StatusInfo();
final SuperClassFieldAdapter superClassAdapter = new SuperClassFieldAdapter();
fSuperClassDialogField = new StringButtonDialogField(superClassAdapter);
fSuperClassDialogField.setDialogFieldListener(superClassAdapter);
fSuperClassDialogField.setLabelText(PHPUnitMessages.PHPUnitWizardPage_1);
fSuperClassDialogField.setButtonLabel(PHPUnitMessages.PHPUnitWizardPage_2);
fSuperClassStatus = new StatusInfo();
fClassNameDialogField = new StringDialogField();
fClassNameDialogField.setDialogFieldListener(new ClassNameFieldAdapter());
fClassNameStatus = new StatusInfo();
fClassNameDialogField.setLabelText(PHPUnitMessages.PHPUnitWizardPage_3);
fFileNameDialogField = new StringDialogField();
fFileNameDialogField.setDialogFieldListener(new FileNameFieldAdapter());
fFileNameStatus = new StatusInfo();
fFileNameDialogField.setLabelText(PHPUnitMessages.PHPUnitWizardPage_4);
fElementToTestStatus = new StatusInfo();
}
protected IContainer chooseContainer() {
final ContainerSelectionDialog dialog = new ContainerSelectionDialog(getShell(),
ResourcesPlugin.getWorkspace().getRoot(), false, "Select New Source Folder"); //$NON-NLS-1$
dialog.setHelpAvailable(false);
dialog.setTitle(PHPUnitMessages.PHPUnitWizardPage_10);
dialog.setMessage(PHPUnitMessages.PHPUnitWizardPage_11);
if (dialog.open() == Window.OK) {
final Object[] result = dialog.getResult();
if (result.length == 1) {
IPath path = (IPath) result[0];
IResource foundMemder = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
if (foundMemder instanceof IContainer) {
IContainer container = (IContainer) foundMemder;
fContainerDialogField.setText(container.getFullPath().toOSString());
if (container.getType() == IContainer.FOLDER) {
return PHPUnitValidator.validateContainer(container);
}
if (container.getType() == IContainer.PROJECT) {
return PHPUnitValidator.validateProject(container);
}
}
}
}
return null;
}
abstract protected IType chooseSuperClass();
protected void classNameChanged() {
final StatusInfo status = new StatusInfo();
final String updatedClassName = PHPUnitValidator.validateClassName(getClassName(),
fContainer != null ? fContainer.getProject() : null, status);
if ("".equals(updatedClassName) || updatedClassName.equalsIgnoreCase(fClassNameProposal)) //$NON-NLS-1$
fClassNameManual = false;
else
fClassNameManual = true;
fClassNameStatus = status;
fFileNameProposal = getClassName() != null ? getClassName() + DEFAULT_EXTENSION : ""; //$NON-NLS-1$
if (!fFileNameManual && fFileNameDialogField != null) {
fFileNameDialogField.setText(fFileNameProposal);
}
updateStatus(getStatusList());
}
private void classNameFieldChanged(final DialogField field) {
if (field == fClassNameDialogField)
classNameChanged();
updateStatus(getStatusList());
}
private void containerChangeControlPressed(final DialogField field) {
// take the current jproject as init element of the dialog
final IContainer root = chooseContainer();
if (root != null) {
setContainer(root);
}
}
protected void containerChanged() {
final StatusInfo status = new StatusInfo();
IContainer newContainer = PHPUnitValidator.validateContainer(fContainerDialogField.getText(), true, status);
// when we changed the project in the field, we invalidate all cached
// elements.
if (fContainer != newContainer) {
invalidatCachedElements();
}
fContainer = newContainer;
fContainerStatus = status;
if (fContainer != null) {
IProject project = fContainer.getProject();
if (project != null) {
IScriptProject scriptProject = DLTKCore.create(project);
if (fScriptProject != scriptProject) {
fScriptProject = scriptProject;
fSearchEngine = new PHPUnitSearchEngine(fScriptProject);
}
}
}
updateStatus(getStatusList());
}
protected abstract void invalidatCachedElements();
private void containerDialogFieldChanged(final DialogField field) {
if (field == fContainerDialogField) {
containerChanged();
}
updateStatus(getStatusList());
}
protected void createClassNameControls(final Composite composite, final int nColumns) {
fClassNameDialogField.doFillIntoGrid(composite, nColumns);
// DialogField.createEmptySpace(composite);
final Text text = fClassNameDialogField.getTextControl(null);
LayoutUtil.setWidthHint(text, getMaxFieldWidth());
}
protected void createContainerControls(final Composite parent, final int nColumns) {
fContainerDialogField.doFillIntoGrid(parent, nColumns);
LayoutUtil.setWidthHint(fContainerDialogField.getTextControl(null), getMaxFieldWidth());
}
@Override
public void createControl(final Composite parent) {
initializeDialogUnits(parent);
final Composite composite = new Composite(parent, SWT.NONE);
final int nColumns = 3;
final GridLayout layout = new GridLayout(3, false);
composite.setLayout(layout);
createContainerControls(composite, nColumns);
createSuperClassControls(composite, nColumns);
createElementToTestControls(composite, nColumns);
createSeparator(composite, nColumns);
createClassNameControls(composite, nColumns);
createFileNameControls(composite, nColumns);
setControl(composite);
Dialog.applyDialogFont(composite);
setFocus();
updateStatus(getStatusList());
}
abstract protected void createElementToTestControls(Composite composite, int columns);
protected void createFileNameControls(final Composite composite, final int nColumns) {
fFileNameDialogField.doFillIntoGrid(composite, nColumns);
}
protected void createSeparator(final Composite composite, final int nColumns) {
new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, nColumns, 1));
}
protected void createSuperClassControls(final Composite composite, final int nColumns) {
fSuperClassDialogField.doFillIntoGrid(composite, nColumns);
final Text text = fSuperClassDialogField.getTextControl(null);
// text.setEditable(false);
LayoutUtil.setWidthHint(text, getMaxFieldWidth());
new Label(composite, SWT.NONE);
fSuperClassFileNameLabel = new Label(composite, SWT.NONE);
final GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.grabExcessHorizontalSpace = true;
fSuperClassFileNameLabel.setLayoutData(gridData);
LayoutUtil.setWidthHint(fSuperClassFileNameLabel, getMaxFieldWidth());
new Label(composite, SWT.NONE);
superClassChanged();
}
abstract protected String defaultSuperClass();
@Override
public void dispose() {
fContainerDialogField.setDialogFieldListener(null);
fSuperClassDialogField.setDialogFieldListener(null);
fClassNameDialogField.setDialogFieldListener(null);
fFileNameDialogField.setDialogFieldListener(null);
super.dispose();
}
protected void fileNameChanged() {
final StatusInfo status = new StatusInfo();
final String updatedFileName = PHPUnitValidator.validateFileName(getFileName(),
fContainer != null ? fContainer : null, status);
if (updatedFileName.equals("") || updatedFileName.equalsIgnoreCase(fFileNameProposal)) {//$NON-NLS-1$
fFileNameManual = false;
} else {
fFileNameManual = true;
}
fFileNameStatus = status;
updateStatus(getStatusList());
}
private void fileNameFieldChanged(final DialogField field) {
if (field == fFileNameDialogField)
fileNameChanged();
updateStatus(getStatusList());
}
public String getClassName() {
return fClassNameDialogField.getText().trim();
}
protected String getContainerLabel() {
return PHPUnitMessages.PHPUnitWizardPage_15;
}
public String getFileName() {
return fFileNameDialogField.getText().trim();
}
protected IContainer getInitialContainer(final IStructuredSelection selection) {
if (selection != null && !selection.isEmpty()) {
final Object obj = selection.getFirstElement();
if (obj instanceof IModelElement) {
IResource resource = ((IModelElement) obj).getResource();
if (resource != null && !(resource instanceof IContainer)) {
resource = resource.getParent();
}
return (IContainer) resource;
} else if (obj instanceof IResource) {
IResource resource = (IResource) obj;
if (resource != null && !(resource instanceof IContainer)) {
resource = resource.getParent();
}
return (IContainer) resource;
}
}
return null;
}
protected IModelElement getInitialPHPElement(final IStructuredSelection selection) {
IModelElement modelElement = null;
int offset = -1;
if (selection != null && !selection.isEmpty()) {
Object obj = selection.getFirstElement();
if (obj instanceof NodeImpl) {
if (obj instanceof IAdaptable) {
obj = ((IAdaptable) obj).getAdapter(IModelElement.class);
}
} else if (obj != null && obj instanceof ISourceModule) {
// get current document offset
if (selection instanceof ITextSelection) {
ITextSelection textSelection = (ITextSelection) selection;
offset = textSelection.getOffset();
}
// find the IType at current offset
IType selectedType = null;
ISourceModule sourceModule = (ISourceModule) obj;
if (offset > -1) {
selectedType = PHPModelUtils.getCurrentType(sourceModule, offset);
} else {
IType[] types = null;
try {
types = sourceModule.getTypes();
} catch (ModelException e) {
PHPUnitPlugin.log(e);
}
if (types != null && types.length >= 1) {
selectedType = types[0];
}
}
// found currently selected IType
if (selectedType != null) {
int flags;
try {
flags = selectedType.getFlags();
if (!PHPFlags.isInterface(flags) && !PHPFlags.isAbstract(flags) && fSearchEngine != null
&& !fSearchEngine.isCase(selectedType)) {
modelElement = (IType) selectedType;
}
} catch (ModelException e) {
PHPUnitPlugin.log(e);
}
}
// no luck ti find currently selected IType
if (modelElement == null) {
modelElement = sourceModule;
}
} else if (obj instanceof IType) {
modelElement = (IType) obj;
} else if (obj instanceof IFile) {
IFile file = (IFile) obj;
boolean isPhpFile = PHPToolkitUtil.isPHPFile(file);
if (isPhpFile) {
modelElement = DLTKCore.create((IFile) obj);
} else {
// TODO message not php file
}
}
}
return modelElement;
}
/**
* Initialized the page with the current selection
*
* @param selection
* The selection
*/
public Object init(final IStructuredSelection selection) {
final IModelElement element;
final IContainer container;
final Object result;
if ((element = getInitialPHPElement(selection)) != null) {
initContainerPage(element);
if (element instanceof IType) {
setClassName(((IType) element).getElementName());
}
result = element;
} else if ((container = getInitialContainer(selection)) != null) {
setContainer(container);
setSuperClass(null);
result = container;
} else {
result = null;
// we set empty string just to invoke validation
fContainerDialogField.setText(""); //$NON-NLS-1$
}
updateStatus(getStatusList());
return result;
}
/**
* Initializes the source folder field with a valid root. The root is
* computed from the given PHPlement.
*
* @param elem
* the PHP Element used to compute the initial root used as the
* source folder
*/
protected void initContainerPage(final IModelElement modelElement) {
IModelElement tempElement = modelElement;
if (modelElement != null) {
while (!((tempElement instanceof IScriptFolder) || (tempElement instanceof IScriptProject))) {
tempElement = tempElement.getParent();
}
}
IContainer container = null;
if (tempElement instanceof IScriptFolder) {
IResource resource = tempElement.getResource();
if (resource instanceof IFolder) {
container = (IFolder) resource;
}
if (resource instanceof IProject) {
container = (IProject) resource;
}
}
if (tempElement instanceof IScriptProject) {
container = ((IScriptProject) tempElement).getProject();
}
setContainer(container);
}
public void setClassName(final String name) {
fClassNameDialogField.setText(name);
}
public void setContainer(final IContainer root) {
fContainer = root;
if (fContainer != null) {
IProject project = fContainer.getProject();
if (project != null) {
IScriptProject scriptProject = DLTKCore.create(project);
if (fScriptProject != scriptProject) {
fScriptProject = scriptProject;
fSearchEngine = new PHPUnitSearchEngine(fScriptProject);
}
}
}
final String str = root == null ? "" : root.getFullPath().toOSString(); //$NON-NLS-1$
fContainerDialogField.setText(str);
}
protected void setFocus() {
fClassNameDialogField.setFocus();
}
public void setSuperClass(final IType classData) {
fSuperClassDialogField.setText(classData != null ? classData.getElementName() : defaultSuperClass());
}
@Override
public void setVisible(final boolean visible) {
super.setVisible(visible);
fPageVisible = visible;
updateStatus(getStatusList());
}
private void superClassButtonPressed(final DialogField field) {
final IType classData = chooseSuperClass();
if (classData != null) {
setSuperClass(classData);
}
}
protected void superClassChanged() {
final StatusInfo status = new StatusInfo();
Object element = fSuperClass;
if (fSuperClass == null || !fSuperClass.getElementName().equals(getSuperClassName())) {
fSuperClass = null;
element = getSuperClassName();
}
fSuperClass = (IType) PHPUnitValidator.validateElement(element,
fContainer != null ? fContainer.getProject() : null, false, IModelElement.TYPE, status);
final String superClassName = fSuperClass != null ? fSuperClass.getElementName() : ""; //$NON-NLS-1$
if (fSuperClassFileNameLabel != null && !fSuperClassFileNameLabel.isDisposed())
fSuperClassFileNameLabel.setText(superClassName);
fSuperClassStatus = status;
if ("".equals(getSuperClassName())) //$NON-NLS-1$
status.setError(PHPUnitMessages.PHPUnitWizardPage_20); // higher
// severity
updateStatus(getStatusList());
}
private void superClassFieldChanged(final DialogField field) {
superClassChanged();
}
protected abstract String testSuffix();
protected void updateStatus(final IStatus status) {
setPageComplete(!status.matches(IStatus.ERROR));
if (fPageVisible) {
StatusUtil.applyToStatusLine(this, status);
}
}
protected void updateStatus(final IStatus[] statuses) {
updateStatus(StatusUtil.getMostSevere(statuses));
}
protected int getMaxFieldWidth() {
return convertWidthInCharsToPixels(40);
}
protected IStatus[] getStatusList() {
return new IStatus[] { fContainerStatus, fClassNameStatus, fFileNameStatus, fElementToTestStatus,
fSuperClassStatus };
}
public IType getSuperClass() {
return fSuperClass;
}
public String getSuperClassName() {
return fSuperClassDialogField.getText().trim();
}
public IContainer getTestContainer() {
return fContainer;
}
}