/*
* Licensed Materials - Property of Rogue Wave Software, Inc.
* © Copyright Rogue Wave Software, Inc. 2014, 2017
* © Copyright IBM Corp. 2009, 2014
* © Copyright ILOG 1996, 2009
* All Rights Reserved.
*
* Note to U.S. Government Users Restricted Rights:
* The Software and Documentation were developed at private expense and
* are "Commercial Items" as that term is defined at 48 CFR 2.101,
* consisting of "Commercial Computer Software" and
* "Commercial Computer Software Documentation", as such terms are
* used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
* as applicable.
*/
package tablemodel;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import ilog.views.chart.IlvChart;
import ilog.views.chart.IlvChartInteractor;
import ilog.views.chart.IlvChartLayout;
import ilog.views.chart.IlvChartRenderer;
import ilog.views.chart.IlvColor;
import ilog.views.chart.IlvDisplayPoint;
import ilog.views.chart.IlvLegend;
import ilog.views.chart.IlvStyle;
import ilog.views.chart.data.IlvSwingTableDataSource;
import ilog.views.chart.event.ChartHighlightInteractionEvent;
import ilog.views.chart.event.ChartInteractionEvent;
import ilog.views.chart.event.ChartInteractionListener;
import ilog.views.chart.graphic.IlvMarker;
import ilog.views.chart.graphic.IlvMarkerFactory;
import ilog.views.chart.graphic.IlvMarkerIcon;
import ilog.views.chart.interactor.IlvChartEditPointInteractor;
import ilog.views.chart.interactor.IlvChartInfoViewInteractor;
import ilog.views.chart.print.IlvChartPrintableDocument;
import ilog.views.chart.renderer.IlvPolylineChartRenderer;
import ilog.views.chart.renderer.IlvSinglePolylineRenderer;
import shared.AbstractChartExample;
import shared.PDFGenerator;
/**
* This sample shows how to bind a <code>javax.swing.TableModel</code> to a
* chart data source.
*/
public class TableModelDemo extends AbstractChartExample {
// static private final Color BG_COLOR = IlvColor.lightSteelBlue;
static private IlvMarker[] MARKERS = { IlvMarkerFactory.getCircleMarker(), IlvMarkerFactory.getDiamondMarker(),
IlvMarkerFactory.getSquareMarker(), IlvMarkerFactory.getTriangleMarker(), IlvMarkerFactory.getCrossMarker(),
IlvMarkerFactory.createCompoundMarker(IlvMarkerFactory.getSquareMarker(), IlvMarkerFactory.getPlusMarker()),
IlvMarkerFactory.createCompoundMarker(IlvMarkerFactory.getCircleMarker(), IlvMarkerFactory.getCrossMarker()),
IlvMarkerFactory.createCompoundMarker(IlvMarkerFactory.getPlusMarker(), IlvMarkerFactory.getCrossMarker()) };
/** The EditPoint interactor used to modify the chart data model. */
IlvChartEditPointInteractor editInter;
/** The cell editor used to edit Date objects. */
TableCellEditor dateEditor = new DateCellEditor(new JTextField());
/** The table data source referencing the table model. */
IlvSwingTableDataSource tableDs;
/** The JTable */
JTable table;
/** The chart */
IlvChart chart;
/**
* Initializes a new <code>TableModelDemo</code> object.
**/
Override
public void init(Container container) {
super.init(container);
// container.setLayout(new GridLayout(0,1));
container.setLayout(new BorderLayout());
// Create the chart.
chart = createChart();
// Create the swing TableModel containing the data.
AbstractTableModel swingModel = null;
try {
swingModel = createSwingTableModel();
} catch (ParseException e) {
swingModel = new DefaultTableModel();
} catch (NumberFormatException e) {
swingModel = new DefaultTableModel();
}
// Bind an IlvSwingTableDataSource to this swing table model. The series
// being arranged by column, the data source is of type COLUMN_SERIES.
// Since a specific column is used for the abscissa (the Year column) for
// all the series, the index in the table model of the year column
// is also specified (0).
tableDs = new IlvSwingTableDataSource(swingModel, IlvSwingTableDataSource.COLUMN_SERIES, 0, -1);
// At this time, the data sets corresponding to the table model series
// have been created.
// Connect the data source to a polyline chart renderer.
// The IlvPolylineChartRenderer will create a renderer for each data set
// of its data source and hold them in an internal list. These sub-
// renderers are called child renderers and can be parsed using an
// Iterator (see below).
IlvPolylineChartRenderer disp = new IlvPolylineChartRenderer();
disp.setDataSource(tableDs);
chart.addRenderer(disp);
// To visualize every point, we want all the chart renderers to draw
// a square mark at each point. To do so, we associate an IlvMarker
// with every renderer held by <code>disp</code>, each child renderer
// being retrieved via an iterator on the <code>disp</code> children.
IlvSinglePolylineRenderer child;
int i = 0;
final Icon[] markerIcons = new Icon[disp.getChildCount()];
for (Iterator<IlvChartRenderer> ite = disp.getChildIterator(); ite.hasNext(); ++i) {
child = (IlvSinglePolylineRenderer) ite.next();
child.setStyle(child.getStyle().setStroke(new BasicStroke(2)));
child.setMarker(MARKERS[i % 8]);
child.setMarkerSize(4);
IlvStyle style = new IlvStyle(child.getStyle().getStrokePaint(),
IlvColor.brighter(child.getStyle().getStrokeColor()));
child.setMarkerStyle(style);
markerIcons[i] = new IlvMarkerIcon(MARKERS[i % 8], 4, style);
}
// Create the JTable associated with the same TableModel as the chart.
table = new JTable(swingModel);
table.getTableHeader().setReorderingAllowed(true);
// Uses a specialized cell renderer that displays the renderers markers in
// the header cell.
table.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer() {
Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
column = table.convertColumnIndexToModel(column);
if (column > 0)
((JLabel) comp).setIcon(markerIcons[column - 1]);
else
((JLabel) comp).setIcon(null);
((JLabel) comp).setOpaque(false);
return comp;
}
});
Dimension dim = table.getPreferredScrollableViewportSize();
dim.height = Math.min(table.getRowHeight() * table.getRowCount(), dim.width);
table.setPreferredScrollableViewportSize(dim);
// Use a customized cell renderer to handle Date formatting.
table.getColumn("Year").setCellRenderer(new DefaultTableCellRenderer() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy");
Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
setText(dateFormat.format((Date) value));
return this;
}
});
// Use a customized cell editor to handle Date editing.
table.setDefaultEditor(Date.class, dateEditor);
table.setCellSelectionEnabled(true);
// Add interactors to the chart. The infoView interactor pops up
// a tooltip showing information about the data point when the
// mouse moves over it. Furthermore, we want to select the corresponding
// table cell. To do this, we add a chart interaction listener that
// selects or deselects the cell depending on whether the data point has
// been highlighted.
IlvChartInteractor inter = new IlvChartInfoViewInteractor();
inter.addChartInteractionListener(new ChartInteractionListener() {
Override
public void interactionPerformed(ChartInteractionEvent evt) {
ChartHighlightInteractionEvent hevt = (ChartHighlightInteractionEvent) evt;
if (hevt.isHighlighted()) {
IlvDisplayPoint dp = hevt.getDisplayPoint();
int row = dp.getIndex();
int col = tableDs.getDataSetIndex(dp.getDataSet()) + 1;
ListSelectionModel rowsel = table.getSelectionModel();
ListSelectionModel colsel = table.getColumnModel().getSelectionModel();
col = table.convertColumnIndexToView(col);
rowsel.setSelectionInterval(row, row);
colsel.setSelectionInterval(col, col);
} else {
table.getSelectionModel().clearSelection();
table.getColumnModel().getSelectionModel().clearSelection();
}
}
});
chart.addInteractor(inter);
// Add an IlvChartEditPointInteractor. This interactor allows editing
// of the points of a data set. Since we want real-time modifications
// (the modifications are sent to the data sets when the pointer moves
// and not when the button is released), we turn on the opaqueEdit mode.
editInter = new IlvChartEditPointInteractor();
editInter.setOpaqueEdit(true);
chart.addInteractor(editInter);
JScrollPane jsp = new JScrollPane(table);
jsp.setColumnHeaderView(table.getTableHeader());
// Connect an IlvLegend to the chart in the top-left corner.
IlvLegend legend = new IlvLegend();
legend.setAntiAliasing(true);
chart.addLegend(legend, IlvChartLayout.NORTH_WEST);
JLabel label = new JLabel("Click on a point to edit", JLabel.CENTER);
label.setOpaque(true);
label.setBackground(Color.white);
label.setBorder(BorderFactory.createLineBorder(label.getForeground()));
JPanel panel = new JPanel(new BorderLayout());
panel.add(label, BorderLayout.NORTH);
panel.add(chart, BorderLayout.CENTER);
container.add(panel, BorderLayout.CENTER);
label = new JLabel("Click in a cell to change its value", JLabel.CENTER);
label.setOpaque(true);
label.setBackground(Color.white);
label.setBorder(BorderFactory.createLineBorder(label.getForeground()));
panel = new JPanel(new BorderLayout());
panel.add(jsp, BorderLayout.CENTER);
panel.add(label, BorderLayout.SOUTH);
container.add(panel, BorderLayout.SOUTH);
JToolBar toolbar = createToolBar();
container.add(toolbar, BorderLayout.NORTH);
}
/**
* Creates the document to be printed.
*/
Override
protected IlvChartPrintableDocument createPrintableDocument() {
// We use a custom IlvChartPrintableDocument subclass to add a title
// and a table dump on the printed page.
return new TablePrintableDocument("TableModelDemo", table, chart);
}
/**
* Creates the XSL-FO element to be shown in the PDF.
*/
Override
protected Element createFOElement(Document document, PDFGenerator pdfgen) {
return createFOElementForChart(chart, document, pdfgen);
}
/**
* Populates the specified toolbar.
*/
Override
protected void populateToolBar(JToolBar toolbar) {
super.populateToolBar(toolbar);
addPrintingToToolBar(toolbar);
}
/**
* Returns an initialized <code>IlvChart</code>.
*/
protected IlvChart createChart() {
IlvChart chart = new IlvChart();
chart.setAntiAliasing(true);
// Color[] colors = new Color[] { IlvColor.brighter(BG_COLOR), IlvColor.darker(BG_COLOR) };
// chart.getChartArea().setPlotBackground(colors, true);
chart.setBorder(BorderFactory.createEtchedBorder());
// The x series being years, set the scale as TIME_SCALE.
chart.getXScale().setTimeUnit(null);
// Avoid having overlapping labels.
chart.getXScale().setSkippingLabel(true);
chart.getXGrid().setMajorPaint(chart.getForeground());
chart.getYGrid(0).setMajorPaint(chart.getForeground());
// Initialize the chart title and scale titles.
// The header is a JComponent that can be added at the top of the chart.
// As a convenience, the setHeaderText method offers an easy way to
// have just a label as header: a JLabel initialized with the specified
// string is automatically created and added to the chart.
chart.setHeaderText("U.S. Average length of Haul for Domestic Interstate Freight");
// Set the scales title (the y title being rotated by -90 deg).
chart.getXScale().setTitle("Years", 0);
chart.getYScale(0).setTitle("Ton-miles per year", -90);
// Add a check box to enable/disable editing along the x-axis.
// When it is selected, the x editing mode of the EditPoint interactor
// is enabled, thereby allowing the user to modify the abscissa of a point.
// By default, this mode is disabled.
// This check box is added as the footer.
JCheckBox box = new JCheckBox("X editing allowed");
box.setHorizontalAlignment(SwingConstants.CENTER);
box.addActionListener(new ActionListener() {
Override
public void actionPerformed(ActionEvent evt) {
editInter.setXEditAllowed(((JCheckBox) evt.getSource()).isSelected());
}
});
chart.setFooter(box);
return chart;
}
/**
* Returns a swing table model filled with the data to bind. The series should
* be ordered by column, the x series being the first one (index 0).
*/
protected AbstractTableModel createSwingTableModel() throws ParseException, NumberFormatException {
String[] names = { "Year", "Air", "Oil Pipeline", "Rail", "Intercity Truck", "Coastal", "Inland Lake", "Internal",
"Intraport" };
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Object[][] data = {
{ format.parse("1960"), new Double(553), new Double(233000), new Double(572309), new Double(285000),
new Double(256000), new Double(65990), new Double(89614), new Double(1730) },
{ format.parse("1965"), new Double(1353), new Double(306393), new Double(697878), new Double(359000),
new Double(302546), new Double(75918), new Double(109701), new Double(1638) },
{ format.parse("1970"), new Double(2189), new Double(431000), new Double(764809), new Double(412000),
new Double(359784), new Double(79416), new Double(155816), new Double(1179) },
{ format.parse("1975"), new Double(3470), new Double(507000), new Double(754252), new Double(454000),
new Double(315846), new Double(68517), new Double(180399), new Double(1222) },
{ format.parse("1980"), new Double(4528), new Double(588200), new Double(918958), new Double(555000),
new Double(631149), new Double(61747), new Double(227343), new Double(1596) },
{ format.parse("1985"), new Double(5156), new Double(564300), new Double(876984), new Double(610000),
new Double(610977), new Double(48184), new Double(232708), new Double(1102) },
{ format.parse("1990"), new Double(9064), new Double(584100), new Double(1033875), new Double(735000),
new Double(479134), new Double(60930), new Double(292393), new Double(1087) },
{ format.parse("1991"), new Double(8858), new Double(578500), new Double(1038875), new Double(758000),
new Double(502133), new Double(55339), new Double(289959), new Double(968) },
{ format.parse("1992"), new Double(9820), new Double(588800), new Double(1066781), new Double(815000),
new Double(502311), new Double(55785), new Double(297639), new Double(950) },
{ format.parse("1993"), new Double(10675), new Double(592900), new Double(1109309), new Double(861000),
new Double(448404), new Double(56438), new Double(283894), new Double(922) },
{ format.parse("1994"), new Double(11688), new Double(608000), new Double(1200701), new Double(908000),
new Double(457601), new Double(58263), new Double(297762), new Double(1293) } };
DefaultTableModel model = new DefaultTableModel(data, names) {
// The getColumnClass should be overridden to specify the type
// of our data. Since a data set only contains double values,
// this method is used by the IlvSwingTableDataSource to
// find the right converter to use to convert data of a given
// column into a <code>double</code> value. By default, converters
// exist for Date and Double. You can specify your own converter
// by subclassing <code>IlvDataConverter</code> and registering
// it invoking IlvSwingTableDataSource.setDefaultConverter().
Override
public Class<?> getColumnClass(int col) {
return (col == 0) ? Date.class : Double.class;
}
Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
};
return model;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
Override
public void run() {
JFrame frame = new JFrame("Table model sample");
TableModelDemo sample = new TableModelDemo();
sample.init(frame.getContentPane());
sample.setFrameGeometry(700, 540, true);
frame.setVisible(true);
}
});
}
}