QJCC homepage

biz.chitec.quarterback.swing
Class TableCellSizeAdjustor

java.lang.Object
  extended bybiz.chitec.quarterback.swing.TableCellSizeAdjustor
All Implemented Interfaces:
javax.swing.event.ChangeListener, java.util.EventListener, java.beans.PropertyChangeListener, javax.swing.event.TableColumnModelListener, javax.swing.event.TableModelListener, TableRowHeightListener

public final class TableCellSizeAdjustor
extends java.lang.Object
implements javax.swing.event.TableModelListener, javax.swing.event.TableColumnModelListener, javax.swing.event.ChangeListener, java.beans.PropertyChangeListener, TableRowHeightListener

Adjusts width and height of table colums according to their content. TableCellSizeAdjustor listens for changes in data or column arrangement of a table and readjusts the table's column widths, so that for each column, the widest content of all rows fits into the table. Furthermore, it adjusts the cell heights so that the largest content fits, either row by row (default) or globally. Cell size is determined through the renderer object's preferred size. It is possible to advise TableCellSizeAdjustor to additionally take the editor's size into consideration and use the width and height maximum of renderer and editor.

TableCellSizeAdjustor doesn't make any assumptions about the content of the table, apart from the model object itself not changing. Otherwise, it just uses the normal interfaces and methods. TableCellSizeAdjustor turns the table in AUTO_RESIZE_OFF mode as the resizing is now managed completely by the adjustor.

TableCellSizeAdjustor is bound to its table by using the static method adjustorForTable(JTable):

    ...
    JTable jt=new JTable();
    TableCellSizeAdjustor tcsa=TableCellSizeAdjustor.adjustorForTable(jt);
    ...
    
After changes of the table's model or column model (with Table.setModel() or Table.setColumnModel()) the TableCellSizeAdjustor must be informed through its method rebindListeners():
    ...
    jt.setModel(newmodel);
    tcsa.rebindListeners();
    ...
    
Implementation notes:

Version:
$Id: 15da64f9405b9b3ab7bb0091660ede674008c76a $
Author:
Dirk Hillbrecht 1999-2000, chitec/Dirk Hillbrecht 2000,2001,2002, cantamen/Dirk Hillbrecht 2003-2005 Distributed under the terms of the GNU LGPL.

Nested Class Summary
private  class TableCellSizeAdjustor.AdjustmentInstruction
          Wrapper for instructions on what to recalculate.
private  class TableCellSizeAdjustor.RowHeightStorage
          Internal class to store special row heights.
 
Field Summary
static int ADJUST_BOTH
          Constant for creation method: adjust width and height of the cells.
static int ADJUST_BOTH_HEIGHT_GLOBALLY
          Constant for creation method: adjust widths and heights of cells, handle heights globally.
static int ADJUST_HEIGHT
          Constant for creation method: adjust only the height of the cells.
static int ADJUST_HEIGHT_GLOBALLY
          Constant for creation method: adjust height globally, i.e. all cells get height of highest one
static int ADJUST_WIDTH
          Constant for creation method: adjust only the width of the cells.
private  boolean adjustheight
          Internal flag: Adjust height?
private  boolean adjustheightglobally
          Internal flag: Adjust height globally?
private  boolean adjustwidth
          Internal flag: Adjust width?
private  java.util.List ajis
          List of adjustment instructions
private  int allmaxheight
          maximum height for all rows
private  boolean checkeditor
          Internal flag: Adjust by CellEditor size?
private  boolean checkheader
          Change by msouthern 10-Mar-04: use column header names in column width calculations
private  int columncount
          column count
private  int divident
          fraction of change for maximum value to shrink before column size is recalculated completely
private  int divisor
          fraction of change for maximum value to shrink before column size is recalculated completely
private static int DONOTHING
          internal constant: no new maximum values found in last computation
private  boolean enabled
          Flag: adjustor enabled?
private  QuickIntArray fillingcolumns
          Index of row to be resized so that the viewport is completely filled up.
private  int fixedwidth
          Cumulated width of all automatically sized rows
