/* ==============================================
* Simtools : The tools library used in JSynoptic
* ==============================================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* 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;
* either version 2.1 of the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2003, by :
* Corporate:
* Astrium SAS
* EADS CRC
* Individual:
* Nicolas Brodu
*
* $Id: ImageMapper.java,v 1.16 2008/10/23 15:53:14 ogor Exp $
*
* Changes
* -------
* 25-Sep-2003 : Initial public release (NB);
* 07-Oct-03: Implemented all edit dialogs (NB);
* 03-Nov-03 : Separated generic and color part (NB)
*
*/
package simtools.ui;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ResourceBundle;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.TableCellRenderer;
import simtools.util.CurrentPathProvider;
import simtools.util.FileSerializer;
import simtools.util.ImageSerializer;
/**
* This class maps data sources and index to images. The mapping is user
* defined, and based for example on the value of the data source For example,
* green value < 10, red above. Useful for making plots with "alarm" colors
*
* The data source shall not be saved into the object. Rather, this class goal
* is to implement a mapping independent of the data source given. The same is
* true for the images
*
*/
public class ImageMapper extends GenericMapper {
public static JFileChooser fileChooser;
static final long serialVersionUID = 3227030744000505758L;
public static ResourceBundle resources = ResourceFinder.get(ImageMapper.class);
/** The image mappers are application global */
public static Vector imageMappers;
static {
imageMappers = new Vector();
}
/**
* An optional default directory for Image Mappers
*/
public static File defaultDirectory = null;
public ImageMapper() {
super();
}
public ImageMapper(String name) {
super(name);
}
/**
* Wipe off mapper images buffer.
*/
public void wipeOff() {
for (int j = 0; j < imageMappers.size(); j++) {
ArrayList values = ((ImageMapper) imageMappers.get(j)).getAllMapperValues();
for (int i = 0; i < values.size(); i++) {
((ImageFile) values.get(i)).image = null;
}
}
}
/**
* This class is what is effectively mapped to a value or range
*/
public static class ImageFile implements Serializable {
/**
*
*/
private static final long serialVersionUID = -2345851876725741737L;
public transient BufferedImage image;
public File file;
protected String relativeFilePath;
public String toString() {
if (file == null) {
return "null";
}
return file.getName();
}
// Take care of serialisation. Special handling for images
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
// Set image file relative path from file
if (file != null) {
relativeFilePath = FileSerializer.writeIntoString(file, CurrentPathProvider.currentPathProvider
.getCurrentPath());
}
out.defaultWriteObject();
ImageSerializer.write(out, image);
}
private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException,
java.io.IOException {
in.defaultReadObject();
image = ImageSerializer.read(in);
// Get file form serialized reltive path
if (relativeFilePath != null) {
file = FileSerializer.readFromString(relativeFilePath, CurrentPathProvider.currentPathProvider
.getCurrentPath());
}
}
}
/**
* If the mapper already exists in the list, update its values Otherwise add
* it to the list of existing mappers
*
* @param m,
* the mapper to update
* @return
*/
public static ImageMapper updateImageMapper(ImageMapper m) {
ImageMapper ret = ImageMapper.getImageMapper(m.toString());
if (ret == null) {
imageMappers.add(m);
ret =m;
}
return ret;
}
/**
* Method <b>getSvgMapperFromName<\b> returns mapper linked to specified
* name return null if no mapper were found
*
* @param name
* @return
*/
public static ImageMapper getImageMapper(String id) {
if (imageMappers != null) {
for (Iterator it = imageMappers.iterator(); it.hasNext();) {
ImageMapper sm = (ImageMapper) it.next();
if ((sm.toString() != null) && (sm.toString().equals(id))) {
return sm;
}
}
}
return null;
}
/*
* The editor button that brings up the dialog. We extend DefaultCellEditor
* for convenience, even though it mean we have to create a dummy check box.
* Another approach would be to copy the implementation of TableCellEditor
* methods from the source code for DefaultCellEditor.
*/
protected static class ImageEditor extends DefaultCellEditor {
ImageFile currentImage = null;
public ImageEditor(JButton b) {
super(new JCheckBox()); // Unfortunately, the constructor
// expects a check box, combo box,
// or text field.
editorComponent = b;
setClickCountToStart(2); // This is usually 1 or 2.
// Must do this so that editing stops when appropriate.
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
protected void fireEditingStopped() {
super.fireEditingStopped();
}
public Object getCellEditorValue() {
return currentImage;
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
((JButton) editorComponent).setText(value.toString());
currentImage = (ImageFile) value;
return editorComponent;
}
}
protected static class ImageRenderer extends JLabel implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object o, boolean isSelected, boolean hasFocus,
int row, int column) {
ImageFile imf = (ImageFile) o;
if ((o == null) || (imf.file == null)) {
setText("null");
} else {
setText(imf.file.getName());
}
return this;
}
}
public MapperTableModel createModel() {
return new ImageMapperTableModel();
}
protected class ImageMappingTable extends ExpressionMappingTable {
/**
* @param dialog
*/
public ImageMappingTable(JDialog owner) {
super(owner);
}
/**
* Sets up the renderer to a color renderer
*
* @see simtools.ui.GenericMapper.ExpressionMappingTable#setUpRenderer()
*/
protected void setUpRenderer() {
setDefaultRenderer(ImageFile.class, new ImageRenderer());
}
/**
* Sets up the editor to a color editor
*
* @see simtools.ui.GenericMapper.ExpressionMappingTable#setUpEditor()
*/
protected void setUpEditor() {
// First, set up the button that brings up the dialog.
final JButton button = new JButton("");
// Now create an editor to encapsulate the button, and
// set it up as the editor for all Color cells.
final ImageEditor imageEditor = new ImageEditor(button);
setDefaultEditor(ImageFile.class, imageEditor);
// Here's the code that brings up the dialog.
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Set up the file chooser.
if (fileChooser == null) {
fileChooser = new JFileChooser();
// Add a custom file filter and disable the default
// (Accept All) file filter.
fileChooser.addChoosableFileFilter(new ImageFileFilter());
fileChooser.setAcceptAllFileFilterUsed(false);
// Add the preview pane.
fileChooser.setAccessory(new ImagePreview(fileChooser));
// Set image file chooser directory
File imageDirectory = ((defaultDirectory != null) && defaultDirectory.exists()) ? defaultDirectory
: CurrentPathProvider.currentPathProvider.getCurrentPath();
fileChooser.setCurrentDirectory(imageDirectory);
}
if ((imageEditor.currentImage != null) && (imageEditor.currentImage.file != null)) {
fileChooser.setSelectedFile(imageEditor.currentImage.file);
} else {
fileChooser.setSelectedFile(null);
}
// Show it.
int returnVal = fileChooser.showDialog(ImageMappingTable.this, resources.getString("SelectImage"));
// Process the results.
if (returnVal == JFileChooser.APPROVE_OPTION) {
if (imageEditor.currentImage == null) {
imageEditor.currentImage = new ImageFile();
}
imageEditor.currentImage.file = fileChooser.getSelectedFile();
try {
imageEditor.currentImage.image = ImageIO.read(imageEditor.currentImage.file);
} catch (IOException e1) {
imageEditor.currentImage.image = null;
}
}
}
});
}
}
protected class ImageMapperTableModel extends MapperTableModel {
public Class getColumnClass(int c) {
if (c == 1) {
return ImageFile.class;
}
return super.getColumnClass(c);
}
public String getColumnName(int col) {
if (col == 1) {
return resources.getString("Image");
}
return super.getColumnName(col);
}
public boolean isCellEditable(int row, int col) {
if (col == 1) {
return true;
}
return super.isCellEditable(row, col);
}
}
protected ExpressionMappingTable createTable(JDialog parent) {
return new ImageMappingTable(parent);
}
protected Object createNewValue() {
return new ImageFile();
}
public static ImageMapper createImageMapperDialog(JDialog owner) {
ImageMapper cm = new ImageMapper();
cm.editDialog(owner);
return cm;
}
public static void main(String[] args) {
// GenericMapper cm = new GenericMapper();
ImageMapper cm = new ImageMapper();
cm.editDialog(null);
System.exit(0);
}
/**
* Method <b>isSvgFile</b> test if the file is an svg file Parameters: the
* file f
*
* @return true if the parameter File f is a svg file (*.svg) false else
*/
public static class ImageFileFilter extends FileFilter {
public boolean accept(File f) {
String name = f.getName().toLowerCase();
return name.endsWith("jpg") || name.endsWith("jpeg") || name.endsWith("png") || name.endsWith("bmp")
|| name.endsWith("gif") || name.endsWith("tif") || f.isDirectory();
}
public String getDescription() {
return resources.getString("bitmappedImages");
}
}
}