Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 100078 Details for
Bug 229735
[ui] Strange behavior of check boxes when filtering available software view
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
patch to ContainerCheckedTreeViewer and DeferredFetchFilteredTree
bug229735.patch (text/plain), 13.83 KB, created by
Susan McCourt
on 2008-05-13 18:50:40 EDT
(
hide
)
Description:
patch to ContainerCheckedTreeViewer and DeferredFetchFilteredTree
Filename:
MIME Type:
Creator:
Susan McCourt
Created:
2008-05-13 18:50:40 EDT
Size:
13.83 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.equinox.p2.ui >Index: src/org/eclipse/equinox/internal/p2/ui/dialogs/DeferredFetchFilteredTree.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.equinox/p2/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/DeferredFetchFilteredTree.java,v >retrieving revision 1.6 >diff -u -r1.6 DeferredFetchFilteredTree.java >--- src/org/eclipse/equinox/internal/p2/ui/dialogs/DeferredFetchFilteredTree.java 13 May 2008 18:30:56 -0000 1.6 >+++ src/org/eclipse/equinox/internal/p2/ui/dialogs/DeferredFetchFilteredTree.java 13 May 2008 22:49:22 -0000 >@@ -1,5 +1,7 @@ > package org.eclipse.equinox.internal.p2.ui.dialogs; > >+import java.util.ArrayList; >+import java.util.Iterator; > import org.eclipse.core.runtime.*; > import org.eclipse.core.runtime.jobs.*; > import org.eclipse.equinox.internal.p2.ui.ProvUIMessages; >@@ -13,8 +15,7 @@ > import org.eclipse.jface.dialogs.ControlEnableState; > import org.eclipse.jface.dialogs.PopupDialog; > import org.eclipse.jface.resource.JFaceResources; >-import org.eclipse.jface.viewers.TreeViewer; >-import org.eclipse.jface.viewers.Viewer; >+import org.eclipse.jface.viewers.*; > import org.eclipse.swt.SWT; > import org.eclipse.swt.events.*; > import org.eclipse.swt.graphics.Point; >@@ -51,6 +52,7 @@ > WorkbenchJob filterJob; > ControlEnableState enableState; > Object viewerInput; >+ ArrayList checkState = new ArrayList(); > > class InputSchedulingRule implements ISchedulingRule { > Object input; >@@ -108,8 +110,31 @@ > } > > protected TreeViewer doCreateTreeViewer(Composite composite, int style) { >- if (useCheckBoxTree) >- return new ContainerCheckedTreeViewer(composite, style); >+ if (useCheckBoxTree) { >+ final ContainerCheckedTreeViewer v = new ContainerCheckedTreeViewer(composite, style); >+ v.addCheckStateListener(new ICheckStateListener() { >+ public void checkStateChanged(CheckStateChangedEvent event) { >+ // We use an additive check state cache so we need to remove >+ // previously checked items if the user unchecked them. >+ if (!event.getChecked() && checkState != null) { >+ Iterator iter = checkState.iterator(); >+ ArrayList toRemove = new ArrayList(1); >+ while (iter.hasNext()) { >+ Object element = iter.next(); >+ if (v.getComparer().equals(element, event.getElement())) { >+ toRemove.add(element); >+ // Do not break out of the loop. We may have duplicate equal >+ // elements in the cache. Since the cache is additive, we want >+ // to be sure we've gotten everything. >+ } >+ } >+ checkState.removeAll(toRemove); >+ } >+ >+ } >+ }); >+ return v; >+ } > return super.doCreateTreeViewer(composite, style); > } > >@@ -172,6 +197,9 @@ > // Store the input because it's not reset in the viewer until > // after this listener is run. > viewerInput = newInput; >+ >+ // Reset the state for remembering check marks >+ checkState = new ArrayList(); > // Cancel the load and filter jobs and null out the scheduling rule > // so that a new one will be created on the new input when needed. > filterRule = null; >@@ -195,7 +223,70 @@ > * @see org.eclipse.ui.dialogs.FilteredTree#doCreateRefreshJob() > */ > protected WorkbenchJob doCreateRefreshJob() { >- filterJob = super.doCreateRefreshJob(); >+ // See bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=229735 >+ // Ideally we would not have to copy the filtering job, but this >+ // gives us the most precise control over how and when to preserve >+ // the check mark state. We have modified the superclass job so >+ // that everything is expanded rather than recursively expanding >+ // the tree and checking for the stop time. This simplifies the >+ // restoration of the correct checkmarks. >+ filterJob = new WorkbenchJob("Refresh Filter") {//$NON-NLS-1$ >+ public IStatus runInUIThread(IProgressMonitor monitor) { >+ if (treeViewer.getControl().isDisposed()) { >+ return Status.CANCEL_STATUS; >+ } >+ >+ String text = getFilterString(); >+ if (text == null) { >+ return Status.OK_STATUS; >+ } >+ >+ if (monitor.isCanceled()) >+ return Status.CANCEL_STATUS; >+ boolean initial = initialText != null && initialText.equals(text); >+ if (initial) { >+ patternFilter.setPattern(null); >+ } else if (text != null) { >+ patternFilter.setPattern(text); >+ } >+ >+ Control redrawFalseControl = treeComposite != null ? treeComposite : treeViewer.getControl(); >+ try { >+ // don't want the user to see updates that will be made to >+ // the tree >+ // we are setting redraw(false) on the composite to avoid >+ // dancing scrollbar >+ redrawFalseControl.setRedraw(false); >+ treeViewer.getTree().setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); >+ rememberLeafCheckState(); >+ treeViewer.refresh(true); >+ // The superclass did a recursive expand so it could be more responsive to subsequent >+ // typing. We are expanding all so that we know everything is realized when we go to >+ // restore the check state afterward. >+ treeViewer.expandAll(); >+ if (text.length() > 0 && !initial) { >+ // enabled toolbar - there is text to clear >+ // and the list is currently being filtered >+ updateToolbar(true); >+ } else { >+ // disabled toolbar - there is no text to clear >+ // and the list is currently not filtered >+ updateToolbar(false); >+ } >+ } finally { >+ // done updating the tree - set redraw back to true >+ TreeItem[] items = getViewer().getTree().getItems(); >+ if (items.length > 0 && getViewer().getTree().getSelectionCount() == 0) { >+ treeViewer.getTree().setTopItem(items[0]); >+ } >+ restoreLeafCheckState(); >+ redrawFalseControl.setRedraw(true); >+ treeViewer.getTree().setCursor(null); >+ } >+ return Status.OK_STATUS; >+ } >+ }; >+ > filterJob.addJobChangeListener(new JobChangeAdapter() { > public void aboutToRun(final IJobChangeEvent event) { > final boolean[] shouldLoad = new boolean[1]; >@@ -247,6 +338,7 @@ > } > if (filterText != null && !filterText.isDisposed()) { > filterText.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); >+ getViewer().getTree().setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); > savedFilterText = filterText.getText(); > filterText.setText(WAIT_STRING); > } >@@ -257,6 +349,7 @@ > if (filterText != null && !filterText.isDisposed() && !filterText.isEnabled()) { > filterText.setText(filterTextToRestore); > filterText.setCursor(null); >+ getViewer().getTree().setCursor(null); > filterText.setFocus(); > filterText.setSelection(filterTextToRestore.length(), filterTextToRestore.length()); > } >@@ -297,6 +390,14 @@ > contentProvider.setSynchronous(true); > display.asyncExec(new Runnable() { > public void run() { >+ // We have just loaded all content. Trigger a viewer expand. >+ // This really only need be done before filtering, but it can >+ // be slow the very first time, so we may as well do it while >+ // the user is already waiting rather than after they expect >+ // things to be responsive. >+ if (getViewer() != null && !getViewer().getTree().isDisposed()) { >+ getViewer().expandAll(); >+ } > restoreAfterLoading(savedFilterText); > } > }); >@@ -339,4 +440,43 @@ > return; > super.textChanged(); > } >+ >+ void rememberLeafCheckState() { >+ if (!useCheckBoxTree) >+ return; >+ ContainerCheckedTreeViewer v = (ContainerCheckedTreeViewer) getViewer(); >+ Object[] checked = v.getCheckedElements(); >+ if (checkState == null) >+ checkState = new ArrayList(checked.length); >+ for (int i = 0; i < checked.length; i++) >+ if (!v.getGrayed(checked[i])) >+ checkState.add(checked[i]); >+ } >+ >+ void restoreLeafCheckState() { >+ if (!useCheckBoxTree) >+ return; >+ ContainerCheckedTreeViewer v = (ContainerCheckedTreeViewer) getViewer(); >+ if (v == null || v.getTree().isDisposed()) >+ return; >+ if (checkState == null) >+ return; >+ >+ v.setCheckedElements(new Object[0]); >+ v.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; >+ while (iter.hasNext()) { >+ element = iter.next(); >+ if (!v.isExpandable(element)) { >+ // setChecked does an internal expand >+ v.setChecked(element, true); >+ } >+ } >+ // We are only firing one event, knowing that this is enough for our listeners. >+ if (element != null) >+ v.fireCheckStateChanged(element, true); >+ } > } >\ No newline at end of file >Index: src/org/eclipse/equinox/internal/p2/ui/dialogs/ContainerCheckedTreeViewer.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.equinox/p2/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/ContainerCheckedTreeViewer.java,v >retrieving revision 1.2 >diff -u -r1.2 ContainerCheckedTreeViewer.java >--- src/org/eclipse/equinox/internal/p2/ui/dialogs/ContainerCheckedTreeViewer.java 30 Apr 2008 22:46:53 -0000 1.2 >+++ src/org/eclipse/equinox/internal/p2/ui/dialogs/ContainerCheckedTreeViewer.java 13 May 2008 22:49:22 -0000 >@@ -11,38 +11,48 @@ > package org.eclipse.equinox.internal.p2.ui.dialogs; > > import java.util.ArrayList; >+import java.util.Iterator; > import org.eclipse.equinox.internal.provisional.p2.ui.query.QueriedElement; > import org.eclipse.jface.viewers.*; > import org.eclipse.swt.widgets.*; > > /** >- * CheckboxTreeViewer with special behaviour of the checked / gray state on >- * container (non-leaf) nodes: >- * Copied from org.eclipse.ui.dialogs >- * Altered to achieve the following: >- * (1)checking a parent will also expand it when we know it's a long >+ * Copy of ContainerCheckedTreeViewer which is specialized for use >+ * with DeferredFetchFilteredTree. Originally copied from >+ * org.eclipse.ui.dialogs and altered to achieve the following: >+ * >+ * (1)checking a parent will expand it when we know it's a long > * running operation that involves a placeholder. > * The modified method is doCheckStateChanged(). > * > * (2)when preserving selection, we do not want the check state >- * of the parents to influence the check state of the children. >- * When children appear due to relaxed filtering, >- * we never want to assume they should also be selected. There are >- * cases where this is not necessarily the right thing to do, but >- * there are more cases where it is wrong. >- * The added methods are preservingSelection(Runnable) and >- * updateParentsUsingChildren(TreeItem). >- * Modified method is updateChildrenItems(TreeItem parent). >- >+ * to be rippled through the child and parent nodes. >+ * Since we know that preservingSelection(Runnable) isn't working >+ * properly, no need to do a bunch of work here. >+ * The added methods is preservingSelection(Runnable). >+ * Modified methods are updateChildrenItems(TreeItem parent) and >+ * updateParentItems(TreeItem parent). > * >- * (3) API added to update parent selection according to children. >- * This is used after a filter refresh to ensure that parents are >- * up to date. Added method is >- * updateParentSelectionsUsingChildren() >+ * (3)we correct the problem with preservingSelection(Runnable) by >+ * remembering the check state and restoring it after a refresh. We >+ * fire a check state event so clients monitoring the selection will know >+ * what's going on. Added methods are internalRefresh(Object, boolean), >+ * saveCheckedState(), restoreCheckedState(), and >+ * fireCheckStateChanged(Object, boolean). That last method is public >+ * so that DeferredFetchFilteredTree can do the same thing when it >+ * remembers selections. >+ * >+ * This class does not correct the general problem reported in >+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=170521 >+ * That is handled by preserving selections additively in >+ * DeferredFetchFilteredTree. This class simply provides the API >+ * needed by that class and manages the parent state according to the >+ * children. > */ > public class ContainerCheckedTreeViewer extends CheckboxTreeViewer { > > private boolean rippleCheckMarks = true; >+ private ArrayList savedCheckState; > > /** > * Constructor for ContainerCheckedTreeViewer. >@@ -254,4 +264,43 @@ > super.preservingSelection(updateCode); > rippleCheckMarks = true; > } >+ >+ protected void internalRefresh(Object element, boolean updateLabels) { >+ saveCheckedState(); >+ super.internalRefresh(element, updateLabels); >+ restoreCheckedState(); >+ } >+ >+ // We only remember the leaves. This is specific to our >+ // use case, not necessarily a good idea for fixing the general >+ // problem. >+ private void saveCheckedState() { >+ Object[] checked = getCheckedElements(); >+ savedCheckState = new ArrayList(checked.length); >+ for (int i = 0; i < checked.length; i++) >+ if (!isExpandable(checked[i]) && !getGrayed(checked[i])) >+ savedCheckState.add(checked[i]); >+ } >+ >+ // Now we restore checked state. >+ private void restoreCheckedState() { >+ setCheckedElements(new Object[0]); >+ setGrayedElements(new Object[0]); >+ Object element = null; >+ // We are assuming that once a leaf, always a leaf. >+ Iterator iter = savedCheckState.iterator(); >+ while (iter.hasNext()) { >+ element = iter.next(); >+ setChecked(element, true); >+ } >+ // Listeners need to know something changed. >+ if (element != null) >+ fireCheckStateChanged(element, true); >+ } >+ >+ // This method is public so that the DeferredFetchFilteredTree can also >+ // call it. >+ public void fireCheckStateChanged(Object element, boolean state) { >+ fireCheckStateChanged(new CheckStateChangedEvent(this, element, state)); >+ } > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 229735
: 100078