/******************************************************************************* * 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; } }