blob: 630b0cce58d5665d52d9e7d606a2e20627648fa5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* Martin Karpisek (martin.karpisek@gmail.com) - bug 229474
*******************************************************************************/
package org.eclipse.ant.internal.ui.datatransfer;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.UnknownElement;
import org.apache.tools.ant.taskdefs.Javac;
import org.eclipse.ant.internal.core.IAntCoreConstants;
import org.eclipse.ant.internal.ui.AntUIPlugin;
import org.eclipse.ant.internal.ui.AntUtil;
import org.eclipse.ant.internal.ui.model.AntModelContentProvider;
import org.eclipse.ant.internal.ui.model.AntProjectNode;
import org.eclipse.ant.internal.ui.model.AntTargetNode;
import org.eclipse.ant.internal.ui.model.AntTaskNode;
import org.eclipse.ant.internal.ui.model.IAntElement;
import org.eclipse.ant.internal.ui.model.IAntModel;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
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.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.IOverwriteQuery;
import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider;
import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider;
import org.eclipse.ui.wizards.datatransfer.ImportOperation;
public class AntNewJavaProjectPage extends WizardPage {
private static class ImportOverwriteQuery implements IOverwriteQuery {
@Override
public String queryOverwrite(String file) {
return ALL;
}
}
private Text fProjectNameField;
private Text fLocationPathField;
private Button fBrowseButton;
private Button fLinkButton;
private IAntModel fAntModel;
private ModifyListener fLocationModifyListener = new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
// no lexical or position, has task info
fAntModel = AntUtil.getAntModel(getProjectLocationFieldValue(), false, false, true);
AntProjectNode projectNode = fAntModel == null ? null : fAntModel.getProjectNode();
if (fAntModel != null && projectNode != null) {
setProjectName(); // page will be validated on setting the project name
List<AntTaskNode> javacNodes = new ArrayList<>();
getJavacNodes(javacNodes, projectNode);
fTableViewer.setInput(javacNodes.toArray());
if (!javacNodes.isEmpty()) {
fTableViewer.setSelection(new StructuredSelection(javacNodes.get(0)));
}
fTableViewer.getControl().setEnabled(true);
} else {
fTableViewer.setInput(new Object[] {});
fTableViewer.getControl().setEnabled(false);
}
setPageComplete(validatePage());
}
};
private ModifyListener fNameModifyListener = new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
setPageComplete(validatePage());
}
};
private static final int SIZING_TEXT_FIELD_WIDTH = 250;
private TableViewer fTableViewer;
public AntNewJavaProjectPage() {
super("newPage"); //$NON-NLS-1$
setPageComplete(false);
setTitle(DataTransferMessages.AntNewJavaProjectPage_9);
setDescription(DataTransferMessages.AntNewJavaProjectPage_10);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createControl(Composite parent) {
initializeDialogUnits(parent);
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = IDialogConstants.VERTICAL_MARGIN;
layout.marginWidth = IDialogConstants.HORIZONTAL_MARGIN;
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
layout.numColumns = 3;
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
composite.setFont(parent.getFont());
createProjectNameGroup(composite);
createProjectLocationGroup(composite);
createTargetsTable(composite);
fLinkButton = new Button(composite, SWT.CHECK);
fLinkButton.setText(DataTransferMessages.AntNewJavaProjectPage_24);
fLinkButton.setFont(parent.getFont());
GridData gd = new GridData();
gd.horizontalAlignment = GridData.FILL;
gd.grabExcessHorizontalSpace = false;
gd.horizontalSpan = 2;
fLinkButton.setLayoutData(gd);
validatePage();
// Show description on opening
setErrorMessage(null);
setMessage(null);
setControl(composite);
}
/**
* Creates the project location specification controls.
*
* @param parent
* the parent composite
*/
private final void createProjectLocationGroup(Composite parent) {
// new project label
Label projectContentsLabel = new Label(parent, SWT.NONE);
projectContentsLabel.setText(DataTransferMessages.AntNewJavaProjectPage_11);
projectContentsLabel.setFont(parent.getFont());
createUserSpecifiedProjectLocationGroup(parent);
}
/**
* Creates the project name specification controls.
*
* @param parent
* the parent composite
*/
private final void createProjectNameGroup(Composite parent) {
Font dialogFont = parent.getFont();
// new project label
Label projectLabel = new Label(parent, SWT.NONE);
projectLabel.setText(DataTransferMessages.AntNewJavaProjectPage_12);
projectLabel.setFont(dialogFont);
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
projectLabel.setLayoutData(gd);
// new project name entry field
fProjectNameField = new Text(parent, SWT.BORDER);
gd = new GridData();
gd.horizontalAlignment = GridData.FILL;
gd.grabExcessHorizontalSpace = false;
gd.horizontalSpan = 2;
fProjectNameField.setLayoutData(gd);
fProjectNameField.setFont(dialogFont);
fProjectNameField.addModifyListener(fNameModifyListener);
}
/**
* Creates the project location specification controls.
*
* @param projectGroup
* the parent composite
*/
private void createUserSpecifiedProjectLocationGroup(Composite projectGroup) {
Font dialogFont = projectGroup.getFont();
// project location entry field
fLocationPathField = new Text(projectGroup, SWT.BORDER);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
data.widthHint = SIZING_TEXT_FIELD_WIDTH;
fLocationPathField.setLayoutData(data);
fLocationPathField.setFont(dialogFont);
// browse button
fBrowseButton = new Button(projectGroup, SWT.PUSH);
fBrowseButton.setText(DataTransferMessages.AntNewJavaProjectPage_13);
fBrowseButton.setFont(dialogFont);
setButtonLayoutData(fBrowseButton);
fBrowseButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
handleBrowseButtonPressed();
}
});
fLocationPathField.addModifyListener(fLocationModifyListener);
}
/**
* Returns the current project name
*
* @return the project name
*/
private String getProjectName(AntProjectNode projectNode) {
String projectName = projectNode.getLabel();
if (projectName == null) {
projectName = DataTransferMessages.AntNewJavaProjectPage_14;
}
return projectName;
}
/**
* Returns the value of the project name field with leading and trailing spaces removed.
*
* @return the project name in the field
*/
private String getProjectNameFieldValue() {
if (fProjectNameField == null) {
return IAntCoreConstants.EMPTY_STRING;
}
return fProjectNameField.getText().trim();
}
/**
* Returns the value of the project location field with leading and trailing spaces removed.
*
* @return the project location directory in the field
*/
private String getProjectLocationFieldValue() {
return fLocationPathField.getText().trim();
}
/**
* Determine the buildfile the user wishes to operate from
*/
private void handleBrowseButtonPressed() {
String lastUsedPath = IAntCoreConstants.EMPTY_STRING;
FileDialog dialog = new FileDialog(getShell(), SWT.SINGLE | SWT.SHEET);
dialog.setFilterExtensions(new String[] { "*.xml" }); //$NON-NLS-1$ ;
dialog.setFilterPath(lastUsedPath);
String result = dialog.open();
if (result == null) {
return;
}
IPath filterPath = new Path(dialog.getFilterPath());
String buildFileName = dialog.getFileName();
IPath path = filterPath.append(buildFileName).makeAbsolute();
fLocationPathField.setText(path.toOSString());
}
/**
* Returns whether this page's controls currently all contain valid values.
*
* @return <code>true</code> if all controls are valid, and <code>false</code> if at least one is invalid
*/
private boolean validatePage() {
String locationFieldContents = getProjectLocationFieldValue();
if (locationFieldContents.equals(IAntCoreConstants.EMPTY_STRING)) {
setErrorMessage(null);
setMessage(DataTransferMessages.AntNewJavaProjectPage_15);
return false;
}
IPath path = new Path(IAntCoreConstants.EMPTY_STRING);
if (!path.isValidPath(locationFieldContents)) {
setErrorMessage(DataTransferMessages.AntNewJavaProjectPage_16);
return false;
}
if (fAntModel == null) {
if (getBuildFile(locationFieldContents) == null) {
setErrorMessage(DataTransferMessages.AntNewJavaProjectPage_0);
return false;
}
setErrorMessage(DataTransferMessages.AntNewJavaProjectPage_17);
return false;
}
if (fAntModel.getProjectNode() == null) {
setErrorMessage(DataTransferMessages.AntNewJavaProjectPage_2);
return false;
}
if (getProjectNameFieldValue().length() == 0) {
setErrorMessage(DataTransferMessages.AntNewJavaProjectPage_18);
return false;
}
try {
IProject existingProject = ResourcesPlugin.getWorkspace().getRoot().getProject(getProjectNameFieldValue());
if (existingProject.exists()) {
setErrorMessage(DataTransferMessages.AntNewJavaProjectPage_19);
return false;
}
}
catch (IllegalArgumentException e) {
setErrorMessage(NLS.bind(DataTransferMessages.AntNewJavaProjectPage_23, e.getLocalizedMessage()));
return false;
}
if (fTableViewer.getTable().getItemCount() == 0) {
setErrorMessage(DataTransferMessages.AntNewJavaProjectPage_1);
setPageComplete(false);
return false;
}
setErrorMessage(null);
setMessage(null);
return true;
}
/**
* Set the project name using either the name of the parent of the file or the name entry in the xml for the file
*/
private void setProjectName() {
AntProjectNode node = fAntModel.getProjectNode();
String projectName = getProjectName(node);
fProjectNameField.setText(projectName);
}
/**
* Return a .xml file from the specified location. If there isn't one return null.
*/
private File getBuildFile(String locationFieldContents) {
File buildFile = new File(locationFieldContents);
if (!buildFile.isFile() || !buildFile.exists()) {
return null;
}
return buildFile;
}
/**
* Creates a new project resource based on the Ant buildfile. The classpath is configured based on the classpath of the javac declaration in the
* buildfile.
*
* @return the created project resource, or <code>null</code> if the project was not created
*/
protected IJavaProject createProject() {
final IJavaProject[] result = new IJavaProject[1];
final String projectName = getProjectNameFieldValue();
final File buildFile = getBuildFile(getProjectLocationFieldValue());
final List<?> selectedJavacs = ((IStructuredSelection) fTableViewer.getSelection()).toList();
final boolean link = fLinkButton.getSelection();
WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor monitor) throws CoreException {
List<?> javacTasks = resolveJavacTasks(selectedJavacs);
ProjectCreator creator = new ProjectCreator();
Iterator<?> iter = javacTasks.iterator();
while (iter.hasNext()) {
Javac javacTask = (Javac) iter.next();
IJavaProject javaProject = creator.createJavaProjectFromJavacNode(projectName, javacTask, monitor);
importBuildFile(monitor, javaProject, buildFile, link);
result[0] = javaProject;
}
}
};
// run the new project creation operation
try {
getContainer().run(true, true, op);
}
catch (InterruptedException e) {
return null;
}
catch (InvocationTargetException e) {
// ie.- one of the steps resulted in a core exception
Throwable t = e.getTargetException();
IStatus status = null;
if (t instanceof CoreException) {
status = ((CoreException) t).getStatus();
} else {
status = new Status(IStatus.ERROR, AntUIPlugin.PI_ANTUI, IStatus.OK, "Error occurred. Check log for details ", t); //$NON-NLS-1$
AntUIPlugin.log(t);
}
ErrorDialog.openError(getShell(), DataTransferMessages.AntNewJavaProjectPage_21, null, status);
}
return result[0];
}
protected void importBuildFile(IProgressMonitor monitor, IJavaProject javaProject, File buildFile, boolean link) {
if (link) {
IProject project = javaProject.getProject();
IFile iBuildFile = project.getFile(buildFile.getName());
if (!iBuildFile.exists()) {
try {
iBuildFile.createLink(new Path(buildFile.getAbsolutePath()), IResource.ALLOW_MISSING_LOCAL, monitor);
}
catch (CoreException e) {
ErrorDialog.openError(getShell(), DataTransferMessages.AntNewJavaProjectPage_22, null, e.getStatus());
}
}
} else {
IImportStructureProvider structureProvider = FileSystemStructureProvider.INSTANCE;
File rootDir = buildFile.getParentFile();
try {
ImportOperation op = new ImportOperation(javaProject.getPath(), rootDir, structureProvider, new ImportOverwriteQuery(), Collections.singletonList(buildFile));
op.setCreateContainerStructure(false);
op.run(monitor);
}
catch (InterruptedException e) {
// should not happen
}
catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof CoreException) {
ErrorDialog.openError(getShell(), DataTransferMessages.AntNewJavaProjectPage_22, null, ((CoreException) t).getStatus());
}
}
}
}
private List<?> resolveJavacTasks(List<?> javacNodes) {
List<Object> resolvedJavacTasks = new ArrayList<>(javacNodes.size());
Iterator<?> nodes = javacNodes.iterator();
while (nodes.hasNext()) {
AntTaskNode taskNode = (AntTaskNode) nodes.next();
Task javacTask = taskNode.getTask();
if (javacTask instanceof UnknownElement) {
if (((UnknownElement) javacTask).getRealThing() == null) {
javacTask.maybeConfigure();
}
resolvedJavacTasks.add(((UnknownElement) javacTask).getRealThing());
} else {
resolvedJavacTasks.add(javacTask);
}
}
return resolvedJavacTasks;
}
private void getJavacNodes(List<AntTaskNode> javacNodes, IAntElement parent) {
if (!parent.hasChildren()) {
return;
}
List<IAntElement> children = parent.getChildNodes();
for (IAntElement node : children) {
if (node instanceof AntTargetNode) {
getJavacNodes(javacNodes, node);
} else if (node instanceof AntTaskNode) {
AntTaskNode task = (AntTaskNode) node;
if ("javac".equals(task.getName())) { //$NON-NLS-1$
javacNodes.add(task);
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IDialogPage#setVisible(boolean)
*/
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
if (visible) {
fLocationPathField.setFocus();
}
}
/**
* Creates the table which displays the available targets
*
* @param parent
* the parent composite
*/
private void createTargetsTable(Composite parent) {
Font font = parent.getFont();
Label label = new Label(parent, SWT.NONE);
label.setFont(font);
label.setText(DataTransferMessages.AntNewJavaProjectPage_3);
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gd.horizontalSpan = 3;
label.setLayoutData(gd);
Table table = new Table(parent, SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION);
GridData data = new GridData(GridData.FILL_BOTH);
int availableRows = availableRows(parent);
data.heightHint = table.getItemHeight() * (availableRows / 20);
data.widthHint = 250;
data.horizontalSpan = 3;
table.setLayoutData(data);
table.setFont(font);
fTableViewer = new TableViewer(table);
fTableViewer.setLabelProvider(new JavacTableLabelProvider());
fTableViewer.setContentProvider(new AntModelContentProvider());
fTableViewer.getControl().setEnabled(false);
}
/**
* Return the number of rows available in the current display using the current font.
*
* @param parent
* The Composite whose Font will be queried.
* @return int The result of the display size divided by the font size.
*/
private int availableRows(Composite parent) {
int fontHeight = (parent.getFont().getFontData())[0].getHeight();
int displayHeight = parent.getDisplay().getClientArea().height;
return displayHeight / fontHeight;
}
}