private  javax.swing.table.TableCellRenderer headerrenderer
          Compatibility code for Java 1.3
private  javax.swing.JTable jt
          The JTable this Adjustor is working on.
private  QuickIntArray lockedcolumns
          Index of rows to be left alone regarding width, i.e.
private  int[] maxheight
          maximum needed height for columns
private  int[] maxheightidx
          row index of heighest entry in column
private  int maxrow
          maximum handled row index so far (for optimisation of inserts at the end)
private  int[] maxwidth
          maximum needed width for columns
private  int[] maxwidthidx
          row index of widest entry in column
private  javax.swing.JViewport parentviewport
          Viewport containing the table.
private  boolean postponeadjustment
          Internal flag: Are there any postponed adjustments due to disabling?
private  boolean recalccompletely
          flag: Everything must be calculated
private static int RESIZECOMPLETELY
          internal constant: recalculate column sizes with respect to all cells
private  java.util.Set rowheightproviders
          Set with row height providers the cell size adjustor listens to
private  TableCellSizeAdjustor.RowHeightStorage rowheightstorage
          Storage for row heights of dynamic cells
private static java.lang.Integer ROWMAX
          internal constant: maximum value for row height cache
private static int SETBOTH
          internal constant: use width and height of last computation
private static int SETHEIGHT
          internal constant: take maximum height of currently handled column into consideration to be new maximum height
private static int SETWIDTH
          internal constant: set width of currently handled column
private  javax.swing.table.TableColumn[] tablecolumn
          the table's columns
private  javax.swing.table.TableColumnModel tcm
          The TableColumnModel of the JTable.
private  javax.swing.table.TableModel tm
          The TableModel of the JTable.
private  boolean toggleadjust
          Internal flag: Do the adjustment?
static int WIDTHOFFSET
          Offset for computed column width.
 
Constructor Summary
private TableCellSizeAdjustor(javax.swing.JTable jtx, int mode, boolean checkeditorx, boolean checkheaderx)
          "Real" constructor of the class.
 
Method Summary
private  int adjustColumnPart(int firstrow, int lastrow, int column)
          Adjust the part of a column.
private  int adjustCompleteColumn(int column)
          Adjusts a complete column including header
private  void adjustFillingColumns(boolean recalcfixedwidth)
          Adjusts the columns which are defined as "filling", i.e. get the rest of the space.
static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt)
          Creates new Adjustor for width and height, puts it to table, returns it.
static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt, boolean checkeditorx)
          Creates new Adjustor for width and height, puts it to table, returns it.
static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt, int mode)
          Creates new Adjustor with given adjustments, puts it to table, returns it.
static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt, int mode, boolean checkeditorx)
          Creates new Adjustor with given adjustments, puts it to table, returns it.
static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt, int mode, boolean checkeditorx, boolean chn)
          Creates new Adjustor with given adjustments, puts it to table, returns it.
private  int collectHeights()
          Collect height values for all columns.
 void columnAdded(javax.swing.event.TableColumnModelEvent e)
          From TableColumnModelListener.
 void columnMarginChanged(javax.swing.event.ChangeEvent e)
          From TableColumnModelListener.
 void columnMoved(javax.swing.event.TableColumnModelEvent e)
          From TableColumnModelListener.
 void columnRemoved(javax.swing.event.TableColumnModelEvent e)
          From TableColumnModelListener.
 void columnSelectionChanged(javax.swing.event.ListSelectionEvent e)
          From TableColumnModelListener.
private  void finishSingleAdjustment(int instr, int column)
          Performs the real adjustment for one column after calculations have been done.
private  void handleCellRenderer(int col, javax.swing.table.TableCellRenderer tcr)
          Special handling of renderers which handle multi line rendering or give special hints to cell height
private  void initArrays()
          Init internal storages.
