//
// GUITools.java
//
/*
OME Bio-Formats package for reading and converting biological file formats.
Copyright (C) 2005-@year@ UW-Madison LOCI and Glencoe Software, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package loci.formats.gui;
import java.lang.reflect.InvocationTargetException;
import java.util.Vector;
import javax.swing.JFileChooser;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
import loci.formats.FileStitcher;
import loci.formats.IFormatHandler;
import loci.formats.IFormatReader;
import loci.formats.IFormatWriter;
import loci.formats.ImageReader;
import loci.formats.ImageWriter;
import loci.formats.ReaderWrapper;
import loci.formats.WriterWrapper;
/**
* A utility class for working with graphical user interfaces.
*
* <dl><dt><b>Source code:</b></dt>
* <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/bio-formats/src/loci/formats/gui/GUITools.java">Trac</a>,
* <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/gui/GUITools.java;hb=HEAD">Gitweb</a></dd></dl>
*
* @author Curtis Rueden ctrueden at wisc.edu
*/
public final class GUITools {
// -- Fields --
/** String to use for "all types" combination filter. */
private static final String ALL_TYPES = "All supported file types";
// -- Constructor --
private GUITools() { }
// -- File chooser --
/** Constructs a list of file filters for the given file format handler. */
public static FileFilter[] buildFileFilters(IFormatHandler handler) {
FileFilter[] filters = null;
// unwrap reader
while (true) {
if (handler instanceof ReaderWrapper) {
handler = ((ReaderWrapper) handler).getReader();
}
else if (handler instanceof FileStitcher) {
handler = ((FileStitcher) handler).getReader();
}
else if (handler instanceof WriterWrapper) {
handler = ((WriterWrapper) handler).getWriter();
}
else break;
}
// handle special cases of ImageReader and ImageWriter
if (handler instanceof ImageReader) {
ImageReader imageReader = (ImageReader) handler;
IFormatReader[] readers = imageReader.getReaders();
Vector filterList = new Vector();
Vector comboList = new Vector();
for (int i=0; i<readers.length; i++) {
filterList.add(new FormatFileFilter(readers[i]));
// NB: Some readers need to open a file to determine if it is the
// proper type, when the extension alone is insufficient to
// distinguish. This behavior is fine for individual filters, but not
// for ImageReader's combination filter, because it makes the combo
// filter too slow. So rather than composing the combo filter from
// FormatFileFilters, we use faster but less accurate
// ExtensionFileFilters instead.
String[] suffixes = readers[i].getSuffixes();
String format = readers[i].getFormat();
comboList.add(new ExtensionFileFilter(suffixes, format));
}
comboList.add(new NoExtensionFileFilter());
FileFilter combo = makeComboFilter(sortFilters(comboList));
if (combo != null) filterList.add(combo);
filters = sortFilters(filterList);
}
else if (handler instanceof ImageWriter) {
IFormatWriter[] writers = ((ImageWriter) handler).getWriters();
Vector filterList = new Vector();
for (int i=0; i<writers.length; i++) {
String[] suffixes = writers[i].getSuffixes();
String format = writers[i].getFormat();
filterList.add(new ExtensionFileFilter(suffixes, format));
}
filters = sortFilters(filterList);
}
// handle default reader and writer cases
else if (handler instanceof IFormatReader) {
IFormatReader reader = (IFormatReader) handler;
filters = new FileFilter[] {new FormatFileFilter(reader)};
}
else {
String[] suffixes = handler.getSuffixes();
String format = handler.getFormat();
filters = new FileFilter[] {new ExtensionFileFilter(suffixes, format)};
}
return filters;
}
/** Constructs a file chooser for the given file format handler. */
public static JFileChooser buildFileChooser(IFormatHandler handler) {
return buildFileChooser(handler, true);
}
/**
* Constructs a file chooser for the given file format handler.
* If preview flag is set, chooser has an preview pane showing
* a thumbnail and other information for the selected file.
*/
public static JFileChooser buildFileChooser(IFormatHandler handler,
boolean preview)
{
return buildFileChooser(buildFileFilters(handler), preview);
}
/**
* Builds a file chooser with the given file filters,
* as well as an "All supported file types" combo filter.
*/
public static JFileChooser buildFileChooser(final FileFilter[] filters) {
return buildFileChooser(filters, true);
}
/**
* Builds a file chooser with the given file filters, as well as an "All
* supported file types" combo filter, if one is not already specified.
* @param preview If set, chooser has a preview pane showing a
* thumbnail and other information for the selected file.
*/
public static JFileChooser buildFileChooser(final FileFilter[] filters,
final boolean preview)
{
// NB: construct JFileChooser in the AWT worker thread, to avoid deadlocks
final JFileChooser[] jfc = new JFileChooser[1];
Runnable r = new Runnable() {
public void run() {
JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
FileFilter[] ff = sortFilters(filters);
FileFilter combo = null;
if (ff.length > 0 && ff[0] instanceof ComboFileFilter) {
// check for existing "All supported file types" filter
ComboFileFilter cff = (ComboFileFilter) ff[0];
if (ALL_TYPES.equals(cff.getDescription())) combo = cff;
}
// make an "All supported file types" filter if we don't have one yet
if (combo == null) {
combo = makeComboFilter(ff);
if (combo != null) fc.addChoosableFileFilter(combo);
}
for (int i=0; i<ff.length; i++) fc.addChoosableFileFilter(ff[i]);
if (combo != null) fc.setFileFilter(combo);
if (preview) new PreviewPane(fc);
jfc[0] = fc;
}
};
if (Thread.currentThread().getName().startsWith("AWT-EventQueue")) {
// current thread is the AWT event queue thread; just execute the code
r.run();
}
else {
// execute the code with the AWT event thread
try {
SwingUtilities.invokeAndWait(r);
}
catch (InterruptedException exc) { return null; }
catch (InvocationTargetException exc) { return null; }
}
return jfc[0];
}
// -- Helper methods --
/**
* Creates an "All supported file types" combo filter
* encompassing all of the given filters.
*/
private static FileFilter makeComboFilter(FileFilter[] filters) {
return filters.length > 1 ? new ComboFileFilter(filters, ALL_TYPES) : null;
}
/**
* Sorts the given list of file filters, keeping the "All supported
* file types" combo filter (if any) at the front of the list.
*/
private static FileFilter[] sortFilters(FileFilter[] filters) {
filters = ComboFileFilter.sortFilters(filters);
shuffleAllTypesToFront(filters);
return filters;
}
/**
* Sorts the given list of file filters, keeping the "All supported
* file types" combo filter (if any) at the front of the list.
*/
private static FileFilter[] sortFilters(Vector filterList) {
FileFilter[] filters = ComboFileFilter.sortFilters(filterList);
shuffleAllTypesToFront(filters);
return filters;
}
/**
* Looks for an "All supported file types" combo filter
* and shuffles it to the front of the list.
*/
private static void shuffleAllTypesToFront(FileFilter[] filters) {
for (int i=0; i<filters.length; i++) {
if (filters[i] instanceof ComboFileFilter) {
if (ALL_TYPES.equals(filters[i].getDescription())) {
FileFilter f = filters[i];
for (int j=i; j>=1; j--) filters[j] = filters[j - 1];
filters[0] = f;
break;
}
}
}
}
}