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