Connecting to Swing TableModel instances
Provides an overview on how to display Gantt data from a Swing TableModel
Describes the classes used to display Gantt data coming from a Swing TableModel
Describes the data required for activities, resources, constraints and reservations.
Explains the IlvTableGanttModel instances used to configure an
IlvTableGanttModel object.
Describes the steps necessary to configure an
IUlvTableGanttModel object with two
IlvTableGanttModel instances.
Explains how once you have imported the data, modifications applied to the
IlvTableGanttModel instance are passed along to the TableModel object.
Describes how to handle changes to the TableModel instances during the lifetime of the application dynamically modify the
IlvTableGanttModel object.
Explains how to use the import Gantt data from CSV files using the
JViews Gantt and Rogue Wave®
JViews Framework APIs.
Explains how to map columns to a time-interval property.
Overview
The class
IlvTableGanttModel is a specific implementation of the
IlvGanttModel interface that allows you to display Gantt data coming from Swing
TableModel instances.
A subclass of
IlvTableGanttModel, called
IlvJDBCGanttModel, is also provided in the library to enable you to load data from databases through instances of a
TableModel implementation,
IlvRowSetTableModel, which can access a database through JDBC™. If this is the implementation you need, see
Connecting to data through JDBC.
For a table Gantt data model (class
IlvTableGanttModel), data pertaining to activities, resources, constraints, and reservations must be contained in a
TableModel instance. A set of configuration parameters allow you to map this data to the information that the
IlvTableGanttModel object needs to build its contents.
Data required by IlvTableGanttModel
A table Gantt data model requires the following information:
For activities (IlvTableActivity)
The following table shows the data required by IlvTableGanttModel for activities.
Property description | Time Information | ID | Parent ID | Name |
Start Time | End Time | Time Interval |
Property name | START_TIME_PROPERTY | END_TIME_PROPERTY | TIME_INTERVAL_PROPERTY | ID_PROPERTY | PARENT_ID_PROPERTY | NAME_PROPERTY |
Required type | Date | Date | IlvTimeInterval | String | String (can be null) | String |
Property description | Time Information | ID | Parent ID | Name |
NOTE The time information is required either as delimiters (start/end) or as a time interval
For resources (IlvTableResource)
The following table shows the data required by IlvTableGanttModel for resources.
Property description | Quantity | ID | Parent ID | Name |
Property name | QUANTITY_PROPERTY | ID_PROPERTY | PARENT_ID_PROPERTY | NAME_PROPERTY |
Required type | Float | String | String (can be null) | String |
For constraints (IlvTableConstraint)
The following table shows the data required by IlvTableGanttModel for constraints.
Property description | Constraint Type | Identifier of the From activity | Identifier of the To activity |
Property name | TYPE_PROPERTY | FROM_ACTIVITY_ID | TO_ACTIVITY_ID |
Required type | IlvConstraintType | String | String |
For reservations (IlvTableReservation)
The following table shows the data required by IlvTableGanttModel for reservations.
Property description | ID of the activity | ID of the resource |
Property name | ACTIVITY_ID_PROPERTY | RESOURCE_ID_PROPERTY |
Required type | String | String |
The column types in the
TableModel instance must not necessarily be the same as the ones required by the
IlvTableGanttModel properties. If they are different, the
IlvTableGanttModel object must be configured such as to convert the values to the right type, as explained in the next section
Converting TableModel data to IlvTableGanttModel data.
Converting TableModel data to IlvTableGanttModel data
Suppose you have the following two TableModel instances:
Activities
The following table represents a TableModel instance for activities. The column name is returned by the method TableModel.getColumnName(int) and the column type is returned by the method TableModel.getColumnClass(int).
Column name | Category (0) | ID (1) | StartTime (2) | EndTime (3) | ParentID (4) |
Column type | String | String | String (formatted M/d/yy) | String(formatted M/d/yy) | String |
Column name | Category (0) | ID (1) | StartTime (2) | EndTime (3) | ParentID (4) |
You can see that the TableModel instance contains:
the required
ID and
parent ID data with the right type;
start-time and end-time data, but expressed as String objects whereas
IlvTableGanttModel requires Date objects;
no name information;
a
Category column that does not correspond to any required property.
Constraints
The following table represents a TableModel instance for constraints. The column name is returned by the method TableModel.getColumnName(int) and the column type is returned by the method TableModel.getColumnClass(int).
Column name | Type (0) | FromActivityID (1) | ToActivityID (2) |
Column type | Integer | String | String |
Column name | Type (0) | FromActivityID (1) | ToActivityID (2) |
You can see that the
TableModel instance contains the required
FromActivity and
ToActivity IDs with the right type. It also contains the constraint type. However, the latter is expressed as an Integer, instead of an
IlvConstraintType instance. Therefore, you need to map the corresponding values as shown in the following table:
IlvConstraintType | Integer |
START_START | 1 |
START_END | 2 |
END_END | 3 |
END_START | 4 |
IlvConstraintType | Integer |
For a basic use of
IlvTableGanttModel, that is, when you import the data from the database to the Gantt data model a single time and as read-only, there are no particular requirements on how the
TableModel instances are implemented. This will be different with more advanced uses (see
Read/write support and
Dynamic behavior).
Configuring the IlvTableGanttModel object correctly
To configure your IlvTableGanttModel object correctly with these two TableModel instances:
1. Create the table Gantt data model
This is done by instantiating IlvTableGanttModel:
IlvTableGanttModel tableModel = new IlvTableGanttModel();
2. Create the mapper for activities
The activities mapper is taken from the activities table model and the mapping instructions for the required properties.
The arguments after the table model are:
the ID column,
the name column,
the start time column,
the end time column, and
the parent ID column.
Indexes of columns are used in the code sample below but you could also use column names:
IlvTableModelMapper activityMapper =
IlvTableGanttModel.createActivityMapper(activityModel, 1, 1, 2, 3, 4);
As the TableMode instance does not provide name information, the ID column is used instead (index 1).
The tables in
Constraints show that the
StartTime and
EndTime columns do not use the required type; therefore, you should also, theoretically, register a converter from the column actual type (String) to the type required by
IlvTableGanttModel (Date). Practically, this is not mandatory in this case because this particular converter is already registered by default. However, if it was necessary, the code would be:
IlvConvert.addConverter(new IlvConverter() {
private final DateFormat formatter =
DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
public Object convert(Object value, Class toType)
throws IlvConvertException {
try {
return formatter.parse((String)value);
} catch (ParseException e) {
throw new IlvConvertException("error");
}
}
public Class[] fromTypes() {
return new Class[] {String.class};
}
public Class[] toTypes() {
return new Class[] {Date.class};
}
}
3. Add an instance of IlvTableModelPropertyDescriptor to the mapper
This is done in order to map the optional column (that is, the activity category) available in the table:
activityMapper.addPropertyDescriptor("OptionalCategory",
new IlvBasicTableModelPropertyDescriptor("CATEGORY"), null);
These code lines map the contents of the Category column of the
TableModel instance to the activity property
CATEGORY of the
IlvTableGanttModel object without trying to convert the values (null as
requiredType parameter). The values will then be accessible on each activity by a call to the method
getProperty("CATEGORY") on the
IlvTableActivity instance.
At this stage, the mapper for activities is fully configured.
4. Pass it to the IlvTableGanttModel
tableModel.setActivityMapper(activityMapper);
5. Repeat previous steps
Repeat from Create the mapper for activities to Pass it to the IlvTableGanttModel for the constraints.
Here, you are going to use column names instead of indexes to build the mapper. Note that the last parameter is different from the one used for activities. Its role is to map the different values taken by the constraint types in the TableModel (1, 2, 3, or 4 in this case) to the values required by the IlvTableGanttModel object, namely IlvTableConstraintType.START_START, START_END, END_START, and END_END, in this order:
IlvTableModelMapper constraintMapper =
IlvTableGanttModel.createConstraintMapper
(constraintModel,
"FromActivityID",
"ToActivityID",
"Type",
new Object[] {new Integer(1),
new Integer(2),
new Integer(4),
new Integer(3)});
6. Carry out any other necessary conversion or add the optional properties
In this example, there are none, so you can move on to the next step.
7. Pass the result to the model
The following code example shows how to do this.
tableModel.setConstraintMapper(constraintMapper);
All the tables you want to deal with are now configured.
8. Initialize the model
You now import the data from the TableModel instances:
try {
tableModel.initializeMapping();
} catch (IlvTableModelMappingException e) {
// in case something went wrong
}
If you do nothing else after this initialization step, use the
TableModel instances and the
IlvTableGanttModel object as read-only. If you want to add read/write and dynamic capabilities, see
Read/write support or
Dynamic behavior.
Read/write support
Users often need to interact with the model through a Schedule or Gantt chart, and then, they want the result of the interaction to be persistent. In such cases, the
TableModel instance connected to the
IlvTableGanttModel object must additionally implement the interface
IlvTableModel which allows you to add or remove rows from the
TableModel instance.
public interface IlvTableModel extends TableModel {
public void addRow(Object[] rowData);
public void insertRow(int rowIndex, Object[] rowData);
public void removeRow(int rowIndex);
}
If you do not add this interface, exceptions may be raised when the application tries to modify the IlvTableGanttModel object.
The Swing class
DefaultTableModel already contains the required methods. You can therefore easily use it for read/write operations with
IlvTableGanttModel. All you have to do is mark a subclass with the interface
IlvTableModel:
public BasicTableModel extends DefaultTableModel
implements IlvTableModel {
public BasicTableModel() {
super();
}
}
From then on, each change to the IlvTableGanttModel object will update the TableModel object accordingly.
If you want the predefined actions on
IlvHierarchyChart instances to create the right type of activities, resources, constraints, and reservations, you can configure these instances to use the
IlvTableGanttModel-aware factories by calling:
tableGanttModel.configureHierachyChart(hierachyChart);
Dynamic behavior
When importing data from a Swing
TableModel instance to a Gantt data model, you may also need the Gantt data model to update automatically when the contents of the underlying
TableModel instances are modified
after the mapper has been initialized. Such updating does not take place by default because additional events need to be thrown which regular implementations of
TableModel do not throw. If you need this updating feature, you must code your own
TableModel implementation to fire the additional events described in the
IlvTableModelEvent class.
As described in
Read/write support, it is easy to code a
TableModel instance from the Swing class
DefaultTableModel so that it supports dynamic modification of the model
after initialization. It consists in firing the appropriate events before the parent class methods are called:
class BasicTableModel extends DefaultTableModel
implements IlvTableModel {
public BasicTableModel() {
super();
}
public void setDataVector(Vector dataVector, Vector columnIdentifiers) {
IlvTableModelEvent.fireBeforeTableStructureChanged(this);
super.setDataVector(dataVector, columnIdentifiers);
}
public void removeRow(int row) {
IlvTableModelEvent.fireBeforeTableRowsDeleted(this, row, row);
super.removeRow(row);
}
public void setColumnCount(int columnCount) {
IlvTableModelEvent.fireBeforeTableStructureChanged(this);
super.setColumnCount(columnCount);
}
}
The events will allow the IlvTableGanttModel object to update correctly according to the changes made to the BasicTableModel object.
Reading data from CSV files
The class
IlvTableGanttModel is particularly useful because it allows you to import any kind of data to a
JViews Gantt application provided you can read this data from a Swing
TableModel instance.
One way to do so is to use the subclass
IlvJDBCGanttModel which allows you to load data from a database via a JDBC™ implementation of the class
TableModel. See
Connecting to data through JDBC for details.
Another way is to use the class IlvTableGanttModel to read Gantt data from CSV (Comma-Separated Values) files. This section shows an example based on the following file, containing activities information:
A1, Root Activity, 1/31/04, 10/17/04,
A2, First Child Activity, 1/31/04, 4/2/04, A1
A3, Second Child Activity, 4/2/04, 10/17/04, A2
As for a JDBC connection, Rogue Wave® JViews Framework provides a utility API that allows a Gantt data model to read the contents of a CSV file from a TableModel instance. All you have to do is connect that CSV file to your Gantt data model like this:
TableModel activities = null;
try {
activities = IlvCSVReader.getInstance(',').
read(new FileReader("file.csv"));
} catch (IOException e) {
}
IlvTableGanttModel model = new IlvTableGanttModel();
IlvTableModelMapper activitiesMapper =
IlvTableGanttModel.createActivityMapper(activities, 0, 1, 2, 3, 4);
model.setActivityMapper(activitiesMapper);
try {
model.initializeMapping();
} catch (IlvTableModelMappingException e) {
}
Complex mappings
So far, you have seen only simple mappings: one column of a table corresponds to one property in the Gantt data model with, possibly, type conversion if necessary. However, the JViews Gantt API is generic enough to enable more complex mapping.
For example, instead of mapping the
StartTime and
EndTime columns to the start-time and end-time properties of activities, you can map the two columns directly to the time-interval property of activities. Referring again to the example used in
Connecting to Swing TableModel instances, where the start and end times were respectively available in columns (2) and (3).
To map columns to a time-interval property:
class TimeIntervalPropertyDescriptor
implements IlvTableModelPropertyDescriptor {
private final int[] indexes = new int[2];
private final DateFormat formatter =
DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
public TimeIntervalPropertyDescriptor(int start, int end) {
indexes[0] = start;
indexes[1] = end;
}
public Object getProperty(TableModel model, int rowIndex)
throws IlvTableModelMappingException, IlvConvertException {
try {
// get the start & end time on the table
Date start = formatter.parse((String)model.getValueAt(indexes[0],
rowIndex));
Date end = formatter.parse((String)model.getValueAt(indexes[1],
rowIndex));
// return the IlvTimeInterval
return new IlvTimeInterval(start, end);
} catch (ParseException e) {
throw new IlvConvertException("error");
}
}
public void setProperty(TableModel model, int rowIndex, Object
propertyValue)
throws IlvConvertException, IlvTableModelMappingException {
// extract start & end time from the time interval
Date start = ((IlvTimeInterval)propertyValue).getStart();
Date end = ((IlvTimeInterval)propertyValue).getEnd();
// set the values back in the table
model.setValueAt(formatter.format(start), indexes[0], rowIndex);
model.setValueAt(formatter.format(end), indexes[1], rowIndex);
}
public int[] getColumns(TableModel model) {
return indexes;
}
}
2. Build the activity mapper with it:
IlvTableModelMapper activityMapper = new IlvTableModelMapper(activityTable);
activityMapper.
addPropertyDescriptor(IlvTableActivity.TIME_INTERVAL_PROPERTY,
new TimeIntervalPropertyDescriptor(2, 3),
IlvTimeInterval.class);
activityMapper.
addPropertyDescriptor(IlvTableActivity.ID_PROPERTY,
new IlvBasicTableModelPropertyDescriptor(1), String.class);
// ...
3. Associate it with the IlvTableGanttModel object.
tableModel.setActivityMapper(activityMapper);
The JViews Gantt API enables you to code even more complex mappings. However, keep in mind that the more complex the mapping, the more time-consuming it is, which may significantly slow your application because the Gantt data model makes frequent calls to these methods.
Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.