001/* 002 * $Id$ 003 * 004 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 * 021 */ 022package org.jdesktop.swingx.table; 023 024import static org.jdesktop.swingx.table.TableUtilities.isDataChanged; 025import static org.jdesktop.swingx.table.TableUtilities.isInsert; 026import static org.jdesktop.swingx.table.TableUtilities.isStructureChanged; 027import static org.jdesktop.swingx.table.TableUtilities.isUpdate; 028import static org.jdesktop.swingx.table.TableUtilities.setPreferredRowHeight; 029 030import java.beans.PropertyChangeEvent; 031import java.beans.PropertyChangeListener; 032import java.util.logging.Logger; 033 034import javax.swing.JTable; 035import javax.swing.SwingUtilities; 036import javax.swing.event.TableModelEvent; 037import javax.swing.event.TableModelListener; 038import javax.swing.table.TableModel; 039 040/** 041 * A controller to adjust JTable rowHeight based on sizing requirements of its renderers. 042 * 043 * @author Jeanette Winzenburg, Berlin 044 */ 045public class TableRowHeightController { 046 047 private JTable table; 048 private TableModelListener tableModelListener; 049 private PropertyChangeListener tablePropertyListener; 050 051 /** 052 * Instantiates an unbound TableRowHeightController. 053 */ 054 public TableRowHeightController() { 055 this(null); 056 } 057 058 /** 059 * Instantiates a TableRowHeightController and installs itself to the given table. 060 * The row heights of all visible rows are automatically adjusted on model changes. 061 * 062 * @param table the table to control. 063 */ 064 public TableRowHeightController(JTable table) { 065 install(table); 066 } 067 068 /** 069 * Installs this controller on the given table. Releases control from previously 070 * installed table, if any. 071 * @param table the table to install upon. 072 */ 073 public void install(JTable table) { 074 release(); 075 if (table != null) { 076 this.table = table; 077 installListeners(); 078 updatePreferredRowHeights(); 079 } 080 } 081 082 /** 083 * Release this controller from its table. Does nothing if no table installed. 084 * 085 */ 086 public void release() { 087 if (table == null) 088 return; 089 uninstallListeners(); 090 table = null; 091 } 092 093 /** 094 * Sets the row heights of the rows in the range of first- to lastRow, inclusive. 095 * The coordinates are model indices. 096 * 097 * @param firstRow the first row in model coordinates 098 * @param lastRow the last row in model coordinates 099 */ 100 protected void updatePreferredRowHeights(int firstRow, int lastRow) { 101 for (int row = firstRow; row <= lastRow; row++) { 102 int viewRow = table.convertRowIndexToView(row); 103 if (viewRow >= 0) { 104// int oldHeight = table.getRowHeight(viewRow); 105// LOG.info("in viewRow/old/new: " + viewRow + " / " + oldHeight + " / " + table.getRowHeight(viewRow)); 106 setPreferredRowHeight(table, viewRow); 107 } 108 } 109 } 110 111 /** 112 * Sets the row heights of all rows. 113 */ 114 protected void updatePreferredRowHeights() { 115 if (table.getRowCount() == 0) return; 116 updatePreferredRowHeights(0, table.getModel().getRowCount() - 1); 117 } 118 119 /** 120 * @param oldValue 121 */ 122 protected void updateModel(TableModel oldValue) { 123 if (oldValue != null) { 124 oldValue.removeTableModelListener(getTableModelListener()); 125 } 126 table.getModel().addTableModelListener(getTableModelListener()); 127 updatePreferredRowHeights(); 128 } 129 130 131 /** 132 * @return 133 */ 134 protected PropertyChangeListener createTablePropertyListener() { 135 PropertyChangeListener l = new PropertyChangeListener() { 136 137 @Override 138 public void propertyChange(PropertyChangeEvent evt) { 139 invokedPropertyChanged(evt); 140 } 141 142 /** 143 * @param evt 144 */ 145 private void invokedPropertyChanged(final PropertyChangeEvent evt) { 146 SwingUtilities.invokeLater(new Runnable() { 147 @Override 148 public void run() { 149 if ("model".equals(evt.getPropertyName())) { 150 updateModel((TableModel) evt.getOldValue()); 151 } 152 153 } 154 }); 155 } 156 }; 157 return l; 158 } 159 160 protected TableModelListener createTableModelListener() { 161 TableModelListener l = new TableModelListener() { 162 @Override 163 public void tableChanged(final TableModelEvent e) { 164 SwingUtilities.invokeLater(new Runnable() { 165 @Override 166 public void run() { 167 invokedTableChanged(e); 168 } 169 }); 170 } 171 172 private void invokedTableChanged(TableModelEvent e) { 173 if (isStructureChanged(e) || isDataChanged(e)) { 174 updatePreferredRowHeights(); 175 } else if (isUpdate(e) || isInsert(e)) { 176 updatePreferredRowHeights(e.getFirstRow(), e.getLastRow()); 177 } 178 // do nothing on delete 179 } 180 }; 181 return l; 182 } 183 /** 184 * 185 */ 186 private void uninstallListeners() { 187 table.removePropertyChangeListener(getPropertyChangeListener()); 188 table.getModel().removeTableModelListener(getTableModelListener()); 189 // whatever else turns out to be needed 190 } 191 192 private void installListeners() { 193 table.addPropertyChangeListener(getPropertyChangeListener()); 194 table.getModel().addTableModelListener(getTableModelListener()); 195 // whatever else turns out to be needed 196 } 197 198 /** 199 * @return 200 */ 201 protected TableModelListener getTableModelListener() { 202 if (tableModelListener == null) { 203 tableModelListener = createTableModelListener(); 204 } 205 return tableModelListener; 206 } 207 208 /** 209 * @return 210 */ 211 protected PropertyChangeListener getPropertyChangeListener() { 212 if (tablePropertyListener == null) { 213 tablePropertyListener = createTablePropertyListener(); 214 } 215 return tablePropertyListener; 216 } 217 218 @SuppressWarnings("unused") 219 private static final Logger LOG = Logger 220 .getLogger(TableRowHeightController.class.getName()); 221}