Time for action – sorting items in a viewer
The TreeViewer
already shows data in a sorted list, but this is not a view-imposed sort. Because the data is stored in a TreeMap
, the sort ordering is created by the TreeMap
itself, which in turn is sorting on the value of the toString
method. To use a different ordering (say, based on the timezone offset) the choices are either to modify the TreeMap
to add a Comparator
and sort the data at creation time, or add a sorter to the TreeViewer
. The first choice is applicable if the data is only used by a single view, or if the data is coming from a large external data store which can perform the sorting more efficiently (such as a relational database). For smaller data sets, the sorting can be done in the viewer itself.
- JFace structured viewers allow view-specific sorting with the
ViewerComparator
. Create a new subclass calledTimeZoneViewerComparator
in thecom.packtpub.e4.clock.ui.internal
package, and implement thecompare
method as follows:public class TimeZoneViewerComparator extends ViewerComparator { public int compare(Viewer viewer, Object z1, Object z2) { int compare; if (z1 instanceof ZoneId && z2 instanceof ZoneId) { Instant now = Instant.now(); ZonedDateTime zdt1 = ZonedDateTime.ofInstant(now,(ZoneId)z1); ZonedDateTime zdt2 = ZonedDateTime.ofInstant(now,(ZoneId)z2); compare = zdt1.compareTo(zdt2); } else { compare = o1.toString().compareTo(o2.toString()); } return compare; } }
- Set the comparator on the
treeViewer
in theTimeZoneTreeView
as follows:treeViewer.setComparator(new TimeZoneViewerComparator());
- Run the Eclipse instance, open the Time Zone Tree View, and the time zones should be sorted first by offset, then alphabetically:
- To add a viewer-specific sort, modify the compare method of the
TimeZoneViewerComparator
class to get aREVERSE
key from the viewer's data. Use it to invert the results of the sort:// return compare; boolean reverse = Boolean.parseBoolean(String.valueOf(viewer.getData("REVERSE"))); return reverse ? -compare : compare;
- To see the effect of this sort, set the
REVERSE
key just before thesetComparator()
call at the end of the create method ofTimeZoneTreeView
:treeViewer.setData("REVERSE", Boolean.TRUE); treeViewer.setComparator(new TimeZoneViewerComparator());
- Re-launch the Eclipse instance, and the view should be in the reverse order.
What just happened?
By adding the TimeZoneViewerComparator
to the TimeZoneTreeViewer
, data can be sorted in an appropriate manner for the viewer in question. Typically this will be done in conjunction with selecting an option in the view—for example, an option may be present to reverse the ordering, or to sort by name or offset.
Tip
When implementing a specific Comparator
, check that the method can handle multiple object types (including ones that may not be expected). The data in the viewer may change, or be different at run-time than expected. Use instanceof
to check that the items are of the expected type.
To store properties that are specific to a viewer, use the setData
and getData
calls on the viewer itself. This allows a generic comparator to be used across views while still respecting per view filtration/sorting operations.
The preceding example hard-codes the sort data, which requires an Eclipse re-launch to see the effect. Typically after modifying properties that may affect the view's sorting or filtering, refresh is invoked on the viewer to bring the display in line with the new settings.