Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[nebula-dev] [CompositeTable] Selection/Check + Viewer API

Currently, CompositeTable treats the concepts of focus, selection, and
"current" as identical.  I would like to separate focus and selection and
track them separately, similar to the way that an SWT Table treats
selection, with SINGLE and MULTI support and methods to retrieve the
selected indices and items.  As a next step, I would like to implement CHECK
style selections.  Ultimately, I would like to use CompositeTable as an
ISelectionProvider that can act as a drop-in replacement for a TableViewer
and as an ICheckable that can replace CheckboxTableViewer.

There are a number of issues that need to be solved, and I'd like to
describe my ideas and get some feedback from the list before I dive in.  I'd
appreciate any comments you could provide.

0. Fill the architectural role of JFace Viewer.

Overall, I propose to build a CompositeTableViewer (CTV) class to fill the
architectural role of a JFace Viewer.  Unfortunately, due to the
statically-typed Item in method signatures, this class cannot derive from
Viewer.  I will attempt to make it semantically compatible, even if it
cannot have true binary compatibility.

1. Emulate the JFace Element-Item mapping.

Unlike the native Table and Tree controls (and the other Nebula grids),
CompositeTable does not have a concept of an Item to represent each row.
CompositeTable is "pure virtual" -- rows are continuously reused, while SWT
Table is "lazy" -- rows are created as needed, but once present they are not
reused.  AFAIK, this was a deliberate choice to avoid memory cost.
Unfortunately, much of the JFace Viewer API depends on the existence of a
statically-typed and long-lived Item for each row.

CompositeTable does have the concept of an index, however.  Operations on
rows are performed in terms of a row index within the entire collection
being displayed.  This could be seen as roughly equivalent to SWT operations
that are performed in terms of an Item.  Therefore, I propose that the
selection and check concepts should work in terms of collection indices
within CompositeTable.  Thus CT can take on the architectural role of the
SWT widget within the JFace architecture, despite the lack of an Item
concept.  All JFace API that accepts an Item parameter would be rewritten to
take an Integer parameter instead.

AFAIK, JFace does not guarantee that an Item will always map to the same
element.  A change in sort order will change this mapping.  Does anyone know
of a reason why an index number could not stand in for an Item within a
Viewer implementation?

2. Emulate the SWT Table selection/check API.

2a. Table provides various selection-related methods -- often with multiple
overloads: deselect/deselectAll, select/selectAll, setSelection,
showSelection, getSelectonIndex/getSelectionIndices, getSelectionCount,
isSelected, addSelectionListener/removeSelectionListener.  Also, the
remove/removeAll() methods interact with the selection state.  The
check-state methods on TableItem would need to be moved up to
CompositeTable, as well: get/setGrayed, get/setChecked.

2b. Some of the CompositeTable APIs use an index relative to the top of the
control, instead of relative to the collection being displayed.  There seems
to be an easy workaround for each case.  I propose that the API be
standardized to always operate in terms of the entire collection.
Operations which need to work in terms of the row Control arrangement should
be package-private or protected.

3. Implement visual feedback for selection and checked states.

3a. On one hand, it would be nice if CompositeTable could provide a
consistent UI for selection and checked states "for free" like an SWT Table
does.  On the other hand, the whole purpose of CompositeTable is to support
custom rendering of table rows.  My instinct is to leave this up to the
label provider to render, but provide a mechanism in CompositeTable to track
selections and checked states cheaply, outside of the row Control itself.
That way, generic ISelectionProvider and ICheckable implementations can be
written, even though they do not know how the selection and checked states
will be manipulated by users.  Client code will need to update the mapping
between the CompositeTable's internal state and the visual state of each
row, in whatever way is appropriate for the specific row Control.

Would it be better for setSelection to automatically refresh any affected
row Controls, or should it be the client code's responsibility to refresh
if/when it is necessary?

3b. Even if a general solution is impossible, I could provide a default
implementation that wraps each row Control in a new Composite.  Selection
would appear as a border highlight and could be toggled by clicking on a
small "tab" or "handle" along one side of the row -- just a blank space that
responds to click events.  (This might also need some kind of visual
affordance, to indicate that it can be clicked.)  Checked state would be
implemented by a standard SWT.CHECK Button with no label, placed within the
"tab".

