Bug 181308 - [Viewers] Add checked state provider to CheckBox*Viewer
Summary: [Viewers] Add checked state provider to CheckBox*Viewer
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.2.1   Edit
Hardware: All All
: P3 enhancement with 1 vote (vote)
Target Milestone: 3.5 M4   Edit
Assignee: Boris Bokowski CLA
QA Contact:
URL:
Whiteboard:
Keywords: contributed
: 9390 45795 157324 180598 183539 247787 (view as bug list)
Depends on: 205923
Blocks: 147027 182714
  Show dependency tree
 
Reported: 2007-04-05 16:20 EDT by Keith McQueen CLA
Modified: 2008-12-01 10:39 EST (History)
13 users (show)

See Also:


Attachments
The ICheckedStateProvider interface (3.30 KB, application/octet-stream)
2007-04-05 16:24 EDT, Keith McQueen CLA
no flags Details
A subclass of the CheckboxTableViewer (9.41 KB, application/octet-stream)
2007-04-05 16:26 EDT, Keith McQueen CLA
no flags Details
Modified ICheckedStateProvider.java (1.17 KB, text/plain)
2007-10-04 13:07 EDT, Keith McQueen CLA
no flags Details
Alternate implementation for CheckboxTreeViewer (6.52 KB, text/x-java)
2008-06-20 12:51 EDT, Cole Markham CLA
no flags Details
ICheckStateProvider - interface, modified Check*Viewers, tests (33.65 KB, patch)
2008-11-13 09:27 EST, Matthew Bisson CLA
bokowski: iplog+
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Keith McQueen CLA 2007-04-05 16:20:20 EDT
It would be nice to have a provider (similar to the label or font or color providers) to determine the checked/grayed state of elements in a CheckBox*Viewer (either Table or Tree).  This would generally simplify the programming model and give the developer better control over how the model objects are displayed in the viewer.
Comment 1 Keith McQueen CLA 2007-04-05 16:24:29 EDT
Created attachment 63105 [details]
The ICheckedStateProvider interface

The ICheckedStateProvider interface defines the necessary functionality of a provider that will determine the checked/grayed state of a model object as well as respond to the (un)checking/(un)graying of a model element.
Comment 2 Keith McQueen CLA 2007-04-05 16:26:14 EDT
Created attachment 63106 [details]
A subclass of the CheckboxTableViewer

