| package org.eclipse.epf.authoring.ui.views; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.emf.common.notify.AdapterFactory; |
| import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider; |
| import org.eclipse.epf.library.edit.util.TngUtil; |
| import org.eclipse.epf.uma.CustomCategory; |
| import org.eclipse.jface.util.SafeRunnable; |
| import org.eclipse.jface.viewers.CheckStateChangedEvent; |
| import org.eclipse.jface.viewers.CheckboxTreeViewer; |
| import org.eclipse.jface.viewers.ICheckStateListener; |
| import org.eclipse.jface.viewers.ITreeViewerListener; |
| import org.eclipse.jface.viewers.TreeExpansionEvent; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Item; |
| import org.eclipse.swt.widgets.Tree; |
| import org.eclipse.swt.widgets.TreeItem; |
| import org.eclipse.swt.widgets.Widget; |
| import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer; |
| |
| /** |
| * ContainerCheckedTreeViewer class that supports MethodElements. |
| * Specifically, has changes to support FeatureValueWrapperItemProviders. |
| * |
| * Also, expands the tree for checked items when they are set via |
| * setCheckedElements(..) iff expandWhenChecking is true. |
| * @author Jeff Hardy |
| * @author Phong Nguyen Le |
| */ |
| public class MethodContainerCheckedTreeViewer extends |
| ContainerCheckedTreeViewer { |
| |
| protected boolean expandWhenChecking = false; |
| protected boolean initializingTreeCheckState = false; |
| |
| protected ListenerList childrenCheckStateListeners = new ListenerList(); |
| |
| /** |
| * Constructor for MethodContainerCheckedTreeViewer. |
| * @see CheckboxTreeViewer#CheckboxTreeViewer(Composite) |
| */ |
| public MethodContainerCheckedTreeViewer(Composite parent) { |
| super(parent); |
| initViewer(); |
| } |
| |
| /** |
| * Constructor for MethodContainerCheckedTreeViewer. |
| * @see CheckboxTreeViewer#CheckboxTreeViewer(Composite,int) |
| */ |
| public MethodContainerCheckedTreeViewer(Composite parent, int style) { |
| super(parent, style); |
| initViewer(); |
| } |
| |
| /** |
| * Constructor for MethodContainerCheckedTreeViewer. |
| * @see CheckboxTreeViewer#CheckboxTreeViewer(Tree) |
| */ |
| public MethodContainerCheckedTreeViewer(Tree tree) { |
| super(tree); |
| initViewer(); |
| } |
| |
| protected void initViewer() { |
| setUseHashlookup(true); |
| addCheckStateListener(new ICheckStateListener() { |
| public void checkStateChanged(CheckStateChangedEvent event) { |
| updateWrappers(event.getElement()); |
| doCheckStateChanged(event.getElement()); |
| } |
| }); |
| addTreeListener(new ITreeViewerListener() { |
| public void treeCollapsed(TreeExpansionEvent event) { |
| } |
| |
| public void treeExpanded(TreeExpansionEvent event) { |
| Widget item = findItem(event.getElement()); |
| if (item instanceof TreeItem) { |
| initializeItem((TreeItem) item); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * The item has expanded. Updates the checked state of its children. |
| */ |
| protected void initializeItem(TreeItem item) { |
| if (item.getChecked() && !item.getGrayed()) { |
| updateChildrenItems(item); |
| } |
| } |
| |
| /** |
| * Updates the check state of all created children |
| */ |
| protected void updateChildrenItems(TreeItem parent) { |
| Item[] children = getChildren(parent); |
| boolean state = parent.getChecked(); |
| for (int i = 0; i < children.length; i++) { |
| TreeItem curr = (TreeItem) children[i]; |
| if (curr.getData() != null |
| && ((curr.getChecked() != state) || curr.getGrayed())) { |
| curr.setChecked(state); |
| curr.setGrayed(false); |
| notifyChildrenCheckStateListeners(new CheckStateChangedEvent(this, curr.getData(), |
| state)); |
| updateChildrenItems(curr); |
| } |
| } |
| } |
| |
| @Override |
| protected void doCheckStateChanged(Object element) { |
| if (initializingTreeCheckState) { |
| // when initializing, don't update children: |
| // parent may have been gray-checked and we don't |
| // want to white-check all children |
| // children will be checked because setCheckedElements(..) |
| // typically receives list of all checked elements |
| Widget item = findItem(element); |
| if (item instanceof TreeItem) { |
| TreeItem treeItem = (TreeItem) item; |
| treeItem.setGrayed(false); |
| updateParentItems(treeItem.getParentItem()); |
| } |
| } else { |
| super.doCheckStateChanged(element); |
| } |
| } |
| |
| public void updateParents(Object element) { |
| Widget item = findItem(element); |
| if (item instanceof TreeItem) { |
| TreeItem treeItem = (TreeItem) item; |
| updateParentItems(treeItem.getParentItem()); |
| } |
| } |
| |
| /** |
| * Updates the check / gray state of all parent items |
| */ |
| protected void updateParentItems(TreeItem item) { |
| if (item != null) { |
| Item[] children = getChildren(item); |
| boolean containsChecked = false; |
| boolean containsUnchecked = false; |
| for (int i = 0; i < children.length; i++) { |
| TreeItem curr = (TreeItem) children[i]; |
| containsChecked |= curr.getChecked(); |
| containsUnchecked |= (!curr.getChecked() || curr.getGrayed()); |
| } |
| item.setChecked(containsChecked); |
| item.setGrayed(containsChecked && containsUnchecked); |
| if (expandWhenChecking && item.getChecked()) { |
| item.setExpanded(true); |
| } |
| updateParentItems(item.getParentItem()); |
| } |
| } |
| |
| private void updateWrappers(Object object) { |
| boolean state = getChecked(object); |
| Object element = TngUtil.unwrap(object); |
| if(object != element) { |
| setChecked(element, state); |
| } |
| AdapterFactory adapterFactory = null; |
| if (getContentProvider() instanceof AdapterFactoryContentProvider) { |
| adapterFactory = ((AdapterFactoryContentProvider) getContentProvider()) |
| .getAdapterFactory(); |
| } |
| if (adapterFactory != null) { |
| Collection<?> wrappers = TngUtil.getWrappers(adapterFactory, |
| element); |
| if (!wrappers.isEmpty()) { |
| for (Object wrapper : wrappers) { |
| setChecked(wrapper, state); |
| } |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.CheckboxTreeViewer#setCheckedElements(java.lang.Object[]) |
| */ |
| public void setCheckedElements(Object[] elements) { |
| // fix elements list to use EPF's wrappers |
| List<Object> treeElements = new ArrayList<Object>(); |
| AdapterFactory adapterFactory = null; |
| if (getContentProvider() instanceof AdapterFactoryContentProvider) { |
| adapterFactory = ((AdapterFactoryContentProvider)getContentProvider()).getAdapterFactory(); |
| } |
| for (int i = 0; i < elements.length; i++) { |
| Object element = elements[i]; |
| if (adapterFactory != null) { |
| treeElements.addAll(TngUtil.getWrappers(adapterFactory, element)); |
| } |
| if(!(element instanceof CustomCategory)) { |
| treeElements.add(element); |
| } |
| } |
| initializingTreeCheckState = true; |
| super.setCheckedElements(treeElements.toArray()); |
| initializingTreeCheckState = false; |
| } |
| |
| /** |
| * Returns a list of top-most checked elements in this viewer's tree, |
| * including currently hidden ones that are marked as |
| * checked but are under a collapsed ancestor. |
| * |
| * Only returns white-checked items, not grayed items |
| * |
| * @return the array of checked elements |
| * |
| * @see #setCheckedElements |
| */ |
| public Object[] getTopCheckedElements() { |
| ArrayList v = new ArrayList(); |
| Control tree = getControl(); |
| internalCollectTopChecked(v, tree); |
| return v.toArray(); |
| } |
| |
| |
| /** |
| * Gathers the top-most checked states of the given widget and its |
| * descendents, following a pre-order traversal of the tree. |
| * |
| * @param result a writable list of elements (element type: <code>Object</code>) |
| * @param widget the widget |
| */ |
| private void internalCollectTopChecked(List result, Widget widget) { |
| Item[] items = getChildren(widget); |
| for (int i = 0; i < items.length; i++) { |
| Item item = items[i]; |
| if (item instanceof TreeItem && ((TreeItem) item).getChecked() && !((TreeItem) item).getGrayed()) { |
| Object data = item.getData(); |
| if (data != null) { |
| result.add(data); |
| } |
| } |
| if (item instanceof TreeItem && (!((TreeItem) item).getChecked() || ((TreeItem) item).getGrayed())) { |
| internalCollectTopChecked(result, item); |
| } |
| } |
| } |
| |
| |
| public boolean isExpandWhenChecking() { |
| return expandWhenChecking; |
| } |
| |
| public void setExpandWhenChecking(boolean expandWhenChecking) { |
| this.expandWhenChecking = expandWhenChecking; |
| } |
| |
| /** |
| * notified when children checkstate is changed (by checking a parent) |
| * @param listener |
| */ |
| public void addChildrenCheckStateListener(ICheckStateListener listener) { |
| childrenCheckStateListeners.add(listener); |
| } |
| |
| public void removeChildrenCheckStateListener(ICheckStateListener listener) { |
| childrenCheckStateListeners.remove(listener); |
| } |
| |
| protected void notifyChildrenCheckStateListeners(final CheckStateChangedEvent event) { |
| for (final Object listener : childrenCheckStateListeners.getListeners()) { |
| SafeRunner.run(new SafeRunnable() { |
| public void run() { |
| ((ICheckStateListener)listener).checkStateChanged(event); |
| } |
| }); |
| } |
| } |
| |
| } |