home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 November
/
Chip_1998-11_cd.bin
/
tema
/
Cafe
/
jfc.bin
/
DefaultTableModel.java
< prev
next >
Wrap
Text File
|
1998-02-26
|
30KB
|
795 lines
/*
* @(#)DefaultTableModel.java 1.14 98/02/02
*
* Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
package com.sun.java.swing.table;
import java.io.Serializable;
import java.util.Date;
import java.util.Vector;
import java.util.Enumeration;
import com.sun.java.swing.event.TableModelEvent;
/**
* This is an implementation of TableModel that uses a Vector of Vectors
* to store the cell value objects.
* <p>
* <b>Note:</b><br>
* The DefaultTableModel's API contains the methods addColumn(),
* removeColumn(), but not methods to insert a column at an index
* nor methods to move the columns. This is because JTable does
* not display the columns based on the order of the columns in
* this model. So rearranging them here doesn't do much. See
* the column ordering methods in TableColumnModel.
* <p>
* Warning: serialized objects of this class will not be compatible with
* future swing releases. The current serialization support is appropriate
* for short term storage or RMI between Swing1.0 applications. It will
* not be possible to load serialized Swing1.0 objects with future releases
* of Swing. The JDK1.2 release of Swing will be the compatibility
* baseline for the serialized form of Swing objects.
*
* @version 1.14 02/02/98
* @author Alan Chung
*
* @see TableModel
* @see #getDataVector()
*/
public class DefaultTableModel extends AbstractTableModel
implements Serializable {
//
// Instance Variables
//
/** The Vector of Vector of Object values */
protected Vector dataVector;
/** The Vector column identifiers */
protected Vector columnIdentifiers;
/** The number of columns in the table */
int numColumns;
/** The number of rows in the table */
int numRows;
//
// Constructors
//
/**
* Constructs a default DefaultTableModel which is a table of
* zero columns and zero rows.
*/
public DefaultTableModel() {
this((Vector)null,0);
}
/**
* Constructs a DefaultTableModel with <i>numColumns</i> and
* <i>numRows</i> of <b>null</b> object values.
*
* @param numColumns The number of columns the table holds
* @param numRows The number of rows the table holds
*
* @see #setValueAt()
*/
public DefaultTableModel(int numColumns, int numRows) {
this(new Vector(numColumns), numRows);
}
/**
* Constructs a DefaultTableModel with as many columns as there are
* elements in <i>columnIds</i> and
* <i>numRows</i> of <b>null</b> object values. Each column's
* identifier object will be taken from the <i>columnIds</i>
* vector.
*
* @param columnIds Vector containing identifier objects
* to be used to identify the columns. If this
* null then the model has no columns
* @param numRows The number of rows the table holds
* @see #setValueAt()
*/
public DefaultTableModel(Vector columnIds, int numRows) {
super();
if (columnIds != null) {
numColumns = columnIds.size();
columnIdentifiers = columnIds;
}
else {
numColumns = 0;
columnIdentifiers = new Vector();
}
dataVector = new Vector();
this.numRows = 0;
if (numRows != 0)
this.setNumRows(numRows);
}
/**
* Constructs a DefaultTableModel with as many columns as there are
* elements in <i>columnIds</i> and
* <i>numRows</i> of <b>null</b> object values. Each column's
* identifier object will be taken from the <i>columnIds</i>
* array.
*
* @param columnIds Array containing identifier objects
* to be used to identify the columns. If this
* null then the model has no columns
* @param numRows The number of rows the table holds
* @see #setValueAt()
*/
public DefaultTableModel(Object[] columnIds, int numRows) {
this(DefaultTableModel.convertToVector(columnIds), numRows);
}
/**
* Constructs a DefaultTableModel and initialize the table
* by passing <i>data</i> and <i>columnIds</i> to the setDataVector()
* method. See the documentation of the getDataVector() method for details
* on how to structure <i>data</i> properly.
*
* @exception IllegalArgumentException see setDataVector().
* @param data The data of the table
* @param columnIds Vector containing identifier objects
* to be used to identify the columns.
* @see #getDataVector()
* @see #setDataVector()
*/
public DefaultTableModel(Vector data, Vector columnIds) {
this((Vector)null,0);
this.setDataVector(data, columnIds);
}
/**
* Constructs a DefaultTableModel and initialize the table
* by passing <i>data</i> and <i>columnIds</i> to the setDataVector()
* method. The first index in the Object[][] is the row index and
* the second is the column index.
*
* @exception IllegalArgumentException see setDataVector().
* @param data The data of the table
* @param columnIds Array containing identifier objects
* to be used to identify the columns.
* @see #getDataVector()
* @see #setDataVector()
*/
public DefaultTableModel(Object[][] data, Object[] columnIds) {
this((Vector)null,0);
this.setDataVector(data, columnIds);
}
//
// Querying and Modifying the Column Identifies
//
//
// Querying and Modifying the data structure
//
/**
* This returns the Vector of Vectors that contains the table's
* data values. The vectors contained in the outer vector are
* each a single row of values. In other words, to get to the cell
* at row 1, column 5 <p>
*
* <code>((Vector)getDataVector().elementAt(1)).elementAt(5);</code><p>
*
* You can directly alter the returned Vector. You can change the cell
* values, the number of rows, but you may <b>not</b> change the number
* of columns in the model. If you need to alter the number of columns
* in the model, you can do so with addColumn(), removeColumn(), or
* the setDataVector() methods. Once you have finished modifying the
* dataVector, you <b>must</b> inform the model of the new data using
* the newDataAvailable(), rowsRemoved() or the newRowsAdded() methods.
* Depending on which one of the three best describes the changes made.
* These methods will give the model a chance to modify its internal
* variables based upon the new data vector. The new data methods
* will also generate the appropriate TableModelListener
* messages to notify any listeners of this model.
*
* @see #newDataAvailable()
* @see #newRowsAdded()
* @see #rowsRemoved()
* @see #setDataVector()
*/
public Vector getDataVector() {
return dataVector;
}
/**
* This replaces the current dataVector instance variable with the
* parameter <i>newData</i>. <i>columnIds</i> are the identifiers
* of the new columns. The first identifier in <i>columnIds</i> is
* mapped to column 1 in <i>newData</i>. <p>
*
* The size of the <i>columnIds</i> vector must
* equal the size of the <i>newData</i> vector. If <i>columnIds</i> is
* <b>null</b> then it will reuse the currect vector of column identifiers.
* Finally, this method calls newDataAvailable() to generate the
* appropriate notification.
*
* @param newData The new data vector
* @param columnIds The corresponding column identifiers for
* the new data vector
* @exception IllegalArgumentException if newData is null or if the number
* of columns in newData does not equal the
* number of the column identifiers in columnIds.
* @see #newDataAvailable()
* @see #getDataVector()
*/
public void setDataVector(Vector newData, Vector columnIds) {
Vector oldIds = columnIdentifiers;
if (newData == null)
throw new IllegalArgumentException("setDataVector() - Null parameter");
if (columnIds != null) {
columnIdentifiers = columnIds;
}
dataVector = newData;
numColumns = ((Vector)dataVector.elementAt(0)).size();
this.newDataAvailable(null);
}
/**
* This replaces the value in the dataVector instance variable with the
* values in the array <i>newData</i>. The first index in the Object[][]
* array is the row index and the second is the column index.
* <i>columnIds</i> are the identifiers of the new columns.
* Finally, this method calls newDataAvailable() to generate the
* appropriate notification.
*
* @param newData The new data array
* @param columnIds The corresponding column identifiers for
* the new data array
* @exception IllegalArgumentException if newData is null or if the number
* of columns in newData does not equal the
* number of the column identifiers in columnIds.
* @see #newDataAvailable()
* @see #getDataVector()
*/
public void setDataVector(Object[][] newData, Object[] columnIds) {
Vector ids = null;
if (columnIds != null)
ids = DefaultTableModel.convertToVector(columnIds);
setDataVector(DefaultTableModel.convertToVector(newData), ids);
}
/**
* This method is used to informed the model that the model's dataVector
* has been changed directly. The <i>event</i> describes the extent
* of the update. This method will send the tableChanged() notification
* message to all the listeners. <p>
*
* If <i>event</i> is <b>null</b> or if the number of rows in dataVector
* is different from numRows, then it will assume all the data
* in dataVector is new or updated. It will recalculate numRows, and
* will generate the correct TableModelEvent to send out with the
* nofication.
*
* @parameter event This TableModelEvent describes where the
* change happened. If <b>null</b> it assumes
* all data is new or updated
*
* @see #getDataVector()
* @see #newRowsAdded()
* @see #rowsRemoved()
*/
public void newDataAvailable(TableModelEvent event) {
if ((event == null) || (dataVector.size() != numRows)) {
// Assume all changed
numRows = dataVector.size();
event = new TableModelEvent(this, TableModelEvent.HEADER_ROW);
// Because the new data rows might not have the correct number
// of columns we need to do this to make sure dataVector is not
// malformed.
this.setColumnIdentifiers(columnIdentifiers);
}
// Now we sent the notification
fireTableChanged(event);
}
/**
* This method will recalculate numRows, it will also make sure
* the new rows have the correct number of columns. Then it
* will send out the tableChanged() notification message
* to all the listeners.
*
* @parameter event This TableModelEvent describes where the
* rows were added. If <b>null</b> it assumes
* all the rows were newly added.
* @see #getDataVector()
*/
public void newRowsAdded(TableModelEvent event) {
numRows = dataVector.size();
int start = event.getFirstRow();
int end = event.getLastRow();
if (start < 0) start = 0;
if (end < 0) end = numRows-1;
// Have to make sure all the new columns have the correct
// number of columns
for (int i=start; i <= end; i++)
((Vector)dataVector.elementAt(i)).setSize(numColumns);
// Now we send the notification
fireTableChanged(event);
}
/**
* This method will recalculate numRows, then it
* will send out the tableRowsRemoved() notification message
* to all the listeners.
*
* @parameter event This TableModelEvent describes where the
* rows were removed.
* @exception IllegalArgumentException if event is null
* @see #getDataVector()
*/
public void rowsRemoved(TableModelEvent event) {
if (event == null)
throw new IllegalArgumentException("rowsRemoved() - null parameter");
numRows = dataVector.size();
// Now we send the notification
fireTableChanged(event);
}
/**
* Replaces the column identifiers in the model.
*
* @param newIdentifiers Vector of column identifiers. A null means
* setting the model to zero columns
* @see #setNumRows()
*/
public void setColumnIdentifiers(Vector newIdentifiers) {
if (newIdentifiers != null) {
columnIdentifiers = newIdentifiers;
numColumns = newIdentifiers.size();
}
else {
columnIdentifiers = new Vector();
numColumns = 0;
}
// Generate notification
fireTableStructureChanged();
}
/**
* Replaces the column identifiers in the model. If the number of
* <i>newIdentifiers</i> is greater than the current numColumns,
* new columns are added to the end of each row in the model.
* If the number of <i>newIdentifier</i> is less than the current
* number of columns, all the extra columns at the end of a row are
* discarded. <p>
*
* @param newIdentifiers Array of column identifiers. A null means
* setting the model to zero columns
* @see #setNumRows()
*/
public void setColumnIdentifiers(Object[] newIdentifiers) {
this.setColumnIdentifiers(DefaultTableModel.convertToVector(newIdentifiers));
}
/**
* Sets the number of rows in the model. If the new size is greater
* than the current size, new rows are added to the end of the model
* If the new size is less than the current size, all
* rows at index <i>newSize</i> and greater are discarded. <p>
*
* @param newSize the new number of rows
* @see #setColumnIdentifiers()
*/
public void setNumRows(int newSize) {
if ((newSize < 0) || (newSize == numRows))
return;
int oldNumRows = numRows;
if (newSize <= numRows) {
// newSize is smaller than our current size, so we can just
// let Vector discard the extra rows
numRows = newSize;
dataVector.setSize(numRows);
// Generate notification
rowsRemoved(new TableModelEvent(this, numRows, oldNumRows-1,
TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE));
}
else {
// We are adding rows to the model
while(numRows < newSize) {
Vector newRow = new Vector(numColumns);
dataVector.addElement(newRow);
numRows++;
}
// Generate notification
newRowsAdded(new TableModelEvent(this, oldNumRows, numRows-1,
TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
}
}
/**
* Add a column to the model. The new column will have the
* idenitifier <i>columnIdentifier</i>. This method will send a
* tableChanged() notification message to all the listeners.
* This method is a cover for <i>addColumn(Object, Vector)</i> which
* uses null as the data vector.
*
* @param columnIdentifier the identifier of the column being added
* @exception IllegalArgumentException if columnIdentifier is null
*/
public void addColumn(Object columnIdentifier) {
addColumn(columnIdentifier, (Vector)null);
}
/**
* Add a column to the model. The new column will have the
* idenitifier <i>columnIdentifier</i>. <i>columnData</i> is the
* optional Vector of data for the column. If it is <b>null</b>
* the column is filled with <b>null</b> values. Otherwise,
* the new data will be added to model starting with the first
* element going to row 0, etc. This method will send a
* tableChanged() notification message to all the listeners.
*
* @param columnIdentifier the identifier of the column being added
* @param columnData optional data of the column being added
* @exception IllegalArgumentException if columnIdentifier is null
*/
public void addColumn(Object columnIdentifier, Vector columnData) {
if (columnIdentifier == null)
throw new IllegalArgumentException("addColumn() - null parameter");
columnIdentifiers.addElement(columnIdentifier);
numColumns++;
// Fill in the new column, with nulls or with columnData
int index = 0;
Enumeration enumeration = dataVector.elements();
while (enumeration.hasMoreElements()) {
Object value;
if ((columnData != null) && (index < columnData.size()))
value = columnData.elementAt(index);
else
value = null;
((Vector)enumeration.nextElement()).addElement(value);
index++;
}
// Generate notification
fireTableChanged(null);
}
/**
* Add a column to the model. The new column will have the
* idenitifier <i>columnIdentifier</i>. <i>columnData</i> is the
* optional array of data for the column. If it is <b>null</b>
* the column is filled with <b>null</b> values. Otherwise,
* the new data will be added to model starting with the first
* element going to row 0, etc. This method will send a
* tableChanged() notification message to all the listeners.
*
* @param columnIdentifier the identifier of the column being added
* @param columnData optional data of the column being added
* @exception IllegalArgumentException if columnIdentifier is null
*/
public void addColumn(Object columnIdentifier, Object[] columnData) {
if (columnIdentifier == null)
throw new IllegalArgumentException("addColumn() - null parameter");
columnIdentifiers.addElement(columnIdentifier);
numColumns++;
// Fill in the new column, with nulls or with columnData
int index = 0;
Enumeration enumeration = dataVector.elements();
while (enumeration.hasMoreElements()) {
Object value;
if ((columnData != null) && (index < columnData.length))
value = columnData[index];
else
value = null;
((Vector)enumeration.nextElement()).addElement(value);
index++;
}
// Generate notification
fireTableChanged(null);
}
/**
* Add a row to the end of the model. The new row will contain
* <b>null</b> values unless <i>rowData</i> is specified. Notification
* of the row being added will be generated.
*
* @param rowData optional data of the row being added
*/
public void addRow(Vector rowData) {
Vector newRow = rowData;
if (newRow == null)
newRow = new Vector(numColumns);
dataVector.addElement(rowData);
numRows++;
// Generate notification
newRowsAdded(new TableModelEvent(this, numRows-1, numRows-1,
TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
}
/**
* Add a row to the end of the model. The new row will contain
* <b>null</b> values unless <i>rowData</i> is specified. Notification
* of the row being added will be generated.
*
* @param rowData optional data of the row being added
*/
public void addRow(Object[] rowData) {
Vector newVector = null;
if (rowData != null)
newVector = DefaultTableModel.convertToVector(rowData);
this.addRow(newVector);
}
/**
* Insert a row at <i>row</i> in the model. The new row will contain
* <b>null</b> values unless <i>rowData</i> is specified. Notification
* of the row being added will be generated.
*
* @param row the row index of the row to be inserted
* @param rowData optional data of the row being added
* @exception ArrayIndexOutOfBoundsException if the row was invalid.
*/
public void insertRow(int row, Vector rowData) {
Vector newRow = rowData;
if (newRow == null)
newRow = new Vector(numColumns);
newRow.setSize(numColumns);
dataVector.insertElementAt(newRow, row);
numRows++;
// Generate notification
newRowsAdded(new TableModelEvent(this, row, numRows-1,
TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
}
/**
* Insert a row at <i>row</i> in the model. The new row will contain
* <b>null</b> values unless <i>rowData</i> is specified. Notification
* of the row being added will be generated.
*
* @param row the row index of the row to be inserted
* @param rowData optional data of the row being added
* @exception ArrayIndexOutOfBoundsException if the row was invalid.
*/
public void insertRow(int row, Object[] rowData) {
Vector newVector = null;
if (rowData != null)
newVector = DefaultTableModel.convertToVector(rowData);
this.insertRow(row, newVector);
}
/**
* Moves one or more rows starting at <i>startIndex</i> to <i>endIndex</i>
* in the model to the <i>toIndex</i>. This method will send a
* tableChanged() notification message to all the listeners. <p>
*
* Examples of moves:<p>
* 1. moveRow(1,3,5);<p>
* a|B|C|D|e|f|g|h|i|j|k - before
* a|e|f|B|C|D|g|h|i|j|k - after
* 2. moveRow(6,7,1);<p>
* a|b|c|d|e|f|G|H|i|j|k - before
* a|G|H|b|c|d|e|f|i|j|k - after
*
* @param startIndex the starting row index to be moved
* @param endIndex the ending row index to be moved
* @param toIndex the destination of the rows to be moved
* @exception ArrayIndexOutOfBoundsException if any of the indices are out of
* range. Or if endIndex is less than startIndex.
*/
public void moveRow(int startIndex, int endIndex, int toIndex) {
if ((startIndex < 0) || (startIndex >= numColumns))
throw new ArrayIndexOutOfBoundsException(startIndex);
if ((endIndex < 0) || (endIndex >= numColumns))
throw new ArrayIndexOutOfBoundsException(endIndex);
if (startIndex < endIndex)
throw new ArrayIndexOutOfBoundsException();
if ((startIndex <= toIndex) && (toIndex <= endIndex))
return; // Nothing to move
boolean shift = toIndex < startIndex;
// Generate the proper event
TableModelEvent event = null;
if (shift) {
event = new TableModelEvent(this, toIndex, endIndex);
} else {
event = new TableModelEvent(this, startIndex, toIndex);
}
// Do the move by first removing the row, then reinserting it
for (int i = startIndex; i <= endIndex; i++) {
Object aRow = dataVector.elementAt(i);
dataVector.removeElementAt(i);
dataVector.insertElementAt(aRow, toIndex);
if (shift)
toIndex++;
}
// Generate notification
fireTableChanged(event);
}
/**
* Remove the row at <i>row</i> from the model. Notification
* of the row being removed, rowsRemoved(), will be sent to all
* the listeners.
*
* @param row the row index of the row to be removed
* @exception ArrayIndexOutOfBoundsException if the row was invalid.
*/
public void removeRow(int row) {
dataVector.removeElementAt(row);
numRows--;
// Generate notification
rowsRemoved(new TableModelEvent(this, row, numRows-1,
TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE));
}
//
// Implementing the TableModel interface
//
/**
* @return the number of rows in the model.
*/
public int getRowCount() {
return numRows;
}
/**
* @return the number of columns in the model.
*/
public int getColumnCount() {
return numColumns;
}
/**
* @return a name for this column using the string value of the
* appropriate member in <I>columnIdentfiers</I>. If <I>columnIdentfiers</I>
* is null or does not have and entry for this index return the default
* name provided by the superclass.
*/
public String getColumnName(int column) {
if (columnIdentifiers == null || columnIdentifiers.size() <= column) {
return super.getColumnName(column);
}
Object id = columnIdentifiers.elementAt(column);
if (id == null) {
return super.getColumnName(column);
}
else {
return id.toString();
}
}
/**
* Returns true if the cell at <I>row</I> and <I>column</I>
* is editable. Otherwise, the setValueAt() on the cell will not change
* the value of that cell.
*
* @param row the row whose value is to be looked up
* @param column the column whose value is to be looked up
* @return true if the cell is editable.
* @see #setValueAt()
*/
public boolean isCellEditable(int row, int column) {
return true;
}
/**
* Returns an attribute value for the cell at <I>row</I>
* and <I>column</I>.
*
* @param row the row whose value is to be looked up
* @param column the column whose value is to be looked up
* @return the value Object at the specified cell
* @exception ArrayIndexOutOfBoundsException if an invalid row or
* column was given.
*/
public Object getValueAt(int row, int column) {
Vector rowVector = (Vector)dataVector.elementAt(row);
return rowVector.elementAt(column);
}
/**
* Sets the object value for the cell at <I>column</I> and
* <I>row</I>. <I>aValue</I> is the new value. This method
* will generate a tableChanged() notification.
*
* @param aValue the new value. This can be null.
* @param row the row whose value is to be changed
* @param column the column whose value is to be changed
* @exception ArrayIndexOutOfBoundsException if an invalid row or
* column was given.
*/
public void setValueAt(Object aValue, int row, int column) {
Vector rowVector = (Vector)dataVector.elementAt(row);
rowVector.setElementAt(aValue, column);
// generate notification
fireTableChanged(new TableModelEvent(this, row, row, column));
}
//
// Protected Methods
//
/** Returns a Vector that contains the same objects as the array */
protected static Vector convertToVector(Object[] anArray) {
if (anArray == null)
return new Vector();
Vector v = new Vector(anArray.length);
for (int i=0; i < anArray.length; i++) {
v.addElement(anArray[i]);
}
return v;
}
/** Returns a Vector of Vectors that contains the same objects as the array */
protected static Vector convertToVector(Object[][] anArray) {
if (anArray == null)
return new Vector();
Vector v = new Vector(anArray.length);
for (int i=0; i < anArray.length; i++) {
v.addElement(DefaultTableModel.convertToVector(anArray[i]));
}
return v;
}
} // End of class DefaultTableModel