private  void insertAJI(TableCellSizeAdjustor.AdjustmentInstruction aji)
          Insert a new AdjustmentInstruction into the vector.
 boolean isEnabled()
          Return enabling state.
 void preferredTableRowHeightChange(TableRowHeightEvent e)
          From TableRowHeightListener: preferred height has changed somewhere.
 void propertyChange(java.beans.PropertyChangeEvent evt)
          From PropertyChangeListener to the JTable.
 void reBindListeners()
          Deprecated. Adjustor listens on its own for model changes and rebinds itself internally.
private  void rebindToColumnModel()
          Rebinds the adjustor to the table's column model.
private  void rebindToModel()
          Rebinds the adjustor to the table's model.
private  void runAdjustment()
          Main method of adjustment performance.
 void setEnabled(boolean ex)
          Enable and disable adjustor.
 void setLockedColumns(QuickIntArray qia)
          Set the columns which should not be changed in width.
 void setReadjustFraction(int dividentx, int divisorx)
          change the "complete readjustment" fraction.
private  void setTableRowHeight()
           
private  void setTableRowHeight(int row)
           
private  void shiftIndices(int begin, int offset)
          Helper method to shift indices on insertion or deletion of rows.
 void stateChanged(javax.swing.event.ChangeEvent e)
          From ChangeListener for the JViewport Notices the adjustor of size changes in the JViewport
 void tableChanged(javax.swing.event.TableModelEvent e)
          From TableModelListener.
 void tableRowHeightChange(TableRowHeightEvent e)
          From TableRowHeightListener: row height has changed.
 void tableRowHeightDropCache(TableRowHeightEvent e)
          From TableRowHeightListener: all known row height information is dropped.
 void toggleAdjustment()
          Inserts a call for runAdjustment() into the GUI Event Queue.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

ADJUST_WIDTH

public static final int ADJUST_WIDTH
Constant for creation method: adjust only the width of the cells.

See Also:
Constant Field Values

ADJUST_HEIGHT

public static final int ADJUST_HEIGHT
Constant for creation method: adjust only the height of the cells.

See Also:
Constant Field Values

ADJUST_BOTH

public static final int ADJUST_BOTH
Constant for creation method: adjust width and height of the cells. This is the default.

See Also:
Constant Field Values

ADJUST_HEIGHT_GLOBALLY

public static final int ADJUST_HEIGHT_GLOBALLY
Constant for creation method: adjust height globally, i.e. all cells get height of highest one

See Also:
Constant Field Values

ADJUST_BOTH_HEIGHT_GLOBALLY

public static final int ADJUST_BOTH_HEIGHT_GLOBALLY
Constant for creation method: adjust widths and heights of cells, handle heights globally.

See Also:
Constant Field Values

WIDTHOFFSET

public static final int WIDTHOFFSET
Offset for computed column width. Looks better if some pixels wider than absolutely needed.

See Also:
Constant Field Values

RESIZECOMPLETELY

private static final int RESIZECOMPLETELY
internal constant: recalculate column sizes with respect to all cells

See Also:
Constant Field Values

SETHEIGHT

private static final int SETHEIGHT
internal constant: take maximum height of currently handled column into consideration to be new maximum height

See Also:
Constant Field Values

SETWIDTH

private static final int SETWIDTH
internal constant: set width of currently handled column

See Also:
Constant Field Values

SETBOTH

private static final int SETBOTH
internal constant: use width and height of last computation

See Also:
Constant Field Values

DONOTHING

private static final int DONOTHING
internal constant: no new maximum values found in last computation

See Also:
Constant Field Values

ROWMAX

private static final java.lang.Integer ROWMAX
internal constant: maximum value for row height cache


jt

private javax.swing.JTable jt
The JTable this Adjustor is working on.


tm

private javax.swing.table.TableModel tm
The TableModel of the JTable.


tcm

private javax.swing.table.TableColumnModel tcm
The TableColumnModel of the JTable.


adjustwidth

private boolean adjustwidth
Internal flag: Adjust width?


adjustheight

private boolean adjustheight
Internal flag: Adjust height?


adjustheightglobally

private boolean adjustheightglobally
Internal flag: Adjust height globally? adjustheight must also be set to make this work


