src/java.desktop/share/classes/javax/swing/table/DefaultTableColumnModel.java
changeset 47216 71c04702a3d5
parent 32865 f9cb6e427f9e
child 49501 5daa8ef17089
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     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 javax.swing.*;
       
    29 import javax.swing.event.*;
       
    30 import java.awt.*;
       
    31 import java.util.Vector;
       
    32 import java.util.Enumeration;
       
    33 import java.util.EventListener;
       
    34 import java.beans.PropertyChangeListener;
       
    35 import java.beans.PropertyChangeEvent;
       
    36 import java.io.Serializable;
       
    37 import sun.swing.SwingUtilities2;
       
    38 
       
    39 /**
       
    40  * The standard column-handler for a <code>JTable</code>.
       
    41  * <p>
       
    42  * <strong>Warning:</strong>
       
    43  * Serialized objects of this class will not be compatible with
       
    44  * future Swing releases. The current serialization support is
       
    45  * appropriate for short term storage or RMI between applications running
       
    46  * the same version of Swing.  As of 1.4, support for long term storage
       
    47  * of all JavaBeans&trade;
       
    48  * has been added to the <code>java.beans</code> package.
       
    49  * Please see {@link java.beans.XMLEncoder}.
       
    50  *
       
    51  * @author Alan Chung
       
    52  * @author Philip Milne
       
    53  * @see JTable
       
    54  */
       
    55 @SuppressWarnings("serial") // Same-version serialization only
       
    56 public class DefaultTableColumnModel implements TableColumnModel,
       
    57                         PropertyChangeListener, ListSelectionListener, Serializable
       
    58 {
       
    59 //
       
    60 // Instance Variables
       
    61 //
       
    62 
       
    63     /** Array of TableColumn objects in this model */
       
    64     protected Vector<TableColumn> tableColumns;
       
    65 
       
    66     /** Model for keeping track of column selections */
       
    67     protected ListSelectionModel selectionModel;
       
    68 
       
    69     /** Width margin between each column */
       
    70     protected int columnMargin;
       
    71 
       
    72     /** List of TableColumnModelListener */
       
    73     protected EventListenerList listenerList = new EventListenerList();
       
    74 
       
    75     /** Change event (only one needed) */
       
    76     protected transient ChangeEvent changeEvent = null;
       
    77 
       
    78     /** Column selection allowed in this column model */
       
    79     protected boolean columnSelectionAllowed;
       
    80 
       
    81     /** A local cache of the combined width of all columns */
       
    82     protected int totalColumnWidth;
       
    83 
       
    84 //
       
    85 // Constructors
       
    86 //
       
    87     /**
       
    88      * Creates a default table column model.
       
    89      */
       
    90     public DefaultTableColumnModel() {
       
    91         super();
       
    92 
       
    93         // Initialize local ivars to default
       
    94         tableColumns = new Vector<TableColumn>();
       
    95         setSelectionModel(createSelectionModel());
       
    96         setColumnMargin(1);
       
    97         invalidateWidthCache();
       
    98         setColumnSelectionAllowed(false);
       
    99     }
       
   100 
       
   101 //
       
   102 // Modifying the model
       
   103 //
       
   104 
       
   105     /**
       
   106      *  Appends <code>aColumn</code> to the end of the
       
   107      *  <code>tableColumns</code> array.
       
   108      *  This method also posts the <code>columnAdded</code>
       
   109      *  event to its listeners.
       
   110      *
       
   111      * @param   aColumn         the <code>TableColumn</code> to be added
       
   112      * @exception IllegalArgumentException      if <code>aColumn</code> is
       
   113      *                          <code>null</code>
       
   114      * @see     #removeColumn
       
   115      */
       
   116     public void addColumn(TableColumn aColumn) {
       
   117         if (aColumn == null) {
       
   118             throw new IllegalArgumentException("Object is null");
       
   119         }
       
   120 
       
   121         tableColumns.addElement(aColumn);
       
   122         aColumn.addPropertyChangeListener(this);
       
   123         invalidateWidthCache();
       
   124 
       
   125         // Post columnAdded event notification
       
   126         fireColumnAdded(new TableColumnModelEvent(this, 0,
       
   127                                                   getColumnCount() - 1));
       
   128     }
       
   129 
       
   130     /**
       
   131      *  Deletes the <code>column</code> from the
       
   132      *  <code>tableColumns</code> array.  This method will do nothing if
       
   133      *  <code>column</code> is not in the table's columns list.
       
   134      *  <code>tile</code> is called
       
   135      *  to resize both the header and table views.
       
   136      *  This method also posts a <code>columnRemoved</code>
       
   137      *  event to its listeners.
       
   138      *
       
   139      * @param   column          the <code>TableColumn</code> to be removed
       
   140      * @see     #addColumn
       
   141      */
       
   142     public void removeColumn(TableColumn column) {
       
   143         int columnIndex = tableColumns.indexOf(column);
       
   144 
       
   145         if (columnIndex != -1) {
       
   146             // Adjust for the selection
       
   147             if (selectionModel != null) {
       
   148                 selectionModel.removeIndexInterval(columnIndex,columnIndex);
       
   149             }
       
   150 
       
   151             column.removePropertyChangeListener(this);
       
   152             tableColumns.removeElementAt(columnIndex);
       
   153             invalidateWidthCache();
       
   154 
       
   155             // Post columnAdded event notification.  (JTable and JTableHeader
       
   156             // listens so they can adjust size and redraw)
       
   157             fireColumnRemoved(new TableColumnModelEvent(this,
       
   158                                            columnIndex, 0));
       
   159         }
       
   160     }
       
   161 
       
   162     /**
       
   163      * Moves the column and heading at <code>columnIndex</code> to
       
   164      * <code>newIndex</code>.  The old column at <code>columnIndex</code>
       
   165      * will now be found at <code>newIndex</code>.  The column
       
   166      * that used to be at <code>newIndex</code> is shifted
       
   167      * left or right to make room.  This will not move any columns if
       
   168      * <code>columnIndex</code> equals <code>newIndex</code>.  This method
       
   169      * also posts a <code>columnMoved</code> event to its listeners.
       
   170      *
       
   171      * @param   columnIndex                     the index of column to be moved
       
   172      * @param   newIndex                        new index to move the column
       
   173      * @exception IllegalArgumentException      if <code>column</code> or
       
   174      *                                          <code>newIndex</code>
       
   175      *                                          are not in the valid range
       
   176      */
       
   177     public void moveColumn(int columnIndex, int newIndex) {
       
   178         if ((columnIndex < 0) || (columnIndex >= getColumnCount()) ||
       
   179             (newIndex < 0) || (newIndex >= getColumnCount()))
       
   180             throw new IllegalArgumentException("moveColumn() - Index out of range");
       
   181 
       
   182         TableColumn aColumn;
       
   183 
       
   184         // If the column has not yet moved far enough to change positions
       
   185         // post the event anyway, the "draggedDistance" property of the
       
   186         // tableHeader will say how far the column has been dragged.
       
   187         // Here we are really trying to get the best out of an
       
   188         // API that could do with some rethinking. We preserve backward
       
   189         // compatibility by slightly bending the meaning of these methods.
       
   190         if (columnIndex == newIndex) {
       
   191             fireColumnMoved(new TableColumnModelEvent(this, columnIndex, newIndex));
       
   192             return;
       
   193         }
       
   194         aColumn = tableColumns.elementAt(columnIndex);
       
   195 
       
   196         tableColumns.removeElementAt(columnIndex);
       
   197         boolean selected = selectionModel.isSelectedIndex(columnIndex);
       
   198         selectionModel.removeIndexInterval(columnIndex,columnIndex);
       
   199 
       
   200         tableColumns.insertElementAt(aColumn, newIndex);
       
   201         selectionModel.insertIndexInterval(newIndex, 1, true);
       
   202         if (selected) {
       
   203             selectionModel.addSelectionInterval(newIndex, newIndex);
       
   204         }
       
   205         else {
       
   206             selectionModel.removeSelectionInterval(newIndex, newIndex);
       
   207         }
       
   208 
       
   209         fireColumnMoved(new TableColumnModelEvent(this, columnIndex,
       
   210                                                                newIndex));
       
   211     }
       
   212 
       
   213     /**
       
   214      * Sets the column margin to <code>newMargin</code>.  This method
       
   215      * also posts a <code>columnMarginChanged</code> event to its
       
   216      * listeners.
       
   217      *
       
   218      * @param   newMargin               the new margin width, in pixels
       
   219      * @see     #getColumnMargin
       
   220      * @see     #getTotalColumnWidth
       
   221      */
       
   222     public void setColumnMargin(int newMargin) {
       
   223         if (newMargin != columnMargin) {
       
   224             columnMargin = newMargin;
       
   225             // Post columnMarginChanged event notification.
       
   226             fireColumnMarginChanged();
       
   227         }
       
   228     }
       
   229 
       
   230 //
       
   231 // Querying the model
       
   232 //
       
   233 
       
   234     /**
       
   235      * Returns the number of columns in the <code>tableColumns</code> array.
       
   236      *
       
   237      * @return  the number of columns in the <code>tableColumns</code> array
       
   238      * @see     #getColumns
       
   239      */
       
   240     public int getColumnCount() {
       
   241         return tableColumns.size();
       
   242     }
       
   243 
       
   244     /**
       
   245      * Returns an <code>Enumeration</code> of all the columns in the model.
       
   246      * @return an <code>Enumeration</code> of the columns in the model
       
   247      */
       
   248     public Enumeration<TableColumn> getColumns() {
       
   249         return tableColumns.elements();
       
   250     }
       
   251 
       
   252     /**
       
   253      * Returns the index of the first column in the <code>tableColumns</code>
       
   254      * array whose identifier is equal to <code>identifier</code>,
       
   255      * when compared using <code>equals</code>.
       
   256      *
       
   257      * @param           identifier              the identifier object
       
   258      * @return          the index of the first column in the
       
   259      *                  <code>tableColumns</code> array whose identifier
       
   260      *                  is equal to <code>identifier</code>
       
   261      * @exception       IllegalArgumentException  if <code>identifier</code>
       
   262      *                          is <code>null</code>, or if no
       
   263      *                          <code>TableColumn</code> has this
       
   264      *                          <code>identifier</code>
       
   265      * @see             #getColumn
       
   266      */
       
   267     public int getColumnIndex(Object identifier) {
       
   268         if (identifier == null) {
       
   269             throw new IllegalArgumentException("Identifier is null");
       
   270         }
       
   271 
       
   272         Enumeration<TableColumn> enumeration = getColumns();
       
   273         TableColumn aColumn;
       
   274         int index = 0;
       
   275 
       
   276         while (enumeration.hasMoreElements()) {
       
   277             aColumn = enumeration.nextElement();
       
   278             // Compare them this way in case the column's identifier is null.
       
   279             if (identifier.equals(aColumn.getIdentifier()))
       
   280                 return index;
       
   281             index++;
       
   282         }
       
   283         throw new IllegalArgumentException("Identifier not found");
       
   284     }
       
   285 
       
   286     /**
       
   287      * Returns the <code>TableColumn</code> object for the column
       
   288      * at <code>columnIndex</code>.
       
   289      *
       
   290      * @param   columnIndex     the index of the column desired
       
   291      * @return  the <code>TableColumn</code> object for the column
       
   292      *                          at <code>columnIndex</code>
       
   293      */
       
   294     public TableColumn getColumn(int columnIndex) {
       
   295         return tableColumns.elementAt(columnIndex);
       
   296     }
       
   297 
       
   298     /**
       
   299      * Returns the width margin for <code>TableColumn</code>.
       
   300      * The default <code>columnMargin</code> is 1.
       
   301      *
       
   302      * @return  the maximum width for the <code>TableColumn</code>
       
   303      * @see     #setColumnMargin
       
   304      */
       
   305     public int getColumnMargin() {
       
   306         return columnMargin;
       
   307     }
       
   308 
       
   309     /**
       
   310      * Returns the index of the column that lies at position <code>x</code>,
       
   311      * or -1 if no column covers this point.
       
   312      *
       
   313      * In keeping with Swing's separable model architecture, a
       
   314      * TableColumnModel does not know how the table columns actually appear on
       
   315      * screen.  The visual presentation of the columns is the responsibility
       
   316      * of the view/controller object using this model (typically JTable).  The
       
   317      * view/controller need not display the columns sequentially from left to
       
   318      * right.  For example, columns could be displayed from right to left to
       
   319      * accommodate a locale preference or some columns might be hidden at the
       
   320      * request of the user.  Because the model does not know how the columns
       
   321      * are laid out on screen, the given <code>xPosition</code> should not be
       
   322      * considered to be a coordinate in 2D graphics space.  Instead, it should
       
   323      * be considered to be a width from the start of the first column in the
       
   324      * model.  If the column index for a given X coordinate in 2D space is
       
   325      * required, <code>JTable.columnAtPoint</code> can be used instead.
       
   326      *
       
   327      * @param  x  the horizontal location of interest
       
   328      * @return  the index of the column or -1 if no column is found
       
   329      * @see javax.swing.JTable#columnAtPoint
       
   330      */
       
   331     public int getColumnIndexAtX(int x) {
       
   332         if (x < 0) {
       
   333             return -1;
       
   334         }
       
   335         int cc = getColumnCount();
       
   336         for(int column = 0; column < cc; column++) {
       
   337             x = x - getColumn(column).getWidth();
       
   338             if (x < 0) {
       
   339                 return column;
       
   340             }
       
   341         }
       
   342         return -1;
       
   343     }
       
   344 
       
   345     /**
       
   346      * Returns the total combined width of all columns.
       
   347      * @return the <code>totalColumnWidth</code> property
       
   348      */
       
   349     public int getTotalColumnWidth() {
       
   350         if (totalColumnWidth == -1) {
       
   351             recalcWidthCache();
       
   352         }
       
   353         return totalColumnWidth;
       
   354     }
       
   355 
       
   356 //
       
   357 // Selection model
       
   358 //
       
   359 
       
   360     /**
       
   361      *  Sets the selection model for this <code>TableColumnModel</code>
       
   362      *  to <code>newModel</code>
       
   363      *  and registers for listener notifications from the new selection
       
   364      *  model.  If <code>newModel</code> is <code>null</code>,
       
   365      *  an exception is thrown.
       
   366      *
       
   367      * @param   newModel        the new selection model
       
   368      * @exception IllegalArgumentException      if <code>newModel</code>
       
   369      *                                          is <code>null</code>
       
   370      * @see     #getSelectionModel
       
   371      */
       
   372     public void setSelectionModel(ListSelectionModel newModel) {
       
   373         if (newModel == null) {
       
   374             throw new IllegalArgumentException("Cannot set a null SelectionModel");
       
   375         }
       
   376 
       
   377         ListSelectionModel oldModel = selectionModel;
       
   378 
       
   379         if (newModel != oldModel) {
       
   380             if (oldModel != null) {
       
   381                 oldModel.removeListSelectionListener(this);
       
   382             }
       
   383 
       
   384             selectionModel= newModel;
       
   385             newModel.addListSelectionListener(this);
       
   386         }
       
   387     }
       
   388 
       
   389     /**
       
   390      * Returns the <code>ListSelectionModel</code> that is used to
       
   391      * maintain column selection state.
       
   392      *
       
   393      * @return  the object that provides column selection state.  Or
       
   394      *          <code>null</code> if row selection is not allowed.
       
   395      * @see     #setSelectionModel
       
   396      */
       
   397     public ListSelectionModel getSelectionModel() {
       
   398         return selectionModel;
       
   399     }
       
   400 
       
   401     // implements javax.swing.table.TableColumnModel
       
   402     /**
       
   403      * Sets whether column selection is allowed.  The default is false.
       
   404      * @param  flag true if column selection will be allowed, false otherwise
       
   405      */
       
   406     public void setColumnSelectionAllowed(boolean flag) {
       
   407         columnSelectionAllowed = flag;
       
   408     }
       
   409 
       
   410     // implements javax.swing.table.TableColumnModel
       
   411     /**
       
   412      * Returns true if column selection is allowed, otherwise false.
       
   413      * The default is false.
       
   414      * @return the <code>columnSelectionAllowed</code> property
       
   415      */
       
   416     public boolean getColumnSelectionAllowed() {
       
   417         return columnSelectionAllowed;
       
   418     }
       
   419 
       
   420     // implements javax.swing.table.TableColumnModel
       
   421     /**
       
   422      * Returns an array of selected columns.  If <code>selectionModel</code>
       
   423      * is <code>null</code>, returns an empty array.
       
   424      * @return an array of selected columns or an empty array if nothing
       
   425      *                  is selected or the <code>selectionModel</code> is
       
   426      *                  <code>null</code>
       
   427      */
       
   428     public int[] getSelectedColumns() {
       
   429         if (selectionModel != null) {
       
   430             int iMin = selectionModel.getMinSelectionIndex();
       
   431             int iMax = selectionModel.getMaxSelectionIndex();
       
   432 
       
   433             if ((iMin == -1) || (iMax == -1)) {
       
   434                 return new int[0];
       
   435             }
       
   436 
       
   437             int[] rvTmp = new int[1+ (iMax - iMin)];
       
   438             int n = 0;
       
   439             for(int i = iMin; i <= iMax; i++) {
       
   440                 if (selectionModel.isSelectedIndex(i)) {
       
   441                     rvTmp[n++] = i;
       
   442                 }
       
   443             }
       
   444             int[] rv = new int[n];
       
   445             System.arraycopy(rvTmp, 0, rv, 0, n);
       
   446             return rv;
       
   447         }
       
   448         return  new int[0];
       
   449     }
       
   450 
       
   451     // implements javax.swing.table.TableColumnModel
       
   452     /**
       
   453      * Returns the number of columns selected.
       
   454      * @return the number of columns selected
       
   455      */
       
   456     public int getSelectedColumnCount() {
       
   457         if (selectionModel != null) {
       
   458             int iMin = selectionModel.getMinSelectionIndex();
       
   459             int iMax = selectionModel.getMaxSelectionIndex();
       
   460             int count = 0;
       
   461 
       
   462             for(int i = iMin; i <= iMax; i++) {
       
   463                 if (selectionModel.isSelectedIndex(i)) {
       
   464                     count++;
       
   465                 }
       
   466             }
       
   467             return count;
       
   468         }
       
   469         return 0;
       
   470     }
       
   471 
       
   472 //
       
   473 // Listener Support Methods
       
   474 //
       
   475 
       
   476     // implements javax.swing.table.TableColumnModel
       
   477     /**
       
   478      * Adds a listener for table column model events.
       
   479      * @param x  a <code>TableColumnModelListener</code> object
       
   480      */
       
   481     public void addColumnModelListener(TableColumnModelListener x) {
       
   482         listenerList.add(TableColumnModelListener.class, x);
       
   483     }
       
   484 
       
   485     // implements javax.swing.table.TableColumnModel
       
   486     /**
       
   487      * Removes a listener for table column model events.
       
   488      * @param x  a <code>TableColumnModelListener</code> object
       
   489      */
       
   490     public void removeColumnModelListener(TableColumnModelListener x) {
       
   491         listenerList.remove(TableColumnModelListener.class, x);
       
   492     }
       
   493 
       
   494     /**
       
   495      * Returns an array of all the column model listeners
       
   496      * registered on this model.
       
   497      *
       
   498      * @return all of this default table column model's <code>ColumnModelListener</code>s
       
   499      *         or an empty
       
   500      *         array if no column model listeners are currently registered
       
   501      *
       
   502      * @see #addColumnModelListener
       
   503      * @see #removeColumnModelListener
       
   504      *
       
   505      * @since 1.4
       
   506      */
       
   507     public TableColumnModelListener[] getColumnModelListeners() {
       
   508         return listenerList.getListeners(TableColumnModelListener.class);
       
   509     }
       
   510 
       
   511 //
       
   512 //   Event firing methods
       
   513 //
       
   514 
       
   515     /**
       
   516      * Notifies all listeners that have registered interest for
       
   517      * notification on this event type.  The event instance
       
   518      * is lazily created using the parameters passed into
       
   519      * the fire method.
       
   520      * @param e  the event received
       
   521      * @see EventListenerList
       
   522      */
       
   523     protected void fireColumnAdded(TableColumnModelEvent e) {
       
   524         // Guaranteed to return a non-null array
       
   525         Object[] listeners = listenerList.getListenerList();
       
   526         // Process the listeners last to first, notifying
       
   527         // those that are interested in this event
       
   528         for (int i = listeners.length-2; i>=0; i-=2) {
       
   529             if (listeners[i]==TableColumnModelListener.class) {
       
   530                 // Lazily create the event:
       
   531                 // if (e == null)
       
   532                 //  e = new ChangeEvent(this);
       
   533                 ((TableColumnModelListener)listeners[i+1]).
       
   534                     columnAdded(e);
       
   535             }
       
   536         }
       
   537     }
       
   538 
       
   539     /**
       
   540      * Notifies all listeners that have registered interest for
       
   541      * notification on this event type.  The event instance
       
   542      * is lazily created using the parameters passed into
       
   543      * the fire method.
       
   544      * @param  e  the event received
       
   545      * @see EventListenerList
       
   546      */
       
   547     protected void fireColumnRemoved(TableColumnModelEvent e) {
       
   548         // Guaranteed to return a non-null array
       
   549         Object[] listeners = listenerList.getListenerList();
       
   550         // Process the listeners last to first, notifying
       
   551         // those that are interested in this event
       
   552         for (int i = listeners.length-2; i>=0; i-=2) {
       
   553             if (listeners[i]==TableColumnModelListener.class) {
       
   554                 // Lazily create the event:
       
   555                 // if (e == null)
       
   556                 //  e = new ChangeEvent(this);
       
   557                 ((TableColumnModelListener)listeners[i+1]).
       
   558                     columnRemoved(e);
       
   559             }
       
   560         }
       
   561     }
       
   562 
       
   563     /**
       
   564      * Notifies all listeners that have registered interest for
       
   565      * notification on this event type.  The event instance
       
   566      * is lazily created using the parameters passed into
       
   567      * the fire method.
       
   568      * @param  e the event received
       
   569      * @see EventListenerList
       
   570      */
       
   571     protected void fireColumnMoved(TableColumnModelEvent e) {
       
   572         // Guaranteed to return a non-null array
       
   573         Object[] listeners = listenerList.getListenerList();
       
   574         // Process the listeners last to first, notifying
       
   575         // those that are interested in this event
       
   576         for (int i = listeners.length-2; i>=0; i-=2) {
       
   577             if (listeners[i]==TableColumnModelListener.class) {
       
   578                 // Lazily create the event:
       
   579                 // if (e == null)
       
   580                 //  e = new ChangeEvent(this);
       
   581                 ((TableColumnModelListener)listeners[i+1]).
       
   582                     columnMoved(e);
       
   583             }
       
   584         }
       
   585     }
       
   586 
       
   587     /**
       
   588      * Notifies all listeners that have registered interest for
       
   589      * notification on this event type.  The event instance
       
   590      * is lazily created using the parameters passed into
       
   591      * the fire method.
       
   592      * @param e the event received
       
   593      * @see EventListenerList
       
   594      */
       
   595     protected void fireColumnSelectionChanged(ListSelectionEvent e) {
       
   596         // Guaranteed to return a non-null array
       
   597         Object[] listeners = listenerList.getListenerList();
       
   598         // Process the listeners last to first, notifying
       
   599         // those that are interested in this event
       
   600         for (int i = listeners.length-2; i>=0; i-=2) {
       
   601             if (listeners[i]==TableColumnModelListener.class) {
       
   602                 // Lazily create the event:
       
   603                 // if (e == null)
       
   604                 //  e = new ChangeEvent(this);
       
   605                 ((TableColumnModelListener)listeners[i+1]).
       
   606                     columnSelectionChanged(e);
       
   607             }
       
   608         }
       
   609     }
       
   610 
       
   611     /**
       
   612      * Notifies all listeners that have registered interest for
       
   613      * notification on this event type.  The event instance
       
   614      * is lazily created using the parameters passed into
       
   615      * the fire method.
       
   616      * @see EventListenerList
       
   617      */
       
   618     protected void fireColumnMarginChanged() {
       
   619         // Guaranteed to return a non-null array
       
   620         Object[] listeners = listenerList.getListenerList();
       
   621         // Process the listeners last to first, notifying
       
   622         // those that are interested in this event
       
   623         for (int i = listeners.length-2; i>=0; i-=2) {
       
   624             if (listeners[i]==TableColumnModelListener.class) {
       
   625                 // Lazily create the event:
       
   626                 if (changeEvent == null)
       
   627                     changeEvent = new ChangeEvent(this);
       
   628                 ((TableColumnModelListener)listeners[i+1]).
       
   629                     columnMarginChanged(changeEvent);
       
   630             }
       
   631         }
       
   632     }
       
   633 
       
   634     /**
       
   635      * Returns an array of all the objects currently registered
       
   636      * as <code><em>Foo</em>Listener</code>s
       
   637      * upon this model.
       
   638      * <code><em>Foo</em>Listener</code>s are registered using the
       
   639      * <code>add<em>Foo</em>Listener</code> method.
       
   640      *
       
   641      * <p>
       
   642      *
       
   643      * You can specify the <code>listenerType</code> argument
       
   644      * with a class literal,
       
   645      * such as
       
   646      * <code><em>Foo</em>Listener.class</code>.
       
   647      * For example, you can query a
       
   648      * <code>DefaultTableColumnModel</code> <code>m</code>
       
   649      * for its column model listeners with the following code:
       
   650      *
       
   651      * <pre>ColumnModelListener[] cmls = (ColumnModelListener[])(m.getListeners(ColumnModelListener.class));</pre>
       
   652      *
       
   653      * If no such listeners exist, this method returns an empty array.
       
   654      *
       
   655      * @param <T> the listener type
       
   656      * @param listenerType the type of listeners requested
       
   657      * @return an array of all objects registered as
       
   658      *          <code><em>Foo</em>Listener</code>s on this model,
       
   659      *          or an empty array if no such
       
   660      *          listeners have been added
       
   661      * @exception ClassCastException if <code>listenerType</code>
       
   662      *          doesn't specify a class or interface that implements
       
   663      *          <code>java.util.EventListener</code>
       
   664      *
       
   665      * @see #getColumnModelListeners
       
   666      * @since 1.3
       
   667      */
       
   668     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
       
   669         return listenerList.getListeners(listenerType);
       
   670     }
       
   671 
       
   672 //
       
   673 // Implementing the PropertyChangeListener interface
       
   674 //
       
   675 
       
   676     // PENDING(alan)
       
   677     // implements java.beans.PropertyChangeListener
       
   678     /**
       
   679      * Property Change Listener change method.  Used to track changes
       
   680      * to the column width or preferred column width.
       
   681      *
       
   682      * @param  evt  <code>PropertyChangeEvent</code>
       
   683      */
       
   684     public void propertyChange(PropertyChangeEvent evt) {
       
   685         String name = evt.getPropertyName();
       
   686 
       
   687         if (name == "width" || name == "preferredWidth") {
       
   688             invalidateWidthCache();
       
   689             // This is a misnomer, we're using this method
       
   690             // simply to cause a relayout.
       
   691             fireColumnMarginChanged();
       
   692         }
       
   693 
       
   694     }
       
   695 
       
   696 //
       
   697 // Implementing ListSelectionListener interface
       
   698 //
       
   699 
       
   700     // implements javax.swing.event.ListSelectionListener
       
   701     /**
       
   702      * A <code>ListSelectionListener</code> that forwards
       
   703      * <code>ListSelectionEvents</code> when there is a column
       
   704      * selection change.
       
   705      *
       
   706      * @param e  the change event
       
   707      */
       
   708     public void valueChanged(ListSelectionEvent e) {
       
   709         fireColumnSelectionChanged(e);
       
   710     }
       
   711 
       
   712 //
       
   713 // Protected Methods
       
   714 //
       
   715 
       
   716     /**
       
   717      * Creates a new default list selection model.
       
   718      *
       
   719      * @return a newly created default list selection model.
       
   720      */
       
   721     protected ListSelectionModel createSelectionModel() {
       
   722         return new DefaultListSelectionModel();
       
   723     }
       
   724 
       
   725     /**
       
   726      * Recalculates the total combined width of all columns.  Updates the
       
   727      * <code>totalColumnWidth</code> property.
       
   728      */
       
   729     protected void recalcWidthCache() {
       
   730         Enumeration<TableColumn> enumeration = getColumns();
       
   731         totalColumnWidth = 0;
       
   732         while (enumeration.hasMoreElements()) {
       
   733             totalColumnWidth += enumeration.nextElement().getWidth();
       
   734         }
       
   735     }
       
   736 
       
   737     private void invalidateWidthCache() {
       
   738         totalColumnWidth = -1;
       
   739     }
       
   740 
       
   741 } // End of class DefaultTableColumnModel