/*******************************************************************************
* Copyright (c) 2006 Mountainminds GmbH & Co. KG
* This software is provided under the terms of the Eclipse Public License v1.0
* See http://www.eclipse.org/legal/epl-v10.html.
*
* $Id: ClassesViewer.java 420 2007-12-05 11:49:00Z mtnminds $
******************************************************************************/
package com.mountainminds.eclemma.internal.ui.viewers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ILabelProvider;
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.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import com.mountainminds.eclemma.core.IClassFiles;
import com.mountainminds.eclemma.internal.ui.UIMessages;
/**
* Viewer for selecting <code>IClassFiles</code> objects from a given list.
* The viewer lists the corresponding IPackageFragmentRoots. Source based class
* files may have multiple corresponding roots, their selection status is
* connected.
*
* @author Marc R. Hoffmann
* @version $Revision: 420 $
*/
public class ClassesViewer implements ISelectionProvider {
private static class PackageFragmentRootLabelProvider extends LabelProvider {
private ILabelProvider delegate = new WorkbenchLabelProvider();
public Image getImage(Object element) {
return delegate.getImage(element);
}
public String getText(Object element) {
IPackageFragmentRoot root = (IPackageFragmentRoot) element;
String projectname = root.getJavaProject().getElementName();
String path = getPathLabel(root);
if (path.length() > 0) {
String fmt = UIMessages.ClassesViewerEntry_label;
return NLS.bind(fmt, projectname, getPathLabel(root));
} else {
return projectname;
}
}
public void dispose() {
delegate.dispose();
}
}
/**
* The entries will be sorted by project name, type and path name.
*/
private static class PackageFragmentRootSorter extends ViewerSorter {
public int compare(Viewer viewer, Object e1, Object e2) {
IPackageFragmentRoot root1 = (IPackageFragmentRoot) e1;
IPackageFragmentRoot root2 = (IPackageFragmentRoot) e2;
int result = getCollator().compare(root1.getJavaProject().getElementName(),
root2.getJavaProject().getElementName());
if (result != 0) return result;
if (root1.isExternal() != root2.isExternal()) {
return root1.isExternal() ? 1 : -1;
}
return getCollator().compare(getPathLabel(root1), getPathLabel(root2));
}
};
/**
* Calculates a label for the class path of the given package fragment root.
* For external entries this is the full path, otherwise it is the project
* relative path.
*
* @param root package fragement root
* @return label for the class path entry
*/
private static String getPathLabel(IPackageFragmentRoot root) {
IPath path = root.getPath();
if (!root.isExternal()) {
path = path.removeFirstSegments(1);
}
return path.toString();
}
private final Table table;
private final CheckboxTableViewer viewer;
private final List listeners = new ArrayList();
private IClassFiles[] input;
private boolean includebinaries;
private final Set selectedclasses = new HashSet();
/**
* Creates a new viewer within the given parent.
*
* @param parent
* composite to create the viewer's table in
* @param style
* flags specifying the table's style
*/
public ClassesViewer(Composite parent, int style) {
this(new Table(parent, SWT.CHECK | style));
}
/**
* Attaches the viewer to the given table.
*
* @param table
* view table
*/
public ClassesViewer(Table table) {
this.table = table;
viewer = new CheckboxTableViewer(table);
viewer.setContentProvider(new ArrayContentProvider());
viewer.setLabelProvider(new PackageFragmentRootLabelProvider());
viewer.setSorter(new PackageFragmentRootSorter());
viewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
updateCheckedStatus(event.getElement(), event.getChecked());
}
});
}
/**
* Returns the table used by the viewer.
*
* @return table used by the viewer
*/
public Table getTable() {
return table;
}
/**
* Sets the input for this viewer.
*
* @param input
* list of classfiles objects the user can select from
*/
public void setInput(IClassFiles[] input) {
this.input = input;
viewer.setInput(getPackageFragmentRoots(input));
}
/**
* Specifies whether binary classpath entries should also be listed.
*
* @param includebinaries
* <code>true</code> if binary entries should be listed
*/
public void setIncludeBinaries(boolean includebinaries) {
this.includebinaries = includebinaries;
if (!includebinaries) {
for (Iterator i = selectedclasses.iterator(); i.hasNext();) {
if (((IClassFiles) i.next()).isBinary()) {
i.remove();
}
}
}
if (input != null) {
viewer.setInput(getPackageFragmentRoots(input));
}
}
/**
* Sets the initially checked classes.
*
* @param classfiles
* list of classfiles that should be checked
*/
public void setSelectedClasses(IClassFiles[] classfiles) {
selectedclasses.clear();
selectedclasses.addAll(Arrays.asList(classfiles));
viewer.setCheckedElements(getPackageFragmentRoots(classfiles));
}
/**
* Sets the initially checked classes from the given locations.
*
* @param locations
* location strings of the classes to select
*/
public void setSelectedClasses(String[] locations) {
Set lset = new HashSet(Arrays.asList(locations));
selectedclasses.clear();
for (int i = 0; i < input.length; i++) {
if (lset.contains(input[i].getLocation().toString())) {
selectedclasses.add(input[i]);
}
}
viewer.setCheckedElements(getPackageFragmentRoots(selectedclasses.toArray()));
}
public void selectAll() {
selectedclasses.clear();
for (int i = 0; i < input.length; i++) {
if (includebinaries || !input[i].isBinary()) {
selectedclasses.add(input[i]);
}
}
viewer.setCheckedElements(getPackageFragmentRoots(selectedclasses.toArray()));
}
public void deselectAll() {
selectedclasses.clear();
viewer.setCheckedElements(new Object[0]);
}
/**
* Returns the currently checked classes.
*
* @return list of class files that are currently checked
*/
public IClassFiles[] getSelectedClasses() {
return (IClassFiles[]) selectedclasses.toArray(new IClassFiles[0]);
}
/**
* Returns the locations of the currently checked classes.
*
* @return list of locations of class files that are currently checked
*/
public String[] getSelectedClassesLocations() {
String[] locs = new String[selectedclasses.size()];
int idx = 0;
for (Iterator i = selectedclasses.iterator(); i.hasNext();) {
locs[idx++] = ((IClassFiles) i.next()).getLocation().toString();
}
return locs;
}
/**
* Registers the given selection listener if not already registered.
*
* @param listener
* listener to add
*/
public void addSelectionChangedListener(ISelectionChangedListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
/**
* Removes the given selection listener.
*
* @param listener
* listener to remove
*/
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
listeners.remove(listener);
}
private IPackageFragmentRoot[] getPackageFragmentRoots(Object[] classfiles) {
Set roots = new HashSet();
for (int i = 0; i < classfiles.length; i++) {
IClassFiles cf = (IClassFiles) classfiles[i];
if (includebinaries || !cf.isBinary()) {
roots.addAll(Arrays.asList(cf.getPackageFragmentRoots()));
}
}
return (IPackageFragmentRoot[]) roots
.toArray(new IPackageFragmentRoot[roots.size()]);
}
private void updateCheckedStatus(Object root, boolean checked) {
for (int i = 0; i < input.length; i++) {
IClassFiles cf = input[i];
if (Arrays.asList(cf.getPackageFragmentRoots()).contains(root)) {
if (checked) {
selectedclasses.add(cf);
} else {
selectedclasses.remove(cf);
}
break;
}
}
viewer.setCheckedElements(getPackageFragmentRoots(selectedclasses.toArray()));
fireSelectionEvent();
}
private void fireSelectionEvent() {
SelectionChangedEvent evt = new SelectionChangedEvent(this, getSelection());
for (Iterator i = listeners.iterator(); i.hasNext();) {
ISelectionChangedListener l = (ISelectionChangedListener) i.next();
l.selectionChanged(evt);
}
}
// ISelectionProvider interface
public ISelection getSelection() {
return new StructuredSelection(getSelectedClasses());
}
public void setSelection(ISelection selection) {
Object[] classfiles = ((IStructuredSelection) selection).toArray();
selectedclasses.clear();
selectedclasses.addAll(Arrays.asList(classfiles));
viewer.setCheckedElements(getPackageFragmentRoots(classfiles));
}
}