TreeViewer.setSelection()不会在给定路径后选择正确的项目

时间:2011-06-09 06:46:28

标签: eclipse selection jface treeviewer

如果在树查看器中有更多基于同一对象的树项,那么当当前选择等于一个时,制作TreePath并将其传递给TreeViewer.setSelection()时不会正确选择项目我想导航。

例:
有一个树有2个项目显示相同的对象(在这种情况下为BigDecimal.ONE)。他们有不同的路径(不同的父母): tree

我希望当我在一个BigDecimal.ONE项目上时,点击该链接并导航到另一个BigDecimal.ONE。在链接的选择监听器上,我使用正确的TreeSelection制作TreePath。然后我打电话给setSelection。但导航不起作用。但是,如果根项目最初是折叠的,我会注意到它会展开它,但不会导航到正确的项目。

代码是这样的:

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.*;

public class TreeViewerExample {

    static class Model {
        String   name;
        Number[] children;

        public Model(String name, Number... numbers) {
            this.name = name;
            this.children = numbers;
        }

        public String toString() {
            return name;
        }
    }

    static class ModelTreeProvider extends LabelProvider implements ITableLabelProvider, ITreeContentProvider {

        public Object[] getChildren(Object parentElement) {
            if (parentElement instanceof Model) {
                return ((Model) parentElement).children;
            } else {
                return new Object[0];
            }
        }
        public Object getParent(Object element) {
            System.err.println("requesting the parent for " + element);
            return null;
        }
        public boolean hasChildren(Object element)
        {
            return getChildren(element) == null ? false : getChildren(element).length > 0;
        }
        public Object[] getElements(Object inputElement)
        {
            return (inputElement instanceof List)? ((List) inputElement).toArray():new Object[0];
        }
        public void dispose()
        {
        }
        public void inputChanged(Viewer arg0, Object arg1, Object arg2)
        {
        }
        public String getColumnText(Object element, int columnIndex)
        {
            return element.toString();
        }
        public Image getColumnImage(Object element, int columnIndex)
        {
            return null;
        }
    }

    public static void main(String[] args) {
        final List<Model> models = new ArrayList<Model>();
        models.add(new Model("Zero and one", BigDecimal.ZERO, BigDecimal.ONE));
        models.add(new Model("One and ten", BigDecimal.ONE, BigDecimal.TEN));

        Window app = new ApplicationWindow(null) {
            private TreeViewer treeViewer;
            private Link       link;
            protected Control createContents(Composite parent) {
                Composite composite = new Composite(parent, SWT.NONE);
                composite.setLayout(new FillLayout());
                treeViewer = new TreeViewer(composite);
                ModelTreeProvider provider = new ModelTreeProvider();
                treeViewer.setContentProvider(provider);
                treeViewer.setLabelProvider(provider);
                treeViewer.setInput(models);
                treeViewer.getTree().addSelectionListener(new SelectionAdapter() {
                    @Override
                    public void widgetSelected(SelectionEvent e) {
                        if (((TreeItem) e.item).getText().equals("1")) {
                            link.setText("This is from "+((TreeItem) e.item).getParentItem().getText()
                                    + "\r\n<a href=\"go\">Go to the other " + ((TreeItem) e.item).getText() + "</a>");
                        } else {
                            link.setText(" - ");
                        }
                        link.setData(e.item);
                    }
                });
                link = new Link(composite, SWT.NONE);
                link.setText(" - ");
                link.addSelectionListener(new SelectionAdapter() {
                    public void widgetSelected(SelectionEvent e) {
                        List<Object> path = new ArrayList<Object>();
                        if (treeViewer.getTree().indexOf(treeViewer.getTree().getSelection()[0].getParentItem()) == 0)
                        {// if the first is selected, go to the second
                            path.add(treeViewer.getTree().getItem(1).getData());
                        } else {
                            path.add(treeViewer.getTree().getItem(0).getData());
                        }
                        path.add(BigDecimal.ONE);
                        treeViewer.setSelection(new TreeSelection(new TreePath(path.toArray())), true);
                    }
                });
                return composite;
            }
        };
        app.setBlockOnOpen(true);
        app.open();
    }
}

我的问题是,这是一个jface bug还是我没有以正确的方式做到这一点?


修改

看来eclipse.org上已经有一个已发布的错误:https://bugs.eclipse.org/bugs/show_bug.cgi?id=332736

1 个答案:

答案 0 :(得分:1)

看起来这是JFace中的一个错误。毕竟,您正在传递TreePath,因此它应该确定您想要的对象的确切实例。

问题是org.eclipse.jface.viewers.AbstractTreeViewer.isSameSelection(List, Item[])方法。它根据项目中找到的元素(BigInteger s)错误地确定选择是否相同。它应该检查整个树路径,以确保选择确实相​​同。幸运的是,您可以通过覆盖isSameSelection(List, Item[])方法在代码中修复此问题,并正确检查树路径而不是元素本身:

       treeViewer = new TreeViewer(composite) {
            protected boolean isSameSelection(List items, Item[] current) {
                // If they are not the same size then they are not equivalent
                int n = items.size();
                if (n != current.length) {
                    return false;
                }
                Set itemSet = new HashSet(n * 2 + 1);
                for (Iterator i = items.iterator(); i.hasNext();) {
                    Item item = (Item) i.next();
                    itemSet.add(getTreePathFromItem(item));
                }
                // Go through the items of the current collection
                // If there is a mismatch return false
                for (int i = 0; i < current.length; i++) {
                    if (current[i].getData() == null
                            || !itemSet.contains(getTreePathFromItem(current[i]))) {
                        return false;
                    }
                }
                return true;
            }
       };

然而,这将解决这个特殊问题,但无法保证等待找到其他问题。就个人而言,我总是尽量避免在树的不同位置使用相同的元素,以防万一。