/*******************************************************************************
* Copyright (c) 2000, 2009 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 org.eclipse.wst.jsdt.internal.ui.wizards.buildpaths.newsourcepage;
import java.util.ArrayList;
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.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IPostSelectionProvider;
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.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.part.ISetSelectionTarget;
import org.eclipse.wst.jsdt.core.IIncludePathEntry;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.IPackageFragment;
import org.eclipse.wst.jsdt.core.IPackageFragmentRoot;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.internal.core.JavaProject;
import org.eclipse.wst.jsdt.internal.corext.buildpath.ClasspathModifier;
import org.eclipse.wst.jsdt.internal.corext.util.Messages;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.filters.LibraryFilter;
import org.eclipse.wst.jsdt.internal.ui.packageview.PackageExplorerContentProvider;
import org.eclipse.wst.jsdt.internal.ui.packageview.PackageFragmentRootContainer;
import org.eclipse.wst.jsdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
import org.eclipse.wst.jsdt.internal.ui.viewsupport.DecoratingJavaLabelProvider;
import org.eclipse.wst.jsdt.internal.ui.viewsupport.JavaElementImageProvider;
import org.eclipse.wst.jsdt.internal.ui.wizards.NewWizardMessages;
import org.eclipse.wst.jsdt.internal.ui.wizards.buildpaths.CPListElementAttribute;
import org.eclipse.wst.jsdt.internal.ui.workingsets.WorkingSetModel;
import org.eclipse.wst.jsdt.ui.JavaScriptElementComparator;
import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels;
/**
* 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 class DialogPackageExplorer implements IMenuListener, ISelectionProvider, IPostSelectionProvider, ISetSelectionTarget {
/**
* A extended content provider for the package explorer.
*/
private final class PackageContentProvider extends PackageExplorerContentProvider {
public PackageContentProvider() {
super(false);
}
/**
* Get the elements of the current project
*
* @param element the element to get the children from, will
* not be used, instead the project children are returned directly
* @return returns the children of the project
*/
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.
*/
private final class PackageLabelProvider extends AppearanceAwareLabelProvider {
public PackageLabelProvider(long textFlags, int imageFlags) {
super(textFlags, imageFlags);
}
public String getText(Object element) {
if (element instanceof CPListElementAttribute)
return null;
String text= super.getText(element);
try {
if (element instanceof IPackageFragmentRoot) {
IPackageFragmentRoot root= (IPackageFragmentRoot)element;
if (root.exists() && ClasspathModifier.filtersSet(root)) {
IIncludePathEntry entry= root.getRawIncludepathEntry();
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, Integer.valueOf(excluded)});
}
}
if (element instanceof IJavaScriptProject) {
IJavaScriptProject project= (IJavaScriptProject)element;
if (project.exists() && project.isOnIncludepath(project)) {
IPackageFragmentRoot root= project.findPackageFragmentRoot(project.getPath());
if (ClasspathModifier.filtersSet(root)) {
IIncludePathEntry entry= root.getRawIncludepathEntry();
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, Integer.valueOf(excluded)});
}
}
}
if (element instanceof IFile || element instanceof IFolder) {
IResource resource= (IResource)element;
if (resource.exists() && ClasspathModifier.isExcluded(resource, fCurrJProject))
return Messages.format(NewWizardMessages.DialogPackageExplorer_LabelProvider_Excluded, text);
}
} catch (JavaScriptModelException e) {
JavaScriptPlugin.log(e);
}
return text;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.internal.ui.viewsupport.JavaUILabelProvider#getForeground(java.lang.Object)
*/
public Color getForeground(Object element) {
try {
if (element instanceof IPackageFragmentRoot) {
IPackageFragmentRoot root= (IPackageFragmentRoot)element;
if (root.exists() && ClasspathModifier.filtersSet(root))
return getBlueColor();
}
if (element instanceof IJavaScriptProject) {
IJavaScriptProject project= (IJavaScriptProject)element;
if (project.exists() && project.isOnIncludepath(project)) {
IPackageFragmentRoot root= project.findPackageFragmentRoot(project.getPath());
if (root != null && ClasspathModifier.filtersSet(root))
return getBlueColor();
}
}
if (element instanceof IFile || element instanceof IFolder) {
IResource resource= (IResource)element;
if (resource.exists() && ClasspathModifier.isExcluded(resource, fCurrJProject))
return getBlueColor();
}
} catch (JavaScriptModelException e) {
JavaScriptPlugin.log(e);
}
return null;
}
private Color getBlueColor() {
return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
}
}
/**
* A extended element sorter for the package explorer. The java elements
* are sorted in the normal way.
*/
private final class ExtendedJavaElementSorter extends JavaScriptElementComparator {
public ExtendedJavaElementSorter() {
super();
}
public int compare(Viewer viewer, Object e1, Object e2) {
if (e1 instanceof CPListElementAttribute)
return -1;
if (e2 instanceof CPListElementAttribute)
return 1;
return super.compare(viewer, e1, e2);
}
}
/**
* An extended filter for the package explorer which filters
* libraries,
* files named ".classpath" or ".project",
* the default package, and
* hidden folders.
*/
private final class PackageFilter extends LibraryFilter {
public boolean select(Viewer viewer, Object parentElement, Object element) {
try {
if (element instanceof IFile) {
IFile file= (IFile) element;
if (file.getName().equals(JavaProject.CLASSPATH_FILENAME) || file.getName().equals(".project")) //$NON-NLS-1$//$NON-NLS-2$
return false;
} else if (element instanceof IPackageFragmentRoot) {
IIncludePathEntry cpe= ((IPackageFragmentRoot)element).getRawIncludepathEntry();
if (cpe == null || cpe.getEntryKind() == IIncludePathEntry.CPE_CONTAINER || cpe.getEntryKind() == IIncludePathEntry.CPE_LIBRARY || cpe.getEntryKind() == IIncludePathEntry.CPE_VARIABLE)
return false;
} else if (element instanceof PackageFragmentRootContainer) {
return false;
} else if (element instanceof IPackageFragment) {
IPackageFragment fragment= (IPackageFragment)element;
if (fragment.isDefaultPackage() && !fragment.hasChildren())
return false;
} else if (element instanceof IFolder) {
IFolder folder= (IFolder)element;
if (folder.getName().startsWith(".")) //$NON-NLS-1$
return false;
}
} catch (JavaScriptModelException e) {
JavaScriptPlugin.log(e);
}
/*if (element instanceof IPackageFragmentRoot) {
IPackageFragmentRoot root= (IPackageFragmentRoot)element;
if (root.getElementName().endsWith(".jar") || root.getElementName().endsWith(".zip")) //$NON-NLS-1$ //$NON-NLS-2$
return false;
}*/
return super.select(viewer, parentElement, element);
}
}
/** 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 java project
* @see #setInput(IJavaScriptProject)
*/
private IJavaScriptProject fCurrJProject;
private PackageContentProvider fContentProvider;
public DialogPackageExplorer() {
fActionGroup= null;
fCurrJProject= null;
fCurrentSelection= new StructuredSelection();
}
public Control createControl(Composite parent) {
fPackageViewer= new TreeViewer(parent, SWT.MULTI);
fPackageViewer.setComparer(WorkingSetModel.COMPARER);
fPackageViewer.addFilter(new PackageFilter());
fPackageViewer.setComparator(new ExtendedJavaElementSorter());
fPackageViewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
Object element= ((IStructuredSelection)event.getSelection()).getFirstElement();
if (fPackageViewer.isExpandable(element)) {
fPackageViewer.setExpandedState(element, !fPackageViewer.getExpandedState(element));
}
}
});
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(new DisposeListener() {
public void widgetDisposed(DisposeEvent 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;
}
/**
* Populate the context menu with the necessary actions.
*
* @see org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager)
*/
public void menuAboutToShow(IMenuManager manager) {
if (fActionGroup == null) // no context menu
return;
JavaScriptPlugin.createStandardGroups(manager);
fActionGroup.fillContextMenu(manager);
}
/**
* Set the content and label provider of the
* <code>fPackageViewer</code>
*/
public void setContentProvider() {
if (fContentProvider != null) {
fContentProvider.dispose();
}
fContentProvider= new PackageContentProvider();
fContentProvider.setIsFlatLayout(true);
PackageLabelProvider labelProvider= new PackageLabelProvider(AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS | JavaScriptElementLabels.P_COMPRESSED,
AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS | JavaElementImageProvider.SMALL_ICONS);
fPackageViewer.setContentProvider(fContentProvider);
fPackageViewer.setLabelProvider(new DecoratingJavaLabelProvider(labelProvider, false));
}
/**
* Set the input for the package explorer.
*
* @param project the project to be displayed
*/
public void setInput(IJavaScriptProject project) {
IJavaScriptProject oldProject= fCurrJProject;
fCurrJProject= project;
if (fContentProvider != null)
fContentProvider.inputChanged(fPackageViewer, oldProject, fCurrJProject);
fPackageViewer.setInput(new Object[0]);
List selectedElements= new ArrayList();
selectedElements.add(fCurrJProject);
setSelection(selectedElements);
}
public void dispose() {
if (fContentProvider != null) {
fContentProvider.dispose();
fContentProvider= null;
}
if (fActionGroup != null) {
fActionGroup.dispose();
fActionGroup= null;
}
fPackageViewer= null;
}
/**
* 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(new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
fPackageViewer.refresh();
IStructuredSelection selection= new StructuredSelection(elements);
fPackageViewer.setSelection(selection, true);
fPackageViewer.getTree().setFocus();
if (elements.size() == 1 && elements.get(0) instanceof IJavaScriptProject)
fPackageViewer.expandToLevel(elements.get(0), 1);
}
}, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
} catch (CoreException e) {
JavaScriptPlugin.log(e);
}
}
/**
* The current list of selected elements. The
* list may be empty if no element is selected.
*
* @return the current selection
*/
public ISelection getSelection() {
return fCurrentSelection;
}
/**
* Get the viewer's control
*
* @return the viewers control
*/
public Control getViewerControl() {
return fPackageViewer.getControl();
}
/**
* {@inheritDoc}
*/
public void addSelectionChangedListener(ISelectionChangedListener listener) {
fPackageViewer.addSelectionChangedListener(listener);
}
/**
* {@inheritDoc}
*/
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
fPackageViewer.removeSelectionChangedListener(listener);
}
/**
* {@inheritDoc}
*/
public void setSelection(ISelection selection) {
setSelection(((StructuredSelection)selection).toList());
}
/**
* {@inheritDoc}
*/
public void addPostSelectionChangedListener(ISelectionChangedListener listener) {
fPackageViewer.addPostSelectionChangedListener(listener);
}
/**
* {@inheritDoc}
*/
public void removePostSelectionChangedListener(ISelectionChangedListener listener) {
fPackageViewer.removePostSelectionChangedListener(listener);
}
/**
* {@inheritDoc}
*/
public void selectReveal(ISelection selection) {
setSelection(selection);
}
}