Создание подкласса DefaultRowSorter для сортировки таблицы по дереву -

В этом вопросе я спросил, как можно было заставить JXTreeTable (SwingX )отсортировать его верхний элемент.

Я взглянул на библиотеку(aephyr ), предложенную mKorbel , и попытался объединить ее с JXTreeTable (Я создал новый класс с именем JXSortableTreeTable, скопировав исходный код JXTreeTable. ).

На данный момент мне удалось реализовать механизм сортировки узлов дерева -таблицы, т.е. когда convertRowIndexToModelмоего пользовательского сортировщика (см. ниже )вызывается, индексы, которые он возвращает, правильный.

Таким образом, у меня есть класс, который выглядит так:

public class TreeTableRowSorter  extends DefaultRowSorter {
    private M treeTableModel; // model
    private List indices; // list where each entry is the model index
    private IdentityHashMap sorters;

    private class IndicesMapFiller { // class that fills the "map" this.indices
        public void fillIndicesMap(Object node) { // recursive
            // Fills the indices "map"
        }
    }

    @Override
    public int convertRowIndexToModel(int index) {
        return indices.get(index);
    }

    @Override
    public int convertRowIndexToView(int index) {
        return indices.indexOf(index);
    }

    @Override
    public void toggleSortOrder(int columnIndex) {
        sorters.get(treeTableModel.getRoot()).toggleSortOrder(columnIndex);

        super.toggleSortOrder(columnIndex);
    }

    @Override
    public void sort() {
        getRowSorter(treeTableModel.getRoot()).sort(true);

        indices = new ArrayList();

        for (int i = 0; i < getViewRowCount(); i++)
            indices.add(-1);

        IndicesMapFiller filler = new IndicesMapFiller(indices);

        filler.fillIndicesMap(treeTableModel.getRoot());

        System.out.println("INDICES: " + indices);
    }

    private class TreeTableRowSorterModelWrapper extends ModelWrapper {
        private final Object node;
        private final TreeTableRowSorterModelWrapper parent;

        public TreeTableRowSorterModelWrapper(Object node, TreeTableRowSorterModelWrapper parent) {
            this.node = node;
            this.parent = parent;
        }

        @Override
        public M getModel() {
            return treeTableModel;
        }

        @Override
        public int getColumnCount() {
            return (treeTableModel == null) ? 0 : treeTableModel.getColumnCount();
        }

        @Override
        public int getRowCount() {
            // Returns only the number of direct visible children in order for
            // each NodeSorter to only sort its children (and not its children's
            // children)
            int rowCount = treeTableModel.getDirectVisibleChildrenCount(node, getParentPath());

            return rowCount;
        }

        public TreePath getParentPath() {
            Object root = treeTableModel.getRoot();
            if (root == null || node == root)
                return null;

            if (parent.getNode() == root)
                return new TreePath(root);

            return parent.getParentPath().pathByAddingChild(parent);
        }

        @Override
        public Object getValueAt(int row, int column) {
            Object node = treeTableModel.getChild(getNode(), row);
            return treeTableModel.getValue(node, column);
        }

        public Object getNode() {
            return node;
        }
    }

    public class NodeSorter extends DefaultRowSorter {
        private NodeSorter parent;

        private Map children;

        public NodeSorter(Object root) {
            this(null, root);
        }

        public NodeSorter(NodeSorter par, Object node) {
            parent = par;

            TreeTableRowSorterModelWrapper parentWrapper =
                    (parent == null) ? null : (TreeTableRowSorterModelWrapper) parent.getModelWrapper();

            TreeTableRowSorterModelWrapper wrapper =
                    new TreeTableRowSorterModelWrapper(node, parentWrapper);
            setModelWrapper(wrapper);

            children = createChildren();
            if (parent != null)
                setMaxSortKeys(Integer.MAX_VALUE);

            if (node == null)
                return;

            // Create the sorters for all children (even those not yet shown)
            int childCount = getModel().getChildCount(node);

            for (int i = 0; i < childCount; i++) {
                Object childNode = getModel().getChild(node, i);
                getChildSorter(childNode, sorters);
            }
        }

        protected Map createChildren() {
            int childCount = getModel().getChildCount(getNode());

            IdentityHashMap map = new IdentityHashMap(childCount);

            return map;
        }

