/*
* #%L
* BSD implementations of Bio-Formats readers and writers
* %%
* Copyright (C) 2005 - 2015 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
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.
*
* @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() {
@Override
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;
}
}
}
}
}