/* * 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); } }); } }