TreeViewer.setSelection () не выбирает правильный элемент после указанного пути - PullRequest
2 голосов
/ 09 июня 2011

Если в средстве просмотра дерева есть больше элементов дерева, основанных на одном и том же объекте, создание 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 или я делаю это неправильно?


РЕДАКТИРОВАТЬ:

Похоже, что на eclipse.org уже есть опубликованная ошибка: https://bugs.eclipse.org/bugs/show_bug.cgi?id=332736

1 Ответ

1 голос
/ 10 июня 2011

Похоже, что это ошибка в 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;
            }
       };

Это, однако, исправит эту конкретную проблему, но нетГарантируйте, что есть другие проблемы, ждущие, чтобы быть найденными.Лично я всегда стараюсь держаться подальше от одинаковых элементов в разных местах дерева, на всякий случай.

...