Time for action – viewing time zones in tables
To display the time zones in tabular form, a new view will be created called Time Zone Table View.
- Right-click on the
com.packtpub.e4.clock.ui
project and navigate to Plug-in Tools | Open Manifest. Open the Extensions tab and right-click on theorg.eclipse.ui.views
, followed by navigating to New | e4view and filling in the following:- ID:
com.packtpub.e4.clock.ui.views.TimeZoneTableView
- Name:
Time Zone Table View
- Class:
com.packtpub.e4.clock.ui.views.TimeZoneTableView
- Category:
com.packtpub.e4.clock.ui
- Icon:
icons/sample.gif
- ID:
- The
plugin.xml
should now contain:<e4view category="com.packtpub.e4.clock.ui" class="com.packtpub.e4.clock.ui.views.TimeZoneTableView" icon="icons/sample.gif" id="com.packtpub.e4.clock.ui.views.TimeZoneTableView" name="Time Zone Table View" restorable="true"> </e4view>
- Create the class using the editor's short-cuts to create a new class
TimeZoneTableView
in thecom.packtpub.e4.clock.ui.views
package, or with the new class wizard. Once the view is created, add an emptyTableViewer
, and use anArrayContentProvider
with the set of availableZoneIds
:package com.packtpub.e4.clock.ui.views; import javax.annotation.PostConstruct; import org.eclipse.e4.ui.di.Focus; public class TimeZoneTableView { private TableViewer tableViewer; @PostConstruct public void create(Composite parent) { tableViewer = new TableViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL); tableViewer.getTable().setHeaderVisible(true); tableViewer.setContentProvider( ArrayContentProvider.getInstance()); tableViewer.setInput(ZoneId.getAvailableZoneIds()); } @Focus public void focus() { tableViewer.getControl().setFocus(); } }
- Run the Eclipse instance, and a one-dimensional list of time zones will be shown in the Time Zone Table View:
- Convert the array of
String
instances to an array ofZoneId
instances and set that as the input:// tableViewer.setInput(ZoneId.getAvailableZoneIds()); tableViewer.setInput(ZoneId.getAvailableZoneIds() // get ids .stream().map(ZoneId::of).toArray());
- The table shows a list of the
ZoneId
objects. That's because there is noLabelProvider
, so they're just being rendered with theirtoString()
representation. Because a table has multiple columns, aTableViewer
has multipleTableViewerColumn
instances. Each one represents a column in theTable
, and each has its own size, title, and label provider. Creating a new column often involves setting up standard features (such as the width) as well as hooking in the required fields to display. To make it easy to reuse, create anabstract
subclass ofColumnLabelProvider
calledTimeZoneColumn
(in thecom.packtpub.e4.clock.ui.internal
package) with abstractgetText
andgetTitle
methods, and concretegetWidth
andgetAlignment
methods:public abstract class TimeZoneColumn extends ColumnLabelProvider { public abstract String getText(Object element); public abstract String getTitle(); public int getWidth() { return 250; } public int getAlignment() { return SWT.LEFT; } }
- Add a helper method
addColumnTo
to theTimeZoneColumn
class, which makes it easier to add it to a viewer:public TableViewerColumn addColumnTo(TableViewer viewer) { TableViewerColumn tableViewerColumn = new TableViewerColumn(viewer, SWT.NONE); TableColumn column = tableViewerColumn.getColumn(); column.setMoveable(true); column.setResizable(true); column.setText(getTitle()); column.setWidth(getWidth()); column.setAlignment(getAlignment()); tableViewerColumn.setLabelProvider(this); return tableViewerColumn; }
- Now create a custom subclass
TimeZoneIDColumn
in the same package that returns theID
column for aTimeZone
:public class TimeZoneIDColumn extends TimeZoneColumn { public String getText(Object element) { if (element instanceof ZoneId) { return ((ZoneId) element).getId(); } else { return ""; } } public String getTitle() { return "ID"; } }
- Modify the
TimeZoneTableView
class, and at the end of thecreate
method, instantiate the column and call theaddColumnTo
method, above the call to thesetInput
method:new TimeZoneIDColumn().addColumnTo(tableViewer); tableViewer.setInput(ZoneId.getAvailableZoneIds()...);
Note
Note that the columns need to be created before the
setInput()
call, as otherwise they won't display properly. - Run the Eclipse instance, and show the Time Zone Table View. The
ID
column should be displayed on its own. - To add more columns, copy the
TimeZoneIDColumn
class, modifying the title returned and the returned property of the associated time zone. For example, create a copy of theTimeZoneIDColumn
calledTimeZoneDisplayNameColumn
, and modify the get method and title:// return ((ZoneId) element).getId(); return ((ZoneId) element).getDisplayName(TextStyle.FULL, Locale.getDefault()); // return "ID"; return "Display Name";
- Optionally, do the same with the other properties of
TimeZone
, such as the offset (withgetOffset()
), and whether it's in daylight savings time or not (withuseDaylightTime()
). The columns can then be added to the table:new TimeZoneDisplayNameColumn().addColumnTo(tableViewer); new TimeZoneOffsetColumn().addColumnTo(tableViewer); new TimeZoneSummerTimeColumn().addColumnTo(tableViewer);
- Run the Eclipse instance, go to the Time Zone Table View, and the additional column(s) should be seen:
What just happened?
A TableViewer
was created and multiple ColumnLabelProvider
instances were added to it for displaying individual fields of an object. Subclassing ColumnLabelProvider
avoids the need to use anonymous inner classes, and it gives a helper function which can be used to create and wire in the column (with specified title and width) while delegating those properties to the concrete subclasses of TimeZoneColumn
. This avoids the need for tracking columns by ID
.
For specific customizations of the columns, the underlying SWT Column
is used to set functionality required by the application, including allowing the column to be movable with setMovable(true)
and resizable with setResizable(true)
. Similarly, table-wide operations (such as showing the header) are done by manipulating the underlying SWT Table
and invoking setHeaderVisible(true)
.
It's important to note that the columns of the tree viewer are calculated when the setInput
method is called, so columns that are added after this line may not show properly. Generally the setInput
should be left until the end of the table's construction.
Pop quiz: understanding tables
Q1. How are a column's headers enabled in a TableViewer
?
Q2. What is a TableViewerColumn
for?
Q3. What standard content provider can be used with a TableViewer
?
Q4. What's the difference between a TableViewerColumn
and a TableColumn
?