/*******************************************************************************
* Copyright (C) 2003, 2004, 2007, 2008, 2013, Guillaume Brocker
*
* 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:
* Guillaume Brocker - Initial API and implementation
*
******************************************************************************/
package eclox.ui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
import org.eclipse.ui.model.IWorkbenchAdapter;
import eclox.core.Plugin;
import eclox.core.doxyfiles.ResourceCollector;
/**
* Allow the user to choose one doxyfile among a list.
*
* @author gbrocker
*/
public class DoxyfileSelector {
/**
* Implement the tree content provider for the dialog.
*/
private static class MyContentProvider implements ITreeContentProvider {
/**
* The doxyfile collection.
*/
private Collection<?> m_input = null;
/**
* Disposes of this content provider. This is called by the viewer when it is disposed.
*/
public void dispose() {}
/**
* Notifies this content provider that the given viewer's input has been switched to a different element.
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
m_input = (Collection<?>) newInput;
}
/**
* Returns the child elements of the given parent element.
*
* @param parentElement the parent element
*
* @return an array of child elements
*/
public Object[] getChildren(Object parentElement) {
Collection<IFile> children = new ArrayList<IFile>();
Iterator<?> doxyfileIt = m_input.iterator();
while(doxyfileIt.hasNext()) {
IFile doxyfile = (IFile) doxyfileIt.next();
if(doxyfile.getProject() == parentElement) {
children.add(doxyfile);
}
}
return children.toArray();
}
/**
* Returns the elements to display in the viewer when its input is set to the given element. These elements can be presented as rows in a table, items in a list, etc. The result is not modified by the viewer.
*
* @param inputElement the input element
*
* @return the array of elements to display in the viewer
*/
public Object[] getElements(Object inputElement) {
Collection<?> doxyfiles = (Collection<?>) inputElement;
Object[] result = null;
if(doxyfiles != null) {
Collection<IProject> projects = new HashSet<IProject>();
Iterator<?> doxyfileIt = doxyfiles.iterator();
while(doxyfileIt.hasNext() == true) {
IFile doxyfile = (IFile) doxyfileIt.next();
projects.add(doxyfile.getProject());
}
result = projects.toArray();
}
else {
result = new Object[0];
}
return result;
}
/**
* Returns the parent for the given element, or null indicating that the parent can't be computed.
*
* In this case the tree-structured viewer can't expand a given node correctly if requested.
*
* @param element the element
*
* @return the parent element, or null if it has none or if the parent cannot be computed.
*/
public Object getParent(Object element) {
Object result = null;
if(element instanceof IProject) {
return null;
}
else if(element instanceof IFile) {
return ((IFile)element).getProject();
}
return result;
}
/**
* Returns whether the given element has children.
*
* Intended as an optimization for when the viewer does not need the actual children. Clients may be able to implement this more efficiently than getChildren.
*
* @param element the element
*
* @return true if the given element has children, and false if it has no children
*/
public boolean hasChildren(Object element) {
return element instanceof IProject;
}
}
/**
* Implement a label provider for the doxyfile selector tree viewer.
*/
private static class MyLabelProvider extends LabelProvider {
/**
* Returns the image for the label of the given element.
* The image is owned by the label provider and must not be disposed directly.
* Instead, dispose the label provider when no longer needed.
*
* @param element the element for which to provide the label image
*
* @return the image used to label the element,
* or null if there is no image for the given object
*/
public Image getImage(Object element) {
// Pre-condition.
assert element instanceof IResource;
Image result = null;
IResource resourse = (IResource) element;
IWorkbenchAdapter workbenchAdapter = (IWorkbenchAdapter) resourse.getAdapter( IWorkbenchAdapter.class );
if( workbenchAdapter != null ) {
result = workbenchAdapter.getImageDescriptor( element ).createImage();
}
return result;
}
/**
* The LabelProvider implementation of this ILabelProvider method returns
* the element's toString string. Subclasses may override.
*
* @param element the element for which to provide the label text
*
* @return the text string used to label the element,
* or null if there is no text label for the given object
*/
public String getText(Object element) {
// Pre-condition.
assert element instanceof IResource;
String result = null;
IResource resourse = (IResource) element;
IWorkbenchAdapter workbenchAdapter = (IWorkbenchAdapter) resourse.getAdapter( IWorkbenchAdapter.class );
if( workbenchAdapter != null ) {
result = workbenchAdapter.getLabel( element );
}
return result;
}
}
/**
* Implement a doxyfile selection validator.
*/
private static class MySelectionValidator implements ISelectionStatusValidator {
/**
* Validates an array of elements and returns the resulting status.
*
* @param selection The elements to validate
*
* @return The resulting status
*/
public IStatus validate(Object[] selection) {
IStatus result = null;
if(selection.length == 1 && selection[0] instanceof IFile) {
result = new Status(
Status.OK,
Plugin.getDefault().getBundle().getSymbolicName(),
0,
"",
null
);
}
else {
result = new Status(
Status.ERROR,
Plugin.getDefault().getBundle().getSymbolicName(),
0,
"You must choose a Doxyfile to build.",
null);
}
return result;
}
}
private boolean hadDoxyfiles = false; ///< Tells if there were doxyfiles for selection.
private IFile doxyfile = null; ///< The selected doxyfile
private IResource root = null; ///< The root resource that is that will be starting point for doxyfiles search.
/**
* Initializes DoxyfileSelector
*
* @param rootResource the root resource to search for doxyfiles, the workspace root if null
*/
public DoxyfileSelector( IResource rootResource ) {
this.root = rootResource;
}
/**
* Opens the selection dialog and tells if the user validated to selection.
*
* @return true when a selection was made, false otherwise.
*/
public boolean open() {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
ISelection selection = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection();
IStructuredSelection structuredSelection = (selection != null && selection instanceof IStructuredSelection) ? (IStructuredSelection) selection : new StructuredSelection();
boolean result = false;
try {
ResourceCollector collector = root != null ? ResourceCollector.run(root) : ResourceCollector.run();
hadDoxyfiles = collector.isEmpty() == false;
if( collector.isEmpty() == false ) {
ElementTreeSelectionDialog selectionDialog = new ElementTreeSelectionDialog(shell, new MyLabelProvider(), new MyContentProvider());
selectionDialog.setAllowMultiple( false );
selectionDialog.setInput( collector.getDoxyfiles() );
selectionDialog.setValidator( new MySelectionValidator() );
selectionDialog.setEmptyListMessage( "No Doxyfile found in opened projects." );
selectionDialog.setMessage( "Select a Doxyfile:" );
selectionDialog.setTitle( "Doxyfile Selection" );
selectionDialog.setInitialSelections( structuredSelection.toArray() );
// Opens the selection dialog and save the selection.
if( selectionDialog.open() == ElementTreeSelectionDialog.OK ) {
doxyfile = (IFile) selectionDialog.getFirstResult();
result = true;
}
}
}
catch( Throwable t ) {
eclox.ui.Plugin.log(t);
}
return result;
}
/**
* Convenient method that prompts the user to select a doxyfile.
*
* @param root The root resource to search for doxyfiles
*
* @return the selected doxyfile, null otherwise
*/
public static IFile open( IResource root ) {
DoxyfileSelector selector = new DoxyfileSelector(root);
selector.open();
return selector.getDoxyfile();
}
/**
* @brief Asks the user for a doxyfile.
*
* @return a doxyfile, null if none has been choosen
*/
public IFile getDoxyfile() {
return doxyfile;
}
/**
* @brief Tells if there were doxyfiles for last selection.
*
* @return true or false
*/
public boolean hadDoxyfiles() {
return hadDoxyfiles;
}
}