blob: 8f3b8cf846a0a5e4f697eb5119f4da184c46e50d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 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.ui.internal.editors.text;
import java.util.ArrayList;
import java.util.Collection;
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.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.resources.IContainer;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.util.SafeRunnable;
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.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;
/*
* XXX: This is an copy of the internal ResourceTreeAndListGroup class, see http://bugs.eclipse.org/147027
*/
/**
* Workbench-level composite that combines a CheckboxTreeViewer and
* CheckboxListViewer. All viewer selection-driven interactions are handled
* within this object
*/
class SelectResourcesBlock implements ICheckStateListener, ISelectionChangedListener, ITreeViewerListener {
/**
* The IElementFilter is a interface that defines
* the API for filtering the current selection of
* a ResourceTreeAndListGroup in order to find a
* subset to update as the result of a type filtering.
* This is meant as an internal class and is used exclusively
* by the import dialog.
*/
interface IElementFilter {
void filterElements(Collection<Object> elements) throws InterruptedException;
void filterElements(Object[] elements) throws InterruptedException;
}
private Object root;
private Object currentTreeSelection;
private Collection<Object> expandedTreeNodes= new HashSet<>();
private Map<Object, List<Object>> checkedStateStore= new HashMap<>(9);
private Collection<Object> whiteCheckedTreeItems= new HashSet<>();
private ListenerList listeners= new ListenerList(ListenerList.IDENTITY);
private ITreeContentProvider treeContentProvider;
private IStructuredContentProvider listContentProvider;
private ILabelProvider treeLabelProvider;
private ILabelProvider listLabelProvider;
// widgets
private CheckboxTreeViewer treeViewer;
private CheckboxTableViewer listViewer;
//height hint for viewers
private static int PREFERRED_HEIGHT= 150;
/**
* Create an instance of this class. Use this constructor if you wish to specify the width
* and/or height of the combined widget (to only hard code one of the sizing dimensions, specify
* the other dimension's value as -1)
*
* @param parent the parent composite
* @param rootObject the root object
* @param treeContentProvider the tree content provider
* @param treeLabelProvider the tree label provider
* @param listContentProvider the list content provider
* @param listLabelProvider the list label provider
* @param style the style flags for the new Composite
* @param useHeightHint If true then use the height hint to make this group big enough
*/
public SelectResourcesBlock(Composite parent, Object rootObject, ITreeContentProvider treeContentProvider, ILabelProvider treeLabelProvider, IStructuredContentProvider listContentProvider, ILabelProvider listLabelProvider, int style, boolean useHeightHint) {
root= rootObject;
this.treeContentProvider= treeContentProvider;
this.listContentProvider= listContentProvider;
this.treeLabelProvider= treeLabelProvider;
this.listLabelProvider= listLabelProvider;
createContents(parent, style, useHeightHint);
}
/**
* Add 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) {
listeners.add(listener);
}
/**
* Iterates over the passed elements which are being realized for the
* first time and check each one in the tree viewer as appropriate.
*
* @param elements the elements
*/
private void checkNewTreeElements(Object[] elements) {
for (int i= 0; i < elements.length; ++i) {
Object currentElement= elements[i];
boolean checked= checkedStateStore.containsKey(currentElement);
treeViewer.setChecked(currentElement, checked);
treeViewer.setGrayed(currentElement, checked && !whiteCheckedTreeItems.contains(currentElement));
}
}
/**
* An item was checked in one of self's two views. Determine which view this
* occurred in and delegate appropriately
*
* @param event the check state event
* @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent)
*/
@Override
public void checkStateChanged(final CheckStateChangedEvent event) {
//Potentially long operation - show a busy cursor
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() {
@Override
public void run() {
if (event.getCheckable().equals(treeViewer))
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 style the style flags for the new Composite
* @param useHeightHint If true use the preferredHeight.
*/
private void createContents(Composite parent, int style, boolean useHeightHint) {
// group pane
Composite composite= new Composite(parent, style);
composite.setFont(parent.getFont());
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, useHeightHint);
createListViewer(composite, useHeightHint);
initialize();
}
/**
* Creates this block's list viewer.
*
* @param parent the parent control
* @param useHeightHint if <code>true</code> use the height hints
*/
private void createListViewer(Composite parent, boolean useHeightHint) {
listViewer= CheckboxTableViewer.newCheckList(parent, SWT.BORDER);
GridData data= new GridData(GridData.FILL_BOTH);
if (useHeightHint)
data.heightHint= PREFERRED_HEIGHT;
data.widthHint= getViewerWidthHint(parent);
listViewer.getTable().setLayoutData(data);
listViewer.getTable().setFont(parent.getFont());
listViewer.setContentProvider(listContentProvider);
listViewer.setLabelProvider(listLabelProvider);
listViewer.addCheckStateListener(this);
}
/**
* Create this block's tree viewer.
*
* @param parent the parent control
* @param useHeightHint if <code>true</code> use the height hints
*/
private void createTreeViewer(Composite parent, boolean useHeightHint) {
Tree tree= new Tree(parent, SWT.CHECK | SWT.BORDER);
GridData data= new GridData(GridData.FILL_BOTH);
if (useHeightHint)
data.heightHint= PREFERRED_HEIGHT;
data.widthHint= getViewerWidthHint(parent);
tree.setLayoutData(data);
tree.setFont(parent.getFont());
treeViewer= new CheckboxTreeViewer(tree);
treeViewer.setUseHashlookup(true);
treeViewer.setContentProvider(treeContentProvider);
treeViewer.setLabelProvider(treeLabelProvider);
treeViewer.addTreeListener(this);
treeViewer.addCheckStateListener(this);
treeViewer.addSelectionChangedListener(this);
}
private int getViewerWidthHint(Control control) {
GC gc= new GC(control);
int width= Dialog.convertWidthInCharsToPixels(gc.getFontMetrics(), 50);
gc.dispose();
return width;
}
/**
* 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.
*
* @param treeElement java.lang.Object
* @return boolean
*/
private 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<Object> checked= checkedStateStore.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. Only ask expanded nodes
if (expandedTreeNodes.contains(treeElement)) {
Object[] children= treeContentProvider.getChildren(treeElement);
for (int i= 0; i < children.length; ++i) {
if (checkedStateStore.containsKey(children[i]))
return true;
}
}
return false;
}
/**
* Expands an element in a tree viewer.
*
* @param element the element to be expanded
*/
private void expandTreeElement(final Object element) {
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() {
@Override
public void run() {
// 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 (expandedTreeNodes.contains(element))
checkNewTreeElements(treeContentProvider.getChildren(element));
else {
expandedTreeNodes.add(element);
if (whiteCheckedTreeItems.contains(element)) {
//If this is the first expansion and this is a white
// checked node then check the children
Object[] children= treeContentProvider.getChildren(element);
for (int i= 0; i < children.length; ++i) {
if (!whiteCheckedTreeItems.contains(children[i])) {
Object child= children[i];
setWhiteChecked(child, true);
treeViewer.setChecked(child, true);
checkedStateStore.put(child, new ArrayList<>());
}
}
//Now be sure to select the list of items too
setListForWhiteSelection(element);
}
}
}
});
}
/**
* Adds all of the selected children of <code>treeElement</code> to result recursively. This
* does not set any values in the checked state.
*
* @param treeElement the tree element being queried
* @param parentLabel the parent label
* @param addAll a boolean to indicate if the checked state store needs to be queried
* @param filter the filter being used on the data
* @throws InterruptedException in case of interruption
*/
private void findAllSelectedListElements(Object treeElement, String parentLabel, boolean addAll, IElementFilter filter) throws InterruptedException {
String fullLabel= null;
if (addAll)
filter.filterElements(listContentProvider.getElements(treeElement));
else { //Add what we have stored
if (checkedStateStore.containsKey(treeElement))
filter.filterElements(checkedStateStore.get(treeElement));
}
Object[] treeChildren= treeContentProvider.getChildren(treeElement);
for (int i= 0; i < treeChildren.length; i++) {
Object child= treeChildren[i];
if (addAll)
findAllSelectedListElements(child, fullLabel, true, filter);
else { //Only continue for those with checked state
if (checkedStateStore.containsKey(child))
findAllSelectedListElements(child, fullLabel, whiteCheckedTreeItems.contains(child), filter);
}
}
}
/**
* Find all of the white checked children of the treeElement and add them to
* the collection. If the element itself is white select add it. If not then
* add any selected list elements and recurse down to the children.
*
* @param treeElement java.lang.Object
* @param result java.util.Collection
*/
private void findAllWhiteCheckedItems(Object treeElement, Collection<Object> result) {
if (whiteCheckedTreeItems.contains(treeElement))
result.add(treeElement);
else {
Collection<Object> listChildren= checkedStateStore.get(treeElement);
//if it is not in the store then it and its children are not interesting
if (listChildren == null)
return;
result.addAll(listChildren);
Object[] children= treeContentProvider.getChildren(treeElement);
for (int i= 0; i < children.length; ++i) {
findAllWhiteCheckedItems(children[i], result);
}
}
}
/**
* Returns a flat list of all of the leaf elements which are checked. Filter
* then based on the supplied ElementFilter. If monitor is canceled then
* return null
*
* @param filter - the filter for the data
* @throws InterruptedException in case of interruption
*/
private void getAllCheckedListItems(IElementFilter filter) throws InterruptedException {
//Iterate through the children of the root as the root is not in the store
Object[] children= treeContentProvider.getChildren(root);
for (int i= 0; i < children.length; ++i) {
findAllSelectedListElements(children[i], null, whiteCheckedTreeItems.contains(children[i]), filter);
}
}
/**
* Returns a flat list of all of the leaf elements which are checked.
*
* @return all of the leaf elements which are checked. This API does not
* return null in order to keep backwards compatibility.
*/
public List<Object> getAllCheckedListItems() {
final ArrayList<Object> returnValue= new ArrayList<>();
IElementFilter passThroughFilter= new IElementFilter() {
@Override
public void filterElements(Collection<Object> elements) throws InterruptedException {
returnValue.addAll(elements);
}
@Override
public void filterElements(Object[] elements) throws InterruptedException {
for (int i= 0; i < elements.length; i++) {
returnValue.add(elements[i]);
}
}
};
try {
getAllCheckedListItems(passThroughFilter);
} catch (InterruptedException exception) {
return new ArrayList<>();
}
return returnValue;
}
/**
* Returns a list of all of the items that are white checked. Any folders
* that are white checked are added and then any files from white checked
* folders are added.
*
* @return the list of all of the items that are white checked
*/
public List<Object> getAllWhiteCheckedItems() {
List<Object> result= new ArrayList<>();
//Iterate through the children of the root as the root is not in the
// store
Object[] children= treeContentProvider.getChildren(root);
for (int i= 0; i < children.length; ++i) {
findAllWhiteCheckedItems(children[i], result);
}
return result;
}
/**
* Logically gray-check all ancestors of <code>treeElement</code> by ensuring that they
* appear in the checked table.
*
* @param treeElement the tree element
*/
private void grayCheckHierarchy(Object treeElement) {
//expand the element first to make sure we have populated for it
expandTreeElement(treeElement);
// if this tree element is already gray then its ancestors all are as
// well
if (checkedStateStore.containsKey(treeElement))
return; // no need to proceed upwards from here
checkedStateStore.put(treeElement, new ArrayList<>());
Object parent= treeContentProvider.getParent(treeElement);
if (parent != null)
grayCheckHierarchy(parent);
}
/**
* Set the checked state of self and all ancestors appropriately. Do not
* white check anyone - this is only done down a hierarchy.
*
* @param treeElement the tree element
*/
private void grayUpdateHierarchy(Object treeElement) {
boolean shouldBeAtLeastGray= determineShouldBeAtLeastGrayChecked(treeElement);
treeViewer.setGrayChecked(treeElement, shouldBeAtLeastGray);
if (whiteCheckedTreeItems.contains(treeElement))
whiteCheckedTreeItems.remove(treeElement);
// proceed up the tree element hierarchy
Object parent= treeContentProvider.getParent(treeElement);
if (parent != null) {
grayUpdateHierarchy(parent);
}
}
public void selectAndReveal(Object treeElement) {
treeViewer.reveal(treeElement);
IStructuredSelection selection= new StructuredSelection(treeElement);
treeViewer.setSelection(selection);
}
/**
* Initialize this group's viewers after they have been laid out.
*/
private void initialize() {
treeViewer.setInput(root);
this.expandedTreeNodes= new ArrayList<>();
this.expandedTreeNodes.add(root);
Object[] topElements= treeContentProvider.getElements(root);
if (topElements.length == 1)
treeViewer.setExpandedState(topElements[0], true);
}
/**
* 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.
*
* @param listElement the list element
* @param state the checked state
* @param updatingFromSelection <code>true</code> if we are inside an
* update caused by selection
*/
private void listItemChecked(Object listElement, boolean state, boolean updatingFromSelection) {
List<Object> checkedListItems= checkedStateStore.get(currentTreeSelection);
//If it has not been expanded do so as the selection of list items will
// affect gray state
if (!expandedTreeNodes.contains(currentTreeSelection))
expandTreeElement(currentTreeSelection);
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(currentTreeSelection);
checkedListItems= checkedStateStore.get(currentTreeSelection);
}
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(currentTreeSelection);
}
}
//Update the list with the selections if there are any
if (checkedListItems.size() > 0)
checkedStateStore.put(currentTreeSelection, checkedListItems);
if (updatingFromSelection)
grayUpdateHierarchy(currentTreeSelection);
}
/**
* Notify all checked state listeners with the given event.
*
* @param event the event
*/
private void notifyCheckStateChangeListeners(final CheckStateChangedEvent event) {
Object[] array= listeners.getListeners();
for (int i= 0; i < array.length; i++) {
final ICheckStateListener l= (ICheckStateListener) array[i];
SafeRunner.run(new SafeRunnable() {
@Override
public void run() {
l.checkStateChanged(event);
}
});
}
}
/**
* Set 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
*/
private void populateListViewer(final Object treeElement) {
listViewer.setInput(treeElement);
//If the element is white checked but not expanded we have not set up
// all of the children yet
if (!(expandedTreeNodes.contains(treeElement)) && whiteCheckedTreeItems.contains(treeElement)) {
//Potentially long operation - show a busy cursor
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() {
@Override
public void run() {
setListForWhiteSelection(treeElement);
listViewer.setAllChecked(true);
}
});
} else {
List<Object> listItemsToCheck= checkedStateStore.get(treeElement);
if (listItemsToCheck != null) {
Iterator<Object> listItemsEnum= listItemsToCheck.iterator();
while (listItemsEnum.hasNext())
listViewer.setChecked(listItemsEnum.next(), true);
}
}
}
/**
* Logically gray-check all ancestors of <code>item</code> by ensuring
* that they appear in the checked table. Add any elements to the
* <code>selectedNodes</code> so we can track that has been done.
*
* @param item the tree item
* @param selectedNodes the set of selected nodes
*/
private void primeHierarchyForSelection(Object item, Set<Object> selectedNodes) {
//Only prime it if we haven't visited yet
if (selectedNodes.contains(item))
return;
checkedStateStore.put(item, new ArrayList<>());
//mark as expanded as we are going to populate it after this
expandedTreeNodes.add(item);
selectedNodes.add(item);
Object parent= treeContentProvider.getParent(item);
if (parent != null)
primeHierarchyForSelection(parent, selectedNodes);
}
/**
* Remove 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) {
listeners.remove(listener);
}
/**
* Handle the selection of an item in the tree viewer
*
* @param event SelectionChangedEvent
*/
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection= (IStructuredSelection) event.getSelection();
Object selectedElement= selection.getFirstElement();
if (selectedElement == null) {
currentTreeSelection= null;
listViewer.setInput(null);
return;
}
// i.e.- if not an item deselection
if (selectedElement != currentTreeSelection)
populateListViewer(selectedElement);
currentTreeSelection= selectedElement;
}
/**
* Select or deselect all of the elements in the tree depending on the value
* of <code>selection</code>. Be sure to update the displayed files as
* well.
*
* @param selection <code>true</code> if selection should be set,
* <code>false</code> if it should be removed
*/
public void setAllSelections(final boolean selection) {
//If there is no root there is nothing to select
if (root == null)
return;
//Potentially long operation - show a busy cursor
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() {
@Override
public void run() {
setTreeChecked(root, selection);
listViewer.setAllChecked(selection);
}
});
}
public void refresh() {
//Potentially long operation - show a busy cursor
BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() {
@Override
public void run() {
treeViewer.refresh();
populateListViewer(currentTreeSelection);
}
});
}
/**
* The treeElement has been white selected. Get the list for the element and
* set it in the checked state store.
*
* @param treeElement the element being updated
*/
private void setListForWhiteSelection(Object treeElement) {
Object[] listItems= listContentProvider.getElements(treeElement);
List<Object> listItemsChecked= new ArrayList<>();
for (int i= 0; i < listItems.length; ++i) {
listItemsChecked.add(listItems[i]);
}
checkedStateStore.put(treeElement, listItemsChecked);
}
/**
* Set the <code>comparator</code> that is to be applied to self's list viewer
*
* @param comparator the comparator to be set
*/
public void setListComparator(ViewerComparator comparator) {
listViewer.setComparator(comparator);
}
/**
* Set the checked state of the passed <code>treeElement</code>
* appropriately, and do so recursively to all of its child tree elements as
* well.
*
* @param treeElement the root of the subtree
* @param state <code>true</code> if checked, <code>false</code> otherwise
*/
private void setTreeChecked(Object treeElement, boolean state) {
if (treeElement.equals(currentTreeSelection)) {
listViewer.setAllChecked(state);
}
if (state) {
setListForWhiteSelection(treeElement);
} else
checkedStateStore.remove(treeElement);
setWhiteChecked(treeElement, state);
treeViewer.setChecked(treeElement, state);
treeViewer.setGrayed(treeElement, false);
// now logically check/uncheck all children as well if it has been
// expanded
if (expandedTreeNodes.contains(treeElement)) {
Object[] children= treeContentProvider.getChildren(treeElement);
for (int i= 0; i < children.length; ++i) {
setTreeChecked(children[i], state);
}
}
}
/**
* Set the comparator that is to be applied to self's tree viewer.
*
* @param comparator the comparator to be set
*/
public void setTreeComparator(ViewerComparator comparator) {
treeViewer.setComparator(comparator);
}
/**
* Adjust the collection of references to white-checked tree elements
* appropriately.
*
* @param treeElement the root of the subtree
* @param isWhiteChecked <code>true</code> if white checked,
* <code>false</code> otherwise
*/
private void setWhiteChecked(Object treeElement, boolean isWhiteChecked) {
if (isWhiteChecked) {
if (!whiteCheckedTreeItems.contains(treeElement))
whiteCheckedTreeItems.add(treeElement);
} else
whiteCheckedTreeItems.remove(treeElement);
}
/**
* Handle the collapsing of an element in a tree viewer.
*
* @param event the collapse event
*/
@Override
public void treeCollapsed(TreeExpansionEvent event) {
// We don't need to do anything with this
}
/**
* Handle the expansion of an element in a tree viewer.
*
* @param event the expansion event
*/
@Override
public void treeExpanded(TreeExpansionEvent event) {
expandTreeElement(event.getElement());
}
/**
* Callback that's invoked when the checked status of an item in the tree is
* changed by the user.
*
* @param treeElement the tree element that has been checked/unchecked
* @param state <code>true</code> if checked, <code>false</code> if
* unchecked
*/
private void treeItemChecked(Object treeElement, boolean state) {
// recursively adjust all child tree elements appropriately
setTreeChecked(treeElement, state);
Object parent= treeContentProvider.getParent(treeElement);
if (parent == null)
return;
// now update upwards in the tree hierarchy
if (state)
grayCheckHierarchy(parent);
else
ungrayCheckHierarchy(parent);
//Update the hierarchy but do not white select the parent
grayUpdateHierarchy(parent);
}
/**
* Logically un-gray-check all ancestors of <code>treeElement</code> if
* appropriate.
*
* @param treeElement the root of the subtree
*/
private void ungrayCheckHierarchy(Object treeElement) {
if (!determineShouldBeAtLeastGrayChecked(treeElement))
checkedStateStore.remove(treeElement);
Object parent= treeContentProvider.getParent(treeElement);
if (parent != null)
ungrayCheckHierarchy(parent);
}
/**
* Update the selections of the tree elements in items to reflect the new
* selections provided.
*
* @param items Map with keys of Object (the tree element) and values of
* List (the selected list elements). NOTE: This method does not
* special case keys with no values (i.e., a tree element with an
* empty list). If a tree element does not have any selected
* items, do not include the element in the Map.
*/
public void updateSelections(Map<IContainer, List<Object>> items) {
// We are replacing all selected items with the given selected items,
// so reinitialize everything.
this.listViewer.setAllChecked(false);
this.treeViewer.setCheckedElements(new Object[0]);
this.whiteCheckedTreeItems= new HashSet<>();
Set<Object> selectedNodes= new HashSet<>();
checkedStateStore= new HashMap<>();
//Update the store before the hierarchy to prevent updating parents
// before all of the children are done
Iterator<IContainer> keyIterator= items.keySet().iterator();
while (keyIterator.hasNext()) {
Object key= keyIterator.next();
primeHierarchyForSelection(key, selectedNodes);
checkedStateStore.put(key, items.get(key));
}
// Update the checked tree items. Since each tree item has a selected
// item, all the tree items will be gray checked.
treeViewer.setCheckedElements(checkedStateStore.keySet().toArray());
treeViewer.setGrayedElements(checkedStateStore.keySet().toArray());
// Update the listView of the currently selected tree item.
if (currentTreeSelection != null) {
Object displayItems= items.get(currentTreeSelection);
if (displayItems != null)
listViewer.setCheckedElements(((List<?>) displayItems).toArray());
}
}
}