| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.internal.ide.dialogs; |
| |
| import java.util.*; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jface.util.ListenerList; |
| import org.eclipse.jface.util.SafeRunnable; |
| import org.eclipse.jface.viewers.*; |
| 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.Tree; |
| import org.eclipse.swt.widgets.Table; |
| |
| import java.io.File; |
| |
| /** |
| * Workbench-level composite that combines a CheckboxTreeViewer and CheckboxListViewer. |
| * All viewer selection-driven interactions are handled within this object |
| */ |
| public class ResourceTreeAndListGroup implements ICheckStateListener, ISelectionChangedListener, ITreeViewerListener { |
| private Object root; |
| private Object currentTreeSelection; |
| private Collection expandedTreeNodes = new HashSet(); |
| private Map checkedStateStore = new HashMap(9); |
| private Collection whiteCheckedTreeItems = new HashSet(); |
| private ListenerList listeners = new ListenerList(); |
| |
| 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 hardcode one of the |
| * sizing dimensions, specify the other dimension's value as -1) |
| * |
| * @param parent org.eclipse.swt.widgets.Composite |
| * @param style int |
| * @param rootObject java.lang.Object |
| * @param childPropertyName java.lang.String |
| * @param parentPropertyName java.lang.String |
| * @param listPropertyName java.lang.String |
| * @param useHeightHint If true then use the height hint |
| * to make this group big enough |
| */ |
| public ResourceTreeAndListGroup( |
| 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); |
| } |
| /** |
| * This method must be called just before this window becomes visible. |
| */ |
| public void aboutToOpen() { |
| determineWhiteCheckedDescendents(root); |
| checkNewTreeElements(treeContentProvider.getElements(root)); |
| currentTreeSelection = null; |
| |
| //select the first element in the list |
| Object[] elements = treeContentProvider.getElements(root); |
| Object primary = elements.length > 0 ? elements[0] : null; |
| if (primary != null) { |
| treeViewer.setSelection(new StructuredSelection(primary)); |
| } |
| treeViewer.getControl().setFocus(); |
| } |
| /** |
| * 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); |
| } |
| /** |
| * Return 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 = treeContentProvider.getChildren(treeElement); |
| for (int i = 0; i < children.length; ++i) { |
| if (!whiteCheckedTreeItems.contains(children[i])) |
| return false; |
| } |
| |
| return true; |
| } |
| /** |
| * Return 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)checkedStateStore.get(treeElement); |
| if (checkedElements == null) // ie.- tree item not even gray-checked |
| return false; |
| |
| return getListItemsSize(treeElement) == checkedElements.size(); |
| } |
| /** |
| * Iterate 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 = 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 CheckStateChangedEvent |
| */ |
| public void checkStateChanged(final CheckStateChangedEvent event) { |
| |
| //Potentially long operation - show a busy cursor |
| BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() { |
| 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 useHeightHint. If true yse the preferredHeight. |
| */ |
| protected 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(); |
| } |
| /** |
| * Create this group's list viewer. |
| */ |
| protected 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; |
| listViewer.getTable().setLayoutData(data); |
| listViewer.getTable().setFont(parent.getFont()); |
| listViewer.setContentProvider(listContentProvider); |
| listViewer.setLabelProvider(listLabelProvider); |
| listViewer.addCheckStateListener(this); |
| } |
| /** |
| * Create this group's tree viewer. |
| */ |
| protected 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; |
| tree.setLayoutData(data); |
| tree.setFont(parent.getFont()); |
| |
| treeViewer = new CheckboxTreeViewer(tree); |
| treeViewer.setContentProvider(treeContentProvider); |
| treeViewer.setLabelProvider(treeLabelProvider); |
| treeViewer.addTreeListener(this); |
| treeViewer.addCheckStateListener(this); |
| treeViewer.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 element 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) 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; |
| } |
| /** |
| * 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 add 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 = treeContentProvider.getElements(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); |
| } |
| /** |
| * Cause the tree viewer to expand all its items |
| */ |
| public void expandAll() { |
| treeViewer.expandAll(); |
| } |
| /** |
| * Expand an element in a tree viewer |
| */ |
| private void expandTreeElement(final Object item) { |
| BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), new Runnable() { |
| 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(item)) |
| checkNewTreeElements(treeContentProvider.getChildren(item)); |
| else { |
| |
| expandedTreeNodes.add(item); |
| if (whiteCheckedTreeItems.contains(item)) { |
| //If this is the first expansion and this is a white checked node then check the children |
| Object[] children = treeContentProvider.getChildren(item); |
| 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(item); |
| } |
| } |
| |
| } |
| }); |
| } |
| /** |
| * Add all of the selected children of nextEntry to result recursively. |
| * This does not set any values in the checked state. |
| * @param The treeElement being queried |
| * @param addAll a boolean to indicate if the checked state store needs to be queried |
| * @param filter IElementFilter - the filter being used on the data |
| * @param monitor IProgressMonitor or null that the cancel is polled for |
| */ |
| private void findAllSelectedListElements( |
| Object treeElement, |
| String parentLabel, |
| boolean addAll, |
| IElementFilter filter, |
| IProgressMonitor monitor) throws InterruptedException{ |
| |
| String fullLabel = null; |
| if(monitor != null && monitor.isCanceled()) |
| return; |
| if(monitor != null){ |
| fullLabel = getFullLabel(treeElement,parentLabel); |
| monitor.subTask(fullLabel); |
| } |
| |
| if (addAll) |
| filter.filterElements(listContentProvider.getElements(treeElement),monitor); |
| else { //Add what we have stored |
| if (checkedStateStore.containsKey(treeElement)) |
| filter.filterElements((Collection) checkedStateStore.get(treeElement),monitor); |
| } |
| |
| Object[] treeChildren = treeContentProvider.getChildren(treeElement); |
| for (int i = 0; i < treeChildren.length; i++) { |
| Object child = treeChildren[i]; |
| if (addAll) |
| findAllSelectedListElements(child, fullLabel,true, filter,monitor); |
| else { //Only continue for those with checked state |
| if (checkedStateStore.containsKey(child)) |
| findAllSelectedListElements( |
| child, |
| fullLabel, |
| whiteCheckedTreeItems.contains(child), |
| filter, |
| monitor); |
| } |
| |
| } |
| } |
| /** |
| * 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 result) { |
| |
| if (whiteCheckedTreeItems.contains(treeElement)) |
| result.add(treeElement); |
| else { |
| Collection listChildren = (Collection) checkedStateStore.get(treeElement); |
| //if it is not in the store then it and it's 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 cancelled then return null |
| * @param filter - the filter for the data |
| * @param monitor IProgressMonitor or null |
| * @return all of the leaf elements which are checked |
| */ |
| public void getAllCheckedListItems(IElementFilter filter, IProgressMonitor monitor) 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, |
| monitor); |
| } |
| } |
| |
| /** |
| * 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 getAllCheckedListItems() { |
| |
| final ArrayList returnValue = new ArrayList(); |
| |
| IElementFilter passThroughFilter = new IElementFilter() { |
| |
| public void filterElements(Collection elements,IProgressMonitor monitor) throws InterruptedException{ |
| returnValue.addAll(elements); |
| } |
| |
| public void filterElements(Object[] elements,IProgressMonitor monitor) throws InterruptedException{ |
| for(int i =0; i < elements.length; i ++){ |
| returnValue.add(elements[i]); |
| } |
| } |
| }; |
| |
| try{ |
| getAllCheckedListItems(passThroughFilter,null); |
| } |
| 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 getAllWhiteCheckedItems() { |
| |
| List 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; |
| } |
| /** |
| * Answer the number of elements that have been checked by the |
| * user. |
| * |
| * @return int |
| */ |
| public int getCheckedElementCount() { |
| return checkedStateStore.size(); |
| } |
| /** |
| * Get the full label of the treeElement (its name and its parent's name). |
| * @param treeElement - the element being exported |
| * @param parentLabel - the label of the parent, can be null |
| * @return String |
| */ |
| protected String getFullLabel(Object treeElement,String parentLabel) { |
| String parentName = parentLabel; |
| |
| if (parentLabel == null) |
| parentName = ""; //$NON-NLS-1$ |
| |
| if (parentName.length() > 0 && (!parentName.endsWith(File.separator))) { |
| parentName += File.separatorChar; |
| } |
| return parentName + treeLabelProvider.getText(treeElement); |
| } |
| /** |
| * Return 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 = listContentProvider.getElements(treeElement); |
| return elements.length; |
| } |
| /** |
| * Get the table the list viewer uses. |
| * @return org.eclipse.swt.widgets.Table |
| */ |
| public Table getListTable() { |
| return this.listViewer.getTable(); |
| } |
| /** |
| * Logically gray-check all ancestors of treeItem by ensuring that they |
| * appear in the checked table |
| */ |
| protected 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. |
| */ |
| 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); |
| } |
| } |
| /** |
| * Set the initial checked state of the passed list element to true. |
| */ |
| public void initialCheckListItem(Object element) { |
| Object parent = treeContentProvider.getParent(element); |
| selectAndReveal(parent); |
| //Check the element in the viewer as if it had been manually checked |
| listViewer.setChecked(element,true); |
| //As this is not done from the UI then set the box for updating from the selection to false |
| listItemChecked(element, true, false); |
| grayUpdateHierarchy(parent); |
| } |
| /** |
| * Set 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); |
| selectAndReveal(element); |
| } |
| |
| private 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. |
| */ |
| protected void initialize() { |
| treeViewer.setInput(root); |
| this.expandedTreeNodes = new ArrayList(); |
| this.expandedTreeNodes.add(root); |
| |
| } |
| /** |
| * 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) 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 = (List) 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 that the passed element has had |
| * its checked state changed to the passed state |
| */ |
| protected void notifyCheckStateChangeListeners(final CheckStateChangedEvent event) { |
| Object[] array = listeners.getListeners(); |
| for (int i = 0; i < array.length; i ++) { |
| final ICheckStateListener l = (ICheckStateListener)array[i]; |
| Platform.run(new SafeRunnable() { |
| public void run() { |
| l.checkStateChanged(event); |
| } |
| public void handleException(Throwable e) { |
| super.handleException(e); |
| //If and unexpected exception happens, remove it |
| //to make sure the workbench keeps running. |
| removeCheckStateListener(l); |
| } |
| }); |
| } |
| } |
| /** |
| *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 |
| */ |
| protected 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() { |
| public void run() { |
| setListForWhiteSelection(treeElement); |
| listViewer.setAllChecked(true); |
| } |
| }); |
| |
| } else { |
| List listItemsToCheck = (List) checkedStateStore.get(treeElement); |
| |
| if (listItemsToCheck != null) { |
| Iterator listItemsEnum = listItemsToCheck.iterator(); |
| while (listItemsEnum.hasNext()) |
| listViewer.setChecked(listItemsEnum.next(), true); |
| } |
| } |
| } |
| /** |
| * Logically gray-check all ancestors of treeItem by ensuring that they |
| * appear in the checked table. Add any elements to the selectedNodes |
| * so we can track that has been done. |
| */ |
| private void primeHierarchyForSelection(Object item, Set 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 selection ISelection |
| */ |
| public void selectionChanged(SelectionChangedEvent event) { |
| IStructuredSelection selection = (IStructuredSelection) event.getSelection(); |
| Object selectedElement = selection.getFirstElement(); |
| if (selectedElement == null) { |
| currentTreeSelection = null; |
| listViewer.setInput(currentTreeSelection); |
| return; |
| } |
| |
| // ie.- 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 the selection |
| * boolean. Be sure to update the displayed files as well. |
| */ |
| 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() { |
| public void run() { |
| setTreeChecked(root, selection); |
| listViewer.setAllChecked(selection); |
| } |
| }); |
| } |
| /** |
| * 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 listItemsChecked = new ArrayList(); |
| for (int i = 0; i < listItems.length; ++i) { |
| listItemsChecked.add(listItems[i]); |
| } |
| |
| checkedStateStore.put(treeElement, listItemsChecked); |
| } |
| /** |
| * Set the list viewer's providers to those passed |
| * |
| * @param contentProvider ITreeContentProvider |
| * @param labelProvider ILabelProvider |
| */ |
| public void setListProviders(IStructuredContentProvider contentProvider, ILabelProvider labelProvider) { |
| listViewer.setContentProvider(contentProvider); |
| listViewer.setLabelProvider(labelProvider); |
| } |
| /** |
| * Set the sorter that is to be applied to self's list viewer |
| */ |
| public void setListSorter(ViewerSorter sorter) { |
| listViewer.setSorter(sorter); |
| } |
| /** |
| * Set 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.root = newRoot; |
| initialize(); |
| } |
| /** |
| * Set 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(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 tree viewer's providers to those passed |
| * |
| * @param contentProvider ITreeContentProvider |
| * @param labelProvider ILabelProvider |
| */ |
| public void setTreeProviders(ITreeContentProvider contentProvider, ILabelProvider labelProvider) { |
| treeViewer.setContentProvider(contentProvider); |
| treeViewer.setLabelProvider(labelProvider); |
| } |
| /** |
| * Set the sorter that is to be applied to self's tree viewer |
| */ |
| public void setTreeSorter(ViewerSorter sorter) { |
| treeViewer.setSorter(sorter); |
| } |
| /** |
| * Adjust 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 (!whiteCheckedTreeItems.contains(treeElement)) |
| whiteCheckedTreeItems.add(treeElement); |
| } else |
| whiteCheckedTreeItems.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 |
| } |
| /** |
| * Handle the expansionsion of an element in a tree viewer |
| */ |
| 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. |
| */ |
| protected 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 treeItem iff appropriate. |
| */ |
| protected void ungrayCheckHierarchy(Object treeElement) { |
| if (!determineShouldBeAtLeastGrayChecked(treeElement)) |
| checkedStateStore.remove(treeElement); |
| |
| Object parent = treeContentProvider.getParent(treeElement); |
| if (parent != null) |
| ungrayCheckHierarchy(parent); |
| } |
| /** |
| * Set the checked state of self and all ancestors appropriately |
| */ |
| protected void updateHierarchy(Object treeElement) { |
| |
| boolean whiteChecked = determineShouldBeWhiteChecked(treeElement); |
| boolean shouldBeAtLeastGray = determineShouldBeAtLeastGrayChecked(treeElement); |
| |
| treeViewer.setChecked(treeElement, shouldBeAtLeastGray); |
| setWhiteChecked(treeElement, whiteChecked); |
| if (whiteChecked) |
| treeViewer.setGrayed(treeElement, false); |
| else |
| treeViewer.setGrayed(treeElement, shouldBeAtLeastGray); |
| |
| // proceed up the tree element hierarchy but gray select all of them |
| Object parent = treeContentProvider.getParent(treeElement); |
| if (parent != null) { |
| grayUpdateHierarchy(parent); |
| } |
| } |
| /** |
| * Update the selections of the tree elements in items to reflect the new |
| * selections provided. |
| * @param 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 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 selectedNodes = new HashSet(); |
| checkedStateStore = new HashMap(); |
| |
| //Update the store before the hierarchy to prevent updating parents before all of the children are done |
| Iterator keyIterator = items.keySet().iterator(); |
| while (keyIterator.hasNext()) { |
| Object key = keyIterator.next(); |
| List selections = (List) items.get(key); |
| //Replace the items in the checked state store with those from the supplied items |
| checkedStateStore.put(key, selections); |
| selectedNodes.add(key); |
| // proceed up the tree element hierarchy |
| Object parent = treeContentProvider.getParent(key); |
| if (parent != null) { |
| // proceed up the tree element hierarchy and make sure everything is in the table |
| primeHierarchyForSelection(parent, selectedNodes); |
| } |
| } |
| |
| // 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()); |
| } |
| } |
| /** |
| * Set the focus on to the list widget. |
| */ |
| public void setFocus(){ |
| |
| this.treeViewer.getTree().setFocus(); |
| } |
| |
| } |
| |
| |