blob: c88e2457b6589fbcadb828eed18aab016a3e936b [file] [log] [blame]
/*******************************************************************************
* 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);
}
}
}