/******************************************************************************* * Copyright (c) 2000, 2011 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 *******************************************************************************/ package com.redhat.ceylon.eclipse.code.preferences; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.DEFAULT_RESOURCE_FOLDER; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.DEFAULT_SOURCE_FOLDER; import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.getCeylonModulesOutputFolder; import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.modelJ2C; import static com.redhat.ceylon.eclipse.util.CeylonHelper.toJavaStringList; import java.io.File; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IWorkspaceRoot; 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.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaModelStatus; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaConventions; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.corext.util.Messages; import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.internal.ui.JavaPluginImages; import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; import org.eclipse.jdt.internal.ui.dialogs.StatusUtil; import org.eclipse.jdt.internal.ui.util.CoreUtility; import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels; import org.eclipse.jdt.internal.ui.viewsupport.ImageDisposer; import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; import org.eclipse.jdt.internal.ui.wizards.TypedElementSelectionValidator; import org.eclipse.jdt.internal.ui.wizards.TypedViewerFilter; import org.eclipse.jdt.internal.ui.wizards.buildpaths.BuildPathBasePage; import org.eclipse.jdt.internal.ui.wizards.buildpaths.BuildPathSupport; import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElement; import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListLabelProvider; //import org.eclipse.jdt.internal.ui.wizards.buildpaths.ClasspathOrderingWorkbookPage; import org.eclipse.jdt.internal.ui.wizards.buildpaths.FolderSelectionDialog; //import org.eclipse.jdt.internal.ui.wizards.buildpaths.LibrariesWorkbookPage; import org.eclipse.jdt.internal.ui.wizards.buildpaths.ProjectsWorkbookPage; import org.eclipse.jdt.internal.ui.wizards.dialogfields.CheckedListDialogField; import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField; import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener; import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter; import org.eclipse.jdt.internal.ui.wizards.dialogfields.IStringButtonAdapter; import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField; import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonDialogField; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.ui.PreferenceConstants; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.MenuAdapter; import org.eclipse.swt.events.MenuEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PartInitException; import org.eclipse.ui.dialogs.ISelectionStatusValidator; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.model.WorkbenchContentProvider; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; import org.eclipse.ui.views.navigator.ResourceComparator; import com.redhat.ceylon.common.Constants; import com.redhat.ceylon.common.config.CeylonConfig; import com.redhat.ceylon.common.config.CeylonConfigFinder; import com.redhat.ceylon.eclipse.code.editor.Navigation; import com.redhat.ceylon.eclipse.ui.CeylonPlugin; import com.redhat.ceylon.eclipse.ui.CeylonResources; import com.redhat.ceylon.ide.common.model.BaseCeylonProject; import com.redhat.ceylon.ide.common.model.CeylonProject; import com.redhat.ceylon.ide.common.model.CeylonProjectConfig; import com.redhat.ceylon.ide.common.model.resourceDirectoriesFromCeylonConfig_; import com.redhat.ceylon.ide.common.model.sourceDirectoriesFromCeylonConfig_; import ceylon.interop.java.CeylonStringIterable; public class CeylonBuildPathsBlock { private final class CeylonConfigNotInSyncListener extends SelectionAdapter { @Override public void widgetSelected(SelectionEvent e) { if (".ceylon/config".equals(e.text)) { IFile configFile= fCurrJProject.getProject().getFile(".ceylon/config"); if (configFile.exists()) { if (! configFile.isSynchronized(IResource.DEPTH_ZERO)) { try { configFile.refreshLocal(IResource.DEPTH_ZERO, null); } catch (CoreException e1) { } } try { Navigation.openInEditor(configFile); } catch (PartInitException e1) { } } else { MessageDialog.openInformation(getShell(), "Ceylon Configuration File", "No configuration file exist\n" + "Default vaues apply :\n" + " 'source' for source files\n" + " 'resource' for resource files"); } } else if ("use".equals(e.text)) { refreshSourcePathsFromConfigFile(); if (fSourceContainerPage != null) { fSourceContainerPage.init(fCurrJProject); } updateUI(); } else if ("resolve".equals(e.text)) { final Set<String> sourceFoldersFromCeylonConfig = new TreeSet<String>(); final Set<String> sourceFoldersFromEclipseProject = new TreeSet<String>(); final Set<String> resourceFoldersFromCeylonConfig = new TreeSet<String>(); final Set<String> resourceFoldersFromEclipseProject = new TreeSet<String>(); fillBuildPathsSetsForComparison(fCurrJProject.getProject(), sourceFoldersFromCeylonConfig, sourceFoldersFromEclipseProject, resourceFoldersFromCeylonConfig, resourceFoldersFromEclipseProject); class BuildPathsComparisonDialog extends Dialog { Set<String> resultSourcesSet = new TreeSet<>(); Set<String> resultResourcesSet = new TreeSet<>(); Tree resultPathsTree; TreeItem resultSources; TreeItem resultResources; final String CONFLICTING = "conflicting"; final String RESULT_FOLDER_SET = "resultFolderSet"; protected BuildPathsComparisonDialog() { super(fSWTWidget.getShell()); } @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setText("Ceylon Build Paths Conflict Resolution"); newShell.setMinimumSize(700, 700); } @Override protected Control createDialogArea(Composite parent) { Color red = Display.getCurrent().getSystemColor(SWT.COLOR_RED); Composite composite = (Composite) super.createDialogArea(parent); GridLayout layout = (GridLayout) composite.getLayout(); layout.numColumns = 1; Group comparisonArea = new Group(composite, SWT.NONE); comparisonArea.setText("Conflicting build paths"); comparisonArea.setLayoutData(new GridData(GridData.FILL_BOTH)); GridLayout comparisonLayout = new GridLayout(); comparisonLayout.numColumns = 2; comparisonLayout.makeColumnsEqualWidth= true; comparisonLayout.verticalSpacing = 5; comparisonArea.setLayout(comparisonLayout); Label explanationLabel = new Label(comparisonArea, SWT.NONE); explanationLabel.setText("The red entries show conflicts.\n" + "You can decide what to do with them through the context menu."); explanationLabel.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); GridData explanationGridData = new GridData(GridData.FILL_HORIZONTAL); explanationGridData.horizontalSpan = 2; explanationLabel.setLayoutData(explanationGridData); Group resultArea = new Group(composite, SWT.NONE); resultArea.setText("Merged build paths"); resultArea.setLayoutData(new GridData(GridData.FILL_BOTH)); GridLayout resultLayout = new GridLayout(); resultLayout.numColumns = 1; resultArea.setLayout(resultLayout); resultPathsTree = new Tree(resultArea, SWT.NONE); resultPathsTree.setLayoutData(new GridData(GridData.FILL_BOTH)); Label label = new Label(comparisonArea, SWT.NONE); label.setText("Eclipse project"); label = new Label(comparisonArea, SWT.NONE); label.setText("Ceylon configuration file"); final Tree projectBasedPathsTree = new Tree(comparisonArea, SWT.NONE); projectBasedPathsTree.setLayoutData(new GridData(GridData.FILL_BOTH)); projectBasedPathsTree.addFocusListener(new FocusListener() { @Override public void focusLost(FocusEvent e) { projectBasedPathsTree.setSelection(new TreeItem[0]); } @Override public void focusGained(FocusEvent e) { } }); final Tree configBasedPathsTree = new Tree(comparisonArea, SWT.NONE); configBasedPathsTree.setLayoutData(new GridData(GridData.FILL_BOTH)); configBasedPathsTree.addFocusListener(new FocusListener() { @Override public void focusLost(FocusEvent e) { configBasedPathsTree.setSelection(new TreeItem[0]); } @Override public void focusGained(FocusEvent e) { } }); final TreeItem projectBasedSources = new TreeItem(projectBasedPathsTree, SWT.NONE); projectBasedSources.setText("Sources"); final TreeItem projectBasedResources = new TreeItem(projectBasedPathsTree, SWT.NONE); projectBasedResources.setText("Resources"); final TreeItem configBasedSources = new TreeItem(configBasedPathsTree, SWT.NONE); configBasedSources.setText("Sources"); final TreeItem configBasedResources = new TreeItem(configBasedPathsTree, SWT.NONE); configBasedResources.setText("Resources"); resultSources = new TreeItem(resultPathsTree, SWT.NONE); resultSources.setText("Sources"); resultResources = new TreeItem(resultPathsTree, SWT.NONE); resultResources.setText("Resources"); TreeItem pathItem = null; for (String folder : sourceFoldersFromEclipseProject) { pathItem = new TreeItem(projectBasedSources, SWT.NONE); pathItem.setText(folder); if (! sourceFoldersFromCeylonConfig.contains(folder)) { pathItem.setForeground(red); pathItem.setData(CONFLICTING, true); } else { resultSourcesSet.add(folder); pathItem.setData(CONFLICTING, false); } pathItem.setData(RESULT_FOLDER_SET, resultSourcesSet); } for (String folder : resourceFoldersFromEclipseProject) { pathItem = new TreeItem(projectBasedResources, SWT.NONE); pathItem.setText(folder); if (! resourceFoldersFromCeylonConfig.contains(folder)) { pathItem.setForeground(red); pathItem.setData(CONFLICTING, true); } else { resultResourcesSet.add(folder); pathItem.setData(CONFLICTING, false); } pathItem.setData(RESULT_FOLDER_SET, resultResourcesSet); } for (String folder : sourceFoldersFromCeylonConfig) { pathItem = new TreeItem(configBasedSources, SWT.NONE); pathItem.setText(folder); if (! sourceFoldersFromEclipseProject.contains(folder)) { pathItem.setForeground(red); pathItem.setData(CONFLICTING, true); } else { resultSourcesSet.add(folder); pathItem.setData(CONFLICTING, false); } pathItem.setData(RESULT_FOLDER_SET, resultSourcesSet); } for (String folder : resourceFoldersFromCeylonConfig) { pathItem = new TreeItem(configBasedResources, SWT.NONE); pathItem.setText(folder); if (! resourceFoldersFromEclipseProject.contains(folder)) { pathItem.setForeground(red); pathItem.setData(CONFLICTING, true); } else { resultResourcesSet.add(folder); pathItem.setData(CONFLICTING, false); } pathItem.setData(RESULT_FOLDER_SET, resultResourcesSet); } updateResultTree(); projectBasedSources.setExpanded(true); projectBasedResources.setExpanded(true); configBasedSources.setExpanded(true); configBasedResources.setExpanded(true); setupMenu(projectBasedPathsTree); setupMenu(configBasedPathsTree); return composite; } private void setupMenu(final Tree projectBasedPathsTree) { final Menu projectBasedMenu = new Menu(projectBasedPathsTree); projectBasedPathsTree.setMenu(projectBasedMenu); projectBasedMenu.addMenuListener(new MenuAdapter() { public void menuShown(MenuEvent e) { MenuItem[] items = projectBasedMenu.getItems(); for (int i = 0; i < items.length; i++) { items[i].dispose(); } TreeItem[] selection = projectBasedPathsTree.getSelection(); if (selection.length > 0) { final TreeItem selectedItem = selection[0]; if ((Boolean)selectedItem.getData(CONFLICTING)) { MenuItem newItem = new MenuItem(projectBasedMenu, SWT.NONE); @SuppressWarnings("unchecked") final Set<String> resultFolderSet = (Set<String>)selectedItem.getData(RESULT_FOLDER_SET); final boolean alreadyInResult = resultFolderSet.contains(selectedItem.getText()); newItem.setText((alreadyInResult ? "Remove from" : "Add to") + " merged build paths"); newItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e) { if (alreadyInResult) { resultFolderSet.remove(selectedItem.getText()); } else { resultFolderSet.add(selectedItem.getText()); } updateResultTree(); } }); } } } }); } private void updateResultTree() { TreeItem pathItem; resultSources.removeAll(); for (String folder : resultSourcesSet) { pathItem = new TreeItem(resultSources, SWT.NONE); pathItem.setText(folder); } resultResources.removeAll(); for (String folder : resultResourcesSet) { pathItem = new TreeItem(resultResources, SWT.NONE); pathItem.setText(folder); } resultSources.setExpanded(true); resultResources.setExpanded(true); } } BuildPathsComparisonDialog dialog = new BuildPathsComparisonDialog(); if (dialog.open() == Dialog.OK && ! (dialog.resultSourcesSet.equals(sourceFoldersFromEclipseProject) && dialog.resultResourcesSet.equals(resourceFoldersFromEclipseProject))) { updateClassPathsFromConfigFile(Arrays.asList(dialog.resultSourcesSet.toArray(new String[0])), new HashSet<String>()); if (fSourceContainerPage != null) { fSourceContainerPage.init(fCurrJProject); } updateUI(); } } } } public static interface IRemoveOldBinariesQuery { /** * Do the callback. Returns <code>true</code> if .class files should be removed from the * old output location. * @param removeLocation true if the folder at oldOutputLocation should be removed, false if only its content * @param oldOutputLocation The old output location * @return Returns true if .class files should be removed. * @throws OperationCanceledException if the operation was canceled */ boolean doQuery(boolean removeLocation, IPath oldOutputLocation) throws OperationCanceledException; } private IWorkspaceRoot fWorkspaceRoot; private CheckedListDialogField<CPListElement> fClassPathList; private CheckedListDialogField<CPListElement> fResourcePathList; private StringButtonDialogField fJavaBuildPathDialogField; private Link fNotInSyncText; private boolean wasInSyncWhenOpening; private boolean someFoldersNeedToBeCreated; private StatusInfo fClassPathStatus; private StatusInfo fOutputFolderStatus; private StatusInfo fBuildPathStatus; private IJavaProject fCurrJProject; private IPath fJavaOutputLocationPath; private IStatusChangeListener fContext; private Control fSWTWidget; private TabFolder fTabFolder; private int fPageIndex; private SourceContainerWorkbookPage fSourceContainerPage; private ResourceContainerWorkbookPage fResourceContainerPage; private ProjectsWorkbookPage fProjectsPage; // private LibrariesWorkbookPage fLibrariesPage; private BuildPathBasePage fCurrPage; private String fUserSettingsTimeStamp; private long fFileTimeStamp; //private IRunnableContext fRunnableContext; //private boolean fUseNewPage; private final IWorkbenchPreferenceContainer fPageContainer; // null when invoked from a non-property page context private final static int IDX_UP= 0; private final static int IDX_DOWN= 1; private final static int IDX_TOP= 3; private final static int IDX_BOTTOM= 4; private final static int IDX_SELECT_ALL= 6; private final static int IDX_UNSELECT_ALL= 7; public CeylonBuildPathsBlock(/*IRunnableContext runnableContext,*/ IStatusChangeListener context, int pageToShow, /*boolean useNewPage,*/ IWorkbenchPreferenceContainer pageContainer) { fPageContainer= pageContainer; fWorkspaceRoot= JavaPlugin.getWorkspace().getRoot(); fContext= context; //fUseNewPage= useNewPage; fPageIndex= pageToShow; fSourceContainerPage= null; fNotInSyncText = null; fResourceContainerPage=null; // fLibrariesPage= null; fProjectsPage= null; fCurrPage= null; //fRunnableContext= runnableContext; JavaBuildPathAdapter jadapter= new JavaBuildPathAdapter(); String[] buttonLabels= new String[] { /* IDX_UP */ NewWizardMessages.BuildPathsBlock_classpath_up_button, /* IDX_DOWN */ NewWizardMessages.BuildPathsBlock_classpath_down_button, /* 2 */ null, /* IDX_TOP */ NewWizardMessages.BuildPathsBlock_classpath_top_button, /* IDX_BOTTOM */ NewWizardMessages.BuildPathsBlock_classpath_bottom_button, /* 5 */ null, /* IDX_SELECT_ALL */ NewWizardMessages.BuildPathsBlock_classpath_checkall_button, /* IDX_UNSELECT_ALL */ NewWizardMessages.BuildPathsBlock_classpath_uncheckall_button }; fClassPathList= new CheckedListDialogField<CPListElement>(jadapter, buttonLabels, new CPListLabelProvider()); fClassPathList.setDialogFieldListener(jadapter); fClassPathList.setLabelText(NewWizardMessages.BuildPathsBlock_classpath_label); fClassPathList.setUpButtonIndex(IDX_UP); fClassPathList.setDownButtonIndex(IDX_DOWN); fClassPathList.setCheckAllButtonIndex(IDX_SELECT_ALL); fClassPathList.setUncheckAllButtonIndex(IDX_UNSELECT_ALL); fClassPathList.setDialogFieldListener(new IDialogFieldListener() { @Override public void dialogFieldChanged(DialogField field) { System.out.print(""); } }); fResourcePathList= new CheckedListDialogField<CPListElement>(jadapter, buttonLabels, new ResourceListLabelProvider()); fResourcePathList.setDialogFieldListener(jadapter); fResourcePathList.setLabelText("Build &resource path order"); fResourcePathList.setUpButtonIndex(IDX_UP); fResourcePathList.setDownButtonIndex(IDX_DOWN); fResourcePathList.setCheckAllButtonIndex(IDX_SELECT_ALL); fResourcePathList.setUncheckAllButtonIndex(IDX_UNSELECT_ALL); fJavaBuildPathDialogField= new StringButtonDialogField(jadapter); fJavaBuildPathDialogField.setButtonLabel(NewWizardMessages.BuildPathsBlock_buildpath_button); fJavaBuildPathDialogField.setDialogFieldListener(jadapter); //fJavaPathDialogField.setLabelText(NewWizardMessages.BuildPathsBlock_buildpath_label); fJavaBuildPathDialogField.setLabelText("Default Java binary class output folder:"); fBuildPathStatus= new StatusInfo(); fClassPathStatus= new StatusInfo(); fOutputFolderStatus= new StatusInfo(); fCurrJProject= null; } public boolean wasInSyncWithCeylonConfigWhenOpening() { return wasInSyncWhenOpening; } public boolean isInSyncWithCeylonConfig() { if (fCurrJProject == null) { return true; } IProject project = fCurrJProject.getProject(); Set<String> sourceFoldersFromCeylonConfig = new TreeSet<String>(); Set<String> sourceFoldersFromEclipseProject = new TreeSet<String>(); Set<String> resourceFoldersFromCeylonConfig = new TreeSet<String>(); Set<String> resourceFoldersFromEclipseProject = new TreeSet<String>(); fillBuildPathsSetsForComparison(project, sourceFoldersFromCeylonConfig, sourceFoldersFromEclipseProject, resourceFoldersFromCeylonConfig, resourceFoldersFromEclipseProject); return sourceFoldersFromCeylonConfig.equals(sourceFoldersFromEclipseProject) && resourceFoldersFromCeylonConfig.equals(resourceFoldersFromEclipseProject); } private void fillBuildPathsSetsForComparison(IProject project, Set<String> sourceFoldersFromCeylonConfig, Set<String> sourceFoldersFromEclipseProject, Set<String> resourceFoldersFromCeylonConfig, Set<String> resourceFoldersFromEclipseProject) { CeylonProjectConfig ceylonConfig = modelJ2C().ceylonModel().getProject(project).getConfiguration(); for (String path : toJavaStringList(ceylonConfig.getProjectSourceDirectories())) { sourceFoldersFromCeylonConfig.add(Path.fromOSString(path).toString()); } for (String path : toJavaStringList(ceylonConfig.getProjectResourceDirectories())) { resourceFoldersFromCeylonConfig.add(Path.fromOSString(path).toString()); } for (CPListElement elem : fClassPathList.getElements()) { if (elem.getClasspathEntry().getEntryKind() == IClasspathEntry.CPE_SOURCE) { IPath path = null; if (elem.getLinkTarget() == null) { path = elem.getPath().makeRelativeTo(project.getFullPath()); } else { path = elem.getLinkTarget(); } sourceFoldersFromEclipseProject.add(path.toString()); } } for (CPListElement elem : fResourcePathList.getElements()) { if (elem.getClasspathEntry().getEntryKind() == IClasspathEntry.CPE_SOURCE) { IPath path = null; if (elem.getLinkTarget() == null) { path = elem.getPath().makeRelativeTo(project.getFullPath()); } else { path = elem.getLinkTarget(); } resourceFoldersFromEclipseProject.add(path.toString()); } } if (sourceFoldersFromEclipseProject.isEmpty()) { sourceFoldersFromEclipseProject.add(Constants.DEFAULT_SOURCE_DIR); } if (resourceFoldersFromEclipseProject.isEmpty()) { resourceFoldersFromEclipseProject.add(Constants.DEFAULT_RESOURCE_DIR); } } // -------- UI creation --------- public Control createControl(Composite parent) { fSWTWidget= parent; Composite composite= new Composite(parent, SWT.NONE); composite.setFont(parent.getFont()); GridLayout layout= new GridLayout(); layout.marginWidth= 0; layout.marginHeight= 0; layout.numColumns= 1; composite.setLayout(layout); fNotInSyncText = new Link(composite, SWT.NONE); wasInSyncWhenOpening = isInSyncWithCeylonConfig(); fNotInSyncText.setVisible(! wasInSyncWhenOpening); GridData notInSyncLayoutData = new GridData(GridData.FILL_HORIZONTAL); notInSyncLayoutData.exclude = wasInSyncWhenOpening; fNotInSyncText.setLayoutData(notInSyncLayoutData); fNotInSyncText.setText("The Ceylon configuration file (<a>.ceylon/config</a>) is not in sync with the current\n" + "Ceylon Build Paths. You can :\n" + " - simply overwrite the Ceylon configuration with OK\n" + " - <a>use</a> the original configuration file settings\n" + " - <a>resolve</a> the conflicts yourself."); fNotInSyncText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED)); fNotInSyncText.addSelectionListener(new CeylonConfigNotInSyncListener()); TabFolder folder= new TabFolder(composite, SWT.NONE); folder.setLayoutData(new GridData(GridData.FILL_BOTH)); folder.setFont(composite.getFont()); TabItem item; item= new TabItem(folder, SWT.NONE); item.setText(NewWizardMessages.BuildPathsBlock_tab_source); item.setImage(JavaPluginImages.get(JavaPluginImages.IMG_OBJS_PACKFRAG_ROOT)); /*if (fUseNewPage) { fSourceContainerPage= new NewSourceContainerWorkbookPage(fClassPathList, fBuildPathDialogField, fRunnableContext, this); } else {*/ fSourceContainerPage= new SourceContainerWorkbookPage(fClassPathList, fJavaBuildPathDialogField); //} item.setData(fSourceContainerPage); item.setControl(fSourceContainerPage.getControl(folder)); item= new TabItem(folder, SWT.NONE); item.setText("Resources"); item.setImage(CeylonResources.FOLDER); fResourceContainerPage = new ResourceContainerWorkbookPage(fResourcePathList, fJavaBuildPathDialogField); item.setData(fResourceContainerPage); item.setControl(fResourceContainerPage.getControl(folder)); IWorkbench workbench= JavaPlugin.getDefault().getWorkbench(); Image projectImage= workbench.getSharedImages().getImage(IDE.SharedImages.IMG_OBJ_PROJECT); fProjectsPage= new ProjectsWorkbookPage(fClassPathList, fPageContainer); item= new TabItem(folder, SWT.NONE); item.setText(NewWizardMessages.BuildPathsBlock_tab_projects); item.setImage(projectImage); item.setData(fProjectsPage); item.setControl(fProjectsPage.getControl(folder)); // fLibrariesPage= new LibrariesWorkbookPage(fClassPathList, fPageContainer); // item= new TabItem(folder, SWT.NONE); // item.setText(NewWizardMessages.BuildPathsBlock_tab_libraries); // item.setImage(JavaPluginImages.get(JavaPluginImages.IMG_OBJS_LIBRARY)); // item.setData(fLibrariesPage); // item.setControl(fLibrariesPage.getControl(folder)); // a non shared image Image cpoImage= JavaPluginImages.DESC_TOOL_CLASSPATH_ORDER.createImage(); composite.addDisposeListener(new ImageDisposer(cpoImage)); // ClasspathOrderingWorkbookPage ordpage= new ClasspathOrderingWorkbookPage(fClassPathList); // item= new TabItem(folder, SWT.NONE); // item.setText(NewWizardMessages.BuildPathsBlock_tab_order); // item.setImage(cpoImage); // item.setData(ordpage); // item.setControl(ordpage.getControl(folder)); if (fCurrJProject != null) { fSourceContainerPage.init(fCurrJProject); fResourceContainerPage.init(fCurrJProject); // fLibrariesPage.init(fCurrJProject); fProjectsPage.init(fCurrJProject); } folder.setSelection(fPageIndex); fCurrPage= (BuildPathBasePage) folder.getItem(fPageIndex).getData(); folder.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { tabChanged(e.item); } }); fTabFolder= folder; Dialog.applyDialogFont(composite); return composite; } private Shell getShell() { if (fSWTWidget != null) { return fSWTWidget.getShell(); } return JavaPlugin.getActiveWorkbenchShell(); } /** * Initializes the classpath for the given project. Multiple calls to init are allowed, * but all existing settings will be cleared and replace by the given or default paths. * @param jproject The java project to configure. Does not have to exist. * @param javaOutputLocation The output location to be set in the page. If <code>null</code> * is passed, jdt default settings are used, or - if the project is an existing Java project- the * output location of the existing project * @param classpathEntries The classpath entries to be set in the page. If <code>null</code> * is passed, jdt default settings are used, or - if the project is an existing Java project - the * classpath entries of the existing project */ public void init(IJavaProject jproject, IPath javaOutputLocation, IClasspathEntry[] classpathEntries, boolean javaCompilationEnabled) { fCurrJProject= jproject; boolean projectExists= false; someFoldersNeedToBeCreated = false; final List<CPListElement> newClassPath; IProject project= fCurrJProject.getProject(); projectExists= (project.exists() && project.getFile(".classpath").exists()); //$NON-NLS-1$ List<String> configSourceDirectories; List<String> configResourceDirectories; if (projectExists) { CeylonProjectConfig config; CeylonProject ceylonProject = modelJ2C().ceylonModel().getProject(project); if (ceylonProject != null) { config = ceylonProject.getConfiguration(); } else { config = new CeylonProjectConfig(ceylonProject); } configSourceDirectories = toJavaStringList(config.getProjectSourceDirectories()); configResourceDirectories = toJavaStringList(config.getProjectResourceDirectories()); } else { File configFile = jproject.getProject().getFile(".ceylon/config").getLocation().toFile(); CeylonConfig ceylonConfig; try { ceylonConfig = CeylonConfigFinder.DEFAULT.loadConfigFromFile(configFile); configSourceDirectories = toJavaStringList(sourceDirectoriesFromCeylonConfig_.sourceDirectoriesFromCeylonConfig(ceylonConfig)); configResourceDirectories = toJavaStringList(resourceDirectoriesFromCeylonConfig_.resourceDirectoriesFromCeylonConfig(ceylonConfig)); } catch (IOException e) { configSourceDirectories = Collections.emptyList(); configResourceDirectories = Collections.emptyList(); } } IClasspathEntry[] existingEntries= null; if (projectExists) { if (javaOutputLocation == null) { javaOutputLocation= fCurrJProject.readOutputLocation(); } existingEntries= fCurrJProject.readRawClasspath(); if (classpathEntries == null) { classpathEntries= existingEntries; //TODO: read existing ceylon output location from classpathEntries } } if (javaOutputLocation == null) { javaOutputLocation= getDefaultJavaOutputLocation(jproject); } if (classpathEntries != null) { newClassPath= getCPListElements(classpathEntries, existingEntries); } else { newClassPath= getDefaultClassPath(jproject); } Set<String> newFolderNames = new HashSet<>(); final List<CPListElement> newResourcePath = new ArrayList<CPListElement>(); if (!configResourceDirectories.isEmpty()) { someFoldersNeedToBeCreated = resourcePathsFromStrings(fCurrJProject, configResourceDirectories, newFolderNames, newResourcePath); } else { String defaultResourceFolderName = CeylonPlugin.getPreferences().getString(DEFAULT_RESOURCE_FOLDER); IFolder defaultResourceFolder = fCurrJProject.getProject().getFolder(defaultResourceFolderName); newResourcePath.add(new CPListElement(fCurrJProject, IClasspathEntry.CPE_SOURCE, defaultResourceFolder.getFullPath(), defaultResourceFolder)); } List<CPListElement> exportedEntries = new ArrayList<CPListElement>(); for (int i= 0; i < newClassPath.size(); i++) { CPListElement curr= newClassPath.get(i); if (curr.isExported() || curr.getEntryKind() == IClasspathEntry.CPE_SOURCE) { exportedEntries.add(curr); } } fJavaOutputLocationPath = javaOutputLocation.makeRelative(); // inits the dialog field fJavaBuildPathDialogField.setText(fJavaOutputLocationPath.toString()); fJavaBuildPathDialogField.enableButton(project.exists()); fClassPathList.setElements(newClassPath); fClassPathList.setCheckedElements(exportedEntries); if (! projectExists) { IPreferenceStore store= PreferenceConstants.getPreferenceStore(); if (!configSourceDirectories.isEmpty() && store.getBoolean(PreferenceConstants.SRCBIN_FOLDERS_IN_NEWPROJ)) { updateClassPathsFromConfigFile(configSourceDirectories, newFolderNames); } } fClassPathList.selectFirstElement(); fResourcePathList.setElements(newResourcePath); // fResourcePathList.setCheckedElements(exportedEntries); fResourcePathList.selectFirstElement(); if (fSourceContainerPage != null) { fSourceContainerPage.init(fCurrJProject); fResourceContainerPage.init(fCurrJProject); fProjectsPage.init(fCurrJProject); // fLibrariesPage.init(fCurrJProject); } initializeTimeStamps(); updateUI(); } public static boolean resourcePathsFromStrings(final IJavaProject javaProject, List<String> configResourceDirectories, Set<String> newFolderNames, final List<CPListElement> newResourcePath) { boolean someFoldersNeedToBeCreated = false; IProject project = javaProject.getProject(); for (final String path: configResourceDirectories) { final IPath iPath = Path.fromOSString(path); if (! iPath.isAbsolute()) { IFolder folder = project.getFolder(iPath); newResourcePath.add(new CPListElement(javaProject, IClasspathEntry.CPE_SOURCE, folder.getFullPath(), folder)); if (!folder.exists()) { someFoldersNeedToBeCreated = true; } } else { try { class CPListElementHolder { public CPListElement value = null; } final CPListElementHolder cpListElement = new CPListElementHolder(); project.accept(new IResourceVisitor() { @Override public boolean visit(IResource resource) throws CoreException { if (resource instanceof IFolder && resource.isLinked() && resource.getLocation() != null && resource.getLocation().equals(iPath)) { cpListElement.value = new CPListElement(null, javaProject, IClasspathEntry.CPE_SOURCE, resource.getFullPath(), resource, resource.getLocation()); return false; } return resource instanceof IFolder || resource instanceof IProject; } }); if (cpListElement.value == null) { String newFolderName = iPath.lastSegment(); IFolder newFolder = project.getFolder(newFolderName); int counter = 1; while (newFolderNames.contains(newFolderName) || newFolder.exists()) { newFolderName = iPath.lastSegment() + "_" + counter++; newFolder = project.getFolder(newFolderName); } newFolderNames.add(newFolderName); cpListElement.value = new CPListElement(null, javaProject, IClasspathEntry.CPE_SOURCE, newFolder.getFullPath(), newFolder, iPath); someFoldersNeedToBeCreated = true; } newResourcePath.add(cpListElement.value); } catch (CoreException e) { e.printStackTrace(); } } } return someFoldersNeedToBeCreated; } protected void updateUI() { if (fSWTWidget == null || fSWTWidget.isDisposed()) { return; } if (Display.getCurrent() != null) { doUpdateUI(); } else { Display.getDefault().asyncExec(new Runnable() { public void run() { if (fSWTWidget == null || fSWTWidget.isDisposed()) { return; } doUpdateUI(); } }); } } protected void doUpdateUI() { boolean isInSync = isInSyncWithCeylonConfig(); boolean notInSyncWasVisible = fNotInSyncText.isVisible(); fNotInSyncText.setVisible(! isInSync); GridData notInSyncLayoutData = (GridData) fNotInSyncText.getLayoutData(); notInSyncLayoutData.exclude = isInSync; fJavaBuildPathDialogField.refresh(); fClassPathList.refresh(); fResourcePathList.refresh(); doStatusLineUpdate(); if (notInSyncWasVisible && isInSync) { fNotInSyncText.getParent().layout(true); } } private String getEncodedSettings() { StringBuffer buf= new StringBuffer(); CPListElement.appendEncodePath(fJavaOutputLocationPath, buf).append(';'); int nElements= fClassPathList.getSize(); buf.append('[').append(nElements).append(']'); for (int i= 0; i < nElements; i++) { CPListElement elem= fClassPathList.getElement(i); elem.appendEncodedSettings(buf); } nElements= fResourcePathList.getSize(); buf.append('[').append(nElements).append(']'); for (int i= 0; i < nElements; i++) { CPListElement elem= fResourcePathList.getElement(i); elem.appendEncodedSettings(buf); } return buf.toString(); } public boolean hasChangesInDialog() { String currSettings= getEncodedSettings(); return !currSettings.equals(fUserSettingsTimeStamp) || someFoldersNeedToBeCreated; } public boolean hasChangesInClasspathFile() { IFile file= fCurrJProject.getProject().getFile(".classpath"); //$NON-NLS-1$ return fFileTimeStamp != file.getModificationStamp(); } public boolean isClassfileMissing() { return !fCurrJProject.getProject().getFile(".classpath").exists(); //$NON-NLS-1$ } public void initializeTimeStamps() { IFile file= fCurrJProject.getProject().getFile(".classpath"); //$NON-NLS-1$ fFileTimeStamp= file.getModificationStamp(); fUserSettingsTimeStamp= getEncodedSettings(); } private ArrayList<CPListElement> getCPListElements(IClasspathEntry[] classpathEntries, IClasspathEntry[] existingEntries) { List<IClasspathEntry> existing= existingEntries == null ? Collections.<IClasspathEntry>emptyList() : Arrays.asList(existingEntries); ArrayList<CPListElement> newClassPath= new ArrayList<CPListElement>(); for (int i= 0; i < classpathEntries.length; i++) { IClasspathEntry curr= classpathEntries[i]; newClassPath.add(CPListElement.create(curr, ! existing.contains(curr), fCurrJProject)); } return newClassPath; } // -------- public api -------- /** * @return Returns the Java project. Can return <code>null<code> if the page has not * been initialized. */ public IJavaProject getJavaProject() { return fCurrJProject; } /** * @return Returns the current output location. Note that the path returned must not be valid. */ public IPath getJavaOutputLocation() { String text = fJavaBuildPathDialogField.getText(); if (text.isEmpty()) { return null; } else { return new Path(text).makeAbsolute(); } } /** * @return Returns the current class path (raw). Note that the entries returned must not be valid. */ public IClasspathEntry[] getRawClassPath() { List<CPListElement> elements= fClassPathList.getElements(); int nElements= elements.size(); IClasspathEntry[] entries= new IClasspathEntry[elements.size()]; for (int i= 0; i < nElements; i++) { CPListElement currElement= elements.get(i); entries[i]= currElement.getClasspathEntry(); } return entries; } public int getPageIndex() { return fPageIndex; } // -------- evaluate default settings -------- private List<CPListElement> getDefaultClassPath(IJavaProject jproj) { List<CPListElement> list= new ArrayList<CPListElement>(); IResource srcFolder; IPreferenceStore store= PreferenceConstants.getPreferenceStore(); String sourceFolderName= CeylonPlugin.getPreferences().getString(DEFAULT_SOURCE_FOLDER); if (store.getBoolean(PreferenceConstants.SRCBIN_FOLDERS_IN_NEWPROJ) && sourceFolderName.length() > 0) { srcFolder= jproj.getProject().getFolder(sourceFolderName); } else { srcFolder= jproj.getProject(); } list.add(new CPListElement(jproj, IClasspathEntry.CPE_SOURCE, srcFolder.getFullPath(), srcFolder)); IClasspathEntry[] jreEntries= PreferenceConstants.getDefaultJRELibrary(); list.addAll(getCPListElements(jreEntries, null)); return list; } public static IPath getDefaultJavaOutputLocation(IJavaProject jproj) { return jproj.getProject().getFullPath().append("classes"); } private class JavaBuildPathAdapter implements IStringButtonAdapter, IDialogFieldListener, IListAdapter<CPListElement> { // -------- IStringButtonAdapter -------- public void changeControlPressed(DialogField field) { buildPathChangeControlPressed(field); } // ---------- IDialogFieldListener -------- public void dialogFieldChanged(DialogField field) { buildPathDialogFieldChanged(field); } // ---------- IListAdapter -------- public void customButtonPressed(ListDialogField<CPListElement> field, int index) { buildPathCustomButtonPressed(field, index); } public void doubleClicked(ListDialogField<CPListElement> field) { } public void selectionChanged(ListDialogField<CPListElement> field) { updateTopButtonEnablement(); } } private void buildPathChangeControlPressed(DialogField field) { if (field == fJavaBuildPathDialogField) { IContainer container= chooseContainer(fJavaOutputLocationPath); if (container != null) { fJavaBuildPathDialogField.setText(container.getFullPath().makeRelative().toString()); } } } public void updateTopButtonEnablement() { fClassPathList.enableButton(IDX_BOTTOM, fClassPathList.canMoveDown()); fClassPathList.enableButton(IDX_TOP, fClassPathList.canMoveUp()); } public void buildPathCustomButtonPressed(ListDialogField<CPListElement> field, int index) { List<CPListElement> elems= field.getSelectedElements(); field.removeElements(elems); if (index == IDX_BOTTOM) { field.addElements(elems); } else if (index == IDX_TOP) { field.addElements(elems, 0); } } private void buildPathDialogFieldChanged(DialogField field) { if (field == fClassPathList) { updateClassPathStatus(); updateTopButtonEnablement(); } else if (field == fJavaBuildPathDialogField) { updateJavaOutputLocationStatus(); } doStatusLineUpdate(); } // -------- verification ------------------------------- private void doStatusLineUpdate() { if (Display.getCurrent() != null) { IStatus res= findMostSevereStatus(); fContext.statusChanged(res); } } private IStatus findMostSevereStatus() { return StatusUtil.getMostSevere(new IStatus[] { fClassPathStatus, fOutputFolderStatus, fBuildPathStatus }); } /** * Validates the build path. */ public void updateClassPathStatus() { fClassPathStatus.setOK(); List<CPListElement> elements= fClassPathList.getElements(); CPListElement entryMissing= null; CPListElement entryDeprecated= null; int nEntriesMissing= 0; IClasspathEntry[] entries= new IClasspathEntry[elements.size()]; for (int i= elements.size()-1 ; i >= 0 ; i--) { CPListElement currElement= elements.get(i); boolean isChecked= fClassPathList.isChecked(currElement); if (currElement.getEntryKind() == IClasspathEntry.CPE_SOURCE) { if (!isChecked) { fClassPathList.setCheckedWithoutUpdate(currElement, true); } if (!fClassPathList.isGrayed(currElement)) { fClassPathList.setGrayedWithoutUpdate(currElement, true); } } else { currElement.setExported(isChecked); } entries[i]= currElement.getClasspathEntry(); if (currElement.isMissing()) { nEntriesMissing++; if (entryMissing == null) { entryMissing= currElement; } } if (entryDeprecated == null & currElement.isDeprecated()) { entryDeprecated= currElement; } } if (nEntriesMissing > 0) { if (nEntriesMissing == 1) { fClassPathStatus.setWarning(Messages.format(NewWizardMessages.BuildPathsBlock_warning_EntryMissing, BasicElementLabels.getPathLabel(entryMissing.getPath(), false))); } else { fClassPathStatus.setWarning(Messages.format(NewWizardMessages.BuildPathsBlock_warning_EntriesMissing, String.valueOf(nEntriesMissing))); } } else if (entryDeprecated != null) { fClassPathStatus.setInfo(entryDeprecated.getDeprecationMessage()); } /* if (fCurrJProject.hasClasspathCycle(entries)) { fClassPathStatus.setWarning(NewWizardMessages.getString("BuildPathsBlock.warning.CycleInClassPath")); //$NON-NLS-1$ } */ updateBuildPathStatus(); } /** * Validates output location & build path. */ private void updateJavaOutputLocationStatus() { fJavaOutputLocationPath= null; String text= fJavaBuildPathDialogField.getText(); if ("".equals(text)) { //$NON-NLS-1$ fOutputFolderStatus.setError(NewWizardMessages.BuildPathsBlock_error_EnterBuildPath); return; } IPath path= getJavaOutputLocation(); fJavaOutputLocationPath= path; IResource res= fWorkspaceRoot.findMember(path); if (res != null) { // if exists, must be a folder or project if (res.getType() == IResource.FILE) { fOutputFolderStatus.setError(NewWizardMessages.BuildPathsBlock_error_InvalidBuildPath); return; } } fOutputFolderStatus.setOK(); String pathStr= fJavaBuildPathDialogField.getText(); Path outputPath= (new Path(pathStr)); pathStr= outputPath.lastSegment(); if (pathStr.equals(".settings") && outputPath.segmentCount() == 2) { //$NON-NLS-1$ fOutputFolderStatus.setWarning(NewWizardMessages.OutputLocation_SettingsAsLocation); } if (pathStr.charAt(0) == '.' && pathStr.length() > 1) { fOutputFolderStatus.setWarning(Messages.format(NewWizardMessages.OutputLocation_DotAsLocation, BasicElementLabels.getResourceName(pathStr))); } updateBuildPathStatus(); } private void updateBuildPathStatus() { List<CPListElement> elements= fClassPathList.getElements(); IClasspathEntry[] entries= new IClasspathEntry[elements.size()]; for (int i= elements.size()-1 ; i >= 0 ; i--) { CPListElement currElement= elements.get(i); entries[i]= currElement.getClasspathEntry(); } IJavaModelStatus status= JavaConventions.validateClasspath(fCurrJProject, entries, fJavaOutputLocationPath); if (!status.isOK()) { fBuildPathStatus.setError(status.getMessage()); return; } fBuildPathStatus.setOK(); } // -------- creation ------------------------------- public static void createProject(IProject project, URI locationURI, IProgressMonitor monitor) throws CoreException { if (monitor == null) { monitor= new NullProgressMonitor(); } monitor.beginTask(NewWizardMessages.BuildPathsBlock_operationdesc_project, 10); // create the project try { if (!project.exists()) { IProjectDescription desc= project.getWorkspace() .newProjectDescription(project.getName()); if (locationURI != null && ResourcesPlugin.getWorkspace() .getRoot().getLocationURI().equals(locationURI)) { locationURI= null; } desc.setLocationURI(locationURI); project.create(desc, monitor); monitor= null; } if (!project.isOpen()) { project.open(monitor); monitor= null; } } finally { if (monitor != null) { monitor.done(); } } } public static void addJavaNature(IProject project, IProgressMonitor monitor) throws CoreException { if (monitor != null && monitor.isCanceled()) { throw new OperationCanceledException(); } if (!project.hasNature(JavaCore.NATURE_ID)) { IProjectDescription description = project.getDescription(); String[] prevNatures= description.getNatureIds(); String[] newNatures= new String[prevNatures.length + 1]; System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length); newNatures[prevNatures.length]= JavaCore.NATURE_ID; description.setNatureIds(newNatures); project.setDescription(description, monitor); } else { if (monitor != null) { monitor.worked(1); } } } public void configureJavaProject(IProgressMonitor monitor) throws CoreException, OperationCanceledException { configureJavaProject(null, monitor); } public void configureJavaProject(String newProjectCompliance, IProgressMonitor monitor) throws CoreException, OperationCanceledException { flush(fClassPathList.getElements(), fResourcePathList.getElements(), getJavaOutputLocation(), getJavaProject(), newProjectCompliance, monitor); initializeTimeStamps(); updateUI(); } /** * Sets the configured build path and output location to the given Java project. * If the project already exists, only build paths are updated. * <p> * If the classpath contains an Execution Environment entry, the EE's compiler compliance options * are used as project-specific options (unless the classpath already contained the same Execution Environment) * * @param classPathEntries the new classpath entries (list of {@link CPListElement}) * @param javaOutputLocation the output location * @param javaProject the Java project * @param newProjectCompliance compliance to set for a new project, can be <code>null</code> * @param monitor a progress monitor, or <code>null</code> * @throws CoreException if flushing failed * @throws OperationCanceledException if flushing has been cancelled */ public static void flush(List<CPListElement> classPathEntries, List<CPListElement> resourcePathEntries, IPath javaOutputLocation, IJavaProject javaProject, String newProjectCompliance, IProgressMonitor monitor) throws CoreException, OperationCanceledException { if (monitor == null) { monitor= new NullProgressMonitor(); } monitor.setTaskName(NewWizardMessages.BuildPathsBlock_operationdesc_java); monitor.beginTask("", classPathEntries.size() * 4 + 4); //$NON-NLS-1$ try { IProject project= javaProject.getProject(); IPath projPath= project.getFullPath(); IPath oldOutputLocation; try { oldOutputLocation= javaProject.getOutputLocation(); } catch (CoreException e) { oldOutputLocation= projPath.append(PreferenceConstants.getPreferenceStore() .getString(PreferenceConstants.SRCBIN_BINNAME)); } if (oldOutputLocation.equals(projPath) && !javaOutputLocation.equals(projPath)) { if (CeylonBuildPathsBlock.hasClassfiles(project)) { if (CeylonBuildPathsBlock.getRemoveOldBinariesQuery(JavaPlugin.getActiveWorkbenchShell()) .doQuery(false, projPath)) { CeylonBuildPathsBlock.removeOldClassfiles(project); } } } else if (!javaOutputLocation.equals(oldOutputLocation)) { IFolder folder= ResourcesPlugin.getWorkspace().getRoot().getFolder(oldOutputLocation); if (folder.exists()) { if (folder.members().length==0) { CeylonBuildPathsBlock.removeOldClassfiles(folder); } else { if (CeylonBuildPathsBlock.getRemoveOldBinariesQuery(JavaPlugin.getActiveWorkbenchShell()) .doQuery(folder.isDerived(), oldOutputLocation)) { CeylonBuildPathsBlock.removeOldClassfiles(folder); } } } } getCeylonModulesOutputFolder(project).delete(true, monitor); monitor.worked(1); IWorkspaceRoot fWorkspaceRoot= JavaPlugin.getWorkspace().getRoot(); //create and set the output path first if (!fWorkspaceRoot.exists(javaOutputLocation)) { CoreUtility.createDerivedFolder(fWorkspaceRoot.getFolder(javaOutputLocation), true, true, new SubProgressMonitor(monitor, 1)); } else { monitor.worked(1); } if (monitor.isCanceled()) { throw new OperationCanceledException(); } for (Iterator<CPListElement> iter= resourcePathEntries.iterator(); iter.hasNext();) { CPListElement entry= iter.next(); IResource res= entry.getResource(); //1 tick if (res instanceof IFolder && entry.getLinkTarget() == null && !res.exists()) { CoreUtility.createFolder((IFolder)res, true, true, new SubProgressMonitor(monitor, 1)); } else { monitor.worked(1); } //3 ticks if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { IPath folderOutput= (IPath) entry.getAttribute(CPListElement.OUTPUT); if (folderOutput != null && folderOutput.segmentCount() > 1) { IFolder folder= fWorkspaceRoot.getFolder(folderOutput); CoreUtility.createDerivedFolder(folder, true, true, new SubProgressMonitor(monitor, 1)); } else { monitor.worked(1); } IPath path= entry.getPath(); if (projPath.equals(path)) { monitor.worked(2); continue; } if (projPath.isPrefixOf(path)) { path= path.removeFirstSegments(projPath.segmentCount()); } IFolder folder= project.getFolder(path); IPath orginalPath= entry.getOrginalPath(); if (orginalPath == null) { if (!folder.exists()) { //New source folder needs to be created if (entry.getLinkTarget() == null) { CoreUtility.createFolder(folder, true, true, new SubProgressMonitor(monitor, 2)); } else { folder.createLink(entry.getLinkTarget(), IResource.ALLOW_MISSING_LOCAL, new SubProgressMonitor(monitor, 2)); } } } else { if (projPath.isPrefixOf(orginalPath)) { orginalPath= orginalPath.removeFirstSegments(projPath.segmentCount()); } IFolder orginalFolder= project.getFolder(orginalPath); if (entry.getLinkTarget() == null) { if (!folder.exists()) { //Source folder was edited, move to new location IPath parentPath= entry.getPath().removeLastSegments(1); if (projPath.isPrefixOf(parentPath)) { parentPath= parentPath.removeFirstSegments(projPath.segmentCount()); } if (parentPath.segmentCount() > 0) { IFolder parentFolder= project.getFolder(parentPath); if (!parentFolder.exists()) { CoreUtility.createFolder(parentFolder, true, true, new SubProgressMonitor(monitor, 1)); } else { monitor.worked(1); } } else { monitor.worked(1); } orginalFolder.move(entry.getPath(), true, true, new SubProgressMonitor(monitor, 1)); } } else { if (!folder.exists() || !entry.getLinkTarget().equals(entry.getOrginalLinkTarget())) { orginalFolder.delete(true, new SubProgressMonitor(monitor, 1)); folder.createLink(entry.getLinkTarget(), IResource.ALLOW_MISSING_LOCAL, new SubProgressMonitor(monitor, 1)); } } } } if (monitor.isCanceled()) { throw new OperationCanceledException(); } } int nEntries= classPathEntries.size(); IClasspathEntry[] classpath= new IClasspathEntry[nEntries]; int i= 0; for (Iterator<CPListElement> iter= classPathEntries.iterator(); iter.hasNext();) { CPListElement entry= iter.next(); classpath[i]= entry.getClasspathEntry(); i++; IResource res= entry.getResource(); //1 tick if (res instanceof IFolder && entry.getLinkTarget() == null && !res.exists()) { CoreUtility.createFolder((IFolder)res, true, true, new SubProgressMonitor(monitor, 1)); } else { monitor.worked(1); } //3 ticks if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { IPath folderOutput= (IPath) entry.getAttribute(CPListElement.OUTPUT); if (folderOutput != null && folderOutput.segmentCount() > 1) { IFolder folder= fWorkspaceRoot.getFolder(folderOutput); CoreUtility.createDerivedFolder(folder, true, true, new SubProgressMonitor(monitor, 1)); } else { monitor.worked(1); } IPath path= entry.getPath(); if (projPath.equals(path)) { monitor.worked(2); continue; } if (projPath.isPrefixOf(path)) { path= path.removeFirstSegments(projPath.segmentCount()); } IFolder folder= project.getFolder(path); IPath orginalPath= entry.getOrginalPath(); if (orginalPath == null) { if (!folder.exists()) { //New source folder needs to be created if (entry.getLinkTarget() == null) { CoreUtility.createFolder(folder, true, true, new SubProgressMonitor(monitor, 2)); } else { folder.createLink(entry.getLinkTarget(), IResource.ALLOW_MISSING_LOCAL, new SubProgressMonitor(monitor, 2)); } } } else { if (projPath.isPrefixOf(orginalPath)) { orginalPath= orginalPath.removeFirstSegments(projPath.segmentCount()); } IFolder orginalFolder= project.getFolder(orginalPath); if (entry.getLinkTarget() == null) { if (!folder.exists()) { //Source folder was edited, move to new location IPath parentPath= entry.getPath().removeLastSegments(1); if (projPath.isPrefixOf(parentPath)) { parentPath= parentPath.removeFirstSegments(projPath.segmentCount()); } if (parentPath.segmentCount() > 0) { IFolder parentFolder= project.getFolder(parentPath); if (!parentFolder.exists()) { CoreUtility.createFolder(parentFolder, true, true, new SubProgressMonitor(monitor, 1)); } else { monitor.worked(1); } } else { monitor.worked(1); } orginalFolder.move(entry.getPath(), true, true, new SubProgressMonitor(monitor, 1)); } } else { if (!folder.exists() || !entry.getLinkTarget().equals(entry.getOrginalLinkTarget())) { orginalFolder.delete(true, new SubProgressMonitor(monitor, 1)); folder.createLink(entry.getLinkTarget(), IResource.ALLOW_MISSING_LOCAL, new SubProgressMonitor(monitor, 1)); } } } } else { if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { IPath path= entry.getPath(); if (! path.equals(entry.getOrginalPath())) { String eeID= JavaRuntime.getExecutionEnvironmentId(path); if (eeID != null) { BuildPathSupport.setEEComplianceOptions(javaProject, eeID, newProjectCompliance); newProjectCompliance= null; // don't set it again below } } if (newProjectCompliance != null) { setOptionsFromJavaProject(javaProject, newProjectCompliance); } } monitor.worked(3); } if (monitor.isCanceled()) { throw new OperationCanceledException(); } } javaProject.setRawClasspath(classpath, javaOutputLocation, new SubProgressMonitor(monitor, 2)); BaseCeylonProject ceylonProject = modelJ2C().ceylonModel().getProject(project); CeylonProjectConfig config = ceylonProject.getConfiguration(); List<String> srcDirs = new ArrayList<String>(); for (CPListElement cpe: classPathEntries) { if (cpe.getEntryKind()==IClasspathEntry.CPE_SOURCE) { srcDirs.add(configFilePath(project, cpe)); } } config.setProjectSourceDirectories(new CeylonStringIterable(srcDirs)); List<String> rsrcDirs = new ArrayList<String>(); for (CPListElement cpe: resourcePathEntries) { rsrcDirs.add(configFilePath(project, cpe)); } config.setProjectResourceDirectories(new CeylonStringIterable(rsrcDirs)); config.save(); } finally { monitor.done(); } } private static String configFilePath(IProject project, CPListElement cpe) { IPath linkTarget = cpe.getLinkTarget(); if (linkTarget==null) { // It's a relative path return cpe.getPath().makeRelativeTo(project.getFullPath()).toString(); } else { return cpe.getLinkTarget().toOSString(); } } private static void setOptionsFromJavaProject(IJavaProject javaProject, String newProjectCompliance) { @SuppressWarnings("unchecked") Map<String, String> options= javaProject.getOptions(false); JavaModelUtil.setComplianceOptions(options, newProjectCompliance); JavaModelUtil.setDefaultClassfileOptions(options, newProjectCompliance); // complete compliance options javaProject.setOptions(options); } public static boolean hasClassfiles(IResource resource) throws CoreException { if (resource.isDerived()) { return true; } if (resource instanceof IContainer) { IResource[] members= ((IContainer) resource).members(); for (int i= 0; i < members.length; i++) { if (hasClassfiles(members[i])) { return true; } } } return false; } public static void removeOldClassfiles(IResource resource) throws CoreException { if (resource.isDerived()) { resource.delete(false, null); } else if (resource instanceof IContainer) { IResource[] members= ((IContainer) resource).members(); for (int i= 0; i < members.length; i++) { removeOldClassfiles(members[i]); } } } public static IRemoveOldBinariesQuery getRemoveOldBinariesQuery(final Shell shell) { return new IRemoveOldBinariesQuery() { public boolean doQuery(final boolean removeFolder, final IPath oldOutputLocation) throws OperationCanceledException { final int[] res= new int[] { 1 }; Display.getDefault().syncExec(new Runnable() { public void run() { Shell sh= shell != null ? shell : JavaPlugin.getActiveWorkbenchShell(); String title= NewWizardMessages.BuildPathsBlock_RemoveBinariesDialog_title; String message; String pathLabel= BasicElementLabels.getPathLabel(oldOutputLocation, false); if (removeFolder) { message= Messages.format(NewWizardMessages.BuildPathsBlock_RemoveOldOutputFolder_description, pathLabel); } else { message= Messages.format(NewWizardMessages.BuildPathsBlock_RemoveBinariesDialog_description, pathLabel); } MessageDialog dialog= new MessageDialog(sh, title, null, message, MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }, 0); res[0]= dialog.open(); } }); if (res[0] == 0) { return true; } else if (res[0] == 1) { return false; } throw new OperationCanceledException(); } }; } // ---------- util method ------------ private IContainer chooseContainer(IPath outputPath) { Class<?>[] acceptedClasses= new Class[] { IProject.class, IFolder.class }; ISelectionStatusValidator validator= new TypedElementSelectionValidator(acceptedClasses, false); IProject[] allProjects= fWorkspaceRoot.getProjects(); ArrayList<IProject> rejectedElements= new ArrayList<IProject>(allProjects.length); IProject currProject= fCurrJProject.getProject(); for (int i= 0; i < allProjects.length; i++) { if (!allProjects[i].equals(currProject)) { rejectedElements.add(allProjects[i]); } } ViewerFilter filter= new TypedViewerFilter(acceptedClasses, rejectedElements.toArray()); ILabelProvider lp= new WorkbenchLabelProvider(); ITreeContentProvider cp= new WorkbenchContentProvider(); IResource initSelection= null; if (outputPath != null) { initSelection= fWorkspaceRoot.findMember(outputPath); } FolderSelectionDialog dialog= new FolderSelectionDialog(getShell(), lp, cp); dialog.setTitle(NewWizardMessages.BuildPathsBlock_ChooseOutputFolderDialog_title); dialog.setValidator(validator); dialog.setMessage(NewWizardMessages.BuildPathsBlock_ChooseOutputFolderDialog_description); dialog.addFilter(filter); dialog.setInput(fWorkspaceRoot); dialog.setInitialSelection(initSelection); dialog.setComparator(new ResourceComparator(ResourceComparator.NAME)); if (dialog.open() == Window.OK) { return (IContainer)dialog.getFirstResult(); } return null; } // -------- tab switching ---------- private void tabChanged(Widget widget) { if (widget instanceof TabItem) { TabItem tabItem= (TabItem) widget; BuildPathBasePage newPage= (BuildPathBasePage) tabItem.getData(); if (fCurrPage != null) { List<?> selection= fCurrPage.getSelection(); if (!selection.isEmpty()) { newPage.setSelection(selection, false); } } fCurrPage= newPage; fPageIndex= tabItem.getParent().getSelectionIndex(); } } private int getPageIndex(int entryKind) { switch (entryKind) { case IClasspathEntry.CPE_CONTAINER: case IClasspathEntry.CPE_LIBRARY: case IClasspathEntry.CPE_VARIABLE: return 2; case IClasspathEntry.CPE_PROJECT: return 1; case IClasspathEntry.CPE_SOURCE: return 0; } return 0; } private CPListElement findElement(IClasspathEntry entry) { CPListElement prefixMatch= null; int entryKind= entry.getEntryKind(); for (int i= 0, len= fClassPathList.getSize(); i < len; i++) { CPListElement curr= fClassPathList.getElement(i); if (curr.getEntryKind() == entryKind) { IPath entryPath= entry.getPath(); IPath currPath= curr.getPath(); if (currPath.equals(entryPath)) { return curr; } // in case there's no full match, look for a similar container (same ID segment): if (prefixMatch == null && entryKind == IClasspathEntry.CPE_CONTAINER) { int n= entryPath.segmentCount(); if (n > 0) { IPath genericContainerPath= n == 1 ? entryPath : entryPath.removeLastSegments(n - 1); if (n > 1 && genericContainerPath.isPrefixOf(currPath)) { prefixMatch= curr; } } } } } return prefixMatch; } public void setElementToReveal(IClasspathEntry entry, String attributeKey) { int pageIndex= getPageIndex(entry.getEntryKind()); if (fTabFolder == null) { fPageIndex= pageIndex; } else { fTabFolder.setSelection(pageIndex); CPListElement element= findElement(entry); if (element != null) { Object elementToSelect= element; if (attributeKey != null) { Object attrib= element.findAttributeElement(attributeKey); if (attrib != null) { elementToSelect= attrib; } } BuildPathBasePage page= (BuildPathBasePage) fTabFolder.getItem(pageIndex).getData(); List<Object> selection= new ArrayList<Object>(1); selection.add(elementToSelect); page.setSelection(selection, true); } } } public void addElement(IClasspathEntry entry) { int pageIndex= getPageIndex(entry.getEntryKind()); if (fTabFolder == null) { fPageIndex= pageIndex; } else { fTabFolder.setSelection(pageIndex); // Object page= fTabFolder.getItem(pageIndex).getData(); // if (page instanceof LibrariesWorkbookPage) { // CPListElement element= CPListElement.create(entry, true, fCurrJProject); // ((LibrariesWorkbookPage) page).addElement(element); // } } } public boolean isOKStatus() { return findMostSevereStatus().isOK(); } public void setFocus() { fSourceContainerPage.setFocus(); } private void refreshSourcePathsFromConfigFile() { final IProject project = fCurrJProject.getProject(); BaseCeylonProject ceylonProject = modelJ2C().ceylonModel().getProject(project); if (ceylonProject != null) { CeylonProjectConfig config = ceylonProject.getConfiguration(); List<String> sourceDirectories = toJavaStringList(config.getProjectSourceDirectories()); updateClassPathsFromConfigFile(sourceDirectories, new HashSet<String>()); } } private void updateClassPathsFromConfigFile(List<String> sourceDirectories, final Set<String> newFolderNames) { final IProject project = fCurrJProject.getProject(); final List<CPListElement> newSourcePath = new ArrayList<CPListElement>(); for (final String path : sourceDirectories) { final IPath iPath = Path.fromOSString(path); if (!iPath.isAbsolute()) { IFolder folder = project.getFolder(iPath); newSourcePath.add(new CPListElement(fCurrJProject, IClasspathEntry.CPE_SOURCE, folder.getFullPath(), folder)); if (!folder.exists()) { someFoldersNeedToBeCreated = true; } } else { try { class CPListElementHolder { public CPListElement value = null; } final CPListElementHolder cpListElement = new CPListElementHolder(); project.accept(new IResourceVisitor() { @Override public boolean visit(IResource resource) throws CoreException { if (resource instanceof IFolder && resource.isLinked() && resource.getLocation() != null && resource.getLocation().equals(iPath)) { cpListElement.value = new CPListElement(null, fCurrJProject, IClasspathEntry.CPE_SOURCE, resource.getFullPath(), resource, resource.getLocation()); return false; } return resource instanceof IFolder || resource instanceof IProject; } }); if (cpListElement.value == null) { String newFolderName = iPath.lastSegment(); IFolder newFolder = project.getFolder(newFolderName); int counter = 1; while (newFolderNames.contains(newFolderName) || newFolder.exists()) { newFolderName = iPath.lastSegment() + "_" + counter++; newFolder = project.getFolder(newFolderName); } newFolderNames.add(newFolderName); cpListElement.value = new CPListElement(null, fCurrJProject, IClasspathEntry.CPE_SOURCE, newFolder.getFullPath(), newFolder, iPath); someFoldersNeedToBeCreated = true; } newSourcePath.add(cpListElement.value); } catch (CoreException ex) { ex.printStackTrace(); } } } ArrayList<CPListElement> exportedEntries = new ArrayList<>(); ArrayList<CPListElement> newClassPath = new ArrayList<>(); // Don't change all the non-source classpath entries for (CPListElement elem : fClassPathList.getElements()) { if (elem.getClasspathEntry().getEntryKind() != IClasspathEntry.CPE_SOURCE) { newClassPath.add(elem); } } for (CPListElement elem : fClassPathList.getCheckedElements()) { if (elem.getClasspathEntry().getEntryKind() != IClasspathEntry.CPE_SOURCE) { exportedEntries.add(elem); } } // Now all the new source entries newClassPath.addAll(newSourcePath); for (CPListElement elem : fClassPathList.getCheckedElements()) { if (newSourcePath.contains(elem)) { exportedEntries.add(elem); } } fClassPathList.setElements(newClassPath); fClassPathList.setCheckedElements(exportedEntries); fClassPathList.selectFirstElement(); } }