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