package com.redhat.ceylon.eclipse.code.preferences; import static com.redhat.ceylon.compiler.typechecker.TypeChecker.LANGUAGE_MODULE_VERSION; import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.getCeylonSystemRepo; import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.interpolateVariablesInRepositoryPath; import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.modelJ2C; import static org.eclipse.jface.layout.GridDataFactory.swtDefaults; import static org.eclipse.ui.views.navigator.ResourceComparator.NAME; import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.internal.ui.wizards.TypedElementSelectionValidator; import org.eclipse.jdt.internal.ui.wizards.TypedViewerFilter; import org.eclipse.jdt.internal.ui.wizards.buildpaths.FolderSelectionDialog; import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.Window; 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.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.DirectoryDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.dialogs.ISelectionStatusValidator; import org.eclipse.ui.model.WorkbenchContentProvider; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.views.navigator.ResourceComparator; import com.redhat.ceylon.common.Constants; import com.redhat.ceylon.common.config.CeylonConfigFinder; import com.redhat.ceylon.common.config.Repositories; import com.redhat.ceylon.eclipse.ui.CeylonPlugin; import com.redhat.ceylon.eclipse.ui.CeylonResources; import com.redhat.ceylon.ide.common.configuration.CeylonRepositoryConfigurator; import com.redhat.ceylon.ide.common.model.CeylonProjectConfig; @SuppressWarnings("serial") public class CeylonRepoConfigBlock extends CeylonRepositoryConfigurator { public interface ValidationCallback { void validationResultChange(boolean isValid, String message); } private IProject project; private ValidationCallback validationCallback; private Text systemRepoText; private Text outputRepoText; private Table lookupRepoTable; private Button systemRepoBrowseButton; private Button outputRepoBrowseButton; private Button addRepoButton; private Button addExternalRepoButton; private Button addAetherRepoButton; private Button addRemoteRepoButton; private Button removeRepoButton; private Button upButton; private Button downButton; private CeylonModuleResolutionBlock moduleResolutionBlock; public CeylonRepoConfigBlock(ValidationCallback validationCallback) { this.validationCallback = validationCallback; moduleResolutionBlock = new CeylonModuleResolutionBlock(); } public IProject getProject() { return project; } public Boolean getFlatClasspath() { return moduleResolutionBlock.getFlatClasspath(); } public String getOverrides() { return moduleResolutionBlock.getOverrides(); } public Boolean getAutoExportMavenDependencies() { return moduleResolutionBlock.getAutoExportMavenDependencies(); } public Boolean getFullyExportMavenDependencies() { return moduleResolutionBlock.getFullyExportMavenDependencies(); } public String getSystemRepo() { return systemRepoText.getText(); } public String getOutputRepo() { return outputRepoText.getText(); } public void performDefaults() { systemRepoText.setText(""); outputRepoText.setText(Repositories.withConfig( CeylonConfigFinder.loadDefaultConfig(null)) .getOutputRepository() .getUrl()); lookupRepoTable.removeAll(); moduleResolutionBlock.performDefaults(); validate(); } public void initState(IProject project, boolean isCeylonNatureEnabled) { this.project = project; String systemRepo = getCeylonSystemRepo(project); if( systemRepo == null || systemRepo.equals("${ceylon.repo}") ) { systemRepoText.setText(""); } else { systemRepoText.setText(systemRepo); } systemRepoText.setEnabled(isCeylonNatureEnabled); systemRepoBrowseButton.setEnabled(isCeylonNatureEnabled); outputRepoText.setEnabled(isCeylonNatureEnabled); outputRepoBrowseButton.setEnabled(isCeylonNatureEnabled); lookupRepoTable.setEnabled(isCeylonNatureEnabled); lookupRepoTable.removeAll(); if (isCeylonNatureEnabled) { CeylonProjectConfig config = modelJ2C().ceylonModel() .getProject(project) .getConfiguration(); loadFromConfiguration(config); outputRepoText.setText(config.getOutputRepo()); } else { outputRepoText.setText(Constants.DEFAULT_MODULE_DIR); } addRepoButton.setEnabled(isCeylonNatureEnabled); addExternalRepoButton.setEnabled(isCeylonNatureEnabled); addAetherRepoButton.setEnabled(isCeylonNatureEnabled); addRemoteRepoButton.setEnabled(isCeylonNatureEnabled); moduleResolutionBlock.initState(project, isCeylonNatureEnabled); } public void initContents(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout(2, false)); composite.setLayoutData(swtDefaults() .grab(true, true) .align(SWT.FILL, SWT.FILL) .create()); initSystemRepoInput(composite); initSystemRepoBrowseButton(composite); initOutputRepoInput(composite); initOutputRepoBrowseButton(composite); initLookupRepoTable(composite); Composite lookupRepoButtons = new Composite(composite, SWT.NONE); lookupRepoButtons.setLayout(new GridLayout(1, false)); lookupRepoButtons.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.TOP) .span(1, 4) .create()); initAddRepoButton(lookupRepoButtons); initAddExternalRepoButton(lookupRepoButtons); initAddAetherRepoButton(lookupRepoButtons); initAddRemoteRepoButton(lookupRepoButtons); initRemoveRepoButton(lookupRepoButtons); initUpDownButtons(lookupRepoButtons); moduleResolutionBlock.initContents(composite); performDefaults(); } private void initSystemRepoInput(Composite composite) { Label systemRepoLabel = new Label(composite, SWT.LEFT | SWT.WRAP); systemRepoLabel.setText( "System repository (contains language module)"); systemRepoLabel.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .span(2, 1) .grab(true, false) .create()); systemRepoText = new Text(composite, SWT.SINGLE | SWT.BORDER); systemRepoText.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .grab(true, false) .create()); systemRepoText.setMessage("IDE System Modules"); systemRepoText.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { String systemRepoUrl = systemRepoText.getText(); if( systemRepoUrl==null || systemRepoUrl.isEmpty() ) { String path = CeylonPlugin.getInstance() .getCeylonRepository() .getAbsolutePath(); systemRepoText.setToolTipText(path); } else { systemRepoText.setToolTipText(""); } validate(); } }); } private void initSystemRepoBrowseButton(final Composite composite) { systemRepoBrowseButton = new Button(composite, SWT.PUSH); systemRepoBrowseButton.setText("Browse..."); systemRepoBrowseButton.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .create()); systemRepoBrowseButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { String result = new DirectoryDialog(composite.getShell(), SWT.SHEET).open(); if (result != null) { systemRepoText.setText(result); } } }); } private void initOutputRepoInput(Composite composite) { Label outputRepoLabel = new Label(composite, SWT.LEFT | SWT.WRAP); outputRepoLabel.setText( "Output repository (contains compiled module archives)"); outputRepoLabel.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .span(2, 1) .grab(true, false) .indent(0, 10) .create()); outputRepoText = new Text(composite, SWT.SINGLE | SWT.BORDER); outputRepoText.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .grab(true, false) .create()); outputRepoText.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { validate(); } }); } private void initOutputRepoBrowseButton(final Composite composite) { outputRepoBrowseButton = new Button(composite, SWT.PUSH); outputRepoBrowseButton.setText("Browse..."); outputRepoBrowseButton.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .create()); outputRepoBrowseButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { IResource result = openSelectRelativeFolderDialog(composite, "Output Repository", "Select a workspace folder for compiled module archives"); if (result != null) { String outputRepoUrl = "." + File.separator + result.getFullPath() .removeFirstSegments(1); outputRepoText.setText(outputRepoUrl); } } }); } private void initLookupRepoTable(Composite composite) { Label lookupRepoLabel = new Label(composite, SWT.LEFT | SWT.WRAP); lookupRepoLabel.setText("Lookup repositories on build path:"); lookupRepoLabel.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .span(2, 1) .grab(true, false) .indent(0, 10) .create()); lookupRepoTable = new Table(composite, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); lookupRepoTable.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.FILL) .grab(true, true) .hint(250, 220) .create()); lookupRepoTable.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateButtonState(); } }); } private void initAddRepoButton(final Composite buttons) { addRepoButton = new Button(buttons, SWT.PUSH); addRepoButton.setText("Add Repository..."); addRepoButton.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .create()); addRepoButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { IResource result = openSelectRelativeFolderDialog(buttons, "Add Repository", "Select a module repository in the workspace"); if( result != null ) { String repo = "." + File.separator + result.getFullPath() .removeFirstSegments(1); addExternalRepo(repo); validate(); } } }); } private void initAddExternalRepoButton(final Composite buttons) { addExternalRepoButton = new Button(buttons, SWT.PUSH); addExternalRepoButton.setText("Add External Repository..."); addExternalRepoButton.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .create()); addExternalRepoButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { String result = new DirectoryDialog(buttons.getShell(), SWT.SHEET).open(); if (result != null) { addExternalRepo(result); validate(); } } }); } private void initAddAetherRepoButton(final Composite buttons) { addAetherRepoButton = new Button(buttons, SWT.PUSH); addAetherRepoButton.setText("Add Maven Repository..."); addAetherRepoButton.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .create()); addAetherRepoButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { AetherRepositoryDialog dlg = new AetherRepositoryDialog(buttons.getShell()); int result = dlg.open(); if (result == InputDialog.OK) { addAetherRepo(dlg.getValue()); } } }); } private void initAddRemoteRepoButton(final Composite buttons) { addRemoteRepoButton = new Button(buttons, SWT.PUSH); addRemoteRepoButton.setText("Add Remote Repository..."); addRemoteRepoButton.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .create()); addRemoteRepoButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { IInputValidator inputValidator = new IInputValidator() { @Override public String isValid(String val) { try { // FIXME: we might want to validate it more than that: for example to check that it's http/https URI uri = new URI(val); if (!uri.isAbsolute()) { return "Unsupported URI: missing scheme"; } return null; } catch (URISyntaxException e) { return "Invalid URI: " + e.getReason(); } } }; InputDialog input = new InputDialog(buttons.getShell(), "Add Remote Repository", "Enter URI of remote module repository", "http://", inputValidator); int result = input.open(); if (result == InputDialog.OK) { addRemoteRepo(input.getValue()); } } }); } private void initRemoveRepoButton(Composite buttons) { removeRepoButton = new Button(buttons, SWT.PUSH); removeRepoButton.setText("Remove Repository"); removeRepoButton.setEnabled(false); removeRepoButton.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER).create()); removeRepoButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { removeSelectedRepo(); lookupRepoTable.deselectAll(); } }); } private void initUpDownButtons(Composite buttons) { upButton = new Button(buttons, SWT.PUSH); upButton.setText("Up"); upButton.setEnabled(false); upButton.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .indent(0, 10) .create()); upButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { moveSelectedReposUp(); } }); downButton = new Button(buttons, SWT.PUSH); downButton.setText("Down"); downButton.setEnabled(false); downButton.setLayoutData(swtDefaults() .align(SWT.FILL, SWT.CENTER) .create()); downButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { moveSelectedReposDown(); } }); } private void validate() { if (!isSystemRepoValid()) { validationCallback.validationResultChange(false, "Please select a system module repository containing the language module"); } else if (!isOutputRepoValid()) { validationCallback.validationResultChange(false, "Please select a output module repository inside project"); } else { validationCallback.validationResultChange(true, null); } } private boolean isSystemRepoValid() { String systemRepoUrl = systemRepoText.getText(); if( systemRepoUrl == null || systemRepoUrl.isEmpty() ) { return true; } systemRepoUrl = interpolateVariablesInRepositoryPath(systemRepoUrl); String ceylonLanguageSubdir = File.separator + "ceylon"+ File.separator + "language"+ File.separator + LANGUAGE_MODULE_VERSION; String ceylonLanguageFileName = File.separator + "ceylon.language-" + LANGUAGE_MODULE_VERSION + ".car"; IPath systemRepoPath = new Path(systemRepoUrl); if (! systemRepoPath.isAbsolute()) { systemRepoPath = project.getLocation() .append(systemRepoPath); } File systemRepoFile = systemRepoPath.toFile(); File ceylonLanguageFile = new File(systemRepoFile + ceylonLanguageSubdir + ceylonLanguageFileName); if (ceylonLanguageFile.exists() && ceylonLanguageFile.isFile()) { return true; } return false; } private boolean isOutputRepoValid() { String outputRepoUrl = outputRepoText.getText(); if (outputRepoUrl.startsWith("./") || outputRepoUrl.startsWith(".\\")) { return true; } return false; } private IResource openSelectRelativeFolderDialog(Control control, String title, String description) { IWorkspaceRoot root = project.getWorkspace().getRoot(); Class<?>[] acceptedClasses = new Class[] { IProject.class, IFolder.class }; ISelectionStatusValidator validator = new TypedElementSelectionValidator(acceptedClasses, false); IProject[] allProjects = root.getProjects(); ArrayList<IProject> rejectedElements = new ArrayList<IProject> (allProjects.length); for (int i= 0; i < allProjects.length; i++) { if (!allProjects[i].equals(project)) { rejectedElements.add(allProjects[i]); } } ViewerFilter filter = new TypedViewerFilter(acceptedClasses, rejectedElements.toArray()); IResource container = null; FolderSelectionDialog dialog = new FolderSelectionDialog(control.getShell(), new WorkbenchLabelProvider(), new WorkbenchContentProvider()); dialog.setTitle(title); dialog.setValidator(validator); dialog.setMessage(description); dialog.addFilter(filter); dialog.setInput(root); dialog.setInitialSelection(container); dialog.setComparator(new ResourceComparator(NAME)); if (dialog.open() == Window.OK) { return (IResource) dialog.getFirstResult(); } return null; } @Override public Object addAllRepositoriesToList(String[] repos) { for (String repo : repos) { TableItem tableItem = new TableItem(lookupRepoTable, SWT.NONE); tableItem.setText(repo); tableItem.setImage(CeylonResources.REPO); } return null; } @Override public Object addRepositoryToList(long index, String repo) { TableItem tableItem = new TableItem(lookupRepoTable, SWT.NONE, (int) index); tableItem.setText(repo); tableItem.setImage(CeylonResources.REPO); lookupRepoTable.setSelection((int) index); return null; } @Override public Object enableDownButton(boolean enabled) { downButton.setEnabled(enabled); return null; } @Override public Object enableRemoveButton(boolean enabled) { removeRepoButton.setEnabled(enabled); return null; } @Override public Object enableUpButton(boolean enabled) { upButton.setEnabled(enabled); return null; } @Override public int[] getSelection() { return lookupRepoTable.getSelectionIndices(); } @Override public String removeRepositoryFromList(long index) { String repo = lookupRepoTable.getItem((int) index) .getText(); lookupRepoTable.deselectAll(); lookupRepoTable.remove((int) index); return repo; } }