/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.gui.swing.image;
// J2SE dependencies
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.image.DataBuffer;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.text.NumberFormat;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
// Geotools dependencies
import org.geotools.resources.Utilities;
import org.geotools.resources.i18n.Vocabulary;
import org.geotools.resources.i18n.VocabularyKeys;
/**
* Display the image sample values as a table. This panel includes a field for band selection
* and scroll bars for the table.
*
* @since 2.3
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (IRD)
*
* @see ImageTableModel
*/
public class ImageSampleValues extends JPanel {
/**
* The table which contains sample values.
*/
private final JTable table;
/**
* The cell renderer for sample values.
*/
private final CellRenderer renderer;
/**
* The model for band selection.
*/
private final SpinnerNumberModel band;
/**
* An empty component for now. May contains geographic coordinates in a future version.
* This is the only component in the "status bar" with a variable width.
*/
private final JLabel comments;
/**
* The color for the selected cell.
*/
private final CurrentColor current;
/**
* The table for displaying row headers.
*/
private static final class RowHeaders extends JTable {
/** The table which contains sample values. */
private final JTable table;
/** Creates new row headers for the specified table. */
public RowHeaders(final ImageTableModel model, final JTable table) {
super(model.new RowHeaders());
this.table = table;
final TableColumn column = getColumnModel().getColumn(0);
column.setCellRenderer(table.getTableHeader().getDefaultRenderer());
column.setPreferredWidth(50);
setPreferredScrollableViewportSize(getPreferredSize());
}
/** Returns the row height, making sure it is identical to the main table. */
public int getRowHeight(final int row) {
return table.getRowHeight(row);
}
}
/**
* The cell renderer for pixel values.
*/
private static final class CellRenderer extends DefaultTableCellRenderer {
/** The formatter for sample values, to be updated for each new image. */
NumberFormat formatter;
/** Constructs a cell renderer. */
public CellRenderer() {
setHorizontalAlignment(RIGHT);
}
/** Format a cell value. */
public void setValue(final Object value) {
final String text;
if (value == null) text = "";
else if (formatter == null) text = value.toString();
else text = formatter.format(value);
setText(text);
}
}
/**
* The component responsible for drawing the color for the selected cell.
* Also a listener for various events of interest for the enclosing class.
*/
private final class CurrentColor extends JPanel implements ChangeListener, ListSelectionListener {
/** The color to be displayed by this component. */
private Color color;
/** Fills this component with a color inferred from the currently selected cell. */
public void paintComponent(final Graphics graphics) {
if (color == null) {
super.paintComponent(graphics);
return;
}
final Color oldColor = graphics.getColor();
graphics.setColor(color);
graphics.fillRect(0, 0, getWidth(), getHeight());
graphics.setColor(oldColor);
}
/** Invoked when a new cell is selected. */
public void valueChanged(final ListSelectionEvent event) {
if (!event.getValueIsAdjusting()) {
final ImageTableModel samples = (ImageTableModel) table.getModel();
final Color c=samples.getColorAt(table.getSelectedRow(), table.getSelectedColumn());
if (!Utilities.equals(c, color)) {
color = c;
repaint();
}
}
}
/** Invoked when the band changed. */
public void stateChanged(final ChangeEvent event) {
final ImageTableModel samples = (ImageTableModel) table.getModel();
samples.setBand(band.getNumber().intValue() - 1);
}
}
/**
* Creates a new table without initial image to display.
*/
public ImageSampleValues() {
super(new GridBagLayout());
// Prepares the component showing comments (not yet used).
comments = new JLabel();
// Prepares the component showing the selected color.
current = new CurrentColor();
current.setBorder(BorderFactory.createLoweredBevelBorder());
Dimension size = new Dimension(current.getMinimumSize());
size.width = 60;
current.setMinimumSize(size);
current.setPreferredSize(size);
// Prepares the table of sample values.
final ImageTableModel model = new ImageTableModel();
renderer = new CellRenderer();
table = new JTable(model);
table.setDefaultRenderer(Float .class, null); // Remove JTable default renderer.
table.setDefaultRenderer(Double.class, null); // Remove JTable default renderer.
table.setDefaultRenderer(Number.class, renderer); // Use same renderer for all numbers.
table.setCellSelectionEnabled(true);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getSelectionModel().addListSelectionListener(current);
table.getColumnModel().getSelectionModel().addListSelectionListener(current);
// Prepares the scroll pane for the previous table, including row headers.
final JScrollPane scroll = new JScrollPane(table);
scroll.setRowHeaderView(new RowHeaders(model, table));
// Prepares the component for selecting the band.
band = new SpinnerNumberModel(1, 1, 1, 1);
final JSpinner spinner = new JSpinner(band);
((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().setColumns(3);
band.addChangeListener(current);
// Places all components on the panel.
final Vocabulary resources = Vocabulary.getResources(getDefaultLocale());
final GridBagConstraints c = new GridBagConstraints();
c.gridy=1; c.insets.bottom=6;
c.gridx=0; c.insets.left =9; add(new JLabel(resources.getLabel(VocabularyKeys.BAND)), c);
c.gridx=1; c.insets.left =0; add(spinner, c); c.fill=c.BOTH;
c.gridx=3; c.insets.right=9; add(current, c);
c.gridx=2; c.weightx=1;
c.insets.left = c.insets.right = 15; add(comments, c);
c.gridx=0; c.weighty=1; c.gridwidth=c.REMAINDER;
c.gridy=0; c.insets.left = c.insets.right = 0;;
add(scroll, c);
}
/**
* Creates a new table that will display the sample values for the specified image.
*/
public ImageSampleValues(final RenderedImage image) {
this();
setImage(image);
}
/**
* Set the rendered image to display.
*/
public void setImage(final RenderedImage image) {
final ImageTableModel samples = (ImageTableModel) table.getModel();
final boolean isFirst = (samples.getRenderedImage() == null);
samples.setRenderedImage(image);
renderer.formatter = samples.getNumberFormat();
final SampleModel model = image.getSampleModel();
final int numBands = model.getNumBands();
final Integer maximum = new Integer(numBands);
if (band.getNumber().intValue() >= numBands) {
band.setValue(maximum);
}
band.setMaximum(maximum);
/*
* Once the spinner is updated, adjusts the columns width. However, we will perform this
* task only for the first image to be displayed. For all others, we will preserve the
* previous widths (which may have been adjusted by the user).
*/
if (isFirst && model.getDataType() == DataBuffer.TYPE_BYTE) {
final TableColumnModel columns = table.getColumnModel();
for (int i=columns.getColumnCount(); --i>=0;) {
final TableColumn column = columns.getColumn(i);
column.setPreferredWidth(40);
}
}
}
}