1 /*
   2  * Copyright (c) 1997, 2004, 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 javax.swing.*;
  29 import javax.swing.event.*;
  30 import java.io.Serializable;
  31 import java.util.EventListener;
  32 
  33 /**
  34  *  This abstract class provides default implementations for most of
  35  *  the methods in the <code>TableModel</code> interface. It takes care of
  36  *  the management of listeners and provides some conveniences for generating
  37  *  <code>TableModelEvents</code> and dispatching them to the listeners.
  38  *  To create a concrete <code>TableModel</code> as a subclass of
  39  *  <code>AbstractTableModel</code> you need only provide implementations
  40  *  for the following three methods:
  41  *
  42  *  <pre>
  43  *  public int getRowCount();
  44  *  public int getColumnCount();
  45  *  public Object getValueAt(int row, int column);
  46  *  </pre>
  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<sup><font size="-2">TM</font></sup>
  54  * has been added to the <code>java.beans</code> package.
  55  * Please see {@link java.beans.XMLEncoder}.
  56  *
  57  * @author Alan Chung
  58  * @author Philip Milne
  59  */
  60 public abstract class AbstractTableModel implements TableModel, Serializable
  61 {
  62 //
  63 // Instance Variables
  64 //
  65 
  66     /** List of listeners */
  67     protected EventListenerList listenerList = new EventListenerList();
  68 
  69 //
  70 // Default Implementation of the Interface
  71 //
  72 
  73     /**
  74      *  Returns a default name for the column using spreadsheet conventions:
  75      *  A, B, C, ... Z, AA, AB, etc.  If <code>column</code> cannot be found,
  76      *  returns an empty string.
  77      *
  78      * @param column  the column being queried
  79      * @return a string containing the default name of <code>column</code>
  80      */
  81     public String getColumnName(int column) {
  82         String result = "";
  83         for (; column >= 0; column = column / 26 - 1) {
  84             result = (char)((char)(column%26)+'A') + result;
  85         }
  86         return result;
  87     }
  88 
  89     /**
  90      * Returns a column given its name.
  91      * Implementation is naive so this should be overridden if
  92      * this method is to be called often. This method is not
  93      * in the <code>TableModel</code> interface and is not used by the
  94      * <code>JTable</code>.
  95      *
  96      * @param columnName string containing name of column to be located
  97      * @return the column with <code>columnName</code>, or -1 if not found
  98      */
  99     public int findColumn(String columnName) {
 100         for (int i = 0; i < getColumnCount(); i++) {
 101             if (columnName.equals(getColumnName(i))) {
 102                 return i;
 103             }
 104         }
 105         return -1;
 106     }
 107 
 108     /**
 109      *  Returns <code>Object.class</code> regardless of <code>columnIndex</code>.
 110      *
 111      *  @param columnIndex  the column being queried
 112      *  @return the Object.class
 113      */
 114     public Class<?> getColumnClass(int columnIndex) {
 115         return Object.class;
 116     }
 117 
 118     /**
 119      *  Returns false.  This is the default implementation for all cells.
 120      *
 121      *  @param  rowIndex  the row being queried
 122      *  @param  columnIndex the column being queried
 123      *  @return false
 124      */
 125     public boolean isCellEditable(int rowIndex, int columnIndex) {
 126         return false;
 127     }
 128 
 129     /**
 130      *  This empty implementation is provided so users don't have to implement
 131      *  this method if their data model is not editable.
 132      *
 133      *  @param  aValue   value to assign to cell
 134      *  @param  rowIndex   row of cell
 135      *  @param  columnIndex  column of cell
 136      */
 137     public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
 138     }
 139 
 140 
 141 //
 142 //  Managing Listeners
 143 //
 144 
 145     /**
 146      * Adds a listener to the list that's notified each time a change
 147      * to the data model occurs.
 148      *
 149      * @param   l               the TableModelListener
 150      */
 151     public void addTableModelListener(TableModelListener l) {
 152         listenerList.add(TableModelListener.class, l);
 153     }
 154 
 155     /**
 156      * Removes a listener from the list that's notified each time a
 157      * change to the data model occurs.
 158      *
 159      * @param   l               the TableModelListener
 160      */
 161     public void removeTableModelListener(TableModelListener l) {
 162         listenerList.remove(TableModelListener.class, l);
 163     }
 164 
 165     /**
 166      * Returns an array of all the table model listeners
 167      * registered on this model.
 168      *
 169      * @return all of this model's <code>TableModelListener</code>s
 170      *         or an empty
 171      *         array if no table model listeners are currently registered
 172      *
 173      * @see #addTableModelListener
 174      * @see #removeTableModelListener
 175      *
 176      * @since 1.4
 177      */
 178     public TableModelListener[] getTableModelListeners() {
 179         return (TableModelListener[])listenerList.getListeners(
 180                 TableModelListener.class);
 181     }
 182 
 183 //
 184 //  Fire methods
 185 //
 186 
 187     /**
 188      * Notifies all listeners that all cell values in the table's
 189      * rows may have changed. The number of rows may also have changed
 190      * and the <code>JTable</code> should redraw the
 191      * table from scratch. The structure of the table (as in the order of the
 192      * columns) is assumed to be the same.
 193      *
 194      * @see TableModelEvent
 195      * @see EventListenerList
 196      * @see javax.swing.JTable#tableChanged(TableModelEvent)
 197      */
 198     public void fireTableDataChanged() {
 199         fireTableChanged(new TableModelEvent(this));
 200     }
 201 
 202     /**
 203      * Notifies all listeners that the table's structure has changed.
 204      * The number of columns in the table, and the names and types of
 205      * the new columns may be different from the previous state.
 206      * If the <code>JTable</code> receives this event and its
 207      * <code>autoCreateColumnsFromModel</code>
 208      * flag is set it discards any table columns that it had and reallocates
 209      * default columns in the order they appear in the model. This is the
 210      * same as calling <code>setModel(TableModel)</code> on the
 211      * <code>JTable</code>.
 212      *
 213      * @see TableModelEvent
 214      * @see EventListenerList
 215      */
 216     public void fireTableStructureChanged() {
 217         fireTableChanged(new TableModelEvent(this, TableModelEvent.HEADER_ROW));
 218     }
 219 
 220     /**
 221      * Notifies all listeners that rows in the range
 222      * <code>[firstRow, lastRow]</code>, inclusive, have been inserted.
 223      *
 224      * @param  firstRow  the first row
 225      * @param  lastRow   the last row
 226      *
 227      * @see TableModelEvent
 228      * @see EventListenerList
 229      *
 230      */
 231     public void fireTableRowsInserted(int firstRow, int lastRow) {
 232         fireTableChanged(new TableModelEvent(this, firstRow, lastRow,
 233                              TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
 234     }
 235 
 236     /**
 237      * Notifies all listeners that rows in the range
 238      * <code>[firstRow, lastRow]</code>, inclusive, have been updated.
 239      *
 240      * @param firstRow  the first row
 241      * @param lastRow   the last row
 242      *
 243      * @see TableModelEvent
 244      * @see EventListenerList
 245      */
 246     public void fireTableRowsUpdated(int firstRow, int lastRow) {
 247         fireTableChanged(new TableModelEvent(this, firstRow, lastRow,
 248                              TableModelEvent.ALL_COLUMNS, TableModelEvent.UPDATE));
 249     }
 250 
 251     /**
 252      * Notifies all listeners that rows in the range
 253      * <code>[firstRow, lastRow]</code>, inclusive, have been deleted.
 254      *
 255      * @param firstRow  the first row
 256      * @param lastRow   the last row
 257      *
 258      * @see TableModelEvent
 259      * @see EventListenerList
 260      */
 261     public void fireTableRowsDeleted(int firstRow, int lastRow) {
 262         fireTableChanged(new TableModelEvent(this, firstRow, lastRow,
 263                              TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE));
 264     }
 265 
 266     /**
 267      * Notifies all listeners that the value of the cell at
 268      * <code>[row, column]</code> has been updated.
 269      *
 270      * @param row  row of cell which has been updated
 271      * @param column  column of cell which has been updated
 272      * @see TableModelEvent
 273      * @see EventListenerList
 274      */
 275     public void fireTableCellUpdated(int row, int column) {
 276         fireTableChanged(new TableModelEvent(this, row, row, column));
 277     }
 278 
 279     /**
 280      * Forwards the given notification event to all
 281      * <code>TableModelListeners</code> that registered
 282      * themselves as listeners for this table model.
 283      *
 284      * @param e  the event to be forwarded
 285      *
 286      * @see #addTableModelListener
 287      * @see TableModelEvent
 288      * @see EventListenerList
 289      */
 290     public void fireTableChanged(TableModelEvent e) {
 291         // Guaranteed to return a non-null array
 292         Object[] listeners = listenerList.getListenerList();
 293         // Process the listeners last to first, notifying
 294         // those that are interested in this event
 295         for (int i = listeners.length-2; i>=0; i-=2) {
 296             if (listeners[i]==TableModelListener.class) {
 297                 ((TableModelListener)listeners[i+1]).tableChanged(e);
 298             }
 299         }
 300     }
 301 
 302     /**
 303      * Returns an array of all the objects currently registered
 304      * as <code><em>Foo</em>Listener</code>s
 305      * upon this <code>AbstractTableModel</code>.
 306      * <code><em>Foo</em>Listener</code>s are registered using the
 307      * <code>add<em>Foo</em>Listener</code> method.
 308      *
 309      * <p>
 310      *
 311      * You can specify the <code>listenerType</code> argument
 312      * with a class literal,
 313      * such as
 314      * <code><em>Foo</em>Listener.class</code>.
 315      * For example, you can query a
 316      * model <code>m</code>
 317      * for its table model listeners with the following code:
 318      *
 319      * <pre>TableModelListener[] tmls = (TableModelListener[])(m.getListeners(TableModelListener.class));</pre>
 320      *
 321      * If no such listeners exist, this method returns an empty array.
 322      *
 323      * @param listenerType the type of listeners requested; this parameter
 324      *          should specify an interface that descends from
 325      *          <code>java.util.EventListener</code>
 326      * @return an array of all objects registered as
 327      *          <code><em>Foo</em>Listener</code>s on this component,
 328      *          or an empty array if no such
 329      *          listeners have been added
 330      * @exception ClassCastException if <code>listenerType</code>
 331      *          doesn't specify a class or interface that implements
 332      *          <code>java.util.EventListener</code>
 333      *
 334      * @see #getTableModelListeners
 335      *
 336      * @since 1.3
 337      */
 338     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
 339         return listenerList.getListeners(listenerType);
 340     }
 341 } // End of class AbstractTableModel