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