3c. Client code would enable the default selection/check support by
specifying style bits in the constructor.  SWT.SINGLE or SWT.MULTI would
enable selection, and SWT.CHECK would add checked state support.  SWT.LEAD
and SWT.TRAIL would control the location of the selection "tab".

3d. In the future, the selection "tab" could be the basis for a new drag and
drop row-reordering feature.  I don't intend to work on this myself for a
long time, since the rest of this proposal will take long enough!

4. Emulate the JFace IContentProvider/ILabelProvider separation of concerns.

CTV will manage the mapping from a data element to a row index and from a
row index to a row Control.  It will adapt existing
IStructuredContentProvider and ILazyContentProvider implementations to work
with CompositeTable.  Custom logic will still be required to push data from
the data element into the row Control and vice versa, but this will be
separated from the source of the data in the same way that JFace separates
IContentProvider from ILabelProvider.

5. Emulate the ILabelProvider API.

I would appreciate help on this aspect of the design.

In the JFace architecture, an ILabelProvider is responsible for mapping a
data element into terms that the SWT Control can use directly.  It performs
this mapping on an element-by-element basis.

5a. With ILabelProvider and ITableLabelProvider, each portion of the GUI is
mapped with separate method calls, such as getText() and getImage().  With
IViewerLabelProvider, the entire GUI is mapped in a single method.  Since
the structure of a CompositeTable row Control is unspecified and varies from
instance to instance, it seems more appropriate to use the all-at-once
approach and let the provider handle differences in structure by itself.

5b. With JFace IViewerLabelProvider, the Viewer is responsible for the last
step of pushing data from the ViewerLabel into the Item.  I don't see how
this will be possible for CTV, since a row Control is a black box.

AFAIK, this separation between the label provider and the SWT Item was
intended to allow label decorators to modify the values created by the
provider before they are set on the Item.  This is a worthwhile
optimization, and I would prefer to support the same pattern with
CompositeTable.  Unfortunately, I can't figure out a way to do it.  Even if
it was possible to construct an intermediate object similar to ViewerLabel
that would work for arbitrary row Controls, the CTV cannot know what to do
with it when it is time to actually update the Control.

I propose that this aspect of the JFace API is incompatible with
CompositeTable's purpose, and so it should not be emulated.  The object
which will fill the architectural role of ILabelProvider will be responsible
for directly modifying the row Control.  The concept of a label decorator
will be outside the scope of this design.  The update method will be passed
the row Control directly, rather than an intermediate object.

5c. IBaseLabelProvider is the root of the type hierarchy for all JFace label
providers.  I intend for the new CTV-specific provider to derive from it.

5d. Name suggestions would be welcome.  ICompositeTableLabelProvider?
Perhaps the name should reflect the expanded role described in 4b --
ICompositeTableRowRenderer?

6. Support as many other JFace features as possible.

Sorting, filtering, and IElementComparer are directly applicable to
CompositeTableViewer.  DoubleClickListener, OpenListener, drag and drop
support, and custom tooltips might or might not make sense.


Conclusion:

This design would provide two useful new capabilities for CompositeTable:
selection and checked states.  It would also provide an MVC harness with an
API as close to JFace as possible without sacrificing core features.
Although it would not be a true drop-in replacement for TableViewer, it
would maximize code reuse and leverage developer experience with the JFace
architecture.

Implementation Notes:

I plan to start with the SWT-level features (2 and 3).  These features are
relatively simple and will be immediately useful, even without JFace-style
APIs.

Once that is complete, I plan to take the source code for the complete
Viewer hierarchy and find-replace from Item to Integer.  If I'm lucky, most
of the code should translate directly.  Since Items cannot be reordered and
serve mostly as opaque keys within the JFace implementation, Integer should
be semantically equivalent in this context.  I believe that the only methods
of Item that the Viewer implementation relies on are getData() and
setData().  It should be possible to replace these methods with simple array
accesses.  Then I will inspect to see where this naïve rule breaks down and
re-implement whatever is necessary.  I expect that the label provider logic
will need significant rework, for example.  Features with questionable
semantics for CTV will be removed or disabled/ignored.


Again, your comments would be very much appreciated.  If anyone else is
interested in helping with this work, that would be appreciated even more!

--
Peter Centgraf




Back to the top