package com.redhat.ceylon.eclipse.code.refactor; 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.ui.PlatformUI.getWorkbench; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; 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.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.dialogs.IMessageProvider; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; 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.Text; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.wizards.IWizardDescriptor; import com.redhat.ceylon.eclipse.code.select.PackageSelectionDialog; import com.redhat.ceylon.eclipse.code.wizard.EditDialog; import com.redhat.ceylon.eclipse.code.wizard.NewPackageWizard; /* * TODO: this class is a huge copy/paste job of NewUnitWizardPage */ public class MoveToNewUnitWizardPage extends UserInputWizardPage { 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; public MoveToNewUnitWizardPage(String title) { super(title); } @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) { createTitle(composite); Text name = createNameField(composite); createDeclarationField(composite); createSeparator(composite); Text folder = createFolderField(composite); createPackageField(composite, folder); name.forceFocus(); } private void createTitle(Composite composite) { Label title = new Label(composite, SWT.LEFT); MoveToNewUnitRefactoring refactoring = (MoveToNewUnitRefactoring) getRefactoring(); String name = refactoring.getNode() .getDeclarationModel() .getName(); title.setText("Move '" + name + "' to a new source file."); GridData gd = new GridData(); gd.horizontalSpan=4; title.setLayoutData(gd); GridData gd2 = new GridData(GridData.FILL_HORIZONTAL); gd2.horizontalSpan=4; new Label(composite, SWT.SEPARATOR|SWT.HORIZONTAL) .setLayoutData(gd2); } 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) { MessageDialog.openWarning(getShell(), "No Source Folder", getSelectSourceFolderMessage()); } else { EditDialog d = new EditDialog(getShell()); d.setText(readHeader()); if (d.open()==Status.OK) { saveHeader(d.getText()); } } } @Override public void widgetDefaultSelected(SelectionEvent e) {} }); new Label(composite, SWT.NONE); return name; } String getCompilationUnitLabel() { return "Compilation unit name: "; } 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()); } private void setSourceDir(String folderName) { try { sourceDir = null; IJavaProject[] projects = JavaCore.create(getWorkspace().getRoot()) .getJavaProjects(); for (IJavaProject jp: projects) { for (IPackageFragmentRoot pfr: jp.getPackageFragmentRoots()) { if (pfr.getPath() .toPortableString() .equals(folderName)) { sourceDir = pfr; return; } } } } catch (JavaModelException jme) { jme.printStackTrace(); } } }); 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) { 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); } } @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) { MessageDialog.openWarning(getShell(), "No Source Folder", getSelectSourceFolderMessage()); } else { IPackageFragment result = PackageSelectionDialog.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); WizardDialog wd = new WizardDialog( Display.getCurrent() .getActiveShell(), 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); WizardDialog wd = new WizardDialog( Display.getCurrent() .getActiveShell(), 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); } public IFile getFile() { String fileName = unitName; if (!fileName.endsWith(".ceylon")) { fileName += ".ceylon"; } IPath path = packageFragment.getPath() .append(fileName); IProject project = sourceDir.getJavaProject() .getProject(); return project.getFile(path.makeRelativeTo(project.getFullPath())); } public IPackageFragment getPackageFragment() { return packageFragment; } public IPackageFragmentRoot getSourceDir() { return sourceDir; } String getUnitName() { return unitName; } 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() { return sourceDir.getJavaProject() .getProject() .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."; } 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() { return "Please enter a legal package name (a period-separated list of all-lowercase identifiers)."; } public void setUnitName(String unitName) { this.unitName = unitName; } @Override public void setPageComplete(boolean complete) { if (packageNameIsDiscouraged()) { setMessage(getDiscouragedNamespaceMessage(), WARNING); } else { setMessage(null); } if (complete) { if (!packageFragment.exists()) { setMessage("Package does not exist: " + packageFragment.getElementName(), IMessageProvider.ERROR); super.setPageComplete(false); return; } for (String file: getFileNames()) { IPath path = packageFragment.getPath() .append(file) .addFileExtension("ceylon"); if (getWorkspace() .getRoot() .getFile(path) .exists()) { setMessage("Existing unit will not be overwritten: " + path.toPortableString(), IMessageProvider.ERROR); super.setPageComplete(false); return; } } MoveToNewUnitRefactoring refactoring = (MoveToNewUnitRefactoring) getRefactoring(); refactoring.setTargetProject( getPackageFragment() .getResource() .getProject()); refactoring.setTargetFile(getFile()); refactoring.setTargetPackage(getPackageFragment()); refactoring.setIncludePreamble(isIncludePreamble()); } super.setPageComplete(complete); } String getDiscouragedNamespaceMessage() { return "Discouraged namespace: " + packageName.split("\\.")[0]; } String[] getFileNames() { return new String[] { unitName }; } }