content: /*******************************************************************************
   * Copyright (c) 2000, 2007 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.javadocexport;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.eclipse.jface.viewers.CheckStateChangedEvent;
  import org.eclipse.jface.viewers.CheckboxTableViewer;
  import org.eclipse.jface.viewers.CheckboxTreeViewer;
  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.IStructuredContentProvider;
  import org.eclipse.jface.viewers.IStructuredSelection;
  import org.eclipse.jface.viewers.ITreeContentProvider;
  import org.eclipse.jface.viewers.ITreeViewerListener;
  import org.eclipse.jface.viewers.SelectionChangedEvent;
  import org.eclipse.jface.viewers.StructuredSelection;
  import org.eclipse.jface.viewers.TreeExpansionEvent;
  import org.eclipse.jface.viewers.ViewerComparator;
  import org.eclipse.jface.viewers.ViewerFilter;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.custom.BusyIndicator;
  import org.eclipse.swt.layout.GridData;
  import org.eclipse.swt.layout.GridLayout;
  import org.eclipse.swt.widgets.Composite;
  import org.eclipse.swt.widgets.Table;
  import org.eclipse.swt.widgets.Tree;
  
  /**
   *	Combines a CheckboxTreeViewer and CheckboxListViewer.
   *	All viewer selection-driven interactions are handled within this viewer
   */
  public class CheckboxTreeAndListGroup implements ICheckStateListener, ISelectionChangedListener, ITreeViewerListener {
  
  	private Object fRoot;
  	private Object fCurrentTreeSelection;
  	private List fExpandedTreeNodes= new ArrayList();
  	private Map fCheckedStateStore= new HashMap(9);
  	private List fWhiteCheckedTreeItems= new ArrayList();
  	private List fListeners= new ArrayList();
  
  	private ITreeContentProvider fTreeContentProvider;
  	private IStructuredContentProvider fListContentProvider;
  	private ILabelProvider fTreeLabelProvider;
  	private ILabelProvider fListLabelProvider;
  
  	// widgets
  	private CheckboxTreeViewer fTreeViewer;
  	private CheckboxTableViewer fListViewer;
  
  	/**
  	 *	Creates an instance of this class.  Use this constructor if you wish to specify
  	 *	the width and/or height of the combined widget (to only hardcode one of the
  	 *	sizing dimensions, specify the other dimension's value as -1)
  	 */
  	public CheckboxTreeAndListGroup(
  			Composite parent,
  			Object rootObject,
  			ITreeContentProvider treeContentProvider,
  			ILabelProvider treeLabelProvider,
  			IStructuredContentProvider listContentProvider,
  			ILabelProvider listLabelProvider,
  			int style,
  			int width,
  			int height) {
  		fRoot= rootObject;
  		fTreeContentProvider= treeContentProvider;
  		fListContentProvider= listContentProvider;
  		fTreeLabelProvider= treeLabelProvider;
  		fListLabelProvider= listLabelProvider;
  		createContents(parent, width, height, style);
  	}
  	/**
  	 * This method must be called just before this window becomes visible.
  	 */
  	public void aboutToOpen() {
  		determineWhiteCheckedDescendents(fRoot);
  		checkNewTreeElements(getTreeChildren(fRoot));
  		fCurrentTreeSelection= null;
  
  		//select the first element in the list
  		Object[] elements= getTreeChildren(fRoot);
  		Object primary= elements.length > 0 ? elements[0] : null;
  		if (primary != null) {
  			fTreeViewer.setSelection(new StructuredSelection(primary));
  		}
  		fTreeViewer.getControl().setFocus();
  	}
  	/**
  	 *	Adds the passed listener to self's collection of clients
  	 *	that listen for changes to element checked states
  	 *
  	 *	@param listener ICheckStateListener
  	 */
  	public void addCheckStateListener(ICheckStateListener listener) {
  		fListeners.add(listener);
  	}
  	/**
  	 * Adds the receiver and all of it's ancestors to the checkedStateStore if they
  	 * are not already there.
  	 */
  	private void addToHierarchyToCheckedStore(Object treeElement) {
  
  		// if this tree element is already gray then its ancestors all are as well
  		if (!fCheckedStateStore.containsKey(treeElement))
  			fCheckedStateStore.put(treeElement, new ArrayList());
  
  		Object parent= fTreeContentProvider.getParent(treeElement);
  		if (parent != null)
  			addToHierarchyToCheckedStore(parent);
  	}
  	/**
  	 *	Returns a boolean indicating whether all children of the passed tree element
  	 *	are currently white-checked
  	 *
  	 *	@return boolean
  	 *	@param treeElement java.lang.Object
  	 */
  	protected boolean areAllChildrenWhiteChecked(Object treeElement) {
  		Object[] children= getTreeChildren(treeElement);
  		for (int i= 0; i < children.length; ++i) {
  			if (!fWhiteCheckedTreeItems.contains(children[i]))
  				return false;
  		}
  
  		return true;
  	}
  	/**
  	 *	Returns a boolean indicating whether all list elements associated with
  	 *	the passed tree element are currently checked
  	 *
  	 *	@return boolean
  	 *	@param treeElement java.lang.Object
  	 */
  	protected boolean areAllElementsChecked(Object treeElement) {
  		List checkedElements= (List)fCheckedStateStore.get(treeElement);
  		if (checkedElements == null) // ie.- tree item not even gray-checked
  			return false;
  
  		return getListItemsSize(treeElement) == checkedElements.size();
  	}
  	/**
  	 *	Iterates through the passed elements which are being realized for the first
  	 *	time and check each one in the tree viewer as appropriate
  	 */
  	protected void checkNewTreeElements(Object[] elements) {
  		for (int i= 0; i < elements.length; ++i) {
  			Object currentElement= elements[i];
  			boolean checked= fCheckedStateStore.containsKey(currentElement);
  			fTreeViewer.setChecked(currentElement, checked);
  			fTreeViewer.setGrayed(
  				currentElement,
  				checked && !fWhiteCheckedTreeItems.contains(currentElement));
  		}
  	}
  	/**
  	*	An item was checked in one of self's two views.  Determine which
  	*	view this occurred in and delegate appropriately
  	*
  	*	@param event CheckStateChangedEvent
  	*/
  	public void checkStateChanged(final CheckStateChangedEvent event) {
  
  		//Potentially long operation - show a busy cursor
  		BusyIndicator.showWhile(fTreeViewer.getControl().getDisplay(), new Runnable() {
  			public void run() {
  				if (event.getCheckable().equals(fTreeViewer))
  					treeItemChecked(event.getElement(), event.getChecked());
  				else
  					listItemChecked(event.getElement(), event.getChecked(), true);
  
  				notifyCheckStateChangeListeners(event);
  			}
  		});
  	}
  	/**
  	 *	Lay out and initialize self's visual components.
  	 *
  	 *	@param parent org.eclipse.swt.widgets.Composite
  	 *	@param width int
  	 *	@param height int
  	 */
  	protected void createContents(
  		Composite parent,
  		int width,
  		int height,
  		int style) {
  		// group pane
  		Composite composite= new Composite(parent, style);
  		GridLayout layout= new GridLayout();
  		layout.numColumns= 2;
  		layout.makeColumnsEqualWidth= true;
  		layout.marginHeight= 0;
  		layout.marginWidth= 0;
  		composite.setLayout(layout);
  		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
  
  		createTreeViewer(composite, width / 2, height);
  		createListViewer(composite, width / 2, height);
  
  		initialize();
  	}
  	/**
  	 *	Creates this group's list viewer.
  	 */
  	protected void createListViewer(Composite parent, int width, int height) {
  		fListViewer= CheckboxTableViewer.newCheckList(parent, SWT.BORDER);
  		fListViewer.setUseHashlookup(true);
  		GridData data= new GridData(GridData.FILL_BOTH);
  		data.widthHint= width;
  		data.heightHint= height;
  		fListViewer.getTable().setLayoutData(data);
  		fListViewer.setContentProvider(fListContentProvider);
  		fListViewer.setLabelProvider(fListLabelProvider);
  		fListViewer.addCheckStateListener(this);
  	}
  	/**
  	 *	Creates this group's tree viewer.
  	 */
  	protected void createTreeViewer(Composite parent, int width, int height) {
  		Tree tree= new Tree(parent, SWT.CHECK | SWT.BORDER);
  		GridData data= new GridData(GridData.FILL_BOTH);
  		data.widthHint= width;
  		data.heightHint= height;
  		tree.setLayoutData(data);
  
  		fTreeViewer= new CheckboxTreeViewer(tree);
  		fTreeViewer.setUseHashlookup(true);
  		fTreeViewer.setContentProvider(fTreeContentProvider);
  		fTreeViewer.setLabelProvider(fTreeLabelProvider);
  		fTreeViewer.addTreeListener(this);
  		fTreeViewer.addCheckStateListener(this);
  		fTreeViewer.addSelectionChangedListener(this);
  	}
  	/**
  	 * Returns a boolean indicating whether the passed tree element should be
  	 * at LEAST gray-checked.  Note that this method does not consider whether
  	 * it should be white-checked, so a specified tree item which should be
  	 * white-checked will result in a <code>true</code> answer from this method.
  	 * To determine whether a tree item should be white-checked use method
  	 * #determineShouldBeWhiteChecked(Object).
  	 *
  	 * @param treeElement java.lang.Object
  	 * @return boolean
  	 * @see #determineShouldBeWhiteChecked(java.lang.Object)
  	 */
  	protected boolean determineShouldBeAtLeastGrayChecked(Object treeElement) {
  		// if any list items associated with treeElement are checked then it
  		// retains its gray-checked status regardless of its children
  		List checked= (List) fCheckedStateStore.get(treeElement);
  		if (checked != null && (!checked.isEmpty()))
  			return true;
  
  		// if any children of treeElement are still gray-checked then treeElement
  		// must remain gray-checked as well
  		Object[] children= getTreeChildren(treeElement);
  		for (int i= 0; i < children.length; ++i) {
  			if (fCheckedStateStore.containsKey(children[i]))
  				return true;
  		}
  
  		return false;
  	}
  	/**
  	 * Returns a boolean indicating whether the passed tree item should be
  	 * white-checked.
  	 *
  	 * @return boolean
  	 * @param treeElement java.lang.Object
  	 */
  	protected boolean determineShouldBeWhiteChecked(Object treeElement) {
  		return areAllChildrenWhiteChecked(treeElement)
  			&& areAllElementsChecked(treeElement);
  	}
  	/**
  	 *	Recursively adds appropriate tree elements to the collection of
  	 *	known white-checked tree elements.
  	 *
  	 *	@param treeElement java.lang.Object
  	 */
  	protected void determineWhiteCheckedDescendents(Object treeElement) {
  		// always go through all children first since their white-checked
  		// statuses will be needed to determine the white-checked status for
  		// this tree element
  		Object[] children= getTreeChildren(treeElement);
  		for (int i= 0; i < children.length; ++i)
  			determineWhiteCheckedDescendents(children[i]);
  
  		// now determine the white-checked status for this tree element
  		if (determineShouldBeWhiteChecked(treeElement))
  			setWhiteChecked(treeElement, true);
  	}
  	/**
  	 * Causes the tree viewer to expand all its items
  	 */
  	public void expandAll() {
  		fTreeViewer.expandAll();
  	}
  	/**
  	 *	Answers a flat collection of all of the checked elements in the
  	 *	list portion of self
  	 *
  	 *	@return java.util.Vector
  	 */
  	public Iterator getAllCheckedListItems() {
  		Set result= new HashSet();
  		Iterator listCollectionsEnum= fCheckedStateStore.values().iterator();
  		while (listCollectionsEnum.hasNext())
  			result.addAll((List)listCollectionsEnum.next());
  		return result.iterator();
  	}
  	/**
  	 *	Answer a collection of all of the checked elements in the tree portion
  	 *	of self
  	 *
  	 *	@return java.util.Vector
  	 */
  	public Set getAllCheckedTreeItems() {
  		return new HashSet(fCheckedStateStore.keySet());
  	}
  	/**
  	 *	Answers the number of elements that have been checked by the
  	 *	user.
  	 *
  	 *	@return int
  	 */
  	public int getCheckedElementCount() {
  		return fCheckedStateStore.size();
  	}
  	/**
  	 *	Returns a count of the number of list items associated with a
  	 *	given tree item.
  	 *
  	 *	@return int
  	 *	@param treeElement java.lang.Object
  	 */
  	protected int getListItemsSize(Object treeElement) {
  		Object[] elements= getListElements(treeElement);
  		return elements.length;
  	}
  	/**
  	 * Gets the table that displays the folder content
  	 * 
  	 * @return the table used to show the list
  	 */
  	public Table getTable() {
  		return fListViewer.getTable();
  	}
  	/**
  	 * Gets the tree that displays the list for a folder
  	 * 
  	 * @return the tree used to show the folders
  	 */
  	public Tree getTree() {
  		return fTreeViewer.getTree();
  	}
  	/**
  	 * Adds the given filter to the tree viewer and
  	 * triggers refiltering and resorting of the elements.
  	 *
  	 * @param filter a viewer filter
  	 */
  	public void addTreeFilter(ViewerFilter filter) {
  		fTreeViewer.addFilter(filter);
  	}
  	/**
  	 * Adds the given filter to the list viewer and
  	 * triggers refiltering and resorting of the elements.
  	 *
  	 * @param filter a viewer filter
  	 */
  	public void addListFilter(ViewerFilter filter) {
  		fListViewer.addFilter(filter);
  	}
  	/**
  	 *	Logically gray-check all ancestors of treeItem by ensuring that they
  	 *	appear in the checked table
  	 */
  	protected void grayCheckHierarchy(Object treeElement) {
  
  		// if this tree element is already gray then its ancestors all are as well
  		if (fCheckedStateStore.containsKey(treeElement))
  			return; // no need to proceed upwards from here
  
  		fCheckedStateStore.put(treeElement, new ArrayList());
  		if (determineShouldBeWhiteChecked(treeElement)) {
  			setWhiteChecked(treeElement, true);
  		}
  		Object parent= fTreeContentProvider.getParent(treeElement);
  		if (parent != null)
  			grayCheckHierarchy(parent);
  	}
  	/**
  	 *	Sets the initial checked state of the passed list element to true.
  	 */
  	public void initialCheckListItem(Object element) {
  		Object parent= fTreeContentProvider.getParent(element);
  		fCurrentTreeSelection= parent;
  		//As this is not done from the UI then set the box for updating from the selection to false 
  		listItemChecked(element, true, false);
  		updateHierarchy(parent);
  	}
  	/**
  	 *	Sets the initial checked state of the passed element to true,
  	 *	as well as to all of its children and associated list elements
  	 */
  	public void initialCheckTreeItem(Object element) {
  		treeItemChecked(element, true);
  	}
  	/**
  	 *	Initializes this group's viewers after they have been laid out.
  	 */
  	protected void initialize() {
  		fTreeViewer.setInput(fRoot);
  	}
  	/**
  	 *	Callback that's invoked when the checked status of an item in the list
  	 *	is changed by the user. Do not try and update the hierarchy if we are building the
  	 *  initial list.
  	 */
  	protected void listItemChecked(
  		Object listElement,
  		boolean state,
  		boolean updatingFromSelection) {
  		List checkedListItems= (List) fCheckedStateStore.get(fCurrentTreeSelection);
  
  		if (state) {
  			if (checkedListItems == null) {
  				// since the associated tree item has gone from 0 -> 1 checked
  				// list items, tree checking may need to be updated
  				grayCheckHierarchy(fCurrentTreeSelection);
  				checkedListItems= (List) fCheckedStateStore.get(fCurrentTreeSelection);
  			}
  			checkedListItems.add(listElement);
  		} else {
  			checkedListItems.remove(listElement);
  			if (checkedListItems.isEmpty()) {
  				// since the associated tree item has gone from 1 -> 0 checked
  				// list items, tree checking may need to be updated
  				ungrayCheckHierarchy(fCurrentTreeSelection);
  			}
  		}
  
  		if (updatingFromSelection)
  			updateHierarchy(fCurrentTreeSelection);
  	}
  	/**
  	 *	Notifies all checked state listeners that the passed element has had
  	 *	its checked state changed to the passed state
  	 */
  	protected void notifyCheckStateChangeListeners(CheckStateChangedEvent event) {
  		Iterator listenersEnum= fListeners.iterator();
  		while (listenersEnum.hasNext())
  			 ((ICheckStateListener) listenersEnum.next()).checkStateChanged(event);
  	}
  	/**
  	 *Sets the contents of the list viewer based upon the specified selected
  	 *tree element.  This also includes checking the appropriate list items.
  	 *
  	 *@param treeElement java.lang.Object
  	 */
  	protected void populateListViewer(final Object treeElement) {
  		if (treeElement == fCurrentTreeSelection)
  			return;
  		fCurrentTreeSelection= treeElement;
  		fListViewer.setInput(treeElement);
  		List listItemsToCheck= (List) fCheckedStateStore.get(treeElement);
  
  		if (listItemsToCheck != null) {
  			Iterator listItemsEnum= listItemsToCheck.iterator();
  			while (listItemsEnum.hasNext())
  				fListViewer.setChecked(listItemsEnum.next(), true);
  		}
  	}
  	/**
  	 *	Removes the passed listener from self's collection of clients
  	 *	that listen for changes to element checked states
  	 *
  	 *	@param listener ICheckStateListener
  	 */
  	public void removeCheckStateListener(ICheckStateListener listener) {
  		fListeners.remove(listener);
  	}
  	/**
  	 *	Handles the selection of an item in the tree viewer
  	 *
  	 *	@param event ISelection
  	 */
  	public void selectionChanged(final SelectionChangedEvent event) {
  		BusyIndicator.showWhile(getTable().getShell().getDisplay(), new Runnable() {
  			public void run() {
  				IStructuredSelection selection= (IStructuredSelection) event.getSelection();
  				Object selectedElement= selection.getFirstElement();
  				if (selectedElement == null) {
  					fCurrentTreeSelection= null;
  					fListViewer.setInput(fCurrentTreeSelection);
  					return;
  				}
  				populateListViewer(selectedElement);
  			}
  		});
  	}
  
  	/**
  	 * Selects or deselect all of the elements in the tree depending on the value of the selection
  	 * boolean. Be sure to update the displayed files as well.
  	 */
  	public void setAllSelections(final boolean selection) {
  
  		//Potentially long operation - show a busy cursor
  		BusyIndicator.showWhile(fTreeViewer.getControl().getDisplay(), new Runnable() {
  			public void run() {
  				setTreeChecked(fRoot, selection);
  				fListViewer.setAllChecked(selection);
  			}
  		});
  	}
  
  	/**
  	 *	Sets the list viewer's providers to those passed
  	 *
  	 *	@param contentProvider ITreeContentProvider
  	 *	@param labelProvider ILabelProvider
  	 */
  	public void setListProviders(
  		IStructuredContentProvider contentProvider,
  		ILabelProvider labelProvider) {
  		fListViewer.setContentProvider(contentProvider);
  		fListViewer.setLabelProvider(labelProvider);
  	}
  	/**
  	 *	Sets the sorter that is to be applied to self's list viewer
  	 */
  	public void setListComparator(ViewerComparator comparator) {
  		fListViewer.setComparator(comparator);
  	}
  	/**
  	 * Sets the root of the widget to be new Root. Regenerate all of the tables and lists from this
  	 * value.
  	 * 
  	 * @param newRoot 
  	 */
  	public void setRoot(Object newRoot) {
  		this.fRoot= newRoot;
  		initialize();
  	}
  	/**
  	 *	Sets the checked state of the passed tree element appropriately, and
  	 *	do so recursively to all of its child tree elements as well
  	 */
  	protected void setTreeChecked(Object treeElement, boolean state) {
  
  		if (treeElement.equals(fCurrentTreeSelection)) {
  			fListViewer.setAllChecked(state);
  		}
  
  		if (state) {
  			Object[] listItems= getListElements(treeElement);
  			List listItemsChecked= new ArrayList();
  			for (int i= 0; i < listItems.length; ++i)
  				listItemsChecked.add(listItems[i]);
  
  			fCheckedStateStore.put(treeElement, listItemsChecked);
  		} else
  			fCheckedStateStore.remove(treeElement);
  
  		setWhiteChecked(treeElement, state);
  		fTreeViewer.setChecked(treeElement, state);
  		fTreeViewer.setGrayed(treeElement, false);
  
  		// now logically check/uncheck all children as well
  		Object[] children= getTreeChildren(treeElement);
  		for (int i= 0; i < children.length; ++i) {
  			setTreeChecked(children[i], state);
  		}
  	}
  	/**
  	 *	Sets the tree viewer's providers to those passed
  	 *
  	 *	@param contentProvider ITreeContentProvider
  	 *	@param labelProvider ILabelProvider
  	 */
  	public void setTreeProviders(
  		ITreeContentProvider contentProvider,
  		ILabelProvider labelProvider) {
  		fTreeViewer.setContentProvider(contentProvider);
  		fTreeViewer.setLabelProvider(labelProvider);
  	}
  	/**
  	 *	Sets the sorter that is to be applied to self's tree viewer
  	 */
  	public void setTreeComparator(ViewerComparator sorter) {
  		fTreeViewer.setComparator(sorter);
  	}
  	/**
  	 *	Adjusts the collection of references to white-checked tree elements appropriately.
  	 *
  	 *	@param treeElement java.lang.Object
  	 *	@param isWhiteChecked boolean
  	 */
  	protected void setWhiteChecked(Object treeElement, boolean isWhiteChecked) {
  		if (isWhiteChecked) {
  			if (!fWhiteCheckedTreeItems.contains(treeElement))
  				fWhiteCheckedTreeItems.add(treeElement);
  		} else
  			fWhiteCheckedTreeItems.remove(treeElement);
  	}
  	/**
  	 *	Handle the collapsing of an element in a tree viewer
  	 */
  	public void treeCollapsed(TreeExpansionEvent event) {
  		// We don't need to do anything with this
  	}
  
  	/**
  	 *	Handles the expansionsion of an element in a tree viewer
  	 */
  	public void treeExpanded(TreeExpansionEvent event) {
  
  		Object item= event.getElement();
  
  		// First see if the children need to be given their checked state at all.  If they've
  		// already been realized then this won't be necessary
  		if (!fExpandedTreeNodes.contains(item)) {
  			fExpandedTreeNodes.add(item);
  			checkNewTreeElements(getTreeChildren(item));
  		}
  	}
  
  	/**
  	 *  Callback that's invoked when the checked status of an item in the tree
  	 *  is changed by the user.
  	 */
  	protected void treeItemChecked(Object treeElement, boolean state) {
  
  		// recursively adjust all child tree elements appropriately
  		setTreeChecked(treeElement, state);
  
  		Object parent= fTreeContentProvider.getParent(treeElement);
  		if (parent == null)
  			return;
  
  		// now update upwards in the tree hierarchy 
  		if (state)
  			grayCheckHierarchy(parent);
  		else
  			ungrayCheckHierarchy(parent);
  
  		updateHierarchy(treeElement);
  	}
  	/**
  	 *	Logically un-gray-check all ancestors of treeItem iff appropriate.
  	 */
  	protected void ungrayCheckHierarchy(Object treeElement) {
  		if (!determineShouldBeAtLeastGrayChecked(treeElement))
  			fCheckedStateStore.remove(treeElement);
  
  		Object parent= fTreeContentProvider.getParent(treeElement);
  		if (parent != null)
  			ungrayCheckHierarchy(parent);
  	}
  	/**
  	 *	Sets the checked state of self and all ancestors appropriately
  	 */
  	protected void updateHierarchy(Object treeElement) {
  
  		boolean whiteChecked= determineShouldBeWhiteChecked(treeElement);
  		boolean shouldBeAtLeastGray= determineShouldBeAtLeastGrayChecked(treeElement);
  
  		fTreeViewer.setChecked(treeElement, whiteChecked || shouldBeAtLeastGray);
  		setWhiteChecked(treeElement, whiteChecked);
  		if (whiteChecked)
  			fTreeViewer.setGrayed(treeElement, false);
  		else
  			fTreeViewer.setGrayed(treeElement, shouldBeAtLeastGray);
  
  		// proceed up the tree element hierarchy
  		Object parent= fTreeContentProvider.getParent(treeElement);
  		if (parent != null) {
  			updateHierarchy(parent);
  		}
  	}
  	/**
  	 * Update the selections of the tree elements in items to reflect the new
  	 * selections provided.
  	 * 
  	 * @param items with keys of Object (the tree element) and values of List (the selected
  	 * list elements).
  	 */
  	public void updateSelections(final Map items) {
  
  		//Potentially long operation - show a busy cursor
  		BusyIndicator.showWhile(fTreeViewer.getControl().getDisplay(), new Runnable() {
  			public void run() {
  				handleUpdateSelection(items);
  			}
  		});
  	}
  	/**
  	 * Returns the result of running the given elements through the filters.
  	 *
  	 * @param elements the elements to filter
  	 * @return only the elements which all filters accept
  	 */
  	protected Object[] filter(ViewerFilter[] filters, Object[] elements) {
  		if (filters != null) {
  			ArrayList filtered = new ArrayList(elements.length);
  			for (int i = 0; i < elements.length; i++) {
  				boolean add = true;
  				for (int j = 0; j < filters.length; j++) {
  					add = filters[j].select(null, null, elements[i]);
  					if (!add)
  						break;
  				}
  				if (add)
  					filtered.add(elements[i]);
  			}
  			return filtered.toArray();
  		}
  		return elements;
  	}
  
  	private Object[] getTreeChildren(Object element) {
  		return filter(fTreeViewer.getFilters(), fTreeContentProvider.getChildren(element));
  	}
  
  	private Object[] getListElements(Object element) {
  		return filter(fListViewer.getFilters(), fListContentProvider.getElements(element));
  	}
  
  	public Set getWhiteCheckedTreeItems() {
  		return new HashSet(fWhiteCheckedTreeItems);
  	}
  
  	private void handleUpdateSelection(Map items) {
  		Iterator keyIterator= items.keySet().iterator();
  
  		//Update the store before the hierarchy to prevent updating parents before all of the children are done
  		while (keyIterator.hasNext()) {
  			Object key= keyIterator.next();
  			//Replace the items in the checked state store with those from the supplied items
  			List selections= (List) items.get(key);
  			if (selections.size() == 0)
  				//If it is empty remove it from the list
  				fCheckedStateStore.remove(key);
  			else {
  				fCheckedStateStore.put(key, selections);
  				// proceed up the tree element hierarchy
  				Object parent= fTreeContentProvider.getParent(key);
  				if (parent != null) {
  					addToHierarchyToCheckedStore(parent);
  				}
  			}
  		}
  
  		//Now update hierarchies
  		keyIterator= items.keySet().iterator();
  
  		while (keyIterator.hasNext()) {
  			Object key= keyIterator.next();
  			updateHierarchy(key);
  			if (fCurrentTreeSelection != null && fCurrentTreeSelection.equals(key)) {
  				fListViewer.setAllChecked(false);
  				fListViewer.setCheckedElements(((List) items.get(key)).toArray());
  			}
  		}
  	}		
  	
  	/**
  	 * Checks if an element is grey checked.
  	 */
  	public boolean isTreeItemGreyChecked(Object object) {
  		return fTreeViewer.getGrayed(object);	
  	}	
  
  	/**
  	 * For a given element, expand its chidren to a level.
  	 */	
  	public void expandTreeToLevel(Object object, int level) {
  		fTreeViewer.expandToLevel(object, level);	
  	}
  	/**
  	 * @param selection
  	 */
  	public void setTreeSelection(ISelection selection) {
  		fTreeViewer.setSelection(selection);
  	}
  }
  