package com.redhat.ceylon.eclipse.code.navigator; import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.modelJ2C; import static com.redhat.ceylon.eclipse.util.CeylonHelper.toJavaStringList; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; import org.eclipse.jdt.internal.ui.JavaPluginImages; import org.eclipse.jdt.internal.ui.actions.ActionMessages; import org.eclipse.jdt.internal.ui.actions.JarImportWizardAction; import org.eclipse.jdt.internal.ui.packageview.ClassPathContainer; import org.eclipse.jdt.internal.ui.packageview.PackageFragmentRootContainer; import org.eclipse.jdt.internal.ui.preferences.BuildPathsPropertyPage; import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElement; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.AddArchiveToBuildpathAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.AddFolderToBuildpathAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.AddLibraryToBuildpathAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.AddSelectedLibraryToBuildpathAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.ConfigureBuildPathAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.CreateLinkedSourceFolderAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.CreateSourceFolderAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.EditFilterAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.EditOutputFolderAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.ExcludeFromBuildpathAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.IncludeToBuildpathAction; import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.RemoveFromBuildpathAction; import org.eclipse.jdt.ui.IContextMenuConstants; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchSite; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionGroup; import org.eclipse.ui.dialogs.PreferencesUtil; import org.eclipse.ui.part.Page; import org.eclipse.ui.texteditor.IUpdate; import com.redhat.ceylon.eclipse.code.preferences.CeylonBuildPathsBlock; import com.redhat.ceylon.eclipse.code.preferences.CeylonBuildPathsPropertiesPage; import com.redhat.ceylon.eclipse.core.external.ExternalSourceArchiveManager; import com.redhat.ceylon.ide.common.model.BaseCeylonProject; import com.redhat.ceylon.ide.common.model.CeylonProjectConfig; /** * Copied from <code>{@link org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.GenerateBuildPathActionGroup}</code> * to override some of the actions. */ public class GenerateBuildPathActionGroup extends ActionGroup { /** * Pop-up menu: id of the source sub menu (value <code>org.eclipse.jdt.ui.buildpath.menu</code>). * * @since 3.1 */ public static final String MENU_ID= "org.eclipse.jdt.ui.buildpath.menu"; //$NON-NLS-1$ /** * Pop-up menu: id of the build path (add /remove) group of the build path sub menu (value * <code>buildpathGroup</code>). * * @since 3.1 */ public static final String GROUP_BUILDPATH= "buildpathGroup"; //$NON-NLS-1$ /** * Pop-up menu: id of the filter (include / exclude) group of the build path sub menu (value * <code>filterGroup</code>). * * @since 3.1 */ public static final String GROUP_FILTER= "filterGroup"; //$NON-NLS-1$ /** * Pop-up menu: id of the customize (filters / output folder) group of the build path sub menu (value * <code>customizeGroup</code>). * * @since 3.1 */ public static final String GROUP_CUSTOMIZE= "customizeGroup"; //$NON-NLS-1$ private static class NoActionAvailable extends Action { public NoActionAvailable() { setEnabled(false); setText(NewWizardMessages.GenerateBuildPathActionGroup_no_action_available); } } private Action fNoActionAvailable= new NoActionAvailable(); private class UpdateJarFileAction extends JarImportWizardAction implements IUpdate { public UpdateJarFileAction() { setText(ActionMessages.GenerateBuildPathActionGroup_update_jar_text); setDescription(ActionMessages.GenerateBuildPathActionGroup_update_jar_description); setToolTipText(ActionMessages.GenerateBuildPathActionGroup_update_jar_tooltip); setImageDescriptor(JavaPluginImages.DESC_OBJS_JAR); PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.JARIMPORT_WIZARD_PAGE); } /** * {@inheritDoc} */ public void update() { final IWorkbenchPart part= fSite.getPage().getActivePart(); if (part != null) setActivePart(this, part); selectionChanged(this, fSelectionProvider.getSelection()); } } private final IWorkbenchSite fSite; private final ISelectionProvider fSelectionProvider; private final List<Action> fActions; private String fGroupName= IContextMenuConstants.GROUP_REORGANIZE; /** * Creates a new <code>GenerateActionGroup</code>. The group * requires that the selection provided by the page's selection provider * is of type <code>org.eclipse.jface.viewers.IStructuredSelection</code>. * * @param page the page that owns this action group */ public GenerateBuildPathActionGroup(Page page) { this(page.getSite(), page.getSite().getSelectionProvider()); } /** * Creates a new <code>GenerateActionGroup</code>. The group * requires that the selection provided by the part's selection provider * is of type <code>org.eclipse.jface.viewers.IStructuredSelection</code>. * * @param part the view part that owns this action group */ public GenerateBuildPathActionGroup(IViewPart part) { this(part.getSite(), part.getSite().getSelectionProvider()); } /** * Creates a new <code>GenerateActionGroup</code>. The group requires * that the selection provided by the given selection provider is of type * {@link IStructuredSelection}. * * @param site the site that will own the action group. * @param selectionProvider the selection provider used instead of the * page selection provider. * * @since 3.4 */ public GenerateBuildPathActionGroup(IWorkbenchSite site, ISelectionProvider selectionProvider) { fSite= site; fSelectionProvider= selectionProvider; fActions= new ArrayList<Action>(); final CreateLinkedSourceFolderAction addLinkedSourceFolderAction= new CreateLinkedSourceFolderAction(site) { private void doBuildpathAction() { super.run(); } @Override public void run() { alsoManageCeylonConfigFile(new Runnable() { @Override public void run() { doBuildpathAction(); } }, getShell(), getSelectedElements()); } }; fActions.add(addLinkedSourceFolderAction); final CreateSourceFolderAction addSourceFolderAction= new CreateSourceFolderAction(site) { private void doBuildpathAction() { super.run(); } @Override public void run() { alsoManageCeylonConfigFile(new Runnable() { @Override public void run() { doBuildpathAction(); } }, getShell(), getSelectedElements()); } }; fActions.add(addSourceFolderAction); final AddFolderToBuildpathAction addFolder= new AddFolderToBuildpathAction(site) { private void doBuildpathAction() { super.run(); } @Override public void run() { alsoManageCeylonConfigFile(new Runnable() { @Override public void run() { doBuildpathAction(); } }, getShell(), getSelectedElements()); } }; fActions.add(addFolder); final AddSelectedLibraryToBuildpathAction addSelectedLibrary= new AddSelectedLibraryToBuildpathAction(site); fActions.add(addSelectedLibrary); final RemoveFromBuildpathAction remove = new RemoveFromBuildpathAction(site) { private void doBuildpathAction() { super.run(); } @Override public void run() { alsoManageCeylonConfigFile(new Runnable() { @Override public void run() { doBuildpathAction(); } }, getShell(), getSelectedElements()); } }; fActions.add(remove); final AddArchiveToBuildpathAction addArchive= new AddArchiveToBuildpathAction(site); fActions.add(addArchive); final AddLibraryToBuildpathAction addLibrary= new AddLibraryToBuildpathAction(site); fActions.add(addLibrary); final UpdateJarFileAction updateAction= new UpdateJarFileAction(); fActions.add(updateAction); final ExcludeFromBuildpathAction exclude= new ExcludeFromBuildpathAction(site); fActions.add(exclude); final IncludeToBuildpathAction include= new IncludeToBuildpathAction(site); fActions.add(include); final EditFilterAction editFilterAction= new EditFilterAction(site); fActions.add(editFilterAction); final EditOutputFolderAction editOutput= new EditOutputFolderAction(site); fActions.add(editOutput); final ConfigureBuildPathAction configure= new ConfigureBuildPathAction(site) { @Override public void run() { IProject project = null; Object firstElement = getSelectedElements().get(0); HashMap<Object, IClasspathEntry> data= new HashMap<Object, IClasspathEntry>(); if (firstElement instanceof IJavaElement) { IJavaElement element= (IJavaElement) firstElement; IPackageFragmentRoot root= (IPackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); if (root != null) { try { data.put(BuildPathsPropertyPage.DATA_REVEAL_ENTRY, root.getRawClasspathEntry()); } catch (JavaModelException e) { // ignore } } project = element.getJavaProject().getProject(); } else if (firstElement instanceof PackageFragmentRootContainer) { PackageFragmentRootContainer container= (PackageFragmentRootContainer) firstElement; project= container.getJavaProject().getProject(); IClasspathEntry entry = container instanceof ClassPathContainer ? ((ClassPathContainer) container).getClasspathEntry() : JavaCore.newLibraryEntry(new Path("/x/y"), null, null); //$NON-NLS-1$ data.put(BuildPathsPropertyPage.DATA_REVEAL_ENTRY, entry); } else { project= ((IResource) ((IAdaptable) firstElement).getAdapter(IResource.class)).getProject(); } PreferencesUtil.createPropertyDialogOn(getShell(), project, CeylonBuildPathsPropertiesPage.ID, null, data).open(); } }; fActions.add(configure); for (Iterator<Action> iter= fActions.iterator(); iter.hasNext();) { Action action= iter.next(); if (action instanceof ISelectionChangedListener) { ISelectionChangedListener listener = (ISelectionChangedListener) action; selectionProvider.addSelectionChangedListener(listener); listener.selectionChanged(new SelectionChangedEvent(selectionProvider, selectionProvider.getSelection())); } } } public static void alsoManageCeylonConfigFile(Runnable runnable, Shell shell, List<?> selectedElements) { // First check the the config is synchronized to authorize the action IProject project = null; IJavaProject javaProject = null; Object object= selectedElements.get(0); if (object instanceof IJavaElement) { IJavaElement javaElement = (IJavaElement) object; javaProject = javaElement.getJavaProject(); } else if (object instanceof IResource) { IResource resource = (IResource) object; if (!ExternalSourceArchiveManager.isInSourceArchive(resource)) { javaProject= JavaCore.create(resource.getProject()); } } if (javaProject != null) { project = javaProject.getProject(); } if (project == null) { return; } BaseCeylonProject ceylonProject = modelJ2C() .ceylonModel() .getProject(project); if (ceylonProject != null && !ceylonProject.getSynchronizedWithConfiguration()) { MessageDialog.openError(shell, NewWizardMessages.NewSourceContainerWorkbookPage_ToolBar_RemoveFromCP_tooltip, "The Ceylon configuration file (.ceylon/config) is not synchronized with the current build path settings.\n" + "You should fix this before adding changing the Ceylon build path (a QuickFix is available)."); return; } // Then run the modification action runnable.run(); if (ceylonProject != null) { CeylonProjectConfig config = ceylonProject.getConfiguration(); // And finally update the Ceylon config file try { CPListElement[] classPathEntries = CPListElement.createFromExisting(javaProject); List<CPListElement> resourcePathEntries = new ArrayList<>(); CeylonBuildPathsBlock.resourcePathsFromStrings(javaProject, toJavaStringList(config.getProjectResourceDirectories()), new HashSet<String>(), resourcePathEntries); CeylonBuildPathsBlock.flush(Arrays.asList(classPathEntries), resourcePathEntries, javaProject.readOutputLocation(), javaProject, null, null); } catch (OperationCanceledException|CoreException e) {} } } /* (non-Javadoc) * Function declared in ActionGroup */ @Override public void fillActionBars(IActionBars actionBar) { super.fillActionBars(actionBar); setGlobalActionHandlers(actionBar); } /* (non-Javadoc) * Function declared in ActionGroup */ @Override public void fillContextMenu(IMenuManager menu) { super.fillContextMenu(menu); if (!canOperateOnSelection()) return; String menuText= ActionMessages.BuildPath_label; IMenuManager subMenu= new MenuManager(menuText, MENU_ID); subMenu.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { fillViewSubMenu(manager); } }); subMenu.setRemoveAllWhenShown(true); subMenu.add(new ConfigureBuildPathAction(fSite)); menu.appendToGroup(fGroupName, subMenu); } private void fillViewSubMenu(IMenuManager source) { int added= 0; int i=0; for (Iterator<Action> iter= fActions.iterator(); iter.hasNext();) { Action action= iter.next(); if (action instanceof IUpdate) ((IUpdate) action).update(); if (i == 2) source.add(new Separator(GROUP_BUILDPATH)); else if (i == 8) source.add(new Separator(GROUP_FILTER)); else if (i == 10) source.add(new Separator(GROUP_CUSTOMIZE)); added+= addAction(source, action); i++; } if (added == 0) { source.add(fNoActionAvailable); } } /** * @param actionBar the action bars to set the handler for */ private void setGlobalActionHandlers(IActionBars actionBar) { // TODO implement } private int addAction(IMenuManager menu, IAction action) { if (action != null && action.isEnabled()) { menu.add(action); return 1; } return 0; } private boolean canOperateOnSelection() { ISelection sel= fSelectionProvider.getSelection(); if (!(sel instanceof IStructuredSelection)) return false; IStructuredSelection selection= (IStructuredSelection)sel; if (selection.isEmpty()) return false; for (Iterator<?> iter= selection.iterator(); iter.hasNext();) { Object element= iter.next(); if (element instanceof IWorkingSet) return false; } return true; } /** * {@inheritDoc} */ @Override public void dispose() { if (fActions != null) { for (Iterator<Action> iter= fActions.iterator(); iter.hasNext();) { Action action= iter.next(); if (action instanceof ISelectionChangedListener) fSelectionProvider.removeSelectionChangedListener((ISelectionChangedListener) action); } fActions.clear(); } super.dispose(); } }