        public NodeSorter getParent() {
            return parent;
        }

        TreeTableSortController getMaster() {
            return TreeTableSortController.this;
        }

        NodeSorter getChildSorter(Object node, Map map) {
            NodeSorter s = children.get(node);
            if (s == null && map != null) {
                s = new NodeSorter(this, node);
                children.put(node, s);
                map.put(node, s);
            }
            return s;
        }

        protected TreeTableRowSorterModelWrapper getTreeTableModelWrapper() {
            return (TreeTableRowSorterModelWrapper) getModelWrapper();
        }

        public Object getNode() {
            return ((TreeTableRowSorterModelWrapper) getModelWrapper()).getNode();
        }

        @Override
        public void toggleSortOrder(int columnIndex) {
            for (NodeSorter childSorter : children.values()) {
                childSorter.toggleSortOrder(columnIndex);
            }

            super.toggleSortOrder(columnIndex);
        }

        private boolean firePathEvent = true;

        void sort(boolean sortChildren) {
            if (!isVisible())
                return;

            firePathEvent = false;

            try {
                super.sort();
            } finally {
                firePathEvent = true;
            }

            if (!sortChildren)
                return;

            for (NodeSorter sorter : children.values())
                sorter.sort(sortChildren);
        }

        private TreePath getPathToRoot() {
            if (parent == null)
                return new TreePath(getNode());
            return parent.getPathToRoot()
                   .pathByAddingChild(getNode());
        }
    }

Если данные модели организованы так (с индексом каждого глобального узла в модели, показанным в последнем столбце):

Name       / Date       / File UID | Glob. View Idx | Glob. Model Idx
(Root)
|- Mr. X   / 1996/10/22 / AE123F6D | 0              | 0
|--- File1 / 2012/01/10 / DFC2345Q | 1              | 1
|--- File2 / 2012/01/11 / D321FEC6 | 2              | 2
|- Mrs. Y  / 1975/03/03 / G2GF35EZ | 3              | 3
|--- File3 / 2012/02/29 / 35GERR32 | 4              | 4
|--- File4 / 2012/01/22 / LKJY2342 | 5              | 5
.
.
.

Если я сортирую второй столбец, я хотел бы получить этот вывод:

Name       / Date       / File UID | Glob. View Idx | Glob. Model Idx
(Root)
|- Mrs. Y  / 1975/03/03 / G2GF35EZ | 0              | 3
|--- File4 / 2012/01/22 / LKJY2342 | 1              | 5
|--- File3 / 2012/02/29 / 35GERR32 | 2              | 4
|- Mr. X   / 1996/10/22 / AE123F6D | 3              | 0
|--- File1 / 2012/01/10 / DFC2345Q | 4              | 1
|--- File2 / 2012/01/11 / D321FEC6 | 5              | 2
.
.
.

То, что я на самом деле получаю, точно такое же, как и не отсортированная -версия, за исключением того, что результат convertRowIndexToModel правильный, потому что, если я вызову его для каждой строки модели,Я получаю:

V -> M
0 -> 3
1 -> 5
2 -> 4
3 -> 0
4 -> 1
5 -> 2

Таким образом, мой вопрос сводится к:

При создании подкласса DefaultRowSorter для реализации сортировки древовидной -таблицы, такой как JXTreeTable, какие методы следует переопределить? Поскольку я не могу переопределить viewToModel для rowSorter (private )или любой функции, которая его изменяет (также private ), я реализовал собственное создание карты V ->M и убедился, что она используется при вызове convertRowIndexTo (Model|View )моего сортировщика.

Я чувствую, что чего-то не хватает, например вызова метода преобразования где-то в JXSortableTreeTable или, возможно, в пользовательском сортировщике.

Большое спасибо за помощь и полезные комментарии!

Редактировать> После небольшого тестирования результата, похоже, он скорее связан с иерархическим столбцом JXTreeTable, для которого данные не обновляются, поскольку он отлично работает при сортировке по другим столбцам. (Я также пробовал чтобы изменить иерархический столбец (установить другой столбец )и первый работает, когда он больше не иерархический)

16
задан Community 23 May 2017 в 12:31
поделиться