1. /*
  2. * @(#)DefaultTableModel.java 1.36 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.table;
  8. import java.io.Serializable;
  9. import java.util.Vector;
  10. import java.util.Enumeration;
  11. import javax.swing.event.TableModelEvent;
  12. /**
  13. * This is an implementation of <code>TableModel</code> that
  14. * uses a <code>Vector</code> of <code>Vectors</code> to store the
  15. * cell value objects.
  16. * <p>
  17. * <strong>Warning:</strong>
  18. * Serialized objects of this class will not be compatible with
  19. * future Swing releases. The current serialization support is
  20. * appropriate for short term storage or RMI between applications running
  21. * the same version of Swing. As of 1.4, support for long term storage
  22. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  23. * has been added to the <code>java.beans</code> package.
  24. * Please see {@link java.beans.XMLEncoder}.
  25. *
  26. * @version 1.36 01/23/03
  27. * @author Philip Milne
  28. *
  29. * @see TableModel
  30. * @see #getDataVector
  31. */
  32. public class DefaultTableModel extends AbstractTableModel implements Serializable {
  33. //
  34. // Instance Variables
  35. //
  36. /**
  37. * The <code>Vector</code> of <code>Vectors</code> of
  38. * <code>Object</code> values.
  39. */
  40. protected Vector dataVector;
  41. /** The <code>Vector</code> of column identifiers. */
  42. protected Vector columnIdentifiers;
  43. //
  44. // Constructors
  45. //
  46. /**
  47. * Constructs a default <code>DefaultTableModel</code>
  48. * which is a table of zero columns and zero rows.
  49. */
  50. public DefaultTableModel() {
  51. this(0, 0);
  52. }
  53. private static Vector newVector(int size) {
  54. Vector v = new Vector(size);
  55. v.setSize(size);
  56. return v;
  57. }
  58. /**
  59. * Constructs a <code>DefaultTableModel</code> with
  60. * <code>rowCount</code> and <code>columnCount</code> of
  61. * <code>null</code> object values.
  62. *
  63. * @param rowCount the number of rows the table holds
  64. * @param columnCount the number of columns the table holds
  65. *
  66. * @see #setValueAt
  67. */
  68. public DefaultTableModel(int rowCount, int columnCount) {
  69. this(newVector(columnCount), rowCount);
  70. }
  71. /**
  72. * Constructs a <code>DefaultTableModel</code> with as many columns
  73. * as there are elements in <code>columnNames</code>
  74. * and <code>rowCount</code> of <code>null</code>
  75. * object values. Each column's name will be taken from
  76. * the <code>columnNames</code> vector.
  77. *
  78. * @param columnNames <code>vector</code> containing the names
  79. * of the new columns; if this is
  80. * <code>null</code> then the model has no columns
  81. * @param rowCount the number of rows the table holds
  82. * @see #setDataVector
  83. * @see #setValueAt
  84. */
  85. public DefaultTableModel(Vector columnNames, int rowCount) {
  86. setDataVector(newVector(rowCount), columnNames);
  87. }
  88. /**
  89. * Constructs a <code>DefaultTableModel</code> with as many
  90. * columns as there are elements in <code>columnNames</code>
  91. * and <code>rowCount</code> of <code>null</code>
  92. * object values. Each column's name will be taken from
  93. * the <code>columnNames</code> array.
  94. *
  95. * @param columnNames <code>array</code> containing the names
  96. * of the new columns; if this is
  97. * <code>null</code> then the model has no columns
  98. * @param rowCount the number of rows the table holds
  99. * @see #setDataVector
  100. * @see #setValueAt
  101. */
  102. public DefaultTableModel(Object[] columnNames, int rowCount) {
  103. this(convertToVector(columnNames), rowCount);
  104. }
  105. /**
  106. * Constructs a <code>DefaultTableModel</code> and initializes the table
  107. * by passing <code>data</code> and <code>columnNames</code>
  108. * to the <code>setDataVector</code> method.
  109. *
  110. * @param data the data of the table
  111. * @param columnNames <code>vector</code> containing the names
  112. * of the new columns
  113. * @see #getDataVector
  114. * @see #setDataVector
  115. */
  116. public DefaultTableModel(Vector data, Vector columnNames) {
  117. setDataVector(data, columnNames);
  118. }
  119. /**
  120. * Constructs a <code>DefaultTableModel</code> and initializes the table
  121. * by passing <code>data</code> and <code>columnNames</code>
  122. * to the <code>setDataVector</code>
  123. * method. The first index in the <code>Object[][]</code> array is
  124. * the row index and the second is the column index.
  125. *
  126. * @param data the data of the table
  127. * @param columnNames the names of the columns
  128. * @see #getDataVector
  129. * @see #setDataVector
  130. */
  131. public DefaultTableModel(Object[][] data, Object[] columnNames) {
  132. setDataVector(data, columnNames);
  133. }
  134. /**
  135. * Returns the <code>Vector</code> of <code>Vectors</code>
  136. * that contains the table's
  137. * data values. The vectors contained in the outer vector are
  138. * each a single row of values. In other words, to get to the cell
  139. * at row 1, column 5: <p>
  140. *
  141. * <code>((Vector)getDataVector().elementAt(1)).elementAt(5);</code><p>
  142. *
  143. * @return the vector of vectors containing the tables data values
  144. *
  145. * @see #newDataAvailable
  146. * @see #newRowsAdded
  147. * @see #setDataVector
  148. */
  149. public Vector getDataVector() {
  150. return dataVector;
  151. }
  152. private static Vector nonNullVector(Vector v) {
  153. return (v != null) ? v : new Vector();
  154. }
  155. /**
  156. * Replaces the current <code>dataVector</code> instance variable
  157. * with the new Vector of rows, <code>dataVector</code>.
  158. * <code>columnIdentifiers</code> are the names of the new
  159. * columns. The first name in <code>columnIdentifiers</code> is
  160. * mapped to column 0 in <code>dataVector</code>. Each row in
  161. * <code>dataVector</code> is adjusted to match the number of
  162. * columns in <code>columnIdentifiers</code>
  163. * either by truncating the <code>Vector</code> if it is too long,
  164. * or adding <code>null</code> values if it is too short.
  165. * <p>Note that passing in a <code>null</code> value for
  166. * <code>dataVector</code> results in unspecified behavior,
  167. * an possibly an exception.
  168. *
  169. * @param dataVector the new data vector
  170. * @param columnIdentifiers the names of the columns
  171. * @see #getDataVector
  172. */
  173. public void setDataVector(Vector dataVector, Vector columnIdentifiers) {
  174. this.dataVector = nonNullVector(dataVector);
  175. this.columnIdentifiers = nonNullVector(columnIdentifiers);
  176. justifyRows(0, getRowCount());
  177. fireTableStructureChanged();
  178. }
  179. /**
  180. * Replaces the value in the <code>dataVector</code> instance
  181. * variable with the values in the array <code>dataVector</code>.
  182. * The first index in the <code>Object[][]</code>
  183. * array is the row index and the second is the column index.
  184. * <code>columnIdentifiers</code> are the names of the new columns.
  185. *
  186. * @param dataVector the new data vector
  187. * @param columnIdentifiers the names of the columns
  188. * @see #setDataVector(Vector, Vector)
  189. */
  190. public void setDataVector(Object[][] dataVector, Object[] columnIdentifiers) {
  191. setDataVector(convertToVector(dataVector), convertToVector(columnIdentifiers));
  192. }
  193. /**
  194. * Equivalent to <code>fireTableChanged</code>.
  195. *
  196. * @param event the change event
  197. *
  198. */
  199. public void newDataAvailable(TableModelEvent event) {
  200. fireTableChanged(event);
  201. }
  202. //
  203. // Manipulating rows
  204. //
  205. private void justifyRows(int from, int to) {
  206. // Sometimes the DefaultTableModel is subclassed
  207. // instead of the AbstractTableModel by mistake.
  208. // Set the number of rows for the case when getRowCount
  209. // is overridden.
  210. dataVector.setSize(getRowCount());
  211. for (int i = from; i < to; i++) {
  212. if (dataVector.elementAt(i) == null) {
  213. dataVector.setElementAt(new Vector(), i);
  214. }
  215. ((Vector)dataVector.elementAt(i)).setSize(getColumnCount());
  216. }
  217. }
  218. /**
  219. * Ensures that the new rows have the correct number of columns.
  220. * This is accomplished by using the <code>setSize</code> method in
  221. * <code>Vector</code> which truncates vectors
  222. * which are too long, and appends <code>null</code>s if they
  223. * are too short.
  224. * This method also sends out a <code>tableChanged</code>
  225. * notification message to all the listeners.
  226. *
  227. * @param e this <code>TableModelEvent</code> describes
  228. * where the rows were added.
  229. * If <code>null</code> it assumes
  230. * all the rows were newly added
  231. * @see #getDataVector
  232. */
  233. public void newRowsAdded(TableModelEvent e) {
  234. justifyRows(e.getFirstRow(), e.getLastRow() + 1);
  235. fireTableChanged(e);
  236. }
  237. /**
  238. * Equivalent to <code>fireTableChanged</code>.
  239. *
  240. * @param event the change event
  241. *
  242. */
  243. public void rowsRemoved(TableModelEvent event) {
  244. fireTableChanged(event);
  245. }
  246. /**
  247. * Obsolete as of Java 2 platform v1.3. Please use <code>setRowCount</code> instead.
  248. */
  249. /*
  250. * Sets the number of rows in the model. If the new size is greater
  251. * than the current size, new rows are added to the end of the model
  252. * If the new size is less than the current size, all
  253. * rows at index <code>rowCount</code> and greater are discarded. <p>
  254. *
  255. * @param rowCount the new number of rows
  256. * @see #setRowCount
  257. */
  258. public void setNumRows(int rowCount) {
  259. int old = getRowCount();
  260. if (old == rowCount) {
  261. return;
  262. }
  263. dataVector.setSize(rowCount);
  264. if (rowCount <= old) {
  265. fireTableRowsDeleted(rowCount, old-1);
  266. }
  267. else {
  268. justifyRows(old, rowCount);
  269. fireTableRowsInserted(old, rowCount-1);
  270. }
  271. }
  272. /**
  273. * Sets the number of rows in the model. If the new size is greater
  274. * than the current size, new rows are added to the end of the model
  275. * If the new size is less than the current size, all
  276. * rows at index <code>rowCount</code> and greater are discarded. <p>
  277. *
  278. * @see #setColumnCount
  279. */
  280. public void setRowCount(int rowCount) {
  281. setNumRows(rowCount);
  282. }
  283. /**
  284. * Adds a row to the end of the model. The new row will contain
  285. * <code>null</code> values unless <code>rowData</code> is specified.
  286. * Notification of the row being added will be generated.
  287. *
  288. * @param rowData optional data of the row being added
  289. */
  290. public void addRow(Vector rowData) {
  291. insertRow(getRowCount(), rowData);
  292. }
  293. /**
  294. * Adds a row to the end of the model. The new row will contain
  295. * <code>null</code> values unless <code>rowData</code> is specified.
  296. * Notification of the row being added will be generated.
  297. *
  298. * @param rowData optional data of the row being added
  299. */
  300. public void addRow(Object[] rowData) {
  301. addRow(convertToVector(rowData));
  302. }
  303. /**
  304. * Inserts a row at <code>row</code> in the model. The new row
  305. * will contain <code>null</code> values unless <code>rowData</code>
  306. * is specified. Notification of the row being added will be generated.
  307. *
  308. * @param row the row index of the row to be inserted
  309. * @param rowData optional data of the row being added
  310. * @exception ArrayIndexOutOfBoundsException if the row was invalid
  311. */
  312. public void insertRow(int row, Vector rowData) {
  313. dataVector.insertElementAt(rowData, row);
  314. justifyRows(row, row+1);
  315. fireTableRowsInserted(row, row);
  316. }
  317. /**
  318. * Inserts a row at <code>row</code> in the model. The new row
  319. * will contain <code>null</code> values unless <code>rowData</code>
  320. * is specified. Notification of the row being added will be generated.
  321. *
  322. * @param row the row index of the row to be inserted
  323. * @param rowData optional data of the row being added
  324. * @exception ArrayIndexOutOfBoundsException if the row was invalid
  325. */
  326. public void insertRow(int row, Object[] rowData) {
  327. insertRow(row, convertToVector(rowData));
  328. }
  329. private static int gcd(int i, int j) {
  330. return (j == 0) ? i : gcd(j, i%j);
  331. }
  332. private static void rotate(Vector v, int a, int b, int shift) {
  333. int size = b - a;
  334. int r = size - shift;
  335. int g = gcd(size, r);
  336. for(int i = 0; i < g; i++) {
  337. int to = i;
  338. Object tmp = v.elementAt(a + to);
  339. for(int from = (to + r) % size; from != i; from = (to + r) % size) {
  340. v.setElementAt(v.elementAt(a + from), a + to);
  341. to = from;
  342. }
  343. v.setElementAt(tmp, a + to);
  344. }
  345. }
  346. /**
  347. * Moves one or more rows from the inlcusive range <code>start</code> to
  348. * <code>end</code> to the <code>to</code> position in the model.
  349. * After the move, the row that was at index <code>start</code>
  350. * will be at index <code>to</code>.
  351. * This method will send a <code>tableChanged</code> notification
  352. * message to all the listeners. <p>
  353. *
  354. * <pre>
  355. * Examples of moves:
  356. * <p>
  357. * 1. moveRow(1,3,5);
  358. * a|B|C|D|e|f|g|h|i|j|k - before
  359. * a|e|f|g|h|B|C|D|i|j|k - after
  360. * <p>
  361. * 2. moveRow(6,7,1);
  362. * a|b|c|d|e|f|G|H|i|j|k - before
  363. * a|G|H|b|c|d|e|f|i|j|k - after
  364. * <p>
  365. * </pre>
  366. *
  367. * @param start the starting row index to be moved
  368. * @param end the ending row index to be moved
  369. * @param to the destination of the rows to be moved
  370. * @exception ArrayIndexOutOfBoundsException if any of the elements
  371. * would be moved out of the table's range
  372. *
  373. */
  374. public void moveRow(int start, int end, int to) {
  375. int shift = to - start;
  376. int first, last;
  377. if (shift < 0) {
  378. first = to;
  379. last = end;
  380. }
  381. else {
  382. first = start;
  383. last = to + end - start;
  384. }
  385. rotate(dataVector, first, last + 1, shift);
  386. fireTableRowsUpdated(first, last);
  387. }
  388. /**
  389. * Removes the row at <code>row</code> from the model. Notification
  390. * of the row being removed will be sent to all the listeners.
  391. *
  392. * @param row the row index of the row to be removed
  393. * @exception ArrayIndexOutOfBoundsException if the row was invalid
  394. */
  395. public void removeRow(int row) {
  396. dataVector.removeElementAt(row);
  397. fireTableRowsDeleted(row, row);
  398. }
  399. //
  400. // Manipulating columns
  401. //
  402. /**
  403. * Replaces the column identifiers in the model. If the number of
  404. * <code>newIdentifier</code>s is greater than the current number
  405. * of columns, new columns are added to the end of each row in the model.
  406. * If the number of <code>newIdentifier</code>s is less than the current
  407. * number of columns, all the extra columns at the end of a row are
  408. * discarded. <p>
  409. *
  410. * @param columnIdentifiers vector of column identifiers. If
  411. * <code>null</code>, set the model
  412. * to zero columns
  413. * @see #setNumRows
  414. */
  415. public void setColumnIdentifiers(Vector columnIdentifiers) {
  416. setDataVector(dataVector, columnIdentifiers);
  417. }
  418. /**
  419. * Replaces the column identifiers in the model. If the number of
  420. * <code>newIdentifier</code>s is greater than the current number
  421. * of columns, new columns are added to the end of each row in the model.
  422. * If the number of <code>newIdentifier</code>s is less than the current
  423. * number of columns, all the extra columns at the end of a row are
  424. * discarded. <p>
  425. *
  426. * @param newIdentifiers array of column identifiers.
  427. * If <code>null</code>, set
  428. * the model to zero columns
  429. * @see #setNumRows
  430. */
  431. public void setColumnIdentifiers(Object[] newIdentifiers) {
  432. setColumnIdentifiers(convertToVector(newIdentifiers));
  433. }
  434. /**
  435. * Sets the number of columns in the model. If the new size is greater
  436. * than the current size, new columns are added to the end of the model
  437. * with <code>null</code> cell values.
  438. * If the new size is less than the current size, all columns at index
  439. * <code>columnCount</code> and greater are discarded.
  440. *
  441. * @param columnCount the new number of columns in the model
  442. *
  443. * @see #setColumnCount
  444. */
  445. public void setColumnCount(int columnCount) {
  446. columnIdentifiers.setSize(columnCount);
  447. justifyRows(0, getRowCount());
  448. fireTableStructureChanged();
  449. }
  450. /**
  451. * Adds a column to the model. The new column will have the
  452. * identifier <code>columnName</code>, which may be null. This method
  453. * will send a
  454. * <code>tableChanged</code> notification message to all the listeners.
  455. * This method is a cover for <code>addColumn(Object, Vector)</code> which
  456. * uses <code>null</code> as the data vector.
  457. *
  458. * @param columnName the identifier of the column being added
  459. */
  460. public void addColumn(Object columnName) {
  461. addColumn(columnName, (Vector)null);
  462. }
  463. /**
  464. * Adds a column to the model. The new column will have the
  465. * identifier <code>columnName</code>, which may be null.
  466. * <code>columnData</code> is the
  467. * optional vector of data for the column. If it is <code>null</code>
  468. * the column is filled with <code>null</code> values. Otherwise,
  469. * the new data will be added to model starting with the first
  470. * element going to row 0, etc. This method will send a
  471. * <code>tableChanged</code> notification message to all the listeners.
  472. *
  473. * @param columnName the identifier of the column being added
  474. * @param columnData optional data of the column being added
  475. */
  476. public void addColumn(Object columnName, Vector columnData) {
  477. columnIdentifiers.addElement(columnName);
  478. if (columnData != null) {
  479. int columnSize = columnData.size();
  480. if (columnSize > getRowCount()) {
  481. dataVector.setSize(columnSize);
  482. }
  483. justifyRows(0, getRowCount());
  484. int newColumn = getColumnCount() - 1;
  485. for(int i = 0; i < columnSize; i++) {
  486. Vector row = (Vector)dataVector.elementAt(i);
  487. row.setElementAt(columnData.elementAt(i), newColumn);
  488. }
  489. }
  490. else {
  491. justifyRows(0, getRowCount());
  492. }
  493. fireTableStructureChanged();
  494. }
  495. /**
  496. * Adds a column to the model. The new column will have the
  497. * identifier <code>columnName</code>. <code>columnData</code> is the
  498. * optional array of data for the column. If it is <code>null</code>
  499. * the column is filled with <code>null</code> values. Otherwise,
  500. * the new data will be added to model starting with the first
  501. * element going to row 0, etc. This method will send a
  502. * <code>tableChanged</code> notification message to all the listeners.
  503. *
  504. * @see #addColumn(Object, Vector)
  505. */
  506. public void addColumn(Object columnName, Object[] columnData) {
  507. addColumn(columnName, convertToVector(columnData));
  508. }
  509. //
  510. // Implementing the TableModel interface
  511. //
  512. /**
  513. * Returns the number of rows in this data table.
  514. * @return the number of rows in the model
  515. */
  516. public int getRowCount() {
  517. return dataVector.size();
  518. }
  519. /**
  520. * Returns the number of columns in this data table.
  521. * @return the number of columns in the model
  522. */
  523. public int getColumnCount() {
  524. return columnIdentifiers.size();
  525. }
  526. /**
  527. * Returns the column name.
  528. *
  529. * @return a name for this column using the string value of the
  530. * appropriate member in <code>columnIdentifiers</code>.
  531. * If <code>columnIdentifiers</code> does not have an entry
  532. * for this index, returns the default
  533. * name provided by the superclass
  534. */
  535. public String getColumnName(int column) {
  536. Object id = null;
  537. // This test is to cover the case when
  538. // getColumnCount has been subclassed by mistake ...
  539. if (column < columnIdentifiers.size()) {
  540. id = columnIdentifiers.elementAt(column);
  541. }
  542. return (id == null) ? super.getColumnName(column)
  543. : id.toString();
  544. }
  545. /**
  546. * Returns true regardless of parameter values.
  547. *
  548. * @param row the row whose value is to be queried
  549. * @param column the column whose value is to be queried
  550. * @return true
  551. * @see #setValueAt
  552. */
  553. public boolean isCellEditable(int row, int column) {
  554. return true;
  555. }
  556. /**
  557. * Returns an attribute value for the cell at <code>row</code>
  558. * and <code>column</code>.
  559. *
  560. * @param row the row whose value is to be queried
  561. * @param column the column whose value is to be queried
  562. * @return the value Object at the specified cell
  563. * @exception ArrayIndexOutOfBoundsException if an invalid row or
  564. * column was given
  565. */
  566. public Object getValueAt(int row, int column) {
  567. Vector rowVector = (Vector)dataVector.elementAt(row);
  568. return rowVector.elementAt(column);
  569. }
  570. /**
  571. * Sets the object value for the cell at <code>column</code> and
  572. * <code>row</code>. <code>aValue</code> is the new value. This method
  573. * will generate a <code>tableChanged</code> notification.
  574. *
  575. * @param aValue the new value; this can be null
  576. * @param row the row whose value is to be changed
  577. * @param column the column whose value is to be changed
  578. * @exception ArrayIndexOutOfBoundsException if an invalid row or
  579. * column was given
  580. */
  581. public void setValueAt(Object aValue, int row, int column) {
  582. Vector rowVector = (Vector)dataVector.elementAt(row);
  583. rowVector.setElementAt(aValue, column);
  584. fireTableCellUpdated(row, column);
  585. }
  586. //
  587. // Protected Methods
  588. //
  589. /**
  590. * Returns a vector that contains the same objects as the array.
  591. * @param anArray the array to be converted
  592. * @return the new vector; if <code>anArray</code> is <code>null</code>,
  593. * returns <code>null</code>
  594. */
  595. protected static Vector convertToVector(Object[] anArray) {
  596. if (anArray == null) {
  597. return null;
  598. }
  599. Vector v = new Vector(anArray.length);
  600. for (int i=0; i < anArray.length; i++) {
  601. v.addElement(anArray[i]);
  602. }
  603. return v;
  604. }
  605. /**
  606. * Returns a vector of vectors that contains the same objects as the array.
  607. * @param anArray the double array to be converted
  608. * @return the new vector of vectors; if <code>anArray</code> is
  609. * <code>null</code>, returns <code>null</code>
  610. */
  611. protected static Vector convertToVector(Object[][] anArray) {
  612. if (anArray == null) {
  613. return null;
  614. }
  615. Vector v = new Vector(anArray.length);
  616. for (int i=0; i < anArray.length; i++) {
  617. v.addElement(convertToVector(anArray[i]));
  618. }
  619. return v;
  620. }
  621. } // End of class DefaultTableModel