toggleadjust

private boolean toggleadjust
Internal flag: Do the adjustment?


checkeditor

private boolean checkeditor
Internal flag: Adjust by CellEditor size?


enabled

private boolean enabled
Flag: adjustor enabled?


postponeadjustment

private boolean postponeadjustment
Internal flag: Are there any postponed adjustments due to disabling?


maxwidth

private int[] maxwidth
maximum needed width for columns


maxwidthidx

private int[] maxwidthidx
row index of widest entry in column


maxheight

private int[] maxheight
maximum needed height for columns


maxheightidx

private int[] maxheightidx
row index of heighest entry in column


tablecolumn

private javax.swing.table.TableColumn[] tablecolumn
the table's columns


maxrow

private int maxrow
maximum handled row index so far (for optimisation of inserts at the end)


allmaxheight

private int allmaxheight
maximum height for all rows


columncount

private int columncount
column count


recalccompletely

private boolean recalccompletely
flag: Everything must be calculated


ajis

private java.util.List ajis
List of adjustment instructions


divident

private int divident
fraction of change for maximum value to shrink before column size is recalculated completely


divisor

private int divisor
fraction of change for maximum value to shrink before column size is recalculated completely


headerrenderer

private javax.swing.table.TableCellRenderer headerrenderer
Compatibility code for Java 1.3


parentviewport

private javax.swing.JViewport parentviewport
Viewport containing the table. Needed for fillingcolumns feature.


fixedwidth

private int fixedwidth
Cumulated width of all automatically sized rows


fillingcolumns

private QuickIntArray fillingcolumns
Index of row to be resized so that the viewport is completely filled up.


lockedcolumns

private QuickIntArray lockedcolumns
Index of rows to be left alone regarding width, i.e. NOT resized


rowheightstorage

private TableCellSizeAdjustor.RowHeightStorage rowheightstorage
Storage for row heights of dynamic cells


rowheightproviders

private java.util.Set rowheightproviders
Set with row height providers the cell size adjustor listens to


checkheader

private boolean checkheader
Change by msouthern 10-Mar-04: use column header names in column width calculations

Constructor Detail

TableCellSizeAdjustor

private TableCellSizeAdjustor(javax.swing.JTable jtx,
                              int mode,
                              boolean checkeditorx,
                              boolean checkheaderx)
"Real" constructor of the class. Private by design. Table is set into AUTO_RESIZE_OFF mode, models are received, listeners installed.

Change by msouthern 10-Mar-04: use column header names in column width calculations

Method Detail

adjustorForTable

public static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt)
Creates new Adjustor for width and height, puts it to table, returns it. Size adjustment is done on the base of the renderer objects. Header sizes are taken into respect. Note: Do not use this if the table contains MultiLine-rendered columns. TableCellSizeAdjustor must not fiddle with the row heights in this case!


adjustorForTable

public static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt,
                                                     int mode)
Creates new Adjustor with given adjustments, puts it to table, returns it. Size adjustment is done on the base of the renderer objects. Header sizes are taken into respect.


adjustorForTable

public static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt,
                                                     boolean checkeditorx)
Creates new Adjustor for width and height, puts it to table, returns it. Size adjustment is done either on the base of the renderer objects (bex=false) or on the base of the editor objects (bex=true). Header sizes are taken into respect. Note: Do not use this if the table contains MultiLine-rendered columns. TableCellSizeAdjustor must not fiddle with the row heights in this case!


adjustorForTable

public static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt,
                                                     int mode,
                                                     boolean checkeditorx)
Creates new Adjustor with given adjustments, puts it to table, returns it. Size adjustment is done either on the base of the renderer objects (bex=false) or on the base of the editor objects (bex=true). Header sizes are taken into respect.


adjustorForTable

public static TableCellSizeAdjustor adjustorForTable(javax.swing.JTable jt,
                                                     int mode,
                                                     boolean checkeditorx,
                                                     boolean chn)