The attached subclass of the org.eclipse.jface.viewers.CheckboxTableViewer demonstrates how the viewer could/would make use of the ICheckedStateProvider.  This class is currently being used in our product offering.
Comment 3 Boris Bokowski CLA 2007-04-23 09:44:50 EDT
*** Bug 183539 has been marked as a duplicate of this bug. ***
Comment 4 Boris Bokowski CLA 2007-06-19 14:16:43 EDT
*** Bug 9390 has been marked as a duplicate of this bug. ***
Comment 5 Boris Bokowski CLA 2007-06-19 16:13:24 EDT
*** Bug 45795 has been marked as a duplicate of this bug. ***
Comment 6 Boris Bokowski CLA 2007-10-04 12:04:20 EDT
(In reply to comment #1)
> Created an attachment (id=63105) [details]
> The ICheckedStateProvider interface

I just looked at this attachment and saw the copyright header.  This is in conflict with the terms of use (http://www.eclipse.org/legal/termsofuse.php):

"any Contributions, as defined in the applicable license(s), uploaded, submitted, or otherwise made available to the Eclipse Foundation and/or the Members, by you that relate to such Content are provided under the terms and conditions of both the CPL and the EPL and can be made available to others under the terms of the CPL and/or the EPL."

Could you please clarify the license situation, and upload updated versions of the files if you want to contribute them under EPL, or mark them as obsolete if you don't want to contribute?  Thanks.
Comment 7 Keith McQueen CLA 2007-10-04 13:07:48 EDT
Created attachment 79753 [details]
Modified ICheckedStateProvider.java

Sorry about the previous attachment.  It was really meant just as an example of how I did it.  Here is another copy with all of the copyright/license stripped out.  The other attachment ("A subclass of the CheckBoxTableViewer") really is not contributed to Eclipse per se, so I don't think I need to remove the copyright/license terms.  It really is just a sample of an implementation.  It is meant to give you a starting point and just an idea of one way of providing the desired functionality.  I hope this helps.
Comment 8 Tod Creasey CLA 2007-10-10 10:28:36 EDT
Adding a reference to Bug 205293 as this is easy to hit as the javadoc is not clear for setCheckedElements().
Comment 9 Tod Creasey CLA 2007-10-10 10:30:20 EDT
*** Bug 157324 has been marked as a duplicate of this bug. ***
Comment 10 Boris Bokowski CLA 2008-05-02 14:57:03 EDT
Mass update - removing 3.4 target. This was one of the bugs I marked for investigation (and potential fixing) in 3.4 but I ran out of time. Please ping on the bug if fixing it would be really important for 3.4, and does not require API changes or feature work.
Comment 11 Boris Bokowski CLA 2008-06-20 12:11:14 EDT
*** Bug 180598 has been marked as a duplicate of this bug. ***
Comment 12 Cole Markham CLA 2008-06-20 12:49:34 EDT
Our biggest issue with the current setup was performance. On a tree with ~1000 elements (2 levels, ~20 on the root level) calling setCheckedElements took ~25 seconds when most of the elements are checked.

I tried moving the setChecked logic to the ColumnLabelProvider.update(ViewerCell) method, but the current CheckboxTreeViewer implementation clears the check state (in preservingSelection->applyState).

The solution I used was to copy CheckboxTreeViewer and strip out all of the logic except for the ICheckStateListener support (see attached CustomCheckboxTreeViewer). Then I extend ColumnLabelProvider to set the check state in update(ViewerCell):

   @Override
   public void update(ViewerCell cell)
   {
      super.update(cell);
      Widget widget = cell.getItem();
      if (widget instanceof TreeItem) {
         TreeItem item = (TreeItem)widget;
         Tree parent = item.getParent();
         // Make sure it's a checkbox tree
         if ((parent.getStyle() & SWT.CHECK) != 0){
            Object element = cell.getElement();
            boolean checked = isChecked(element);
            item.setChecked(checked);
            item.setGrayed(isGrayed(element));
         }
      }
   }

   /**
    * @param element
    * @return whether the element should appear grayed
    */
   protected abstract boolean isGrayed(Object element);
   
   /**
    * @param element
    * @return whether the element should appear checked
    */
   protected abstract boolean isChecked(Object element);


That's it, simple and clean. And substantially faster than the previous version. It went from ~25 seconds to no noticeable delay. This is due to the fact that TreeItems are only created when requested by the user instead of having to create them for every element supplied to setCheckedElements.

I'm not sure how this will fit into eclipse due to the api change to CheckboxTreeViewer, but I offer it as a solution to interested parties.
Comment 13 Cole Markham CLA 2008-06-20 12:51:06 EDT
Created attachment 105514 [details]
Alternate implementation for CheckboxTreeViewer
Comment 14 Boris Bokowski CLA 2008-09-22 11:19:05 EDT
*** Bug 247787 has been marked as a duplicate of this bug. ***
Comment 15 yau CLA 2008-09-22 20:28:32 EDT
The following references is copy from the duplicated bug 247787:
>>Another issue I would like to say is, why we need 2 classes(CheckboxTableViewer
>>and TableViewer) instead of just one TableViewer class? I just take a look the
>>source of CheckboxTableViewer. It's simple. Why don't we move the code from
>>CheckBoxTableViewer into TableViewer(and leave an empty CheckboxTableViewer
>>class, for compatibility), so we could just specified a SWT.CHECK style bit to
>>the TableViewer's constructor and then we get checkbox feature supported by the
>>TableViewer, further, we can inspect the checkbox suppport by test
>>((TableViewer.getStyle() & SWT.CHECK) != 0)?

>>------- Comment #3 From Boris Bokowski 2008-09-22 10:51:48 -0400 -------

>(In reply to comment #2)
>> Another issue I would like to say is, why we need 2 classes(CheckboxTableViewer
>> and TableViewer) instead of just one TableViewer class? I just take a look the
>> source of CheckboxTableViewer.

>CheckboxTableViewer has additional behaviour, such as preserving the checked
>state of items across a refresh operation.

We can check style for SWT.CHECK in the appropriate method to determine whether we want to do a checked state preserving or not.

for example, 
public class TableViewer ... {
    ...

    public boolean hasCheckboxSupport() {
       return (getTable().getStyle() & SWT.CHECK) != 0;
    }

    protected void preservingSelection(Runnable updateCode) {
        if (!hasCheckboxSupport())
        {
            preservingSelection(updateCode, false);
            return;
        }

        TableItem[] children = getTable().getItems();
        CustomHashtable checked = newHashtable(children.length * 2 + 1);
        CustomHashtable grayed = newHashtable(children.length * 2 + 1);

        for (int i = 0; i < children.length; i++) {
            TableItem item = children[i];
            Object data = item.getData();
            if (data != null) {
                if (item.getChecked()) {
					checked.put(data, data);
				}
                if (item.getGrayed()) {
					grayed.put(data, data);
				}
            }
        }

        preservingSelection(updateCode, false);
        //super.preservingSelection(updateCode);

        children = getTable().getItems();
        for (int i = 0; i < children.length; i++) {
            TableItem item = children[i];
            Object data = item.getData();
            if (data != null) {
                item.setChecked(checked.containsKey(data));
                item.setGrayed(grayed.containsKey(data));
            }
        }
    }

}
Comment 16 Cole Markham CLA 2008-09-23 09:49:24 EDT
I think the underlying question here is whether checked state should follow the JFace convention of using a provider or not. 

Currently it is tracked more like selection which makes sense for certain use cases. For example, a dialog with a checkbox tree to have the user select from a set of options. This provides a better user interface than using selection which can be lost easily by forgetting to Shift- or CTRL-click.

Where this pattern becomes a problem is when you want check state to reflect some aspect of the model (e.g. visibility). This is much more similar to the use case for a label provider: present to the user some information about an element. The current JFace implementation makes this very difficult. The developer must reset the checked state any time the viewer is refreshed. This is in contrast to the Provider pattern that is used throughout JFace.

I would like to see JFace support both patterns if possible to provide the best flexibility for developers.
Comment 17 Dénes Harmath CLA 2008-10-28 18:32:50 EDT
(In reply to comment #16)
> Where this pattern becomes a problem is when you want check state to reflect
> some aspect of the model (e.g. visibility). This is much more similar to the
> use case for a label provider: present to the user some information about an
> element. The current JFace implementation makes this very difficult. The
> developer must reset the checked state any time the viewer is refreshed. This
> is in contrast to the Provider pattern that is used throughout JFace.

That is the very case I'm struggling with also. Unfortunately, the JFace data binding ViewersObservables.observeCheckedElements() works with this philosophy, too... It would be urgent to resolve this.
Comment 18 Matthew Bisson CLA 2008-11-13 09:27:35 EST
Created attachment 117775 [details]
ICheckStateProvider - interface, modified Check*Viewers, tests

Work on this problem has been done in bug 182714 and here is the final product! It defines the interface ICheckStateProvider which is currently supported by CheckTreeViewer and CheckTableViewer. Upon any refresh, the ICheckStateProvider is asked if a given element is checked or grayed, and the item in the viewer set accordingly. Included also are tests.
Comment 19 Boris Bokowski CLA 2008-11-29 00:13:38 EST
Matthew's patch is in HEAD now.

Keith, Cole, I was hoping for feedback from you (should have written that here, I know). Would you be able to have a look at the new API and say whether it would work for your use cases?
Comment 20 Cole Markham CLA 2008-12-01 10:39:05 EST
Yes, that looks great for our purposes. When we finally move to 3.5 as our target platform we will start using it.