osd-contiki/tools/cooja/java/se/sics/cooja/dialogs/TableColumnAdjuster.java

341 lines
11 KiB
Java
Raw Normal View History

/*
* Copyright (c) 2009, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: TableColumnAdjuster.java,v 1.1 2009/06/12 14:12:59 nifi Exp $
*
* -----------------------------------------------------------------
*
* Author : Niclas Finne
* Created : 2009-05-20
* Updated : $Date: 2009/06/12 14:12:59 $
* $Revision: 1.1 $
*/
package se.sics.cooja.dialogs;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
/**
* This code was originally based on a Java tip from Rob Camick at
* Java Tips Weblog, http://tips4java.wordpress.com.
*/
public class TableColumnAdjuster implements PropertyChangeListener, TableModelListener {
private final JTable table;
private int spacing;
private boolean isColumnHeaderIncluded;
private boolean isColumnDataIncluded;
private boolean isOnlyAdjustLarger;
private boolean isDynamicAdjustment;
/*
* Specify the table and use default spacing
*/
public TableColumnAdjuster(JTable table) {
this(table, 6);
}
/*
* Specify the table and spacing
*/
public TableColumnAdjuster(JTable table, int spacing) {
this.table = table;
this.spacing = spacing;
setColumnHeaderIncluded(true);
setColumnDataIncluded(true);
setOnlyAdjustLarger(true);
setDynamicAdjustment(false);
}
public void packColumns() {
TableColumnModel tcm = table.getColumnModel();
for (int i = 0, n = tcm.getColumnCount(); i < n; i++) {
packColumn(i);
}
}
public void packColumn(final int column) {
adjustColumn(column, false);
}
/*
* Adjust the widths of all the columns in the table
*/
public void adjustColumns() {
TableColumnModel tcm = table.getColumnModel();
for (int i = 0, n = tcm.getColumnCount(); i < n; i++) {
adjustColumn(i, isOnlyAdjustLarger);
}
}
/*
* Adjust the width of the specified column in the table
*/
public void adjustColumn(int column) {
adjustColumn(column, isOnlyAdjustLarger);
}
private void adjustColumn(int column, boolean onlyAdjustLarger) {
int viewColumn = table.convertColumnIndexToView(column);
if (viewColumn < 0) {
return;
}
TableColumn tableColumn = table.getColumnModel().getColumn(viewColumn);
if (! tableColumn.getResizable()) {
return;
}
int columnHeaderWidth = getColumnHeaderWidth(tableColumn, column);
int columnDataWidth = getColumnDataWidth(tableColumn, column);
int preferredWidth = Math.max(columnHeaderWidth, columnDataWidth);
updateTableColumn(tableColumn, preferredWidth, onlyAdjustLarger);
}
/*
* Calculate the width based on the column name
*/
private int getColumnHeaderWidth(TableColumn tableColumn, int column) {
if (! isColumnHeaderIncluded) return 0;
Object value = tableColumn.getHeaderValue();
TableCellRenderer renderer = tableColumn.getHeaderRenderer();
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
Component c = renderer.getTableCellRendererComponent(table, value, false, false, -1, column);
return c.getPreferredSize().width;
}
/*
* Calculate the width based on the widest cell renderer for the
* given column.
*/
private int getColumnDataWidth(TableColumn tableColumn, int column) {
if (! isColumnDataIncluded) return 0;
int preferredWidth = 0;
int maxWidth = tableColumn.getMaxWidth();
for (int row = 0, n = table.getRowCount(); row < n; row++) {
preferredWidth = Math.max(preferredWidth, getCellDataWidth(row, column));
// We've exceeded the maximum width, no need to check other rows
if (preferredWidth >= maxWidth) {
break;
}
}
return preferredWidth;
}
/*
* Get the preferred width for the specified cell
*/
private int getCellDataWidth(int row, int column) {
// Invoke the renderer for the cell to calculate the preferred width
TableCellRenderer cellRenderer = table.getCellRenderer(row, column);
Object value = table.getModel().getValueAt(row, column);
Component c = cellRenderer.getTableCellRendererComponent(table, value, false, false, row, column);
int width = c.getPreferredSize().width + table.getIntercellSpacing().width;
return width;
}
/*
* Update the TableColumn with the newly calculated width
*/
private void updateTableColumn(TableColumn tableColumn, int width, boolean onlyAdjustLarger) {
int currentWidth = tableColumn.getWidth();
width += spacing;
// Don't shrink the column width if onlyAdjustLarger is set
if (width != currentWidth && (!onlyAdjustLarger || width > currentWidth)) {
table.getTableHeader().setResizingColumn(tableColumn);
tableColumn.setWidth(width);
tableColumn.setPreferredWidth(width);
}
}
private void adjustColumnsForNewRows(int firstRow, int lastRow) {
TableColumnModel tcm = table.getColumnModel();
for (int column = 0, n = tcm.getColumnCount(); column < n; column++) {
int viewColumn = table.convertColumnIndexToView(column);
if (viewColumn < 0) {
continue;
}
TableColumn tableColumn = tcm.getColumn(viewColumn);
if (! tableColumn.getResizable()) {
continue;
}
// Find max width for the new rows (only adjust if wider)
int width = 0;
for (int row = firstRow; row <= lastRow; row++) {
int w = getCellDataWidth(row, column);
if (w > width) {
width = w;
}
}
updateTableColumn(tableColumn, width, true);
}
}
/*
* Indicates whether to include the header in the width calculation
*/
public void setColumnHeaderIncluded(boolean isColumnHeaderIncluded) {
this.isColumnHeaderIncluded = isColumnHeaderIncluded;
}
/*
* Indicates whether to include the model data in the width calculation
*/
public void setColumnDataIncluded(boolean isColumnDataIncluded) {
this.isColumnDataIncluded = isColumnDataIncluded;
}
/*
* Indicates whether columns can only be increased in size
*/
public void setOnlyAdjustLarger(boolean isOnlyAdjustLarger) {
this.isOnlyAdjustLarger = isOnlyAdjustLarger;
}
/*
* Indicate whether changes to the model should cause the width to be
* dynamically recalculated.
*/
public void setDynamicAdjustment(boolean isDynamicAdjustment) {
if (this.isDynamicAdjustment != isDynamicAdjustment) {
this.isDynamicAdjustment = isDynamicAdjustment;
if (isDynamicAdjustment) {
table.addPropertyChangeListener(this);
table.getModel().addTableModelListener(this);
} else {
table.removePropertyChangeListener(this);
table.getModel().removeTableModelListener(this);
}
}
}
//
// Implement the PropertyChangeListener
//
public void propertyChange(PropertyChangeEvent e) {
// When the TableModel changes we need to update the listeners
// and column widths
if ("model".equals(e.getPropertyName())) {
if (this.isDynamicAdjustment) {
TableModel model = (TableModel)e.getOldValue();
model.removeTableModelListener(this);
model = (TableModel)e.getNewValue();
model.addTableModelListener(this);
}
adjustColumns();
}
}
//
// Implement the TableModelListener
//
public void tableChanged(final TableModelEvent e) {
if (e.getType() == TableModelEvent.INSERT) {
adjustColumnsForNewRows(e.getFirstRow(), e.getLastRow());
} else if (e.getType() == TableModelEvent.UPDATE) {
int column = e.getColumn();
int lastRow = e.getLastRow();
// Last row might be set higher than the row count if all rows have
// been updated
if (lastRow >= table.getRowCount()) {
lastRow = table.getRowCount() - 1;
}
if (column == TableModelEvent.ALL_COLUMNS) {
// All columns have been updated
if (isOnlyAdjustLarger) {
int firstRow = e.getFirstRow();
if (firstRow >= 0) {
// Handle the rows as new rows since they should only increase
// width as needed
adjustColumnsForNewRows(firstRow, lastRow);
}
} else {
// Could be an increase or decrease so check all rows, all columns
adjustColumns();
}
} else if (isOnlyAdjustLarger) {
// Only need to worry about an increase in width for these cells
int viewColumn = table.convertColumnIndexToView(column);
if (viewColumn < 0) {
// Column is not visible
} else {
TableColumn tableColumn = table.getColumnModel().getColumn(viewColumn);
if (tableColumn.getResizable()) {
int firstRow = e.getFirstRow();
int width = 0;
if (firstRow < 0) {
// Header changed
width = getColumnHeaderWidth(tableColumn, column);
} else {
for (int row = e.getFirstRow(); row <= lastRow; row++) {
int w = getCellDataWidth(row, column);
if (w > width) {
width = w;
}
}
}
updateTableColumn(tableColumn, width, true);
}
}
} else {
// Could be an increase or decrease so check all rows
adjustColumn(column, false);
}
} else {
// Some rows have been deleted.
if (!isOnlyAdjustLarger) {
adjustColumns();
}
}
}
}