Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use CheckboxTreeViewer properly?

I'm facing the problem, that a implemented CheckboxTreeViewer works perfect on Linux Debian, but under Windows doesn't. First of all I don't understand the concept of "setGrayed()".. Is it to show, that only part of the children from a element are selected?

So the problem: When I check an item under Windows, it checks all other elements in the tree. Somehow the whole logic is ignored.

Here is my code from ICheckStateListener:

@Override
public void checkStateChanged(final CheckStateChangedEvent event) {
    // object checked
    final TreePath path = ((ITreeSelection) this.treeViewer.getSelection()).getPaths()[0];
    checkChildren(path, event.getChecked());
    checkParents(path.getParentPath());
    syncData();
}

public void checkParents(final TreePath path) {
    if (path == null) {
        return;
    }
    final IFieldElement<Object> treeElement = (IFieldElement<Object>) path.getLastSegment();
    if (treeElement != null) {
        boolean allChecked = true;
        boolean allUnchecked = true;
        for (final Object fieldElement : treeElement.getChildrenElements()) {
            allChecked = allChecked && this.treeViewer.getChecked(fieldElement);
            allUnchecked = allUnchecked && !this.treeViewer.getChecked(fieldElement);
        }
        if (allUnchecked) {
            this.treeViewer.setChecked(treeElement, false);
            this.treeViewer.setGrayed(treeElement, false);
        } else
        if (allChecked) {
            this.treeViewer.setChecked(treeElement, true);
            this.treeViewer.setGrayed(treeElement, false);
        } else
        if (!allUnchecked && !allChecked) {
            this.treeViewer.setChecked(treeElement, true);
            this.treeViewer.setGrayed(treeElement, true);
        }
    }
    checkParents(path.getParentPath());
}

public void checkChildren(final TreePath path, final boolean checked) {
    if (path == null) {
        return;
    }
    final Object element = path.getLastSegment();
    if (element != null) {
        this.treeViewer.setChecked(element, checked);
        this.treeViewer.setGrayed(element, false);
        this.treeViewer.setSubtreeChecked(element, checked);
        if (element instanceof EventMethod) {
            checkEventMethod(path, element, checked);
        }

    }
}

EDIT: I'm using Eclipse Indigo

Thanks in advance!

like image 691
aphex Avatar asked Jan 17 '13 16:01

aphex


2 Answers

The "grayed" state of a checkbox in a tree is just another state, in addition to checked and unchecked. How you use it is up to you, but generally it means a "partial checked" state. In common practice if an item has some children checked and others unchecked, the parent will show a checked+grayed state. How exactly this is rendered depends on the OS and its version. In some implementations a user can only check or uncheck a tree item, and cannot explicitly set grayed state on an item through mouse clicks. It happens automatically depending on the checked children. Sometimes however there are applications that also allow you to click on the checkbox to make it checked to grayed to unchecked. A grayed state in such cases often means "default" state. Anyhow this is implementation dependent.

I am not exactly sure what the problem is that you are facing but if I have to guess I will say that widgets are behaving differently in Debian vs Windows when it comes throwing events. Since in your implementation whenever an item is checked, you check all its parents and also all its children, so it could be that calling treeViewer.setChecked() on parents in Windows starts throwing events also and your listener gets called that checks all the children of all the parents hence everything gets enabled. Test it out and see if this is the problem. To avoid this create a flag that you set when you first receive an event before modifying anything. And while modifying ignore all checkStateChanged() event calls as long as that flag is set so that your change to an element is not recursively applied to the entire tree. Once your operation is complete for one item checked/unchecked action reset the flag so user events can be handled again.

private boolean ignoreCheckEvent = false;

@Override
public void checkStateChanged(final CheckStateChangedEvent event) {
    if (ignoreCheckEvent)
        return;

    ignoreCheckEvent = true;

    try {
        // object checked
        final TreePath path = ((ITreeSelection) this.treeViewer.getSelection()).getPaths()[0];
        checkChildren(path, event.getChecked());
        checkParents(path.getParentPath());
        syncData();
    }
    finally {
        ignoreCheckEvent = false;
    }
}
like image 142
Waqas Ilyas Avatar answered Sep 28 '22 10:09

Waqas Ilyas


Try with org.eclipse.ui.dialogs.ContainerCheckedTreeViewer

Description : CheckboxTreeViewer with special behaviour of the checked / gray state on container (non-leaf) nodes: The grayed state is used to visualize the checked state of its children. Containers are checked and non-gray if all contained leafs are checked. The container is grayed if some but not all leafs are checked.

like image 30
Dutt Avatar answered Sep 28 '22 12:09

Dutt