blob: 342f20fec55838d72e9d15d5035c4b36ef109a7b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 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.jdt.internal.ui.wizards.buildpaths.newsourcepage;
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.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
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;
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.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.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.corext.buildpath.ClasspathModifier;
import org.eclipse.jdt.internal.corext.buildpath.IClasspathInformationProvider;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.ui.JavaElementSorter;
import org.eclipse.jdt.ui.StandardJavaElementContentProvider;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.filters.LibraryFilter;
import org.eclipse.jdt.internal.ui.filters.OutputFolderFilter;
import org.eclipse.jdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
import org.eclipse.jdt.internal.ui.viewsupport.DecoratingJavaLabelProvider;
import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
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.CPListElementAttribute;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListLabelProvider;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.DialogPackageExplorerActionGroup.DialogExplorerActionContext;
import org.eclipse.jdt.internal.ui.workingsets.WorkingSetModel;
/**
* 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, ISelectionChangedListener {
/**
* A extended content provider for the package explorer which can additionally display
* an output folder item.
*/
private final class PackageContentProvider extends StandardJavaElementContentProvider {
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
*/
public Object[] getElements(Object element) {
if (fCurrJProject == null)
return new Object[0];
return new Object[] {fCurrJProject};
}
/**
* Get the children of the current <code>element</code>. If the
* element is of type <code>IPackageFragmentRoot</code> and
* displaying the output folders is selected, then an icon for
* the output folder is created and displayed additionally.
*
* @param element the current element to get the children from
* @return an array of children
*/
public Object[] getChildren(Object element) {
Object[] children= super.getChildren(element);
if (((element instanceof IPackageFragmentRoot && !((IPackageFragmentRoot)element).isArchive()) ||
(element instanceof IJavaProject && fCurrJProject.isOnClasspath(fCurrJProject))) && isSelected()) {
try {
IClasspathEntry entry;
if (element instanceof IPackageFragmentRoot)
entry= ((IPackageFragmentRoot) element).getRawClasspathEntry();
else
entry= ClasspathModifier.getClasspathEntryFor(fCurrJProject.getPath(), fCurrJProject, IClasspathEntry.CPE_SOURCE);
CPListElement parent= CPListElement.createFromExisting(entry, fCurrJProject);
CPListElementAttribute outputFolder= new CPListElementAttribute(parent, CPListElement.OUTPUT,
parent.getAttribute(CPListElement.OUTPUT), true);
Object[] extendedChildren= new Object[children.length + 1];
System.arraycopy(children, 0, extendedChildren, 1, children.length);
extendedChildren[0]= outputFolder;
return extendedChildren;
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
return null;
}
else
return children;
}
}
/**
* A extended label provider for the package explorer which can additionally display
* an output folder item.
*/
private final class PackageLabelProvider extends AppearanceAwareLabelProvider {
private CPListLabelProvider outputFolderLabel;
public PackageLabelProvider(long textFlags, int imageFlags) {
super(textFlags, imageFlags);
outputFolderLabel= new CPListLabelProvider();
}
public String getText(Object element) {
if (element instanceof CPListElementAttribute)
return outputFolderLabel.getText(element);
String text= super.getText(element);
try {
if (element instanceof IPackageFragmentRoot) {
IPackageFragmentRoot root= (IPackageFragmentRoot)element;
if (root.exists() && ClasspathModifier.filtersSet(root)) {
IClasspathEntry entry= root.getRawClasspathEntry();
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, new Integer(excluded)});
}
}
if (element instanceof IJavaProject) {
IJavaProject project= (IJavaProject)element;
if (project.exists() && project.isOnClasspath(project)) {
IPackageFragmentRoot root= project.findPackageFragmentRoot(project.getPath());
if (ClasspathModifier.filtersSet(root)) {
IClasspathEntry entry= root.getRawClasspathEntry();
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, new Integer(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 (JavaModelException e) {
JavaPlugin.log(e);
}
return text;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.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 IJavaProject) {
IJavaProject project= (IJavaProject)element;
if (project.exists() && project.isOnClasspath(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 (JavaModelException e) {
JavaPlugin.log(e);
}
return null;
}
private Color getBlueColor() {
return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
}
public Image getImage(Object element) {
if (element instanceof CPListElementAttribute)
return outputFolderLabel.getImage(element);
return super.getImage(element);
}
public void dispose() {
outputFolderLabel.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 java elements
* are sorted in the normal way.
*/
private final class ExtendedJavaElementSorter extends JavaElementSorter {
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);
}
}
/**
* A extended filter for the package explorer which filters libraries and
* files if their name is either ".classpath" or ".project".
*/
private final class PackageFilter extends LibraryFilter {
private OutputFolderFilter fOutputFolderFilter= new OutputFolderFilter();
public boolean select(Viewer viewer, Object parentElement, Object element) {
try {
if (element instanceof IFile) {
IFile file= (IFile) element;
if (file.getName().equals(".classpath") || file.getName().equals(".project")) //$NON-NLS-1$//$NON-NLS-2$
return false;
}
if (element instanceof IPackageFragmentRoot) {
IClasspathEntry cpe= ((IPackageFragmentRoot)element).getRawClasspathEntry();
if (cpe == null || cpe.getEntryKind() == IClasspathEntry.CPE_CONTAINER)
return false;
}
} catch (JavaModelException e) {
JavaPlugin.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) &&*/ fOutputFolderFilter.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;
/**
* Flag to indicate whether output folders
* can be created or not. This is used to
* set the content correctly in the case
* that a IPackageFragmentRoot is selected.
*
* @see #showOutputFolders(boolean)
* @see #isSelected()
*/
private boolean fShowOutputFolders= false;
/** Stores the current selection in the tree
* @see #getSelection()
*/
private IStructuredSelection fCurrentSelection;
/** The current java project
* @see #setInput(IJavaProject)
*/
private IJavaProject fCurrJProject;
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.setSorter(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));
} else {
if (element instanceof CPListElementAttribute) {
CPListElementAttribute attribute= (CPListElementAttribute)element;
if (attribute.getKey().equals(CPListElement.OUTPUT)) {
ClasspathModifierAction[] actions= fActionGroup.getActions();
for (int i= 0; i < actions.length; i++) {
if (actions[i].getOperation().getTypeId() == IClasspathInformationProvider.EDIT_OUTPUT) {
actions[i].run();
return;
}
}
}
}
}
}
});
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(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;
fPackageViewer.getControl().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent 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)
*/
public void menuAboutToShow(IMenuManager manager) {
if (fActionGroup == null) // no context menu
return;
JavaPlugin.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 | JavaElementLabels.P_COMPRESSED,
AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS | JavaElementImageProvider.SMALL_ICONS);
fPackageViewer.setContentProvider(contentProvider);
fPackageViewer.setLabelProvider(new DecoratingJavaLabelProvider(labelProvider, false));
}
/**
* Set the input for the package explorer.
*
* @param project the project to be displayed
*/
public void setInput(IJavaProject project) {
fCurrJProject= project;
fPackageViewer.setInput(new Object());
IStructuredSelection selection= new StructuredSelection(project);
fPackageViewer.setSelection(selection);
fPackageViewer.expandToLevel(2);
fCurrentSelection= selection;
try {
if (fActionGroup != null)
fActionGroup.refresh(new DialogExplorerActionContext(fCurrentSelection, fCurrJProject));
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
}
/**
* 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(List elements) {
if (elements == null || elements.size() == 0)
return;
fPackageViewer.refresh();
IStructuredSelection selection= new StructuredSelection(elements);
fPackageViewer.setSelection(selection, true);
fPackageViewer.getTree().setFocus();
if (elements.size() == 1 && elements.get(0) instanceof IJavaProject)
fPackageViewer.expandToLevel(elements.get(0), 1);
}
/**
* 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();
}
/**
* Flag to indicate whether output folders
* can be created or not. This is used to
* set the content correctly in the case
* that a IPackageFragmentRoot is selected.
*/
private boolean isSelected() {
return fShowOutputFolders;
}
/**
* Method that is called whenever setting of
* output folders is allowed or forbidden (for example
* on changing a checkbox with this setting):
*
* @param showOutputFolders <code>true</code> if output
* folders should be shown, <code>false</code> otherwise.
*/
public void showOutputFolders(boolean showOutputFolders) {
fShowOutputFolders= showOutputFolders;
fActionGroup.showOutputFolders(showOutputFolders);
fPackageViewer.refresh();
}
/**
* 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)
*/
public void selectionChanged(SelectionChangedEvent event) {
fCurrentSelection= (IStructuredSelection)event.getSelection();
try {
if (fActionGroup != null)
fActionGroup.setContext(new DialogExplorerActionContext(fCurrentSelection, fCurrJProject));
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
}
}