 |
Home | Changes | Index | Search | Go
Design and implementation notes on SwingX sorting/filtering support
Basic Approach
SwingX sorting/filtering is considered to be the view's responsibility. The view has access to the base, unsorted/-filtered model and may present a sub-set to the user. If it does so, it'll has to provide conversion methods that map indices between view and model coordinates. Mustang's table sorting/filtering followed the SwingX way of life, though the implementation is different. This is fundamentally different from model decoration approaches, like f.i. the TableSorter example in older jdk versions up-to 1.5.
Implications of View-Based Decoration
The most basic precondition is that the view has a notion of view vs model coordinates. It implies that the view has methods to access model values in terms of view coordinates. And that all internal collaborators (especially the UI-Delegates) access the values exclusively through the view.
For Swing that precondition is met only for JTable - all coordinates in all methods are view coordinates (side-note: sometime in the history, a prominent statement of this fact got lost from the JTable class doc ...). So all collaborators are accustomed to the fact and act accordingly. In this case it's straigthforward to hook-in coordinate mapping in the JTable layer, only the table's inner wiring needs to be changed.
Another obvious candidate for sorting/filtering is the JList: sadly, it doesn't have the notion. On the contrary, all collaborators are implemented to access the model directly. So there is no clean way to implement view-based sorting/filtering. That's probably the reason why core Swing didn't add the support for a JList (just guessing, of course :-). SwingX uses a hack and internally wraps the "real" model with a sorting/filtering and expose the latter to fool the UI - with the usual disadvantages ...
Currently, there is no support whatever to sort/filter hierarchical views (J/X/Tree, JXTreeTable): neither in core Swing nor SwingX.
5 vs 6
Further evolution on the SwingX sorting/filtering has been stopped since Mustang is available - no resources to duplicate efforts nor to maintain multiple versions. The only exception are show-stopper issues and/or minor api changes (mostly widening method access) to allow for easier tweaking.
The migration plan is disruptive: at one point in time SwingX will officially targeted at jdk6 and support for the 1.5 version willl be dropped. After that point, it'll be up to community contributions to maintain the older version, if needed (yeah, I know - there will be a need).
SwingX's sorting/filtering implementation is incompatible with Mustang sorting/filtering. More specifically, if you run the 1.5 SwingX version under jdk 6, you must not use 1.6 sorting/filtering support.
SwingX vs Core
Following figure tries to visualize the main differences between SwingX (upper) and core (lower) sorting/filtering. Blueish is meant to denote type-specific, greyish unspecific. The blueish-to-greyish gradient is an effort to indicate that the sorter as such can be (and DefaultRowSorter indeed is) blissfully unaware of the concrete sortable type but is parametrized for it: the typed view (core has only JTable) expects a sorter which handles a TableModel. The arrows are has-a relationships, colors represent same typing hints as collaborators'.
Both have similar collaborators:
- View/Model pair as sortable/filterable target
- Sorter/Filter as sorting/filtering agent
- Adapter (aka: Wrapper) to allow the agent to work uniformly onto targets of different concrete types
The differences are in the details, devil controlled
- Typing: in SwingX the agent is untyped, in core it's "typed" (parameterized) to the specific model's type. That's part of a basically different design streak in SwingX vs. core - the former tries to adapt-away as many collection specifics as possible (this allows a collection-uniform handling of much functionality). The latter goes the opposite direction: special agents (renderers, editors, DnDLocations, ... ) for each of the collection types.
- Adapter: in SwingX it's coupled to the view (and by that coupling indirectly into the model), in core it's coupled to the model. So core sorter agent can't respect view-controlled properties of the model, as f.i. the string representation. On the bright side, core sorters can be shared across different instances of views (provided the model is the same). That's not easily possible in SwingX.
Death-Bound Parts of SwingX
A tentative goal is (open to debate - see related thread in forum) to remove all traces of SwingX-style sorting/filtering, that is all related classes, api, workarounds, ... but at the same time keep the "goodies" - Karl's lovely formulation - which may require new hacks, new api, ... but now based on Mustang
Things to remove:
- Filter and subclasses, FilterPipeline
- (SwingX) SortKey, SortOrder
- SelectionMapper, SizeSequenceMapper, all related dirty code in JXTable
- ColumnHeaderRenderer, LabelProperties
- current form of SortGestureRecognizer (?)
- ...
Things to keep:
- sort api on the view (in view coordinates)
- table mediated sort respect tableColumn properties
- view-sortable property
- WYSIWYM (What-you-see-is-what-you-match)
- SortController (? that was meant as the encapsulation of the interaction from the view into the sort mechanism, unsure if we still need it)
- functionality to configure the sort gesture, currently that's the SortGestureRecognizer - unsure if we can keep it without too much dirt. Ray's version has it, at the price of by-passing core mechanism completely - cool trick, but a trick
- sort/filter functionality on JXList
- ...
SwingX goes Mustang ... Experiments
First steps into the wild are done in the wild: JXTable et al are adjusted to follow the reign in the incubator (src/kleopatra/16, src/rturnbull/). Here speaking about my own experience only (Ray's is slightly different), the initial rip-out of SwingX specifics was astonishingly painless (except for my typical generics agnosy). Many tests could be kept passing with minor adjustment.
On the other hand, there's one difference in JXTable vs. JTable implementation which makes is difficult to keep all functionality of the 1.5 version: the core table does not expose any sorting/filtering api which forces the UI-Delegates to access the RowSorter directly. As a consequence, there's no easy way to hook into the process leading to a loss of control (side-note: arguably, the omission of sorting api is a breach of table netiquette ...)
SortGestureRecognizer
Currently it's the plug-in hook to customize which mouseEvents trigger a sort/unsort. The SwingX default behaviour is single click to toggle the sort and a shift-click to reset the sort. Differing client requirements
- toggle on double-click
- disable unsort
Bug Regressions (due to core bugs)
- Issue ??-swingx: must not sort after click into resize area of the column header
- Issue ??-swingx: must not sort after click if table is disabled
- Issue ??-swingx: model selection must be kept on removing/setting RowSorter
- Issue ??-swingx: model rowHeight must be kept on removing/setting RowSorter
TBD (incomplete migration)
- respect sortable property of tableColumn
- respect comparator property of tableColumn
- cope with different comparable types in cells of a column
- support custom toggle sort order policy (default is ascending/descending, client requirement might be f.i. ascending/descending/unsorted) A pluggable SortController would do that.
Tasks/Issues post-poned until after the migration
Links to relevant resources
|