Creates new Adjustor with given adjustments, puts it to table, returns it. Size adjustment is done either on the base of the renderer objects (bex=false) or on the base of the editor objects (bex=true). Header sizes are taken into respect if chn==true. (added by msouthern 10-Mar-04)


reBindListeners

public void reBindListeners()
Deprecated. Adjustor listens on its own for model changes and rebinds itself internally.

Rebinds the listeners to the table's models. Must be called after any replacement of the table's TableModel or TableColumnModel. TableCellSizeAdjustor must be listener to events of these model objects.


rebindToModel

private void rebindToModel()
Rebinds the adjustor to the table's model. That one is needed for obtaining knowledge of data changes.


rebindToColumnModel

private void rebindToColumnModel()
Rebinds the adjustor to the table's column model. Needed to learn about addition/removal of columns


setReadjustFraction

public void setReadjustFraction(int dividentx,
                                int divisorx)
change the "complete readjustment" fraction. If the widest (or highest) cell in a column shrinks, one has to think about shrinking the whole column. As only the maximum width of each column is stored, recalculation is difficult in this case. In fact, there is no other way than calculating the maximum width of each cell in the column. As this step might be somehow time-consuming, it is not preformed everytime the widest column shrinks but only if it shrinks below a certain threshold level. That level is defined to be the oldest maximum width multiplied with the fraction passed to this method. So, after calling setReadjustFactor(2,3) complete recalculation of a column would only occur if the widest (or highest) element shrinks below two thirds of its old width (or height).

The default value for the fraction is three fourth (3/4).


setLockedColumns

public void setLockedColumns(QuickIntArray qia)
Set the columns which should not be changed in width. All columns given here are handled as no-go. Even if content in these columns change, they are *NOT* resized. If the user does any changes on these columns' size, this is simply taken as a fact. Passing null removes all locked columns. If a fillingcolumn is also locked, locking wins. I.e. the filling column is not resized any more and on the other hand taken into consideration when it comes to any other filling columns' size.

Parameters:
qia - Array of columns not to resize. Null to remove all non-resizing.

tableChanged

public void tableChanged(javax.swing.event.TableModelEvent e)
From TableModelListener. We adjust cells every time something is inserted or updated.

Specified by:
tableChanged in interface javax.swing.event.TableModelListener

columnAdded

public void columnAdded(javax.swing.event.TableColumnModelEvent e)
From TableColumnModelListener. Tells listeners that a column was added to the model. We try to readjust in this case.

Specified by:
columnAdded in interface javax.swing.event.TableColumnModelListener

columnRemoved

public void columnRemoved(javax.swing.event.TableColumnModelEvent e)
From TableColumnModelListener. Tells listeners that a column was removed from the model. We try to readjust in this case.

Specified by:
columnRemoved in interface javax.swing.event.TableColumnModelListener

columnMoved

public void columnMoved(javax.swing.event.TableColumnModelEvent e)
From TableColumnModelListener. Tells listeners that a column was repositioned. We do nothing in this case.

Specified by:
columnMoved in interface javax.swing.event.TableColumnModelListener

columnMarginChanged

public void columnMarginChanged(javax.swing.event.ChangeEvent e)
From TableColumnModelListener. Tells listeners that a column was moved due to a margin change. We do nothing in this case.

Specified by:
columnMarginChanged in interface javax.swing.event.TableColumnModelListener

columnSelectionChanged

public void columnSelectionChanged(javax.swing.event.ListSelectionEvent e)
From TableColumnModelListener. Tells listeners that the selection model of the TableColumnModel changed. We do nothing in this case.

Specified by:
columnSelectionChanged in interface javax.swing.event.TableColumnModelListener

stateChanged

public void stateChanged(javax.swing.event.ChangeEvent e)
From ChangeListener for the JViewport Notices the adjustor of size changes in the JViewport

Specified by:
stateChanged in interface javax.swing.event.ChangeListener

propertyChange

public void propertyChange(java.beans.PropertyChangeEvent evt)
From PropertyChangeListener to the JTable. Notices the adjustor of property changes in the table (new model, new column model...)

