| /******************************************************************************* |
| * Copyright (c) 2000, 2018 IBM Corporation and others. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.ui.wizards.buildpath.newsourcepage; |
| |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.IBuildpathEntry; |
| import org.eclipse.dltk.core.IProjectFragment; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.core.IScriptProjectFilenames; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.internal.corext.buildpath.BuildpathModifier; |
| import org.eclipse.dltk.internal.corext.util.Messages; |
| import org.eclipse.dltk.internal.ui.StandardModelElementContentProvider; |
| import org.eclipse.dltk.internal.ui.filters.LibraryFilter; |
| import org.eclipse.dltk.internal.ui.wizards.NewWizardMessages; |
| import org.eclipse.dltk.internal.ui.wizards.buildpath.BPListElementAttribute; |
| import org.eclipse.dltk.internal.ui.wizards.buildpath.newsourcepage.DialogPackageExplorerActionGroup.DialogExplorerActionContext; |
| import org.eclipse.dltk.ui.DLTKUIPlugin; |
| import org.eclipse.dltk.ui.ModelElementSorter; |
| import org.eclipse.dltk.ui.ScriptElementImageProvider; |
| import org.eclipse.dltk.ui.ScriptElementLabels; |
| import org.eclipse.dltk.ui.viewsupport.AppearanceAwareLabelProvider; |
| import org.eclipse.dltk.ui.viewsupport.StyledDecoratingModelLabelProvider; |
| import org.eclipse.jface.action.IMenuListener; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Menu; |
| |
| /** |
| * A package explorer widget that can be used in dialogs. It uses its own |
| * content provider, label provider, element sorter and filter to display |
| * elements that are not shown usually in the package explorer of the workspace. |
| */ |
| public abstract class DialogPackageExplorer |
| implements IMenuListener, ISelectionChangedListener { |
| /** |
| * A extended content provider for the package explorer which can |
| * additionally display an output folder item. |
| */ |
| private final class PackageContentProvider |
| extends StandardModelElementContentProvider { |
| public PackageContentProvider() { |
| super(); |
| } |
| |
| /** |
| * Get the elements of the current project |
| * |
| * @param element |
| * the element to get the children from, will not be |
| * used, instead the project childrens are returned |
| * directly |
| * @return returns the children of the project |
| */ |
| @Override |
| public Object[] getElements(Object element) { |
| if (fCurrJProject == null || !fCurrJProject.exists()) |
| return new Object[0]; |
| return new Object[] { fCurrJProject }; |
| } |
| } |
| |
| /** |
| * A extended label provider for the package explorer which can additionally |
| * display an output folder item. |
| */ |
| private final class PackageLabelProvider |
| extends AppearanceAwareLabelProvider { |
| |
| public PackageLabelProvider(long textFlags, int imageFlags, |
| IPreferenceStore store) { |
| super(textFlags, imageFlags, store); |
| } |
| |
| @Override |
| public String getText(Object element) { |
| String text = super.getText(element); |
| try { |
| if (element instanceof IProjectFragment) { |
| IProjectFragment root = (IProjectFragment) element; |
| if (root.exists() && BuildpathModifier.filtersSet(root)) { |
| IBuildpathEntry entry = root.getRawBuildpathEntry(); |
| int excluded = entry.getExclusionPatterns().length; |
| if (excluded == 1) |
| return Messages.format( |
| NewWizardMessages.DialogPackageExplorer_LabelProvider_SingleExcluded, |
| text); |
| else if (excluded > 1) |
| return Messages.format( |
| NewWizardMessages.DialogPackageExplorer_LabelProvider_MultiExcluded, |
| new Object[] { text, excluded }); |
| } |
| } |
| if (element instanceof IScriptProject) { |
| IScriptProject project = (IScriptProject) element; |
| if (project.exists() && project.isOnBuildpath(project)) { |
| IProjectFragment root = project |
| .findProjectFragment(project.getPath()); |
| if (BuildpathModifier.filtersSet(root)) { |
| IBuildpathEntry entry = root.getRawBuildpathEntry(); |
| int excluded = entry.getExclusionPatterns().length; |
| if (excluded == 1) |
| return Messages.format( |
| NewWizardMessages.DialogPackageExplorer_LabelProvider_SingleExcluded, |
| text); |
| else if (excluded > 1) |
| return Messages.format( |
| NewWizardMessages.DialogPackageExplorer_LabelProvider_MultiExcluded, |
| new Object[] { text, excluded }); |
| } |
| } |
| } |
| if (element instanceof IFile || element instanceof IFolder) { |
| IResource resource = (IResource) element; |
| if (resource.exists() && BuildpathModifier |
| .isExcluded(resource, fCurrJProject)) |
| return Messages.format( |
| NewWizardMessages.DialogPackageExplorer_LabelProvider_Excluded, |
| text); |
| } |
| } catch (ModelException e) { |
| DLTKUIPlugin.log(e); |
| } |
| return text; |
| } |
| |
| @Override |
| public Color getForeground(Object element) { |
| try { |
| if (element instanceof IProjectFragment) { |
| IProjectFragment root = (IProjectFragment) element; |
| if (root.exists() && BuildpathModifier.filtersSet(root)) |
| return getBlueColor(); |
| } |
| if (element instanceof IScriptProject) { |
| IScriptProject project = (IScriptProject) element; |
| if (project.exists() && project.isOnBuildpath(project)) { |
| IProjectFragment root = project |
| .findProjectFragment(project.getPath()); |
| if (root != null && BuildpathModifier.filtersSet(root)) |
| return getBlueColor(); |
| } |
| } |
| if (element instanceof IFile || element instanceof IFolder) { |
| IResource resource = (IResource) element; |
| if (resource.exists() && BuildpathModifier |
| .isExcluded(resource, fCurrJProject)) |
| return getBlueColor(); |
| } |
| } catch (ModelException e) { |
| DLTKUIPlugin.log(e); |
| } |
| return null; |
| } |
| |
| private Color getBlueColor() { |
| return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE); |
| } |
| |
| @Override |
| public Image getImage(Object element) { |
| return super.getImage(element); |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| } |
| |
| } |
| |
| /** |
| * A extended element sorter for the package explorer which displays the |
| * output folder (if any) as first child of a source folder. The other |
| * script elements are sorted in the normal way. |
| */ |
| private final class ExtendedModelElementSorter extends ModelElementSorter { |
| public ExtendedModelElementSorter() { |
| super(); |
| } |
| |
| @Override |
| public int compare(Viewer viewer, Object e1, Object e2) { |
| if (e1 instanceof BPListElementAttribute) |
| return -1; |
| if (e2 instanceof BPListElementAttribute) |
| return 1; |
| return super.compare(viewer, e1, e2); |
| } |
| } |
| |
| /** |
| * A extended filter for the package explorer which filters libraries and |
| * files if their name is either ".Buildpath" or ".project". |
| */ |
| private final class PackageFilter extends LibraryFilter { |
| @Override |
| public boolean select(Viewer viewer, Object parentElement, |
| Object element) { |
| try { |
| if (element instanceof IFile) { |
| IFile file = (IFile) element; |
| if (file.getName() |
| .equals(IScriptProjectFilenames.BUILDPATH_FILENAME) |
| || file.getName().equals( |
| IScriptProjectFilenames.PROJECT_FILENAME)) |
| return false; |
| } |
| if (element instanceof IProjectFragment) { |
| IBuildpathEntry cpe = ((IProjectFragment) element) |
| .getRawBuildpathEntry(); |
| if (cpe == null || cpe |
| .getEntryKind() == IBuildpathEntry.BPE_CONTAINER) |
| return false; |
| } |
| } catch (ModelException e) { |
| DLTKUIPlugin.log(e); |
| } |
| // if (element instanceof IProjectFragment) { |
| // IProjectFragment root= (IProjectFragment)element; |
| // if (root.getElementName().endsWith(".zip") ) //$NON-NLS-1$ |
| // //$NON-NLS-2$ |
| // return false; |
| // } |
| // return super.select(viewer, parentElement, element);// &&*/ |
| // fOutputFolderFilter.select(viewer, parentElement, element); |
| return true; |
| } |
| } |
| |
| /** The tree showing the project like in the package explorer */ |
| private TreeViewer fPackageViewer; |
| /** The tree's context menu */ |
| private Menu fContextMenu; |
| /** |
| * The action group which is used to fill the context menu. The action group |
| * is also called if the selection on the tree changes |
| */ |
| private DialogPackageExplorerActionGroup fActionGroup; |
| |
| /** |
| * Stores the current selection in the tree |
| * |
| * @see #getSelection() |
| */ |
| private IStructuredSelection fCurrentSelection; |
| |
| /** |
| * The current script project |
| * |
| * @see #setInput(IScriptProject) |
| */ |
| private IScriptProject fCurrJProject; |
| |
| public DialogPackageExplorer() { |
| fActionGroup = null; |
| fCurrJProject = null; |
| fCurrentSelection = new StructuredSelection(); |
| } |
| |
| public Control createControl(Composite parent) { |
| fPackageViewer = new TreeViewer(parent, SWT.MULTI); |
| if (DLTKCore.DEBUG) { |
| System.err.println("Add comparer"); //$NON-NLS-1$ |
| } |
| // fPackageViewer.setComparer(WorkingSetModel.COMPARER); |
| fPackageViewer.addFilter(new PackageFilter()); |
| fPackageViewer.setComparator(new ExtendedModelElementSorter()); |
| fPackageViewer.addDoubleClickListener(event -> { |
| Object element = ((IStructuredSelection) event.getSelection()) |
| .getFirstElement(); |
| if (fPackageViewer.isExpandable(element)) { |
| fPackageViewer.setExpandedState(element, |
| !fPackageViewer.getExpandedState(element)); |
| } |
| }); |
| fPackageViewer.addSelectionChangedListener(this); |
| |
| MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$ |
| menuMgr.setRemoveAllWhenShown(true); |
| menuMgr.addMenuListener(this); |
| fContextMenu = menuMgr.createContextMenu(fPackageViewer.getTree()); |
| fPackageViewer.getTree().setMenu(fContextMenu); |
| parent.addDisposeListener(e -> fContextMenu.dispose()); |
| |
| return fPackageViewer.getControl(); |
| } |
| |
| /** |
| * Sets the action group for the package explorer. The action group is |
| * necessary to populate the context menu with available actions. If no |
| * context menu is needed, then this method does not have to be called. |
| * |
| * Should only be called once. |
| * |
| * @param actionGroup |
| * the action group to be used for the context menu. |
| */ |
| public void setActionGroup( |
| final DialogPackageExplorerActionGroup actionGroup) { |
| fActionGroup = actionGroup; |
| fPackageViewer.getControl().addDisposeListener(e -> { |
| if (actionGroup != null) |
| actionGroup.dispose(); |
| }); |
| } |
| |
| /** |
| * Populate the context menu with the necessary actions. |
| * |
| * @see org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager) |
| */ |
| @Override |
| public void menuAboutToShow(IMenuManager manager) { |
| if (fActionGroup == null) // no context menu |
| return; |
| DLTKUIPlugin.createStandardGroups(manager); |
| fActionGroup.fillContextMenu(manager); |
| } |
| |
| /** |
| * Set the content and label provider of the <code>fPackageViewer</code> |
| */ |
| public void setContentProvider() { |
| PackageContentProvider contentProvider = new PackageContentProvider(); |
| PackageLabelProvider labelProvider = new PackageLabelProvider( |
| AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS |
| | ScriptElementLabels.P_COMPRESSED, |
| AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS |
| | ScriptElementImageProvider.SMALL_ICONS, |
| getPreferenceStore()); |
| fPackageViewer.setContentProvider(contentProvider); |
| fPackageViewer.setLabelProvider( |
| new StyledDecoratingModelLabelProvider(labelProvider, false)); |
| } |
| |
| protected abstract IPreferenceStore getPreferenceStore(); |
| |
| /** |
| * Set the input for the package explorer. |
| * |
| * @param project |
| * the project to be displayed |
| */ |
| public void setInput(IScriptProject project) { |
| fCurrJProject = project; |
| fPackageViewer.setInput(new Object[0]); |
| fCurrentSelection = new StructuredSelection(project); |
| setSelection(Collections.singletonList(project)); |
| } |
| |
| /** |
| * Refresh the project tree |
| */ |
| public void refresh() { |
| fPackageViewer.refresh(true); |
| } |
| |
| /** |
| * Set the selection and focus to the list of elements |
| * |
| * @param elements |
| * the object to be selected and displayed |
| */ |
| public void setSelection(final List<?> elements) { |
| if (elements == null || elements.size() == 0) |
| return; |
| try { |
| ResourcesPlugin.getWorkspace().run(monitor -> { |
| fPackageViewer.refresh(); |
| final IStructuredSelection selection = new StructuredSelection( |
| elements); |
| fPackageViewer.setSelection(selection, true); |
| fPackageViewer.getTree().setFocus(); |
| if (fActionGroup != null) |
| fActionGroup.refresh(new DialogExplorerActionContext( |
| selection, fCurrJProject)); |
| |
| if (elements.size() == 1 |
| && elements.get(0) instanceof IScriptProject) |
| fPackageViewer.expandToLevel(elements.get(0), 1); |
| }, ResourcesPlugin.getWorkspace().getRoot(), |
| IWorkspace.AVOID_UPDATE, new NullProgressMonitor()); |
| } catch (CoreException e) { |
| DLTKUIPlugin.log(e); |
| } |
| } |
| |
| /** |
| * The current list of selected elements. The list may be empty if no |
| * element is selected. |
| * |
| * @return the current selection |
| */ |
| public IStructuredSelection getSelection() { |
| return fCurrentSelection; |
| } |
| |
| /** |
| * Get the viewer's control |
| * |
| * @return the viewers control |
| */ |
| public Control getViewerControl() { |
| return fPackageViewer.getControl(); |
| } |
| |
| /** |
| * Inform the <code>fActionGroup</code> about the selection change and store |
| * the latest selection. |
| * |
| * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) |
| * @see DialogPackageExplorerActionGroup#setContext(DialogExplorerActionContext) |
| */ |
| @Override |
| public void selectionChanged(SelectionChangedEvent event) { |
| fCurrentSelection = event.getStructuredSelection(); |
| try { |
| if (fActionGroup != null) |
| fActionGroup.setContext(new DialogExplorerActionContext( |
| fCurrentSelection, fCurrJProject)); |
| } catch (ModelException e) { |
| DLTKUIPlugin.log(e); |
| } |
| } |
| } |