skip to main content
Programmer's documentation > Developing with the JViews Gantt SDK > Connecting to data > Connecting to Swing TableModel instances
 
Connecting to Swing TableModel instances
Provides an overview on how to display Gantt data from a Swing TableModel
*Overview
*Describes the classes used to display Gantt data coming from a Swing TableModel
*Data required by IlvTableGanttModel
*Describes the data required for activities, resources, constraints and reservations.
*Converting TableModel data to IlvTableGanttModel data
*Explains the IlvTableGanttModel instances used to configure an IlvTableGanttModel object.
*Configuring the IlvTableGanttModel object correctly
*Describes the steps necessary to configure an IUlvTableGanttModel object with two IlvTableGanttModel instances.
*Read/write support
*Explains how once you have imported the data, modifications applied to the IlvTableGanttModel instance are passed along to the TableModel object.
*Dynamic behavior
*Describes how to handle changes to the TableModel instances during the lifetime of the application dynamically modify the IlvTableGanttModel object.
*Reading data from CSV files
*Explains how to use the import Gantt data from CSV files using the JViews Gantt and Rogue Wave® JViews Framework APIs.
*Complex mappings
*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:
1. Write an IlvTableModelPropertyDescriptor implementation:
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.