diff options
Diffstat (limited to 'org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CachedCheckboxTreeViewer.java')
-rw-r--r-- | org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CachedCheckboxTreeViewer.java | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CachedCheckboxTreeViewer.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CachedCheckboxTreeViewer.java new file mode 100644 index 0000000000..9a8200bcbf --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CachedCheckboxTreeViewer.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright (c) 2010 Red Hat, Inc. + * 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: + * Chris Aniszczyk <caniszczyk@gmail.com> - initial implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal; + +import java.util.*; +import org.eclipse.jface.viewers.*; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer; + +/** + * Copy of ContainerCheckedTreeViewer which is specialized for use + * with {@link FilteredCheckboxTree}. This container caches + * the check state of leaf nodes in the tree. When a filter + * is applied the cache stores which nodes are checked. When + * a filter is removed the viewer can be told to restore check + * state from the cache. This viewer updates the check state of + * parent items the same way as {@link CachedCheckboxTreeViewer} + * <p> + * Note: If duplicate items are added to the tree the cache will treat them + * as a single entry. + * </p> + */ +public class CachedCheckboxTreeViewer extends ContainerCheckedTreeViewer { + + private Set checkState = new HashSet(); + + /** + * Constructor for ContainerCheckedTreeViewer. + * @see CheckboxTreeViewer#CheckboxTreeViewer(Tree) + */ + protected CachedCheckboxTreeViewer(Tree tree) { + super(tree); + addCheckStateListener(new ICheckStateListener() { + public void checkStateChanged(CheckStateChangedEvent event) { + updateCheckState(event.getElement(), event.getChecked()); + } + }); + setUseHashlookup(true); + } + + /** + * @param element + * @param state + */ + protected void updateCheckState(final Object element, final boolean state) { + if (state) { + // Add the item (or its children) to the cache + if (checkState == null) { + checkState = new HashSet(); + } + + ITreeContentProvider contentProvider = null; + if (getContentProvider() instanceof ITreeContentProvider) { + contentProvider = (ITreeContentProvider) getContentProvider(); + } + + if (contentProvider != null) { + Object[] children = contentProvider.getChildren(element); + if (children != null && children.length > 0) { + for (int i = 0; i < children.length; i++) { + updateCheckState(children[i], state); + } + } else { + checkState.add(element); + } + } else { + checkState.add(element); + } + } else if (checkState != null) { + // Remove the item (or its children) from the cache + ITreeContentProvider contentProvider = null; + if (getContentProvider() instanceof ITreeContentProvider) { + contentProvider = (ITreeContentProvider) getContentProvider(); + } + + if (contentProvider != null) { + Object[] children = contentProvider.getChildren(element); + if (children.length > 0) { + for (int i = 0; i < children.length; i++) { + updateCheckState(children[i], state); + } + + } + } + checkState.remove(element); + } + } + + /** + * Restores the checked state of items based on the cached check state. This + * will only check leaf nodes, but parent items will be updated by the container + * viewer. No events will be fired. + */ + public void restoreLeafCheckState() { + if (checkState == null) + return; + + getTree().setRedraw(false); + // Call the super class so we don't mess up the cache + super.setCheckedElements(new Object[0]); + setGrayedElements(new Object[0]); + // Now we are only going to set the check state of the leaf nodes + // and rely on our container checked code to update the parents properly. + Iterator iter = checkState.iterator(); + Object element = null; + if (iter.hasNext()) + expandAll(); + while (iter.hasNext()) { + element = iter.next(); + // Call the super class as there is no need to update the check state + super.setChecked(element, true); + } + getTree().setRedraw(true); + } + + /** + * Returns the contents of the cached check state. The contents will be all + * checked leaf nodes ignoring any filters. + * + * @return checked leaf elements + */ + public Object[] getCheckedLeafElements() { + if (checkState == null) { + return new Object[0]; + } + return checkState.toArray(new Object[checkState.size()]); + } + + /** + * Returns the number of leaf nodes checked. This method uses its internal check + * state cache to determine what has been checked, not what is visible in the viewer. + * The cache does not count duplicate items in the tree. + * + * @return number of leaf nodes checked according to the cached check state + */ + public int getCheckedLeafCount() { + if (checkState == null) { + return 0; + } + return checkState.size(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ICheckable#setChecked(java.lang.Object, boolean) + */ + public boolean setChecked(Object element, boolean state) { + updateCheckState(element, state); + return super.setChecked(element, state); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.CheckboxTreeViewer#setCheckedElements(java.lang.Object[]) + */ + public void setCheckedElements(Object[] elements) { + super.setCheckedElements(elements); + if (checkState == null) { + checkState = new HashSet(); + } else { + checkState.clear(); + } + ITreeContentProvider contentProvider = null; + if (getContentProvider() instanceof ITreeContentProvider) { + contentProvider = (ITreeContentProvider) getContentProvider(); + } + + for (int i = 0; i < elements.length; i++) { + Object[] children = contentProvider != null ? contentProvider.getChildren(elements[i]) : null; + if (!getGrayed(elements[i]) && (children == null || children.length == 0)) { + if (!checkState.contains(elements[i])) { + checkState.add(elements[i]); + } + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.CheckboxTreeViewer#setAllChecked(boolean) + */ + public void setAllChecked(boolean state) { + super.setAllChecked(state); + if (state) { + + // Find all visible children, add only the visible leaf nodes to the check state cache + Object[] visible = getFilteredChildren(getRoot()); + if (checkState == null) { + checkState = new HashSet(); + } + + ITreeContentProvider contentProvider = null; + if (getContentProvider() instanceof ITreeContentProvider) { + contentProvider = (ITreeContentProvider) getContentProvider(); + } + + if (contentProvider == null) { + for (int i = 0; i < visible.length; i++) { + checkState.add(visible[i]); + } + } else { + Set toCheck = new HashSet(); + for (int i = 0; i < visible.length; i++) { + addFilteredChildren(visible[i], contentProvider, toCheck); + } + checkState.addAll(toCheck); + } + } else { + // Remove any item in the check state that is visible (passes the filters) + if (checkState != null) { + Object[] visible = filter(checkState.toArray()); + for (int i = 0; i < visible.length; i++) { + checkState.remove(visible[i]); + } + } + } + } + + /** + * If the element is a leaf node, it is added to the result collection. If the element has + * children, this method will recursively look at the children and add any visible leaf nodes + * to the collection. + * + * @param element element to check + * @param contentProvider tree content provider to check for children + * @param result collection to collect leaf nodes in + */ + private void addFilteredChildren(Object element, ITreeContentProvider contentProvider, Collection result) { + if (!contentProvider.hasChildren(element)) { + result.add(element); + } else { + Object[] visibleChildren = getFilteredChildren(element); + for (int i = 0; i < visibleChildren.length; i++) { + addFilteredChildren(visibleChildren[i], contentProvider, result); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.AbstractTreeViewer#remove(java.lang.Object[]) + */ + public void remove(Object[] elementsOrTreePaths) { + for (int i = 0; i < elementsOrTreePaths.length; i++) { + updateCheckState(elementsOrTreePaths[i], false); + } + super.remove(elementsOrTreePaths); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.AbstractTreeViewer#remove(java.lang.Object) + */ + public void remove(Object elementsOrTreePaths) { + updateCheckState(elementsOrTreePaths, false); + super.remove(elementsOrTreePaths); + } + +} |