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