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 listenerList.getListeners(TableModelListener.class);
 180     }
 181 
 182 //
 183 //  Fire methods
 184 //
 185 
 186     /**
 187      * Notifies all listeners that all cell values in the table's
 188      * rows may have changed. The number of rows may also have changed
 189      * and the <code>JTable</code> should redraw the
 190      * table from scratch. The structure of the table (as in the order of the
 191      * columns) is assumed to be the same.
 192      *
 193      * @see TableModelEvent
 194      * @see EventListenerList
 195      * @see javax.swing.JTable#tableChanged(TableModelEvent)
 196      */
 197     public void fireTableDataChanged() {
 198         fireTableChanged(new TableModelEvent(this));
 199     }
 200 
 201     /**
 202      * Notifies all listeners that the table's structure has changed.
 203      * The number of columns in the table, and the names and types of
 204      * the new columns may be different from the previous state.
 205      * If the <code>JTable</code> receives this event and its
 206      * <code>autoCreateColumnsFromModel</code>
 207      * flag is set it discards any table columns that it had and reallocates
 208      * default columns in the order they appear in the model. This is the
 209      * same as calling <code>setModel(TableModel)</code> on the
 210      * <code>JTable</code>.
 211      *
 212      * @see TableModelEvent
 213      * @see EventListenerList
 214      */
 215     public void fireTableStructureChanged() {
 216         fireTableChanged(new TableModelEvent(this, TableModelEvent.HEADER_ROW));
 217     }
 218 
 219     /**
 220      * Notifies all listeners that rows in the range
 221      * <code>[firstRow, lastRow]</code>, inclusive, have been inserted.
 222      *
 223      * @param  firstRow  the first row
 224      * @param  lastRow   the last row
 225      *
 226      * @see TableModelEvent
 227      * @see EventListenerList
 228      *
 229      */
 230     public void fireTableRowsInserted(int firstRow, int lastRow) {
 231         fireTableChanged(new TableModelEvent(this, firstRow, lastRow,
 232                              TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
 233     }
 234 
 235     /**
 236      * Notifies all listeners that rows in the range
 237      * <code>[firstRow, lastRow]</code>, inclusive, have been updated.
 238      *
 239      * @param firstRow  the first row
 240      * @param lastRow   the last row
 241      *
 242      * @see TableModelEvent
 243      * @see EventListenerList
 244      */
 245     public void fireTableRowsUpdated(int firstRow, int lastRow) {
 246         fireTableChanged(new TableModelEvent(this, firstRow, lastRow,
 247                              TableModelEvent.ALL_COLUMNS, TableModelEvent.UPDATE));
 248     }
 249 
 250     /**
 251      * Notifies all listeners that rows in the range
 252      * <code>[firstRow, lastRow]</code>, inclusive, have been deleted.
 253      *
 254      * @param firstRow  the first row
 255      * @param lastRow   the last row
 256      *
 257      * @see TableModelEvent
 258      * @see EventListenerList
 259      */
 260     public void fireTableRowsDeleted(int firstRow, int lastRow) {
 261         fireTableChanged(new TableModelEvent(this, firstRow, lastRow,
 262                              TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE));
 263     }
 264 
 265     /**
 266      * Notifies all listeners that the value of the cell at
 267      * <code>[row, column]</code> has been updated.
 268      *
 269      * @param row  row of cell which has been updated
 270      * @param column  column of cell which has been updated
 271      * @see TableModelEvent
 272      * @see EventListenerList
 273      */
 274     public void fireTableCellUpdated(int row, int column) {
 275         fireTableChanged(new TableModelEvent(this, row, row, column));
 276     }
 277 
 278     /**
 279      * Forwards the given notification event to all
 280      * <code>TableModelListeners</code> that registered
 281      * themselves as listeners for this table model.
 282      *
 283      * @param e  the event to be forwarded
 284      *
 285      * @see #addTableModelListener
 286      * @see TableModelEvent
 287      * @see EventListenerList
 288      */
 289     public void fireTableChanged(TableModelEvent e) {
 290         // Guaranteed to return a non-null array
 291         Object[] listeners = listenerList.getListenerList();
 292         // Process the listeners last to first, notifying
 293         // those that are interested in this event
 294         for (int i = listeners.length-2; i>=0; i-=2) {
 295             if (listeners[i]==TableModelListener.class) {
 296                 ((TableModelListener)listeners[i+1]).tableChanged(e);
 297             }
 298         }
 299     }
 300 
 301     /**
 302      * Returns an array of all the objects currently registered
 303      * as <code><em>Foo</em>Listener</code>s
 304      * upon this <code>AbstractTableModel</code>.
 305      * <code><em>Foo</em>Listener</code>s are registered using the
 306      * <code>add<em>Foo</em>Listener</code> method.
 307      *
 308      * <p>
 309      *
 310      * You can specify the <code>listenerType</code> argument
 311      * with a class literal,
 312      * such as
 313      * <code><em>Foo</em>Listener.class</code>.
 314      * For example, you can query a
 315      * model <code>m</code>
 316      * for its table model listeners with the following code:
 317      *
 318      * <pre>TableModelListener[] tmls = (TableModelListener[])(m.getListeners(TableModelListener.class));</pre>
 319      *
 320      * If no such listeners exist, this method returns an empty array.
 321      *
 322      * @param listenerType the type of listeners requested; this parameter
 323      *          should specify an interface that descends from
 324      *          <code>java.util.EventListener</code>
 325      * @return an array of all objects registered as
 326      *          <code><em>Foo</em>Listener</code>s on this component,
 327      *          or an empty array if no such
 328      *          listeners have been added
 329      * @exception ClassCastException if <code>listenerType</code>
 330      *          doesn't specify a class or interface that implements
 331      *          <code>java.util.EventListener</code>
 332      *
 333      * @see #getTableModelListeners
 334      *
 335      * @since 1.3
 336      */
 337     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
 338         return listenerList.getListeners(listenerType);
 339     }
 340 } // End of class AbstractTableModel