/* Copyright (c) 2005 Ricebridge. All Rights Reserved. * * This file is available under the terms and conditions of the * Ricebridge "Open Source API" policy; Ricebridge grants use of this * copyrighted work under the terms of a BSD-style license only. See * http://www.opensource.org/licenses/bsd-license.php for more * information. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * - Neither the name of the Ricebridge nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.ricebridge.xmlman.in; import com.ricebridge.xmlman.XmlManager; import org.jostraca.util.TextUtil; import org.jostraca.util.Internal; import javax.swing.table.TableModel; import javax.swing.table.AbstractTableModel; import java.util.*; /** Implementation of a {@link javax.swing.table.TableModel} to hold XML record data. * <p>This <code>TableModel</code> can be used directly with a {@link javax.swing.JTable}. * Data is represented by <code>String</code> objects, and can be {@link #setEditable editable}. * Missing data is represented by an empty <code>String</code> in the table cell. You may subclass this class to provide * more functionality.</p> * <p>The <b><a href="XmlTableModel.java.html">Source Code</a></b> of this Java class * is available under a <a href="http://www.opensource.org/licenses/bsd-license.php">BSD-style license</a>.</p> */ public class XmlTableModel extends AbstractTableModel implements TableModel { /** The table may be editable. */ protected boolean iEditable; /** The first line of the CSV file may contain headers. */ protected boolean iDataHasHeaders; /** Flag to indicate that headers have been loaded. */ protected boolean iHeadersStored; /** List of headers as <code>String</code>s. */ protected List iHeaders; /** Table data as a <code>List</code> of <code>String[]</code> arrays. */ protected ArrayList iData; /** Maximum number of fields encountered. */ protected int iMaxNumFields; /** Support {@link java.lang.Class#newInstance} object instantiation. */ public XmlTableModel() { init(); } /** Create a new <code>TableModel</code> with specified a <code>List</code> of <code>String[]</code> arrays. */ public XmlTableModel( List pData ) { init(); List data = Internal.null_list( pData ); iData.addAll(data); if( 0 < iData.size() ) { String[] first = (String[])iData.get(0); iMaxNumFields = first.length; } } /** Initialise the internal data containers before loading new XML record data. */ public void init() { iEditable = false; iDataHasHeaders = false; iHeadersStored = false; iHeaders = new ArrayList(); iData = new ArrayList(); iMaxNumFields = 0; } /** Add a record to the internal data containers for this <code>TableModel</code>. * @param pRecord data fields */ public void addRecord( String[] pRecord ) { if( pRecord.length > iMaxNumFields ) { iMaxNumFields = pRecord.length; } if( iDataHasHeaders && !iHeadersStored ) { iHeaders = Arrays.asList( pRecord ); iHeadersStored = true; } else { iData.add( pRecord ); } } /** The data provided via {@link #addRecord} includes column headers. * <p>When <code>true</code>, the first call to <code>addRecord</code> is assumed to be the list of column headers.</p> * <p>When <code>false</code>, the table has no headers.</p> * <p>You can access this setting like so:<pre> * XmlSpec xmlspec = xmlManager.getXmlSpec(); * xmlSpec.setProperty( "TableModel.dataDataHasHeaders", true ); * </pre></p> * @param pDataHasHeaders data has headers * @see XmlManager#loadTableModel(File,RecordSpec) */ public void setDataHasHeaders( boolean pDataHasHeaders ) { iDataHasHeaders = pDataHasHeaders; } public void setHeaders( String[] pHeaders ) { iHeaders = Arrays.asList( pHeaders ); iMaxNumFields = iHeaders.size(); } /** You can use this setting to make your <a href="http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JTable.html">JTable</a> * editable. * <p>When <code>true</code>, the table cells can be edited.</p> * <p>When <code>false</code>, the table cell cannot be edited.</p> * <p>You can access this setting like so:<pre> * XmlSpec xmlspec = xmlManager.getXmlSpec(); * xmlSpec.setProperty( "TableModel.editable", true ); * </pre></p> * @param pEditable editable table */ public void setEditable( boolean pEditable ) { iEditable = pEditable; } /** Clear all data from table. */ public void clear() { iData.clear(); } // TableModel interface /** Get the name of the column. * @param pIndex index of column (from zero) */ public String getColumnName( int pIndex ) { if( pIndex < iHeaders.size() ) { return String.valueOf( iHeaders.get( pIndex ) ); } return "Column "+(pIndex+1); } /** Get number of rows in table. */ public int getRowCount() { return iData.size(); } /** Get number of columns in table. */ public int getColumnCount() { return iMaxNumFields; } /** Get the value of a table cell. * @param pRow index of row (from zero) * @param pColumn index of column (from zero) */ public Object getValueAt( int pRow, int pColumn ) { if( pRow >= iData.size() ) { return ""; } else { String[] line = (String[]) iData.get( pRow ); if( pColumn >= line.length ) { return ""; } else { return line[pColumn]; } } } /** Indicate that table cell value can be changed. * @param pRow index of row (from zero) * @param pColumn index of column (from zero) */ public boolean isCellEditable( int pRow, int pColumn ) { return iEditable; } /** Set the value of a table cell. * @param pValue new value of cell * @param pRow index of row (from zero) * @param pColumn index of column (from zero) */ public void setValueAt( Object pValue, int pRow, int pColumn ) { if( pRow < iData.size() ) { String[] line = (String[]) iData.get( pRow ); String value = String.valueOf( null==pValue?"":pValue ); if( pColumn >= line.length ) { String[] newline = new String[ pColumn+1 ]; System.arraycopy( line, 0, newline, 0, line.length ); for( int fI = line.length; fI < pColumn; fI++ ) { newline[fI] = ""; } newline[pColumn] = value; iData.set( pRow, newline ); } else { line[pColumn] = value; } } fireTableCellUpdated( pRow, pColumn ); } /** <code>String</code> description of object instance. */ public String toString() { return "XmlTableModel[head:"+iDataHasHeaders+",edit:"+iEditable+", data:"+makeString(iData)+"]"; } // private /** Returns <code>List</code> of <code>String[]</code> arrays as <code>String</code>. */ private String makeString( List pData ) { StringBuffer sb = new StringBuffer( pData.size() * 55 ); sb.append("["); int numRows = getRowCount(); int numCols = getColumnCount(); for( int rowI = 0; rowI < numRows; rowI++ ) { for( int colI = 0; colI < numCols; colI++ ) { sb.append("|"); sb.append( getValueAt(rowI,colI) ); } sb.append("|\n"); } sb.append("]"); return sb.toString(); } }