// // SeriesDialog.java // /* LOCI Plugins for ImageJ: a collection of ImageJ plugins including the Bio-Formats Importer, Bio-Formats Exporter, Bio-Formats Macro Extensions, Data Browser and Stack Slicer. Copyright (C) 2005-@year@ Melissa Linkert, Curtis Rueden and Christopher Peterson. 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.plugins.in; import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import ij.Macro; import ij.gui.GenericDialog; import java.awt.Button; import java.awt.Checkbox; import java.awt.Color; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Panel; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Box; import javax.swing.JPanel; import loci.formats.gui.BufferedImageReader; import loci.plugins.util.WindowTools; /** * Bio-Formats Importer series chooser dialog box. * * <dl><dt><b>Source code:</b></dt> * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/loci-plugins/src/loci/plugins/in/SeriesDialog.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/loci-plugins/src/loci/plugins/in/SeriesDialog.java;hb=HEAD">Gitweb</a></dd></dl> */ public class SeriesDialog extends ImporterDialog implements ActionListener { // -- Constants -- public static final int MAX_COMPONENTS = 256; public static final int MAX_SERIES_THUMBS = 200; public static final int MAX_SERIES_TOGGLES = MAX_SERIES_THUMBS; // -- Fields -- private BufferedImageReader thumbReader; private Panel[] p; private Checkbox[] boxes; // -- Constructor -- /** Creates a series chooser dialog for the Bio-Formats Importer. */ public SeriesDialog(ImportProcess process) { super(process); } // -- ImporterDialog methods -- @Override protected boolean needPrompt() { return !process.isWindowless() && process.getSeriesCount() > 1 && !options.openAllSeries() && !options.isViewNone(); } @Override protected GenericDialog constructDialog() { final int seriesCount = process.getSeriesCount(); // NB: Load thumbnails only when series count is modest. if (seriesCount < MAX_SERIES_THUMBS) { // construct thumbnail reader thumbReader = new BufferedImageReader(process.getReader()); // set up the thumbnail panels p = new Panel[seriesCount]; for (int i=0; i<seriesCount; i++) { thumbReader.setSeries(i); int sx = thumbReader.getThumbSizeX() + 10; // a little extra padding int sy = thumbReader.getThumbSizeY(); p[i] = new Panel(); p[i].add(Box.createRigidArea(new Dimension(sx, sy))); if (options.isForceThumbnails()) { // load thumbnail immediately ThumbLoader.loadThumb(thumbReader, i, p[i], options.isQuiet()); } } } GenericDialog gd = new GenericDialog("Bio-Formats Series Options"); // NB: Provide individual checkboxes only when series count is manageable. if (seriesCount < MAX_SERIES_TOGGLES) { // NB: We need to add the checkboxes in groups, to prevent an // exception from being thrown if there are more than 512 series. // See also: // http://dev.loci.wisc.edu/trac/java/ticket/408 and // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5107980 final int nGroups = (seriesCount + MAX_COMPONENTS - 1) / MAX_COMPONENTS; int nextSeries = 0; for (int i=0; i<nGroups; i++) { final int nRows = Math.min(MAX_COMPONENTS, seriesCount - nextSeries); final String[] labels = new String[nRows]; final boolean[] defaultValues = new boolean[nRows]; for (int row=0; row<nRows; row++) { labels[row] = process.getSeriesLabel(nextSeries); defaultValues[row] = options.isSeriesOn(nextSeries); nextSeries++; } gd.addCheckboxGroup(nRows, 1, labels, defaultValues); } // extract checkboxes, for "Select All" and "Deselect All" functions boxes = WindowTools.getCheckboxes(gd).toArray(new Checkbox[0]); // rebuild dialog so that the thumbnails and checkboxes line up correctly rebuildDialog(gd, nGroups); } else { // too many series; display a simple text field for specifying series gd.addMessage( "Please specify the image series you wish to import.\n" + "Use commas to list multiple series. You can also use\n" + "a dash to represent a range of series. For example,\n" + "to import series 1, 3, 4, 5, 7, 8, 9, 12, 15 & 16,\n" + "you could write: 1, 3-5, 7-9, 12, 15-16\n \n" + "There are " + seriesCount + " total series."); gd.addStringField("Series_list: ", "1"); } return gd; } @Override protected boolean displayDialog(GenericDialog gd) { ThumbLoader loader = null; if (thumbReader != null && !options.isForceThumbnails()) { // spawn background thumbnail loader loader = new ThumbLoader(thumbReader, p, gd); } gd.showDialog(); if (loader != null) loader.stop(); return !gd.wasCanceled(); } @Override protected boolean harvestResults(GenericDialog gd) { final int seriesCount = process.getSeriesCount(); options.clearSeries(); // examine series key regardless of number of series final String macroOptions = Macro.getOptions(); final String macroSeriesList = macroOptions == null ? null : Macro.getValue(macroOptions, "series_list", null); if (macroSeriesList != null) process.setSeriesList(macroSeriesList); if (seriesCount < MAX_SERIES_TOGGLES) { // harvest individual checkbox values for (int i=0; i<seriesCount; i++) { final boolean on = gd.getNextBoolean(); if (on) options.setSeriesOn(i, on); } } else { // harvest series string final String seriesList = gd.getNextString(); process.setSeriesList(seriesList); } // examine series_XX keys regardless of number of series if (macroOptions != null) { for (int i=0; i<seriesCount; i++) { final String seriesKey = "series_" + (i + 1); final boolean on = options.checkKey(macroOptions, seriesKey); if (on) options.setSeriesOn(i, on); } } return true; } // -- ActionListener methods -- public void actionPerformed(ActionEvent e) { final String cmd = e.getActionCommand(); if ("select".equals(cmd)) { for (int i=0; i<boxes.length; i++) boxes[i].setState(true); updateIfGlitched(); } else if ("deselect".equals(cmd)) { for (int i=0; i<boxes.length; i++) boxes[i].setState(false); updateIfGlitched(); } } // -- Helper methods -- private void updateIfGlitched() { if (IS_GLITCHED) { // HACK - work around for Mac OS X AWT bug sleep(200); for (int i=0; i<boxes.length; i++) boxes[i].repaint(); } } private void rebuildDialog(GenericDialog gd, int buttonRow) { // rebuild dialog to organize things more nicely final String cols = p == null ? "pref" : "pref, 3dlu, pref"; final StringBuilder sb = new StringBuilder("pref"); for (int s=1; s<boxes.length; s++) sb.append(", 3dlu, pref"); final String rows = sb.toString(); final PanelBuilder builder = new PanelBuilder(new FormLayout(cols, rows)); final CellConstraints cc = new CellConstraints(); int row = 1; for (int s=0; s<boxes.length; s++) { builder.add(boxes[s], cc.xy(1, row)); if (p != null) builder.add(p[s], cc.xy(3, row)); row += 2; } final JPanel masterPanel = builder.getPanel(); gd.removeAll(); GridBagLayout gdl = (GridBagLayout) gd.getLayout(); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gdl.setConstraints(masterPanel, gbc); gd.add(masterPanel); WindowTools.addScrollBars(gd); gd.setBackground(Color.white); // HACK: workaround for JPanel in a Dialog // add Select All and Deselect All buttons Panel buttons = new Panel(); Button select = new Button("Select All"); select.setActionCommand("select"); select.addActionListener(this); Button deselect = new Button("Deselect All"); deselect.setActionCommand("deselect"); deselect.addActionListener(this); buttons.add(select); buttons.add(deselect); gbc.gridx = 2; gbc.gridy = buttonRow; gbc.anchor = GridBagConstraints.EAST; gbc.insets = new Insets(15, 0, 0, 0); gdl.setConstraints(buttons, gbc); gd.add(buttons); } }