package com.redhat.ceylon.eclipse.code.wizard;
import static com.redhat.ceylon.eclipse.code.select.PackageSelectionDialog.selectPackage;
import static com.redhat.ceylon.eclipse.code.wizard.WizardUtil.getSelectedJavaElement;
import static com.redhat.ceylon.eclipse.ui.CeylonPlugin.PLUGIN_ID;
import static org.eclipse.core.resources.ResourcesPlugin.getWorkspace;
import static org.eclipse.jdt.core.IJavaElement.PACKAGE_FRAGMENT_ROOT;
import static org.eclipse.jdt.internal.ui.refactoring.nls.SourceContainerDialog.getSourceContainer;
import static org.eclipse.jface.dialogs.MessageDialog.openWarning;
import static org.eclipse.ui.PlatformUI.getWorkbench;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.wizards.NewSourceFolderCreationWizard;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.wizards.IWizardDescriptor;
import com.redhat.ceylon.eclipse.code.navigator.GenerateBuildPathActionGroup;
import com.redhat.ceylon.eclipse.ui.CeylonPlugin;
import com.redhat.ceylon.eclipse.util.EditorUtil;
class NewUnitWizardPage extends WizardPage {
private String unitName = "";
private IPackageFragmentRoot sourceDir;
private IPackageFragment packageFragment;
private String packageName = "";
private boolean includePreamble = true;
boolean shared = true;
private IStructuredSelection selection;
private IWorkbench workbench;
private Text unitNameText;
NewUnitWizardPage(String title, String description, String icon) {
super(title, title,
CeylonPlugin.imageRegistry()
.getDescriptor(icon));
setDescription(description);
}
@Override
public void createControl(Composite parent) {
initializeDialogUnits(parent);
initFromSelection();
Composite composite =
new Composite(parent, SWT.NONE);
composite.setFont(parent.getFont());
GridLayout layout = new GridLayout();
layout.numColumns = 4;
composite.setLayout(layout);
createControls(composite);
setControl(composite);
Dialog.applyDialogFont(composite);
setPageComplete(isComplete());
}
void createControls(Composite composite) {
Text name = createNameField(composite);
createDeclarationField(composite);
createSeparator(composite);
Text folder = createFolderField(composite);
createPackageField(composite, folder);
name.forceFocus();
}
void createSeparator(Composite composite) {
Label sep =
new Label(composite,
SWT.SEPARATOR | SWT.HORIZONTAL);
GridData sgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
sgd.horizontalSpan = 4;
sep.setLayoutData(sgd);
}
Text createNameField(Composite composite) {
Label nameLabel =
new Label(composite, SWT.LEFT | SWT.WRAP);
nameLabel.setText(getCompilationUnitLabel());
GridData lgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
lgd.horizontalSpan = 1;
nameLabel.setLayoutData(lgd);
final Text name =
new Text(composite, SWT.SINGLE | SWT.BORDER);
GridData ngd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
ngd.horizontalSpan = 2;
ngd.grabExcessHorizontalSpace = true;
name.setLayoutData(ngd);
name.setText(unitName);
name.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
unitName = name.getText();
if (!unitNameIsLegal()) {
setErrorMessage(
getIllegalUnitNameMessage());
}
else if (sourceDir==null) {
setErrorMessage(
getSelectSourceFolderMessage());
}
else if (!packageNameIsLegal()) {
setErrorMessage(
getIllegalPackageNameMessage());
}
else {
setErrorMessage(null);
}
setPageComplete(isComplete());
}
});
unitNameText = name;
new Label(composite, SWT.NONE);
new Label(composite, SWT.NONE);
Button includeHeader =
new Button(composite, SWT.CHECK);
includeHeader.setText(
"Include preamble in 'header.ceylon' in project root");
includeHeader.setSelection(includePreamble);
GridData igd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
igd.horizontalSpan = 3;
igd.grabExcessHorizontalSpace = true;
includeHeader.setLayoutData(igd);
includeHeader.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
includePreamble = !includePreamble;
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
new Label(composite, SWT.NONE);
Link link = new Link(composite, SWT.NONE);
link.setText("<a>Edit 'header.ceylon'...</a>");
GridData kgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
kgd.horizontalSpan = 2;
kgd.grabExcessHorizontalSpace = true;
link.setLayoutData(kgd);
link.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
if (sourceDir==null) {
openWarning(getShell(),
"No Source Folder",
getSelectSourceFolderMessage());
}
else {
EditDialog ed =
new EditDialog(getShell());
ed.setText(readHeader());
if (ed.open()==Status.OK) {
saveHeader(ed.getText());
}
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
new Label(composite, SWT.NONE);
return name;
}
String getCompilationUnitLabel() {
return "Compilation unit name: ";
}
private void setSourceDir(String folderName) {
try {
sourceDir = null;
IWorkspaceRoot root = getWorkspace().getRoot();
IJavaModel jm = JavaCore.create(root);
for (IJavaProject jp: jm.getJavaProjects()) {
for (IPackageFragmentRoot pfr:
jp.getPackageFragmentRoots()) {
String path =
pfr.getPath()
.toPortableString();
if (path.equals(folderName)) {
sourceDir = pfr;
return;
}
}
}
}
catch (JavaModelException jme) {
jme.printStackTrace();
}
}
Text createFolderField(Composite composite) {
Label folderLabel =
new Label(composite, SWT.LEFT | SWT.WRAP);
folderLabel.setText("Source folder: ");
GridData flgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
flgd.horizontalSpan = 1;
folderLabel.setLayoutData(flgd);
final Text folder =
new Text(composite, SWT.SINGLE | SWT.BORDER);
GridData fgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
fgd.horizontalSpan = 2;
fgd.grabExcessHorizontalSpace = true;
folder.setLayoutData(fgd);
if (sourceDir!=null) {
String folderName =
sourceDir.getPath()
.toPortableString();
folder.setText(folderName);
}
folder.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
setSourceDir(folder.getText());
if (sourceDir!=null &&
packageNameIsLegal()) {
packageFragment =
sourceDir.getPackageFragment(
packageName);
}
if (sourceDir==null) {
setErrorMessage(
getSelectSourceFolderMessage());
}
else if (!packageNameIsLegal()) {
setErrorMessage(
getIllegalPackageNameMessage());
}
else if (!unitNameIsLegal()) {
setErrorMessage(
getIllegalUnitNameMessage());
}
else {
setErrorMessage(null);
}
setPageComplete(isComplete());
}
});
Button selectFolder =
new Button(composite, SWT.PUSH);
selectFolder.setText("Browse...");
GridData sfgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
sfgd.horizontalSpan = 1;
selectFolder.setLayoutData(sfgd);
selectFolder.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
IPackageFragmentRoot pfr =
getSourceContainer(getShell(),
getWorkspace().getRoot(),
sourceDir);
if (pfr!=null) {
sourceDir = pfr;
String folderName =
sourceDir.getPath()
.toPortableString();
folder.setText(folderName);
packageFragment =
sourceDir.getPackageFragment(
packageName);
setPageComplete(isComplete());
}
if (sourceDir==null) {
setErrorMessage(
getSelectSourceFolderMessage());
}
else if (!packageNameIsLegal()) {
setErrorMessage(
getIllegalPackageNameMessage());
}
else if (!unitNameIsLegal()) {
setErrorMessage(
getIllegalUnitNameMessage());
}
else {
setErrorMessage(null);
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
new Label(composite, SWT.NONE);
Link link = new Link(composite, SWT.NONE);
link.setText("<a>Create new source folder...</a>");
GridData kgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
kgd.horizontalSpan = 3;
kgd.grabExcessHorizontalSpace = true;
link.setLayoutData(kgd);
link.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
Object firstElement = selection.getFirstElement();
if (firstElement == null) {
firstElement = EditorUtil.getProject(EditorUtil.getCurrentEditor());
}
GenerateBuildPathActionGroup.alsoManageCeylonConfigFile(
new Runnable() {
@Override
public void run() {
IPackageFragmentRoot pfr =
(IPackageFragmentRoot)
openSourceFolderWizard();
if (pfr!=null) {
sourceDir = pfr;
String folderName =
sourceDir.getPath()
.toPortableString();
folder.setText(folderName);
packageFragment =
sourceDir.getPackageFragment(
packageName);
setPageComplete(isComplete());
}
if (sourceDir==null) {
setErrorMessage(
getSelectSourceFolderMessage());
}
else if (!packageNameIsLegal()) {
setErrorMessage(
getIllegalPackageNameMessage());
}
else if (!unitNameIsLegal()) {
setErrorMessage(
getIllegalUnitNameMessage());
}
else {
setErrorMessage(null);
}
}
},
workbench.getDisplay().getActiveShell(),
Arrays.asList(firstElement));
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
return folder;
}
Text createPackageField(Composite composite, final Text folder) {
final Text pkg = createPackageField(composite);
new Label(composite, SWT.NONE);
Link link = new Link(composite, SWT.NONE);
link.setText("<a>Create new Ceylon package with descriptor...</a>");
GridData kgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
kgd.horizontalSpan = 3;
kgd.grabExcessHorizontalSpace = true;
link.setLayoutData(kgd);
link.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
NewPackageWizard wiz = openPackageWizard();
IPackageFragment pfr =
wiz.getPackageFragment();
if (pfr!=null) {
sourceDir = wiz.getSourceFolder();
String folderName =
sourceDir.getPath()
.toPortableString();
folder.setText(folderName);
pkg.setText(pfr.getElementName());
packageFragment = pfr;
setPageComplete(isComplete());
}
if (!packageNameIsLegal()) {
setErrorMessage(
getIllegalPackageNameMessage());
}
else if (sourceDir==null) {
setErrorMessage(
getSelectSourceFolderMessage());
}
else if (!unitNameIsLegal()) {
setErrorMessage(
getIllegalUnitNameMessage());
}
else {
setErrorMessage(null);
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
return pkg;
}
Text createPackageField(Composite composite) {
Label packageLabel =
new Label(composite, SWT.LEFT | SWT.WRAP);
packageLabel.setText(getPackageLabel());
GridData plgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
plgd.horizontalSpan = 1;
packageLabel.setLayoutData(plgd);
final Text pkg =
new Text(composite, SWT.SINGLE | SWT.BORDER);
GridData pgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
pgd.horizontalSpan = 2;
pgd.grabExcessHorizontalSpace = true;
pkg.setLayoutData(pgd);
pkg.setText(packageName);
pkg.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
packageName = pkg.getText();
if (sourceDir!=null &&
packageNameIsLegal()) {
packageFragment =
sourceDir.getPackageFragment(
packageName);
}
if (!packageNameIsLegal()) {
setErrorMessage(
getIllegalPackageNameMessage());
}
else if (sourceDir==null) {
setErrorMessage(
getSelectSourceFolderMessage());
}
else if (!unitNameIsLegal()) {
setErrorMessage(
getIllegalUnitNameMessage());
}
else {
setErrorMessage(null);
}
setPageComplete(isComplete());
}
});
/*if (packageFragment!=null) {
String pkgName = packageFragment.getElementName();
pkg.setText(pkgName);
}*/
Button selectPackage =
new Button(composite, SWT.PUSH);
selectPackage.setText("Browse...");
GridData spgd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
spgd.horizontalSpan = 1;
selectPackage.setLayoutData(spgd);
selectPackage.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
if (sourceDir==null) {
openWarning(getShell(),
"No Source Folder",
getSelectSourceFolderMessage());
}
else {
IPackageFragment result =
selectPackage(getShell(),
sourceDir);
if (result!=null) {
packageName = result.getElementName();
pkg.setText(packageName);
if (sourceDir!=null) {
packageFragment =
sourceDir.getPackageFragment(
packageName);
}
setPageComplete(isComplete());
}
if (!packageNameIsLegal()) {
setErrorMessage(
getIllegalPackageNameMessage());
}
else if (sourceDir==null) {
setErrorMessage(
getSelectSourceFolderMessage());
}
else if (!unitNameIsLegal()) {
setErrorMessage(
getIllegalUnitNameMessage());
}
else {
setErrorMessage(null);
}
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
return pkg;
}
private NewPackageWizard openPackageWizard() {
IWizardDescriptor descriptor =
getWorkbench()
.getNewWizardRegistry()
.findWizard(PLUGIN_ID + ".newPackageWizard");
if (descriptor!=null) {
try {
NewPackageWizard wizard =
(NewPackageWizard)
descriptor.createWizard();
wizard.init(workbench, selection);
Shell shell =
Display.getCurrent()
.getActiveShell();
WizardDialog wd =
new WizardDialog(shell, wizard);
wd.setTitle(wizard.getWindowTitle());
wd.open();
return wizard;
}
catch (CoreException e) {
e.printStackTrace();
}
}
return null;
}
private IJavaElement openSourceFolderWizard() {
IWizardDescriptor descriptor =
getWorkbench()
.getNewWizardRegistry()
.findWizard("org.eclipse.jdt.ui.wizards.NewSourceFolderCreationWizard");
if (descriptor!=null) {
try {
NewSourceFolderCreationWizard wizard =
(NewSourceFolderCreationWizard)
descriptor.createWizard();
wizard.init(workbench, selection);
Shell shell =
Display.getCurrent()
.getActiveShell();
WizardDialog wd =
new WizardDialog(shell, wizard);
wd.setTitle(wizard.getWindowTitle());
wd.open();
return wizard.getCreatedElement();
}
catch (CoreException e) {
e.printStackTrace();
}
}
return null;
}
void createSharedField(Composite composite) {
new Label(composite, SWT.NONE);
Button sharedPackage =
new Button(composite, SWT.CHECK);
sharedPackage.setText(getSharedPackageLabel());
sharedPackage.setSelection(shared);
GridData igd =
new GridData(GridData.HORIZONTAL_ALIGN_FILL);
igd.horizontalSpan = 3;
igd.grabExcessHorizontalSpace = true;
sharedPackage.setLayoutData(igd);
sharedPackage.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
shared = !shared;
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
}
void createDeclarationField(Composite composite) {}
String getSharedPackageLabel() {
return "Create shared package (visible to other modules)";
}
String getPackageLabel() {
return "Package: ";
}
public void initFromSelection() {
IJavaElement je = getSelectedJavaElement(selection);
if (je instanceof IJavaProject) {
IJavaProject jp = (IJavaProject) je;
if (jp.isOpen()) {
//default to the first source dir
//we find in the selected project
try {
for (IPackageFragmentRoot pfr:
jp.getAllPackageFragmentRoots()) {
if (!pfr.isExternal() &&
!pfr.isArchive()) {
je = pfr;
break;
}
}
}
catch (JavaModelException e) {}
}
}
if (je instanceof IPackageFragmentRoot) {
sourceDir = (IPackageFragmentRoot) je;
packageFragment =
sourceDir.getPackageFragment("");
packageName =
packageFragment.getElementName();
}
else if (je instanceof IPackageFragment) {
packageFragment = (IPackageFragment) je;
packageName =
packageFragment.getElementName();
sourceDir =
(IPackageFragmentRoot)
packageFragment.getAncestor(
PACKAGE_FRAGMENT_ROOT);
}
}
public void init(IWorkbench workbench, IStructuredSelection selection) {
this.selection = selection;
this.workbench = workbench;
}
boolean isComplete() {
return packageNameIsLegal() &&
unitNameIsLegal() &&
sourceDir!=null &&
sourceDir.getPackageFragment(
packageFragment.getElementName())
.equals(packageFragment);
}
IFile getFile() {
String filename =
unitName.endsWith(".ceylon") ?
unitName :
unitName + ".ceylon";
IPath path =
packageFragment.getPath()
.append(filename);
IProject project =
sourceDir.getJavaProject()
.getProject();
IPath relativePath =
path.makeRelativeTo(project.getFullPath());
return project.getFile(relativePath);
}
public IPackageFragment getPackageFragment() {
return packageFragment;
}
public IPackageFragmentRoot getSourceDir() {
return sourceDir;
}
String getUnitName() {
return getFileNameWithoutExtension();
}
Text getUnitNameText() {
return unitNameText;
}
public boolean isIncludePreamble() {
return includePreamble;
}
public boolean isShared() {
return shared;
}
private String readHeader() {
//TODO: use IRunnableWithProgress
StringBuilder sb = new StringBuilder();
IFile file = getHeaderFile();
if (file.exists() && file.isAccessible()) {
InputStream stream = null;
try {
stream = file.getContents();
BufferedReader reader =
new BufferedReader(
new InputStreamReader(stream));
String line;
while ((line = reader.readLine())!=null) {
sb.append(line)
.append(System.lineSeparator());
}
}
catch (Exception ex) {
ex.printStackTrace();
}
finally {
try {
if (stream!=null) stream.close();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
return sb.toString();
}
private void saveHeader(String header) {
//TODO: use IRunnableWithProgress
IFile file = getHeaderFile();
ByteArrayInputStream stream = null;
try {
if (file.exists()) {
file.delete(true, null);
}
stream = new ByteArrayInputStream(
header.getBytes()); //TODO: encoding
file.create(stream, true, null);
}
catch (CoreException e) {
e.printStackTrace();
}
finally {
try {
if (stream!=null) {
stream.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
private IFile getHeaderFile() {
IProject project =
sourceDir.getJavaProject()
.getProject();
return project.getFile("header.ceylon");
}
private boolean unitNameIsLegal() {
return unitName!=null &&
unitIsNameLegal(unitName);
}
boolean unitIsNameLegal(String unitName) {
return unitName.matches("(\\w|-)+(\\.ceylon)?");
}
private String getIllegalUnitNameMessage() {
return "Please enter a legal compilation unit name.";
}
private String getSelectSourceFolderMessage() {
return "Please select a source folder.";
}
/*private static final String KEYWORDS
= escaping_.get_().concatenateKeywords("|");
static final String KEYWORD_PATTERN =
".*\\b(" + KEYWORDS + ")\\b.*";*/
boolean packageNameIsLegal(String packageName) {
return packageName.isEmpty() ||
packageName.matches("^[a-z_]\\w*(\\.[a-z_]\\w*)*$") /*&&
!packageName.matches(KEYWORD_PATTERN)*/;
}
private boolean packageNameIsDiscouraged() {
return packageName.matches("^(ceylon|java|javax)\\b.*");
}
private boolean packageNameIsLegal() {
return packageName!=null &&
packageNameIsLegal(packageName);
}
String getIllegalPackageNameMessage() {
/*if (packageName.matches(KEYWORD_PATTERN)) {
return getIllegalPackageNameMessageStart() +
"\n (May not contain keywords).";
}
else {*/
return getIllegalPackageNameMessageStart() +
"\n (Must be a period-separated list of initial-lowercase identifiers).";
// }
}
String getIllegalPackageNameMessageStart() {
return "Please enter a legal package name.";
}
void setUnitName(String unitName) {
this.unitName = unitName;
}
@Override
public void setPageComplete(boolean complete) {
if (packageNameIsDiscouraged()) {
setMessage(getDiscouragedNamespaceMessage(),
WARNING);
}
else {
setMessage(null);
}
if (complete) {
for (String filename: getFileNames()) {
IPath path =
packageFragment.getPath()
.append(filename)
.addFileExtension("ceylon");
IFile file =
getWorkspace().getRoot()
.getFile(path);
if (file.exists()) {
setMessage("Existing unit will not be overwritten: " +
path.toPortableString(),
WARNING);
break;
}
}
}
super.setPageComplete(complete);
}
String getDiscouragedNamespaceMessage() {
return "Discouraged namespace: " +
packageName.split("\\.")[0];
}
private String getFileNameWithoutExtension() {
if (unitName.endsWith(".ceylon")) {
return unitName.substring(0,
unitName.length()-7);
}
else {
return unitName;
}
}
String[] getFileNames() {
return new String[] { getFileNameWithoutExtension() };
}
}