Skip to content

Commit

Permalink
Better series handling when number of series is extremely large.
Browse files Browse the repository at this point in the history
  • Loading branch information
ctrueden committed Sep 2, 2010
1 parent d231189 commit d0dec52
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 81 deletions.
42 changes: 42 additions & 0 deletions components/loci-plugins/src/loci/plugins/in/ImportProcess.java
Expand Up @@ -28,6 +28,7 @@ Data Browser and Stack Slicer. Copyright (C) 2005-@year@ Melissa Linkert,
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import loci.common.Location;
import loci.common.Region;
Expand Down Expand Up @@ -181,6 +182,47 @@ public boolean isWindowless() {
return baseReader != null && LociPrefs.isWindowless(baseReader);
}

public void setSeriesList(String seriesList) {
final int seriesCount = getSeriesCount();
options.clearSeries();

// remove illegal characters
seriesList = seriesList.replaceAll("[^\\d,\\-]", "");

// parse series list
StringTokenizer st = new StringTokenizer(seriesList, ",");
while (st.hasMoreTokens()) {
final String token = st.nextToken();
int dash = token.indexOf("-");
if (dash < 0) {
// single number
try {
final int s = Integer.parseInt(token) - 1;
options.setSeriesOn(s, true);
}
catch (NumberFormatException exc) {
// skip invalid series number
}
}
else {
// numerical range
final String firstString = token.substring(0, dash);
final String lastString = token.substring(dash + 1);
try {
final int first = Integer.parseInt(firstString) - 1;
final int last = Integer.parseInt(lastString) - 1;
for (int s = first; s <= last; s++) {
if (s >= seriesCount) break; // skip out of bounds series
options.setSeriesOn(s, true);
}
}
catch (NumberFormatException exc) {
// skip invalid numerical range
}
}
}
}

// -- ImportProcess methods - post-READER --

