001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2005, Institut de Recherche pour le Développement
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: package org.geotools.gui.swing.image;
018:
019: // J2SE dependencies
020: import java.awt.Color;
021: import java.awt.Dimension;
022: import java.awt.Graphics;
023: import java.awt.GridBagConstraints;
024: import java.awt.GridBagLayout;
025: import java.awt.image.DataBuffer;
026: import java.awt.image.RenderedImage;
027: import java.awt.image.SampleModel;
028: import java.text.NumberFormat;
029: import javax.swing.BorderFactory;
030: import javax.swing.JLabel;
031: import javax.swing.JPanel;
032: import javax.swing.JScrollPane;
033: import javax.swing.JSpinner;
034: import javax.swing.JTable;
035: import javax.swing.SpinnerNumberModel;
036: import javax.swing.event.ChangeEvent;
037: import javax.swing.event.ChangeListener;
038: import javax.swing.event.ListSelectionEvent;
039: import javax.swing.event.ListSelectionListener;
040: import javax.swing.table.TableColumn;
041: import javax.swing.table.TableColumnModel;
042: import javax.swing.table.AbstractTableModel;
043: import javax.swing.table.DefaultTableCellRenderer;
044:
045: // Geotools dependencies
046: import org.geotools.resources.Utilities;
047: import org.geotools.resources.i18n.Vocabulary;
048: import org.geotools.resources.i18n.VocabularyKeys;
049:
050: /**
051: * Display the image sample values as a table. This panel includes a field for band selection
052: * and scroll bars for the table.
053: *
054: * @since 2.3
055: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/widgets-swing/src/main/java/org/geotools/gui/swing/image/ImageSampleValues.java $
056: * @version $Id: ImageSampleValues.java 20883 2006-08-07 13:48:09Z jgarnett $
057: * @author Martin Desruisseaux
058: *
059: * @see ImageTableModel
060: */
061: public class ImageSampleValues extends JPanel {
062: /**
063: * The table which contains sample values.
064: */
065: private final JTable table;
066:
067: /**
068: * The cell renderer for sample values.
069: */
070: private final CellRenderer renderer;
071:
072: /**
073: * The model for band selection.
074: */
075: private final SpinnerNumberModel band;
076:
077: /**
078: * An empty component for now. May contains geographic coordinates in a future version.
079: * This is the only component in the "status bar" with a variable width.
080: */
081: private final JLabel comments;
082:
083: /**
084: * The color for the selected cell.
085: */
086: private final CurrentColor current;
087:
088: /**
089: * The table for displaying row headers.
090: */
091: private static final class RowHeaders extends JTable {
092: /** The table which contains sample values. */
093: private final JTable table;
094:
095: /** Creates new row headers for the specified table. */
096: public RowHeaders(final ImageTableModel model,
097: final JTable table) {
098: super (model.new RowHeaders());
099: this .table = table;
100: final TableColumn column = getColumnModel().getColumn(0);
101: column.setCellRenderer(table.getTableHeader()
102: .getDefaultRenderer());
103: column.setPreferredWidth(50);
104: setPreferredScrollableViewportSize(getPreferredSize());
105: }
106:
107: /** Returns the row height, making sure it is identical to the main table. */
108: public int getRowHeight(final int row) {
109: return table.getRowHeight(row);
110: }
111: }
112:
113: /**
114: * The cell renderer for pixel values.
115: */
116: private static final class CellRenderer extends
117: DefaultTableCellRenderer {
118: /** The formatter for sample values, to be updated for each new image. */
119: NumberFormat formatter;
120:
121: /** Constructs a cell renderer. */
122: public CellRenderer() {
123: setHorizontalAlignment(RIGHT);
124: }
125:
126: /** Format a cell value. */
127: public void setValue(final Object value) {
128: final String text;
129: if (value == null)
130: text = "";
131: else if (formatter == null)
132: text = value.toString();
133: else
134: text = formatter.format(value);
135: setText(text);
136: }
137: }
138:
139: /**
140: * The component responsible for drawing the color for the selected cell.
141: * Also a listener for various events of interest for the enclosing class.
142: */
143: private final class CurrentColor extends JPanel implements
144: ChangeListener, ListSelectionListener {
145: /** The color to be displayed by this component. */
146: private Color color;
147:
148: /** Fills this component with a color inferred from the currently selected cell. */
149: public void paintComponent(final Graphics graphics) {
150: if (color == null) {
151: super .paintComponent(graphics);
152: return;
153: }
154: final Color oldColor = graphics.getColor();
155: graphics.setColor(color);
156: graphics.fillRect(0, 0, getWidth(), getHeight());
157: graphics.setColor(oldColor);
158: }
159:
160: /** Invoked when a new cell is selected. */
161: public void valueChanged(final ListSelectionEvent event) {
162: if (!event.getValueIsAdjusting()) {
163: final ImageTableModel samples = (ImageTableModel) table
164: .getModel();
165: final Color c = samples.getColorAt(table
166: .getSelectedRow(), table.getSelectedColumn());
167: if (!Utilities.equals(c, color)) {
168: color = c;
169: repaint();
170: }
171: }
172: }
173:
174: /** Invoked when the band changed. */
175: public void stateChanged(final ChangeEvent event) {
176: final ImageTableModel samples = (ImageTableModel) table
177: .getModel();
178: samples.setBand(band.getNumber().intValue() - 1);
179: }
180: }
181:
182: /**
183: * Creates a new table without initial image to display.
184: */
185: public ImageSampleValues() {
186: super (new GridBagLayout());
187:
188: // Prepares the component showing comments (not yet used).
189: comments = new JLabel();
190:
191: // Prepares the component showing the selected color.
192: current = new CurrentColor();
193: current.setBorder(BorderFactory.createLoweredBevelBorder());
194: Dimension size = new Dimension(current.getMinimumSize());
195: size.width = 60;
196: current.setMinimumSize(size);
197: current.setPreferredSize(size);
198:
199: // Prepares the table of sample values.
200: final ImageTableModel model = new ImageTableModel();
201: renderer = new CellRenderer();
202: table = new JTable(model);
203: table.setDefaultRenderer(Float.class, null); // Remove JTable default renderer.
204: table.setDefaultRenderer(Double.class, null); // Remove JTable default renderer.
205: table.setDefaultRenderer(Number.class, renderer); // Use same renderer for all numbers.
206: table.setCellSelectionEnabled(true);
207: table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
208: table.getSelectionModel().addListSelectionListener(current);
209: table.getColumnModel().getSelectionModel()
210: .addListSelectionListener(current);
211:
212: // Prepares the scroll pane for the previous table, including row headers.
213: final JScrollPane scroll = new JScrollPane(table);
214: scroll.setRowHeaderView(new RowHeaders(model, table));
215:
216: // Prepares the component for selecting the band.
217: band = new SpinnerNumberModel(1, 1, 1, 1);
218: final JSpinner spinner = new JSpinner(band);
219: ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField()
220: .setColumns(3);
221: band.addChangeListener(current);
222:
223: // Places all components on the panel.
224: final Vocabulary resources = Vocabulary
225: .getResources(getDefaultLocale());
226: final GridBagConstraints c = new GridBagConstraints();
227: c.gridy = 1;
228: c.insets.bottom = 6;
229: c.gridx = 0;
230: c.insets.left = 9;
231: add(new JLabel(resources.getLabel(VocabularyKeys.BAND)), c);
232: c.gridx = 1;
233: c.insets.left = 0;
234: add(spinner, c);
235: c.fill = c.BOTH;
236: c.gridx = 3;
237: c.insets.right = 9;
238: add(current, c);
239: c.gridx = 2;
240: c.weightx = 1;
241: c.insets.left = c.insets.right = 15;
242: add(comments, c);
243: c.gridx = 0;
244: c.weighty = 1;
245: c.gridwidth = c.REMAINDER;
246: c.gridy = 0;
247: c.insets.left = c.insets.right = 0;
248: ;
249: add(scroll, c);
250: }
251:
252: /**
253: * Creates a new table that will display the sample values for the specified image.
254: */
255: public ImageSampleValues(final RenderedImage image) {
256: this ();
257: setImage(image);
258: }
259:
260: /**
261: * Set the rendered image to display.
262: */
263: public void setImage(final RenderedImage image) {
264: final ImageTableModel samples = (ImageTableModel) table
265: .getModel();
266: final boolean isFirst = (samples.getRenderedImage() == null);
267: samples.setRenderedImage(image);
268: renderer.formatter = samples.getNumberFormat();
269: final SampleModel model = image.getSampleModel();
270: final int numBands = model.getNumBands();
271: final Integer maximum = new Integer(numBands);
272: if (band.getNumber().intValue() >= numBands) {
273: band.setValue(maximum);
274: }
275: band.setMaximum(maximum);
276: /*
277: * Once the spinner is updated, adjusts the columns width. However, we will perform this
278: * task only for the first image to be displayed. For all others, we will preserve the
279: * previous widths (which may have been adjusted by the user).
280: */
281: if (isFirst && model.getDataType() == DataBuffer.TYPE_BYTE) {
282: final TableColumnModel columns = table.getColumnModel();
283: for (int i = columns.getColumnCount(); --i >= 0;) {
284: final TableColumn column = columns.getColumn(i);
285: column.setPreferredWidth(40);
286: }
287: }
288: }
289: }
|