Reputation: 71
I'm using NatTable to display a tree with multiple columns. The tree is flattened into a SortedList which is used to create TreeList.
EventList<Person> eventList = GlazedLists.eventList(perfStats.getFlattenedTree());
TransformedList<Person, Person> rowObjectsGlazedList = GlazedLists.threadSafeList(eventList);
SortedList<Person> sortedList = new SortedList<(rowObjectsGlazedList, null);
TreeList treeList = new TreeList(sortedList, treeFormat, TreeList.nodesStartCollapsed());
This works to display the tree. However, now my issue is how do I sort this properly?
The desired outcome would be for the roots to be properly sorted, then the children inside properly sorted independently and so on.
Right now, I'm using the GlazedListsSortModel and it sorts the flattened tree then builds the display from that which does not work.
Any help or just pointing me in the right direction would be appreciated!
Upvotes: 0
Views: 783
Reputation: 83
I know this question is ooooold, but I just solved the problem for a TreeList I was working on...
I used a TreeList.Format
which doubles as an ISortModel
for my SortHeaderLayer
.
The Comparator
is directly applied to the SortedList
while ISortModel
's getComparatorsForColumnIndex(int)
and getColumnComparator(int)
may return null
.
The Comparator
always takes the whole path to a TreeNode
into account and never returns 0
unless the TreeNode
s are truly identical.
Setting SortDirectionEnum.NONE
in ISortModel
's sort(int, SortDirectionEnum, boolean)
triggers a fallback to ascending order of column 0.
private class MyTreeFormat implements TreeList.Format<TreeNode>, ISortModel {
private final IColumnPropertyAccessor<TreeNode> columnPropertyAccessor;
public MyTreeFormat(final IColumnPropertyAccessor<TreeNode> columnPropertyAccessor) {
this.columnPropertyAccessor = columnPropertyAccessor;
}
// never return 0 unless node1 == node2, else the list will be in arbitrary order and mess up the tree
private final Comparator<TreeNode> comparator = new Comparator<TreeNode>() {
@Override
public int compare(final TreeNode node1, final TreeNode node2) {
if (node1 == node2) return 0;
// paths from root to node 1&2
final Iterator<TreeNode> piter1 = node1.getPath().iterator();
final Iterator<TreeNode> piter2 = node2.getPath().iterator();
while (piter1.hasNext() && piter2.hasNext()) {
final int result = doCompare(piter1.next(), piter2.next());
if (result != 0) return result;
}
return 0;
}
private int doCompare(final TreeNode node1, final TreeNode node2) {
if (node1 == node2) return 0;
int result;
if (sortedColumnIndex == 0) {
result = SpecialComparatorForColumn0.getInstance().compare(node1.getId(), node2.getId());
} else {
final Object data1 = columnPropertyAccessor.getDataValue(node1, sortedColumnIndex);
final Object data2 = columnPropertyAccessor.getDataValue(node2, sortedColumnIndex);
final String s1, s2;
// we have some Date columns while all other columns are Strings:
if (data1 instanceof Date) {
s1 = MY_SIMPLE_DATE_FORMAT.format((Date) data1);
s2 = MY_SIMPLE_DATE_FORMAT.format((Date) data2);
} else {
s1 = String.valueOf(data1);
s2 = String.valueOf(data2);
}
result = s1.compareToIgnoreCase(s2);
if (result == 0) result = SpecialComparatorForColumn0.getInstance().compare(node1.getId(), node2.getId()); // ensures same order for equal values in sort column !!
}
return result * (sortDirection == SortDirectionEnum.ASC ? 1 : -1);
}
};
@Override
public void getPath(final List<TreeNode> path, final TreeNode element) {
for (final TreeNode TreeNode : element.getPath()) {
path.add(TreeNode);
}
}
/**
* Simply always return <code>true</code>.
*
* @return <code>true</code> if this element can have child elements, or
* <code>false</code> if it is always a leaf node.
*/
@Override
public boolean allowsChildren(final TreeNode element) {
return true;
}
/**
* Returns the comparator used to order path elements of the specified
* depth. If enforcing order at this level is not intended, this method
* should return <code>null</code>. We do a simple sorting of the last
* names of the persons to show so the tree nodes are sorted in
* alphabetical order.
*/
@Override
public Comparator<? super TreeNode> getComparator(final int depth) {
return comparator;
}
/* ---------- ISortModel implementation START ----------
* ISortModel for the SortHeaderLayer
* sort only allowed by a single column at a time
* key was to set the sorted list's comparator on sort(...) so the whole tree is reordered on a click on the column header
*/
private int sortedColumnIndex = 0;
private int sortedColumnIndexOld = 0;
private SortDirectionEnum sortDirection = SortDirectionEnum.DESC;
@Override
public List<Integer> getSortedColumnIndexes() {
return Collections.singletonList(sortedColumnIndex);
}
@Override
public boolean isColumnIndexSorted(final int columnIndex) {
return sortedColumnIndex == columnIndex;
}
@Override
public SortDirectionEnum getSortDirection(final int columnIndex) {
if (columnIndex == sortedColumnIndexOld) return sortDirection;
else {
sortedColumnIndexOld = columnIndex;
return sortDirection = SortDirectionEnum.NONE;
}
}
@Override
public int getSortOrder(final int columnIndex) {
return 0;
}
@SuppressWarnings("rawtypes")
@Override
public List<Comparator> getComparatorsForColumnIndex(final int columnIndex) {
return null;
}
@Override
public Comparator<?> getColumnComparator(final int columnIndex) {
return null;
}
@Override
public void sort(final int columnIndex, final SortDirectionEnum sortDirection, final boolean accumulate) {
if (sortDirection == SortDirectionEnum.NONE) {
this.sortDirection = SortDirectionEnum.ASC;
this.sortedColumnIndex = 0;
} else {
this.sortDirection = sortDirection;
this.sortedColumnIndex = columnIndex;
}
bodyLayerStack.getSortedList().setComparator(comparator);
}
@Override
public void clear() {
sort(0, SortDirectionEnum.ASC, false);
}
}
Upvotes: 0
Reputation: 4231
When using a TreeList
you pass in a Comparator
for the tree structure via TreeList#Format
. This is needed to ensure that the tree is created properly, as it is derivated from a List
. So even if there is a sorting applied via SortedList
, the Comparator
of the TreeList#Format
will win in the end.
To solve your requirement you therefore need to implement a TreeList#Format
that takes the column sorting into account. This can be done by using the NatTable SortableTreeComparator
for example. You can have a look at our TreeGridExample to get an idea of how this could look like.
A more extended version can be seen in the GroupByComparator that is used to support sorting by column with the GroupBy feature.
Upvotes: 0