Specified by:
propertyChange in interface java.beans.PropertyChangeListener

preferredTableRowHeightChange

public void preferredTableRowHeightChange(TableRowHeightEvent e)
From TableRowHeightListener: preferred height has changed somewhere. Follow change request if feasible

Specified by:
preferredTableRowHeightChange in interface TableRowHeightListener

tableRowHeightChange

public void tableRowHeightChange(TableRowHeightEvent e)
From TableRowHeightListener: row height has changed. Unused.

Specified by:
tableRowHeightChange in interface TableRowHeightListener

tableRowHeightDropCache

public void tableRowHeightDropCache(TableRowHeightEvent e)
From TableRowHeightListener: all known row height information is dropped. Clear caches internally

Specified by:
tableRowHeightDropCache in interface TableRowHeightListener

toggleAdjustment

public void toggleAdjustment()
Inserts a call for runAdjustment() into the GUI Event Queue. This method is the final step of each event handling (and can also be called directly). It places a Runnable in the AWT event queue which performs the actual table adjustment. The placement is only done if there has not yet been placed such Runnable which has not been executed yet.

Note that should call this method only from within the AWT event handling thread itself and that such a call should normally not be needed anyhow as the table and its model should generate appropriate events on changes that affect the TableCellSizeAdjustor.


setEnabled

public void setEnabled(boolean ex)
Enable and disable adjustor. Disabled adjustors do not do any adjustments, but they remember any adjustments that became needed during the disabling period. If any adjustments are needed, an adjustment is done immideately after re-enabling.


isEnabled

public boolean isEnabled()
Return enabling state.


shiftIndices

private void shiftIndices(int begin,
                          int offset)
Helper method to shift indices on insertion or deletion of rows.


insertAJI

private void insertAJI(TableCellSizeAdjustor.AdjustmentInstruction aji)
Insert a new AdjustmentInstruction into the vector. This method tries to combine several instructions.


runAdjustment

private void runAdjustment()
Main method of adjustment performance. This method is called from the AWT event handling thread to perform the adjustment. First, it decides whether a complete recalculation of everything has to take place. If not, it steps through the adjustment instructions and performs the appropriate steps.


setTableRowHeight

private void setTableRowHeight(int row)

setTableRowHeight

private void setTableRowHeight()

finishSingleAdjustment

private void finishSingleAdjustment(int instr,
                                    int column)
Performs the real adjustment for one column after calculations have been done. Note that this method might get the instruction "RESIZECOMPLETELY" in which case it performs a complete column adjustment itself.


adjustFillingColumns

private void adjustFillingColumns(boolean recalcfixedwidth)
Adjusts the columns which are defined as "filling", i.e. get the rest of the space.

This method is always called if any other columns have been resized or the size of the viewport has changed.

Parameters:
recalcfixedwidth - indicates whether width of all other rows has to be recalculated

collectHeights

private int collectHeights()
Collect height values for all columns. Cell height is adjusted for the complete table. Therefore, the height is computed as the maximum of the required column heights.


handleCellRenderer

private void handleCellRenderer(int col,
                                javax.swing.table.TableCellRenderer tcr)
Special handling of renderers which handle multi line rendering or give special hints to cell height


initArrays

private void initArrays()
Init internal storages. This step has to be performed after structural changes of the table, most notably insertion or deletion of columns. Note that the TableCellSizeAdjustor readjusts the whole table in this case and does not perform any optimisations.


adjustCompleteColumn

private int adjustCompleteColumn(int column)
Adjusts a complete column including header


adjustColumnPart

private int adjustColumnPart(int firstrow,
                             int lastrow,
                             int column)
Adjust the part of a column. The "heart" of the whole object. Actual computation of cell sizes is done in this very routine. To do this, this method passes every value of the wanted part of the column to the appropriate TableCellRenderer or TableCellEditor and stores the highest preferredSize().width and .height it receives.

Note that this methods works on the internal fields of the object rather than passing any parameters forth and back. It does however return a handling instruction informing about any changes that have occured.


QJCC homepage