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