/** Valid only after {@link ImportStep#READER}. */
Expand Down
27 changes: 12 additions & 15 deletions components/loci-plugins/src/loci/plugins/in/ImporterOptions.java
Expand Up @@ -64,7 +64,6 @@ public class ImporterOptions extends OptionsList {
public static final String KEY_OPEN_ALL_SERIES = "openAllSeries";
public static final String KEY_QUIET = "quiet";
//public static final String KEY_RECORD = "record";
public static final String KEY_SERIES = "series";
public static final String KEY_SHOW_METADATA = "showMetadata";
public static final String KEY_SHOW_OME_XML = "showOMEXML";
public static final String KEY_SHOW_ROIS = "showROIs";
Expand Down Expand Up @@ -195,26 +194,26 @@ public void parseArg(String arg) {

/** Handles obsolete macro keys, for backward compatibility. */
public void checkObsoleteOptions() {
String options = Macro.getOptions();
final String macroOptions = Macro.getOptions();

// NB: It would be nice to remove the Standard ImageJ option someday;
// when that happens, the following code provides support for old macros.
// check obsolete view options
//String stackFormat = options == null ?
// null : Macro.getValue(options, "view", null);
//String stackFormat = macroOptions == null ?
// null : Macro.getValue(macroOptions, "view", null);
//final String viewStandard = "Standard ImageJ";
//if (viewStandard.equals(stackFormat)) {
// // Standard ImageJ -> Hyperstack
// options = options.replaceFirst(
// macroOptions = macroOptions.replaceFirst(
// "\\[" + viewStandard + "\\]", VIEW_HYPERSTACK);
// Macro.setOptions(options);
// Macro.setOptions(macroOptions);
// setStackFormat(VIEW_HYPERSTACK);
//}

// check obsolete color options
boolean mergeChannels = checkKey(options, "merge_channels");
boolean rgbColorize = checkKey(options, "rgb_colorize");
boolean customColorize = checkKey(options, "custom_colorize");
final boolean mergeChannels = checkKey(macroOptions, "merge_channels");
final boolean rgbColorize = checkKey(macroOptions, "rgb_colorize");
final boolean customColorize = checkKey(macroOptions, "custom_colorize");
if (mergeChannels) setColorMode(COLOR_MODE_COMPOSITE);
else if (rgbColorize) setColorMode(COLOR_MODE_COLORIZED);
else if (customColorize) setColorMode(COLOR_MODE_CUSTOM);
Expand Down Expand Up @@ -306,11 +305,6 @@ public boolean isColorModeCustom() {
//public boolean isRecord() { return isSet(KEY_RECORD); }
//public void setRecord(boolean b) { setValue(KEY_RECORD, b); }

// series
public String getSeriesInfo() { return getInfo(KEY_SERIES); }
public String getSeries() { return getValue(KEY_SERIES); }
public void setSeries(String s) { setValue(KEY_SERIES, s); }

// showMetadata
public String getShowMetadataInfo() { return getInfo(KEY_SHOW_METADATA); }
public boolean isShowMetadata() { return isSet(KEY_SHOW_METADATA); }
Expand Down Expand Up @@ -404,6 +398,9 @@ public boolean isSeriesOn(int s) {
public void setSeriesOn(int s, boolean value) {
set(seriesOn, s, value, false);
}
public void clearSeries() {
seriesOn.clear();
}

// swap options
public String getInputOrder(int s) { return get(inputOrder, s, null); }
Expand Down Expand Up @@ -485,7 +482,7 @@ private <T extends Object> T get(List<T> list, int index, T defaultValue) {
}

/** Tests whether the given boolean key is set in the specified options. */
private boolean checkKey(String options, String key) {
protected boolean checkKey(String options, String key) {
if (options == null) return false;

// delete anything inside square brackets, for simplicity
Expand Down
130 changes: 69 additions & 61 deletions components/loci-plugins/src/loci/plugins/in/SeriesDialog.java
Expand Up @@ -29,6 +29,7 @@ Data Browser and Stack Slicer. Copyright (C) 2005-@year@ Melissa Linkert,
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import ij.Macro;
import ij.gui.GenericDialog;

import java.awt.Button;
Expand All @@ -41,7 +42,6 @@ Data Browser and Stack Slicer. Copyright (C) 2005-@year@ Melissa Linkert,
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.StringTokenizer;

import javax.swing.Box;
import javax.swing.JPanel;
Expand All @@ -62,6 +62,7 @@ public class SeriesDialog extends ImporterDialog implements ActionListener {

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 --

Expand All @@ -80,40 +81,12 @@ public SeriesDialog(ImportProcess process) {

@Override
protected boolean needPrompt() {
// CTR FIXME - eliminate weird handling of series string here
String seriesString = options.getSeries();
if (process.isWindowless()) {
if (seriesString != null) {
if (seriesString.startsWith("[")) {
seriesString = seriesString.substring(1, seriesString.length() - 2);
}

// default all series to false
final int seriesCount = process.getSeriesCount();
for (int s=0; s<seriesCount; s++) options.setSeriesOn(s, false);

// extract enabled series values from series string
StringTokenizer tokens = new StringTokenizer(seriesString, " ");
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken().trim();
int n = Integer.parseInt(token);
if (n < seriesCount) options.setSeriesOn(n, true);
}
}
options.setSeries(seriesString);
return false;
}

return process.getSeriesCount() > 1 &&
return !process.isWindowless() && process.getSeriesCount() > 1 &&
!options.openAllSeries() && !options.isViewNone();
}

@Override
protected GenericDialog constructDialog() {
// -- CTR FIXME - refactor series-related options into SeriesOptions class
// has a normalize(IFormatReader) method
// call both before and after the dialog here...

final int seriesCount = process.getSeriesCount();

// NB: Load thumbnails only when series count is modest.
Expand All @@ -138,31 +111,44 @@ protected GenericDialog constructDialog() {

GenericDialog gd = new GenericDialog("Bio-Formats Series Options");

// 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:
// https://skyking.microscopy.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++;
// 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:
// https://skyking.microscopy.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);
}
gd.addCheckboxGroup(nRows, 1, labels, defaultValues);
}

// extract checkboxes, for "Select All" and "Deselect All" functions
boxes = WindowTools.getCheckboxes(gd).toArray(new Checkbox[0]);
// 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);
// 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");
gd.addStringField("Series_list: ", "1");
}

return gd;
}
Expand All @@ -182,21 +168,43 @@ protected boolean displayDialog(GenericDialog gd) {
@Override
protected boolean harvestResults(GenericDialog gd) {
final int seriesCount = process.getSeriesCount();
String seriesString = "[";
for (int i=0; i<seriesCount; i++) {
boolean on = gd.getNextBoolean();
options.setSeriesOn(i, on);
if (on) seriesString += i + " ";
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);
}
seriesString += "]";
options.setSeries(seriesString);

// 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) {
String cmd = e.getActionCommand();
final String cmd = e.getActionCommand();
if ("select".equals(cmd)) {
for (int i=0; i<boxes.length; i++) boxes[i].setState(true);
updateIfGlitched();
Expand All @@ -218,7 +226,7 @@ private void updateIfGlitched() {
}

private void rebuildDialog(GenericDialog gd, int buttonRow) {
// rebuild dialog using FormLayout to organize things more nicely
// rebuild dialog to organize things more nicely

final String cols = p == null ? "pref" : "pref, 3dlu, pref";

Expand Down
Expand Up @@ -173,11 +173,6 @@ default = false
# more like a normal, fully memory-resident image stack.
#default = false

[series]
type = string
label = series
default = 0

[showMetadata]
type = boolean
label = Display_metadata
Expand Down

0 comments on commit d0dec52

Please sign in to comment.