/*
* Copyright 2008-2014 by Emeric Vernat
*
* This file is part of Java Melody.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.bull.javamelody.swing;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import net.bull.javamelody.I18NAdapter;
import net.bull.javamelody.swing.print.MExtensionFileFilter;
import net.bull.javamelody.swing.util.MSwingUtilities;
/**
* FileChooser pour une image.
* @author Emeric Vernat
*/
public class ImageFileChooser extends JFileChooser {
private static final long serialVersionUID = 1L;
private static final ImageFileChooser IMAGE_FILE_CHOOSER = new ImageFileChooser();
private final String[] extensions = { "png", "gif", "jpg", "jpeg", "bmp" };
/**
* Constructeur.
*/
public ImageFileChooser() {
super();
setFileFilter(new MExtensionFileFilter(extensions, I18NAdapter.getString("Fichiers_images")));
setAccessory(new ImageFilePreviewer(this));
}
/**
* Ouvre la boîte de dialogue de choix de fichier image.
* <br>Retourne le fichier choisi, ou null si annulé.
* @param parent Component
* @param openOrSave boolean
* @param fileName String
* @return File
*/
public static File chooseImage(Component parent, boolean openOrSave, String fileName) {
int result;
if (fileName != null) {
IMAGE_FILE_CHOOSER.setSelectedFile(new File(fileName));
}
if (openOrSave) {
result = IMAGE_FILE_CHOOSER.showOpenDialog(parent);
} else {
result = IMAGE_FILE_CHOOSER.showSaveDialog(parent);
}
if (result == JFileChooser.APPROVE_OPTION) {
File file = IMAGE_FILE_CHOOSER.getSelectedFile();
file = IMAGE_FILE_CHOOSER.checkFile(file);
return file;
}
return null;
}
/**
* Vérifie qu'un fichier est bien une image valide.
* @param file File
*/
public static void checkImage(File file) {
IMAGE_FILE_CHOOSER.checkFile(file);
}
/**
* En enregistrement, vérifie le format avec l'extension et retourne un nouveau fichier sinon.
* @param file File
* @return File
*/
private File checkFile(File file) {
final String extension = getExtension(file.getName()).toLowerCase();
if (!Arrays.asList(extensions).contains(extension)) {
// En lecture, vérifie le format du fichier sélectionné.
// if (openOrSave) {
// final StringBuilder sb = new StringBuilder(
// "L'extension du fichier sélectionné n'est pas un format d'image accepté");
// sb.append(" (");
// for (final Iterator<String> it = Arrays.asList(extensions).iterator(); it.hasNext();) {
// sb.append(it.next());
// if (it.hasNext()) {
// sb.append(", ");
// }
// }
// sb.append(')');
// throw new IOException(sb.toString());
// }
// si pas d'extension ou extension inconnue, on prend png par défaut
return new File(file.getPath() + ".png");
}
return file;
}
/**
* Gets the extension of a filename.
* <p>
* This method returns the textual part of the filename after the last dot.
* There must be no directory separator after the dot.
* <pre>
* foo.txt --> "txt"
* a/b/c.jpg --> "jpg"
* a/b.txt/c --> ""
* a/b/c --> ""
* </pre>
* <p>
* The output will be the same irrespective of the machine that the code is running on.
* (Author Apache Commons IO 1.1)
*
* @param filename the filename to retrieve the extension of.
* @return the extension of the file or an empty string if none exists.
*/
private static String getExtension(String filename) {
if (filename == null) {
return null;
}
// The extension separator character.
final char extensionSeparator = '.';
// The Unix separator character.
final char unixSeparator = '/';
// The Windows separator character.
final char windowsSeparator = '\\';
final int extensionPos = filename.lastIndexOf(extensionSeparator);
final int lastUnixPos = filename.lastIndexOf(unixSeparator);
final int lastWindowsPos = filename.lastIndexOf(windowsSeparator);
final int lastSeparator = Math.max(lastUnixPos, lastWindowsPos);
final int index = lastSeparator > extensionPos ? -1 : extensionPos;
if (index == -1) {
return "";
}
return filename.substring(index + 1);
}
/**
* Composant de prévisualisation d'images dans le fileChooser.
*/
private static class ImageFilePreviewer extends JComponent implements PropertyChangeListener {
private static final long serialVersionUID = 1L;
private ImageIcon thumbnail;
private String dimension;
ImageFilePreviewer(JFileChooser fc) {
super();
setPreferredSize(new Dimension(100, 85));
fc.addPropertyChangeListener(this);
setBorder(BorderFactory.createLoweredBevelBorder());
}
/**
* Charge le fichier si c'est une image.
* @param f File
* @throws IOException e
*/
public void loadImage(File f) throws IOException {
if (f == null || !f.exists()) {
thumbnail = null;
} else {
final ImageIcon icon = readCompatibleImageIcon(f);
if (icon == null) {
thumbnail = null;
} else {
dimension = icon.getIconWidth() + " x " + icon.getIconHeight();
int width = icon.getIconWidth();
int height = icon.getIconHeight();
if (height > 75) {
width = width * 75 / height;
height = 75;
}
if (width > 90) {
height = height * 90 / width;
width = 90;
}
BufferedImage image = (BufferedImage) icon.getImage();
image = (BufferedImage) MSwingUtilities.getScaledInstance(image, width, height);
thumbnail = new ImageIcon(image);
}
}
}
/**
* Retourne une imageIcon avec un contenu et une palette compatible avec la configuration vidéo
* de l'écran par défaut.
* L'imageIcon est la plus proche de la configuration vidéo et pourra être idéalement affichée sur celle-ci.
* @param file File
* @return ImageIcon
* @throws IOException Exception d'entrée/sortie
*/
public ImageIcon readCompatibleImageIcon(File file) throws IOException {
final BufferedImage image = ImageIO.read(file);
if (image == null) {
return null;
}
final BufferedImage compatibleImage = getGraphicsConfiguration().createCompatibleImage(
image.getWidth(), image.getHeight());
final Graphics g = compatibleImage.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return new ImageIcon(compatibleImage);
}
/** {@inheritDoc} */
@Override
public void propertyChange(PropertyChangeEvent event) {
final String prop = event.getPropertyName();
if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop) && isShowing()) {
try {
loadImage((File) event.getNewValue());
repaint();
} catch (final IOException ex) {
MSwingUtilities.showException(ex);
}
}
}
/** {@inheritDoc} */
@Override
public void paint(Graphics g) {
super.paint(g);
if (thumbnail != null) {
int x = getWidth() / 2 - thumbnail.getIconWidth() / 2;
int y = getHeight() / 2 - thumbnail.getIconHeight() / 2;
if (y < 0) {
y = 0;
}
if (x < 5) {
x = 5;
}
thumbnail.paintIcon(this, g, x, y);
final FontMetrics fontMetrics = getFontMetrics(getFont());
g.setColor(Color.BLACK);
g.drawString(dimension, (getWidth() - fontMetrics.stringWidth(dimension)) / 2,
(getHeight() + thumbnail.getIconHeight()) / 2 + fontMetrics.getHeight());
}
}
}
}