Changeset 5133


Ignore:
Timestamp:
05/29/09 10:58:27 (11 years ago)
Author:
curtis
Message:

Major progress on LOCI plugins refactoring.

  • New options management package, loci.plugins.prefs.
  • Split each dialog into its own class.
  • Eliminated reflection for hyperstacks and composite images (most plugins now require ImageJ v1.39+).
  • Seems functional, but not yet well tested. In particular, Slicer and Colorizer need work, and the upgrade logic is temporarily disabled.
Location:
trunk/components
Files:
11 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/components/bio-formats/src/loci/formats/ClassList.java

    r5093 r5133  
    7777   * @param file Configuration file containing the list of classes. 
    7878   * @param base Base class to which all classes are assignable. 
    79    * @param location Class indicating which package to search for the file.  If 
    80    *  null, 'file' is interpreted as an absolute path name. 
     79   * @param location Class indicating which package to search for the file. 
     80   *  If null, 'file' is interpreted as an absolute path name. 
    8181   * @throws IOException if the file cannot be read. 
    8282   */ 
  • trunk/components/loci-plugins/build.properties

    r5092 r5133  
    1717component.resources-bin  = (none) 
    1818component.resources-text = plugins.config \ 
    19                            loci/plugins/config/*.txt 
     19                           loci/plugins/config/*.txt \ 
     20                           loci/plugins/importer/*.txt 
    2021 
    2122component.main-class     = loci.plugins.About 
  • trunk/components/loci-plugins/src/loci/plugins/Colorizer.java

    r5093 r5133  
    4848import java.awt.event.TextListener; 
    4949import java.awt.image.IndexColorModel; 
    50 import java.io.ByteArrayOutputStream; 
    51 import java.io.PrintStream; 
     50import java.io.IOException; 
    5251import java.util.Arrays; 
    5352import java.util.Vector; 
    5453 
    55 import loci.common.ReflectException; 
    56 import loci.common.ReflectedUniverse; 
    5754import loci.formats.FormatTools; 
    5855import loci.plugins.importer.ImporterOptions; 
     56import loci.plugins.importer.MergeDialog; 
    5957import loci.plugins.util.ImagePlusTools; 
    60 import loci.plugins.util.LibraryChecker; 
     58import loci.plugins.util.OptionsDialog; 
     59import loci.plugins.util.WindowTools; 
    6160 
    6261/** 
     
    7069 */ 
    7170public class Colorizer implements PlugInFilter { 
    72  
    73   // -- Static fields -- 
    74  
    75   private static ReflectedUniverse r = createReflectedUniverse(); 
    76   private static ReflectedUniverse createReflectedUniverse() { 
    77     r = null; 
    78     try { 
    79       r = new ReflectedUniverse(); 
    80       r.exec("import ij.CompositeImage"); 
    81     } 
    82     catch (ReflectException exc) { } 
    83     return r; 
    84   } 
    8571 
    8672  // -- Fields -- 
     
    179165    int nSlices = imp.getNSlices(); 
    180166 
    181     Class c = null; 
    182     try { 
    183       c = Class.forName("ij.CompositeImage"); 
    184     } 
    185     catch (ClassNotFoundException e) { } 
    186  
    187     if (imp.getClass().equals(c) || stack.isRGB() || 
    188       (nChannels == 1 && !color)) 
    189     { 
     167    if (imp.isComposite() || stack.isRGB() || (nChannels == 1 && !color)) { 
    190168      return; 
    191169    } 
     
    195173 
    196174    if (color) { 
    197       if (LibraryChecker.checkComposite() && nChannels > 1) { 
    198         // use reflection to construct CompositeImage, 
    199         // in case ImageJ version is too old 
    200         try { 
    201           r.setVar("imp", ImagePlusTools.reorder(imp, stackOrder, "XYCZT")); 
    202           r.exec("composite = new CompositeImage(imp, CompositeImage.COLOR)"); 
    203           r.setVar("1", 1); 
    204           for (int i=0; i<nChannels; i++) { 
    205             r.setVar("channel", i + 1); 
    206             r.exec("composite.setPosition(channel, 1, 1)"); 
    207             if (doPrompt) { 
    208               promptForColor(i); 
    209             } 
    210             if (lut != null) { 
    211               LUT channelLut = new LUT(lut[i][0], lut[i][1], lut[i][2]); 
    212               r.setVar("lut", channelLut); 
    213               r.exec("composite.setChannelLut(lut)"); 
    214             } 
     175      if (nChannels > 1) { 
     176        imp = ImagePlusTools.reorder(imp, stackOrder, "XYCZT"); 
     177        // NB: ImageJ v1.39+ is required for CompositeImage 
     178        CompositeImage composite = 
     179          new CompositeImage(imp, CompositeImage.COLOR); 
     180        for (int i=0; i<nChannels; i++) { 
     181          composite.setPosition(i + 1, 1, 1); 
     182          if (doPrompt) promptForColor(i); 
     183          if (lut != null) { 
     184            LUT channelLut = new LUT(lut[i][0], lut[i][1], lut[i][2]); 
     185            composite.setChannelLut(channelLut); 
    215186          } 
    216           newImp = (ImagePlus) r.getVar("composite"); 
    217           newImp.setPosition(1, 1, 1); 
    218         } 
    219         catch (ReflectException exc) { 
    220           ByteArrayOutputStream s = new ByteArrayOutputStream(); 
    221           exc.printStackTrace(new PrintStream(s)); 
    222           IJ.error(s.toString()); 
    223         } 
     187        } 
     188        newImp = composite; 
     189        newImp.setPosition(1, 1, 1); 
    224190      } 
    225191      else { 
     
    248214      } 
    249215      else if (nChannels <= 7 && type != ImagePlus.COLOR_256) { 
    250         if (LibraryChecker.checkComposite()) { 
    251           // use reflection to construct CompositeImage, 
    252           // in case ImageJ version is too old 
    253           try { 
    254             r.setVar("imp", ImagePlusTools.reorder(imp, stackOrder, "XYCZT")); 
    255             newImp = (ImagePlus) 
    256               r.exec("new CompositeImage(imp, CompositeImage.COMPOSITE)"); 
    257           } 
    258           catch (ReflectException exc) { 
    259             ByteArrayOutputStream s = new ByteArrayOutputStream(); 
    260             exc.printStackTrace(new PrintStream(s)); 
    261             IJ.error(s.toString()); 
    262           } 
    263         } 
    264         else { 
    265           closeOriginal = false; 
    266           newImp = null; 
    267         } 
     216        imp = ImagePlusTools.reorder(imp, stackOrder, "XYCZT"); 
     217        newImp = new CompositeImage(imp, CompositeImage.COMPOSITE); 
    268218      } 
    269219      else if (nChannels > 7) { 
     
    283233        } 
    284234 
    285         ImporterOptions options = new ImporterOptions();//FIXME 
     235        ImporterOptions options = null; 
     236        try { 
     237          options = new ImporterOptions();//FIXME 
     238        } 
     239        catch (IOException exc) { 
     240          WindowTools.reportException(exc); 
     241        } 
    286242 
    287243        boolean spectral = 
     
    289245 
    290246        if (mergeOption == null) { 
    291           int status = options.promptMergeOption(num, spectral); 
    292           if (status == ImporterOptions.STATUS_OK) { 
     247          MergeDialog mergeDialog = new MergeDialog(options, num); 
     248          int status = mergeDialog.showDialog(); 
     249          if (status == OptionsDialog.STATUS_OK) { 
    293250            mergeOption = options.getMergeOption(); 
    294251          } 
    295           // TEMP - remove this once spectral projection is implemented 
    296           while (mergeOption.equals(ImporterOptions.MERGE_PROJECTION)) { 
    297             IJ.error("Spectral projection has not been implemented."); 
    298             status = options.promptMergeOption(num, spectral); 
    299             if (status == ImporterOptions.STATUS_OK) { 
    300               mergeOption = options.getMergeOption(); 
     252        } 
     253 
     254        if (mergeOption != null) { 
     255          int ndx = mergeOption.indexOf("channels"); 
     256          if (ndx != -1) { 
     257            int n = Integer.parseInt(mergeOption.substring(ndx - 2, ndx - 1)); 
     258 
     259            // add extra blank slices if the number of slices is not a 
     260            // multiple of the number of channels 
     261            if ((stack.getSize() % n) != 0) { 
     262              int toAdd = n - (stack.getSize() % n); 
     263              ImageProcessor blank = 
     264                stack.getProcessor(stack.getSize()).duplicate(); 
     265              blank.setValue(0); 
     266              blank.fill(); 
     267              for (int i=0; i<toAdd; i++) { 
     268                stack.addSlice("", blank); 
     269              } 
     270              imp.setStack(imp.getTitle(), stack); 
    301271            } 
     272 
     273            if (imp.getType() == ImagePlus.GRAY8 && n < 4) { 
     274              newImp = makeRGB(newImp, stack, n); 
     275            } 
     276            imp.setDimensions(n, imp.getNSlices()*num[n - 2], 
     277              imp.getNFrames()); 
     278            imp = ImagePlusTools.reorder(imp, stackOrder, "XYCZT"); 
     279            newImp = new CompositeImage(imp, CompositeImage.COMPOSITE); 
    302280          } 
    303         } 
    304  
    305         try { 
    306           if (mergeOption != null) { 
    307             int ndx = mergeOption.indexOf("channels"); 
    308             if (ndx != -1) { 
    309               int n = Integer.parseInt(mergeOption.substring(ndx - 2, ndx - 1)); 
    310  
    311               // add extra blank slices if the number of slices is not a 
    312               // multiple of the number of channels 
    313               if ((stack.getSize() % n) != 0) { 
    314                 int toAdd = n - (stack.getSize() % n); 
    315                 ImageProcessor blank = 
    316                   stack.getProcessor(stack.getSize()).duplicate(); 
    317                 blank.setValue(0); 
    318                 blank.fill(); 
    319                 for (int i=0; i<toAdd; i++) { 
    320                   stack.addSlice("", blank); 
    321                 } 
    322                 imp.setStack(imp.getTitle(), stack); 
    323               } 
    324  
    325               if (imp.getType() == ImagePlus.GRAY8 && n < 4) { 
    326                 newImp = makeRGB(newImp, stack, n); 
    327               } 
    328               else if (LibraryChecker.checkComposite()) { 
    329                 imp.setDimensions(n, imp.getNSlices()*num[n - 2], 
    330                   imp.getNFrames()); 
    331                 r.setVar("imp", 
    332                   ImagePlusTools.reorder(imp, stackOrder, "XYCZT")); 
    333                 r.exec("mode = CompositeImage.COMPOSITE"); 
    334                 r.exec("newImp = new CompositeImage(imp, mode)"); 
    335                 newImp = (ImagePlus) r.getVar("newImp"); 
    336               } 
    337               else { 
    338                 closeOriginal = false; 
    339                 newImp = null; 
    340               } 
    341             } 
    342             else if (mergeOption.equals(ImporterOptions.MERGE_PROJECTION)) { 
    343               // TODO - Add spectral projection logic here (see ticket #86). 
    344             } 
    345             else closeOriginal = false; 
    346           } 
    347         } 
    348         catch (ReflectException e) { 
    349           ByteArrayOutputStream s = new ByteArrayOutputStream(); 
    350           e.printStackTrace(new PrintStream(s)); 
    351           IJ.error(s.toString()); 
     281          else closeOriginal = false; 
    352282        } 
    353283      } 
     
    357287      newImp.setTitle(imp.getTitle()); 
    358288      newImp.setProperty("Info", imp.getProperty("Info")); 
    359       if (!newImp.getClass().equals(c)) { 
     289      if (!newImp.isComposite()) { 
    360290        newImp.setDimensions(newImp.getStackSize() / (nSlices * nTimes), 
    361291          nSlices, nTimes); 
     
    363293      newImp.setCalibration(calibration); 
    364294      newImp.setFileInfo(imp.getOriginalFileInfo()); 
    365       if (LibraryChecker.checkComposite() && 
    366         !(newImp instanceof CompositeImage)) 
    367       { 
    368         newImp.setOpenAsHyperStack(hyperstack); 
    369       } 
     295      if (!newImp.isComposite()) newImp.setOpenAsHyperStack(hyperstack); 
    370296      newImp.show(); 
    371297    } 
  • trunk/components/loci-plugins/src/loci/plugins/Slicer.java

    r5093 r5133  
    3636import ij.process.ImageProcessor; 
    3737import ij.process.LUT; 
    38  
    39 import java.io.ByteArrayOutputStream; 
    40 import java.io.PrintStream; 
    41  
    42 import loci.common.ReflectException; 
    43 import loci.common.ReflectedUniverse; 
    4438import loci.formats.FormatTools; 
    4539import loci.plugins.util.ImagePlusTools; 
    46 import loci.plugins.util.LibraryChecker; 
    4740 
    4841/** 
     
    134127    Calibration calibration = imp.getCalibration(); 
    135128 
    136     Class c = null; 
    137     try { 
    138       c = Class.forName("ij.CompositeImage"); 
    139     } 
    140     catch (ClassNotFoundException e) { } 
    141  
    142129    int sizeZ = imp.getNSlices(); 
    143130    int sizeC = imp.getNChannels(); 
     
    170157        sliceC ? sizeC : 1, sliceT ? sizeT : 1, newStacks.length, i); 
    171158 
    172       if (imp.getClass().equals(c)) { 
    173         try { 
    174           ReflectedUniverse r = new ReflectedUniverse(); 
    175           r.setVar("imp", imp); 
    176           r.setVar("channel", zct[1] + 1); 
    177           LUT lut = (LUT) r.exec("imp.getChannelLut(channel)"); 
    178           newStacks[i].setColorModel(lut); 
    179         } 
    180         catch (ReflectException e) { } 
     159      if (imp.isComposite()) { 
     160        LUT lut = ((CompositeImage) imp).getChannelLut(zct[1] + 1); 
     161        newStacks[i].setColorModel(lut); 
    181162      } 
    182163 
     
    194175      p.setCalibration(calibration); 
    195176      p.setFileInfo(imp.getOriginalFileInfo()); 
    196       boolean canDoComposite = LibraryChecker.checkComposite(); 
    197       if (canDoComposite && !(p instanceof CompositeImage)) { 
     177      if (!p.isComposite()) { 
    198178        p.setOpenAsHyperStack(hyperstack); 
    199179      } 
    200       if (imp.getClass().equals(c) && !sliceC && canDoComposite) { 
    201         try { 
    202           ReflectedUniverse r = new ReflectedUniverse(); 
    203           r.exec("import ij.CompositeImage"); 
    204           r.setVar("p", ImagePlusTools.reorder(p, stackOrder, "XYCZT")); 
    205           r.exec("c = new CompositeImage(p, CompositeImage.COMPOSITE)"); 
    206           r.exec("c.show()"); 
    207         } 
    208         catch (ReflectException e) { 
    209           ByteArrayOutputStream s = new ByteArrayOutputStream(); 
    210           e.printStackTrace(new PrintStream(s)); 
    211           IJ.error(s.toString()); 
    212         } 
     180      if (imp.isComposite() && !sliceC) { 
     181        p = ImagePlusTools.reorder(p, stackOrder, "XYCZT"); 
     182        new CompositeImage(p, CompositeImage.COMPOSITE).show(); 
    213183      } 
    214184      else p.show(); 
  • trunk/components/loci-plugins/src/loci/plugins/config/ConfigWindow.java

    r5111 r5133  
    2525 
    2626package loci.plugins.config; 
    27  
    28 import ij.Prefs; 
    2927 
    3028import java.awt.Dimension; 
     
    6563 
    6664import loci.plugins.importer.ImporterOptions; 
     65import loci.plugins.util.WindowTools; 
    6766 
    6867/** 
     
    200199    upgradePanel.add(upgradeLabel); 
    201200 
    202     options = new ImporterOptions(); 
    203     options.loadPreferences(); 
     201    try { 
     202      options = new ImporterOptions(); 
     203    } 
     204    catch (IOException exc) { 
     205      WindowTools.reportException(exc); 
     206    } 
     207    options.loadOptions(); 
    204208    upgradeBox = new JCheckBox("", options.doUpgradeCheck()); 
    205209    upgradeBox.addItemListener(this); 
     
    239243  public void itemStateChanged(ItemEvent e) { 
    240244    Object src = e.getSource(); 
     245    // CTR TODO 
     246    /* 
    241247    if (src == upgradeBox) { 
    242248      options.setUpgradeCheck(upgradeBox.isSelected()); 
     
    244250      return; 
    245251    } 
     252    */ 
    246253 
    247254    Object value = formatsList.getSelectedValue(); 
  • trunk/components/loci-plugins/src/loci/plugins/config/InstallWizard.java

    r5093 r5133  
    7575    // capabilities: 
    7676 
    77     // Check for ImageJ 1.39 or newer 
     77    // Check for ImageJ 1.40 or newer 
    7878    // download and install latest ij.jar 
    7979    // don't launch ImageJ updater plugin because it might not exist 
  • trunk/components/loci-plugins/src/loci/plugins/importer/Importer.java

    r5113 r5133  
    4141import java.awt.Rectangle; 
    4242import java.awt.image.IndexColorModel; 
    43 import java.io.ByteArrayOutputStream; 
    4443import java.io.File; 
    4544import java.io.IOException; 
    46 import java.io.PrintStream; 
    4745import java.util.Arrays; 
    4846import java.util.Enumeration; 
    4947import java.util.Hashtable; 
    50 import java.util.StringTokenizer; 
    5148import java.util.Vector; 
    5249 
     
    7269import loci.plugins.LociImporter; 
    7370import loci.plugins.Updater; 
     71import loci.plugins.util.BFVirtualStack; 
    7472import loci.plugins.util.DataBrowser; 
    7573import loci.plugins.util.ImagePlusReader; 
    7674import loci.plugins.util.ImagePlusTools; 
    7775import loci.plugins.util.LociPrefs; 
     76import loci.plugins.util.OptionsDialog; 
    7877import loci.plugins.util.ROIHandler; 
    7978import loci.plugins.util.SearchableWindow; 
     
    121120    debug("parse core options"); 
    122121 
    123     ImporterOptions options = new ImporterOptions(); 
    124     options.loadPreferences(); 
     122    ImporterOptions options = null; 
     123    try { 
     124                                 
     125      options = new ImporterOptions(); 
     126    } 
     127    catch (IOException exc) { 
     128      WindowTools.reportException(exc); 
     129    } 
     130    options.loadOptions(); 
    125131    options.parseArg(arg); 
    126132 
     
    145151    debug("construct reader and check id"); 
    146152 
    147     int status = options.promptLocation(); 
     153    LocationDialog locationDialog = new LocationDialog(options); 
     154    int status = locationDialog.showDialog(); 
    148155    if (!statusOk(status)) return; 
    149     status = options.promptId(); 
     156 
     157    IdDialog idDialog = new IdDialog(options); 
     158    status = idDialog.showDialog(); 
    150159    if (!statusOk(status)) return; 
    151160 
     
    153162    boolean quiet = options.isQuiet(); 
    154163 
    155     Location idLoc = options.getIdLocation(); 
    156     String idName = options.getIdName(); 
    157     String idType = options.getIdType(); 
     164    String location = options.getLocation(); 
     165    Location idLoc = null; 
     166    String idName = id; 
     167    if (ImporterOptions.LOCATION_LOCAL.equals(location)) { 
     168      idLoc = new Location(id); 
     169      idName = idLoc.getName(); 
     170    } 
    158171 
    159172    IFormatReader base = null; 
     
    163176      try { base = reader.getReader(id); } 
    164177      catch (FormatException exc) { 
    165         reportException(exc, quiet, 
     178        WindowTools.reportException(exc, quiet, 
    166179          "Sorry, there was an error reading the file."); 
    167180        return; 
    168181      } 
    169182      catch (IOException exc) { 
    170         reportException(exc, quiet, 
     183        WindowTools.reportException(exc, quiet, 
    171184          "Sorry, there was a I/O problem reading the file."); 
    172185        return; 
     
    181194      } 
    182195      catch (ReflectException exc) { 
    183         reportException(exc, options.isQuiet(), 
     196        WindowTools.reportException(exc, options.isQuiet(), 
    184197          "Sorry, there was a problem constructing the OMERO I/O engine"); 
    185198        return; 
     
    194207      } 
    195208      catch (ReflectException exc) { 
    196         reportException(exc, options.isQuiet(), 
     209        WindowTools.reportException(exc, options.isQuiet(), 
    197210          "Sorry, there was a problem constructing the OME I/O engine"); 
    198211        return; 
     
    200213    } 
    201214    else { 
    202       reportException(null, options.isQuiet(), 
     215      WindowTools.reportException(null, options.isQuiet(), 
    203216        "Sorry, there has been an internal error: unknown data source"); 
    204217    } 
     
    214227 
    215228    boolean windowless = options.isWindowless() || LociPrefs.isWindowless(base); 
    216     if (!windowless) status = options.promptOptions(); 
     229    if (!windowless) { 
     230      ImporterDialog importerDialog = new ImporterDialog(options); 
     231      status = importerDialog.showDialog(); 
     232    } 
    217233    if (!statusOk(status)) return; 
    218234 
     
    229245 
    230246    // save options as new defaults 
    231     options.savePreferences(); 
     247    options.saveOptions(); 
    232248 
    233249    // -- Step 4: analyze and read from data source -- 
     
    252268      if (groupFiles) { 
    253269        debug("prompt for the file pattern"); 
    254         status = options.promptFilePattern(); 
     270        FilePatternDialog filePatternDialog = new FilePatternDialog(options); 
     271        status = filePatternDialog.showDialog(); 
    255272        if (!statusOk(status)) return; 
    256273        id = options.getId(); 
     
    350367      { 
    351368        debug("prompt for which series to import"); 
    352         status = options.promptSeries(r, seriesLabels, series); 
     369        SeriesDialog seriesDialog = new SeriesDialog(options, 
     370          r, seriesLabels, series); 
     371        status = seriesDialog.showDialog(); 
    353372        if (!statusOk(status)) return; 
    354373      } 
     
    363382      if (swapDimensions) { 
    364383        debug("prompt for dimension swapping parameters"); 
    365         options.promptSwap(virtualReader, series); 
     384 
     385        SwapDialog swapDialog = new SwapDialog(options, virtualReader, series); 
     386        status = swapDialog.showDialog(); 
     387        if (!statusOk(status)) return; 
    366388 
    367389        for (int i=0; i<seriesCount; i++) { 
     
    391413          debug("prompt for planar ranges"); 
    392414          IJ.showStatus(""); 
    393           status = options.promptRange(r, series, seriesLabels, 
    394             cBegin, cEnd, cStep, zBegin, zEnd, zStep, tBegin, tEnd, tStep); 
     415          RangeDialog rangeDialog = new RangeDialog(options, 
     416            r, series, seriesLabels, cBegin, cEnd, cStep, 
     417            zBegin, zEnd, zStep, tBegin, tEnd, tStep); 
     418          status = rangeDialog.showDialog(); 
    395419          if (!statusOk(status)) return; 
    396420        } 
     
    412436      } 
    413437      if (cropOnImport) { 
    414         status = options.promptCropSize(r, seriesLabels, series, cropOptions); 
    415         if (!statusOk(status)) return; 
     438        CropDialog cropDialog = new CropDialog(options, 
     439          r, seriesLabels, series, cropOptions); 
     440        status = cropDialog.showDialog(); 
     441        if (!statusOk(status)) return; 
    416442      } 
    417443 
     
    425451        Hashtable meta = r.getMetadata(); 
    426452        //if (seriesCount == 1) meta = r.getMetadata(); 
    427         meta.put(idType, currentFile); 
     453        meta.put(location, currentFile); 
    428454        int digits = digits(seriesCount); 
    429455        for (int i=0; i<seriesCount; i++) { 
     
    482508          } 
    483509          catch (javax.xml.parsers.ParserConfigurationException exc) { 
    484             reportException(exc, options.isQuiet(), 
     510            WindowTools.reportException(exc, options.isQuiet(), 
    485511              "Sorry, there was a problem displaying the OME metadata"); 
    486512          } 
    487513          catch (org.xml.sax.SAXException exc) { 
    488             reportException(exc, options.isQuiet(), 
     514            WindowTools.reportException(exc, options.isQuiet(), 
    489515              "Sorry, there was a problem displaying the OME metadata"); 
    490516          } 
     
    573599          boolean needComposite = doMerge && (cSize > 3 || eight); 
    574600          int merge = (needComposite || !doMerge) ? 1 : cSize; 
    575           // NB: BFVirtualStack extends VirtualStack, which only exists in 
    576           // ImageJ v1.39+. We avoid referencing it directly to keep the 
    577           // class loader happy for earlier versions of ImageJ. 
    578           try { 
    579             ReflectedUniverse ru = new ReflectedUniverse(); 
    580             ru.exec("import loci.plugins.util.BFVirtualStack"); 
    581             ru.setVar("id", id); 
    582             ru.setVar("r", r); 
    583             ru.setVar("colorize", colorize); 
    584             ru.setVar("merge", doMerge); 
    585             ru.setVar("record", options.isRecord()); 
    586             stackB = (ImageStack) ru.exec("stackB = new BFVirtualStack(id, " + 
    587               "r, colorize, merge, record)"); 
    588  
    589             if (doMerge) { 
    590               cCount[i] = 1; 
    591               for (int j=0; j<num[i]; j++) { 
    592                 int[] pos = r.getZCTCoords(j); 
    593                 if (pos[1] > 0) continue; 
    594                 String label = constructSliceLabel( 
    595                   new ChannelMerger(r).getIndex(pos[0], pos[1], pos[2]), r, 
    596                   omexmlMeta, i, zCount, cCount, tCount); 
    597                 ru.setVar("label", label); 
    598                 ru.exec("stackB.addSlice(label)"); 
    599               } 
    600             } 
    601             else { 
    602               for (int j=0; j<num[i]; j++) { 
    603                 String label = constructSliceLabel(j, r, 
    604                   omexmlMeta, i, zCount, cCount, tCount); 
    605                 ru.setVar("label", label); 
    606                 ru.exec("stackB.addSlice(label)"); 
    607               } 
    608             } 
    609           } 
    610           catch (ReflectException exc) { 
    611             reportException(exc, options.isQuiet(), 
    612               "Sorry, there was a problem constructing the virtual stack"); 
    613             return; 
     601 
     602          // NB: ImageJ 1.39+ is required for VirtualStack 
     603          BFVirtualStack virtualStackB = new BFVirtualStack(id, 
     604            r, colorize, doMerge, options.isRecord()); 
     605          stackB = virtualStackB; 
     606          if (doMerge) { 
     607            cCount[i] = 1; 
     608            for (int j=0; j<num[i]; j++) { 
     609              int[] pos = r.getZCTCoords(j); 
     610              if (pos[1] > 0) continue; 
     611              String label = constructSliceLabel( 
     612                new ChannelMerger(r).getIndex(pos[0], pos[1], pos[2]), r, 
     613                omexmlMeta, i, zCount, cCount, tCount); 
     614              virtualStackB.addSlice(label); 
     615            } 
     616          } 
     617          else { 
     618            for (int j=0; j<num[i]; j++) { 
     619              String label = constructSliceLabel(j, r, 
     620                omexmlMeta, i, zCount, cCount, tCount); 
     621              virtualStackB.addSlice(label); 
     622            } 
    614623          } 
    615624        } 
     
    781790      } 
    782791      catch (IOException exc) { 
    783         reportException(exc, options.isQuiet(), 
     792        WindowTools.reportException(exc, options.isQuiet(), 
    784793          "Sorry, there was a problem closing the file"); 
    785794      } 
     
    788797    } 
    789798    catch (FormatException exc) { 
    790       reportException(exc, quiet, 
     799      WindowTools.reportException(exc, quiet, 
    791800        "Sorry, there was a problem reading the data."); 
    792801    } 
    793802    catch (IOException exc) { 
    794       reportException(exc, quiet, 
     803      WindowTools.reportException(exc, quiet, 
    795804        "Sorry, there was an I/O problem reading the data."); 
    796805    } 
     
    879888      } 
    880889      catch (ReflectException exc) { 
    881         reportException(exc, options.isQuiet(), 
     890        WindowTools.reportException(exc, options.isQuiet(), 
    882891          "Sorry, there was a problem interfacing with VisBio"); 
    883892        return; 
     
    902911      } 
    903912      catch (ReflectException exc) { 
    904         reportException(exc, options.isQuiet(), 
     913        WindowTools.reportException(exc, options.isQuiet(), 
    905914          "Sorry, there was a problem interfacing with Image5D"); 
    906915        return; 
     
    912921    } 
    913922    else if (!options.isViewNone()) { 
    914       if (IJ.getVersion().compareTo("1.39l") >= 0) { 
    915         boolean hyper = options.isViewHyperstack() || options.isViewBrowser(); 
    916         imp.setOpenAsHyperStack(hyper); 
    917       } 
     923      // NB: ImageJ 1.39+ is required for hyperstacks 
     924      boolean hyper = options.isViewHyperstack() || options.isViewBrowser(); 
     925      imp.setOpenAsHyperStack(hyper); 
    918926 
    919927      if (!concatenate) { 
     
    10521060  /** Verifies that the given status result is OK. */ 
    10531061  private boolean statusOk(int status) { 
    1054     if (status == ImporterOptions.STATUS_CANCELED) plugin.canceled = true; 
    1055     return status == ImporterOptions.STATUS_OK; 
    1056   } 
    1057  
    1058   /** Reports the given exception with stack trace in an ImageJ error dialog. */ 
    1059   private void reportException(Throwable t, boolean quiet, String msg) { 
    1060     IJ.showStatus(""); 
    1061     if (!quiet) { 
    1062       if (t != null) { 
    1063         ByteArrayOutputStream buf = new ByteArrayOutputStream(); 
    1064         t.printStackTrace(new PrintStream(buf)); 
    1065         String s = new String(buf.toByteArray()); 
    1066         StringTokenizer st = new StringTokenizer(s, "\n\r"); 
    1067         while (st.hasMoreTokens()) IJ.write(st.nextToken()); 
    1068       } 
    1069       IJ.error("Bio-Formats Importer", msg); 
    1070     } 
     1062    if (status == OptionsDialog.STATUS_CANCELED) plugin.canceled = true; 
     1063    return status == OptionsDialog.STATUS_OK; 
    10711064  } 
    10721065 
  • trunk/components/loci-plugins/src/loci/plugins/importer/ImporterOptions.java

    r5113 r5133  
    2626package loci.plugins.importer; 
    2727 
    28 import com.jgoodies.forms.builder.PanelBuilder; 
    29 import com.jgoodies.forms.layout.CellConstraints; 
    30 import com.jgoodies.forms.layout.FormLayout; 
    31  
    32 import ij.IJ; 
    33 import ij.Macro; 
    34 import ij.Prefs; 
    35 import ij.gui.GenericDialog; 
    36 import ij.io.OpenDialog; 
    37  
    38 import java.awt.Button; 
    39 import java.awt.Checkbox; 
    40 import java.awt.Choice; 
    41 import java.awt.Component; 
    42 import java.awt.Dimension; 
    43 import java.awt.GridBagConstraints; 
    44 import java.awt.GridBagLayout; 
    45 import java.awt.KeyboardFocusManager; 
    46 import java.awt.Label; 
    47 import java.awt.Panel; 
    48 import java.awt.Rectangle; 
    49 import java.awt.event.ActionEvent; 
    50 import java.awt.event.FocusEvent; 
    51 import java.awt.event.FocusListener; 
    52 import java.awt.event.ItemEvent; 
    53 import java.awt.event.ItemListener; 
    54 import java.awt.event.MouseEvent; 
    55 import java.awt.event.MouseListener; 
    56 import java.awt.image.BufferedImage; 
    57 import java.util.Arrays; 
    58 import java.util.Hashtable; 
    59 import java.util.StringTokenizer; 
    60 import java.util.Vector; 
    61  
    62 import javax.swing.Box; 
    63 import javax.swing.ImageIcon; 
    64 import javax.swing.JEditorPane; 
    65 import javax.swing.JLabel; 
    66 import javax.swing.JScrollPane; 
     28import java.io.IOException; 
    6729 
    6830import loci.common.Location; 
    69 import loci.formats.AWTImageTools; 
    70 import loci.formats.DimensionSwapper; 
    71 import loci.formats.FilePattern; 
    72 import loci.formats.FormatTools; 
    73 import loci.formats.IFormatReader; 
     31import loci.plugins.prefs.OptionsList; 
     32import loci.plugins.prefs.StringOption; 
    7433import loci.plugins.util.LibraryChecker; 
    75 import loci.plugins.util.WindowTools; 
    7634 
    7735/** 
     
    8543 * <a href="https://skyking.microscopy.wisc.edu/svn/java/trunk/components/loci-plugins/src/loci/plugins/importer/ImporterOptions.java">SVN</a></dd></dl> 
    8644 */ 
    87 public class ImporterOptions 
    88   implements FocusListener, ItemListener, MouseListener 
    89 { 
     45public class ImporterOptions extends OptionsList { 
    9046 
    9147  // -- Constants -- 
    9248 
    93   // enumeration for status 
    94   public static final int STATUS_OK = 0; 
    95   public static final int STATUS_CANCELED = 1; 
    96   public static final int STATUS_FINISHED = 2; 
    97  
    98   // enumeration for stackFormat 
    99   public static final String VIEW_NONE = "Metadata only"; 
    100   public static final String VIEW_STANDARD = "Standard ImageJ"; 
     49  // option keys 
     50  public static final String KEY_AUTOSCALE       = "autoscale"; 
     51  public static final String KEY_COLORIZE        = "colorize"; 
     52  public static final String KEY_CONCATENATE     = "concatenate"; 
     53  public static final String KEY_CROP            = "crop"; 
     54  public static final String KEY_CUSTOM_COLORIZE = "customColorize"; 
     55  public static final String KEY_FIRST           = "firstTime"; 
     56  public static final String KEY_FORCE_THUMBS    = "forceThumbnails"; 
     57  public static final String KEY_GROUP_FILES     = "groupFiles"; 
     58  public static final String KEY_ID              = "id"; 
     59  public static final String KEY_LOCATION        = "location"; 
     60  public static final String KEY_MERGE_CHANNELS  = "mergeChannels"; 
     61  public static final String KEY_MERGE_OPTION    = "mergeOption"; 
     62  public static final String KEY_OPEN_ALL_SERIES = "openAllSeries"; 
     63  public static final String KEY_QUIET           = "quiet"; 
     64  public static final String KEY_RECORD          = "record"; 
     65  public static final String KEY_SERIES          = "series"; 
     66  public static final String KEY_SHOW_METADATA   = "showMetadata"; 
     67  public static final String KEY_SHOW_OME_XML    = "showOMEXML"; 
     68  public static final String KEY_SHOW_ROIS       = "showROIs"; 
     69  public static final String KEY_SPECIFY_RANGES  = "specifyRanges"; 
     70  public static final String KEY_SPLIT_Z         = "splitFocalPlanes"; 
     71  public static final String KEY_SPLIT_T         = "splitTimepoints"; 
     72  public static final String KEY_SPLIT_C         = "splitWindows"; 
     73  public static final String KEY_STACK_FORMAT    = "stackFormat"; 
     74  public static final String KEY_STACK_ORDER     = "stackOrder"; 
     75  public static final String KEY_SWAP_DIMS       = "swapDimensions"; 
     76  public static final String KEY_UPGRADE_CHECK   = "upgradeCheck"; 
     77  public static final String KEY_VIRTUAL         = "virtual"; 
     78  public static final String KEY_WINDOWLESS      = "windowless"; 
     79 
     80  // possible values for location 
     81  public static final String LOCATION_LOCAL = "Local machine"; 
     82  public static final String LOCATION_HTTP  = "Internet"; 
     83  public static final String LOCATION_OME   = "OME server"; 
     84  public static final String LOCATION_OMERO = "OMERO server"; 
     85 
     86  // possible values for stackFormat 
     87  public static final String VIEW_NONE       = "Metadata only"; 
     88  public static final String VIEW_STANDARD   = "Standard ImageJ"; 
    10189  public static final String VIEW_HYPERSTACK = "Hyperstack"; 
    102   public static final String VIEW_BROWSER = "Data Browser"; 
    103   public static final String VIEW_VISBIO = "VisBio"; 
    104   public static final String VIEW_IMAGE_5D = "Image5D"; 
    105   public static final String VIEW_VIEW_5D = "View5D"; 
    106  
    107   // enumeration for stackOrder 
     90  public static final String VIEW_BROWSER    = "Data Browser"; 
     91  public static final String VIEW_VISBIO     = "VisBio"; 
     92  public static final String VIEW_IMAGE_5D   = "Image5D"; 
     93  public static final String VIEW_VIEW_5D    = "View5D"; 
     94 
     95  // class to check for each stackFormat value 
     96  private static final String CLASS_VISBIO   = "loci.visbio.VisBio"; 
     97  private static final String CLASS_IMAGE_5D = "i5d.Image5D"; 
     98  private static final String CLASS_VIEW_5D  = "View5D_"; 
     99 
     100  // possible values for stackOrder 
    108101  public static final String ORDER_DEFAULT = "Default"; 
    109   public static final String ORDER_XYZCT = "XYZCT"; 
    110   public static final String ORDER_XYZTC = "XYZTC"; 
    111   public static final String ORDER_XYCZT = "XYCZT"; 
    112   public static final String ORDER_XYTCZ = "XYTCZ"; 
    113   public static final String ORDER_XYCTZ = "XYCTZ"; 
    114   public static final String ORDER_XYTZC = "XYTZC"; 
    115  
    116   // merging options 
    117   public static final String MERGE_DEFAULT = "Do not merge"; 
    118   public static final String MERGE_PROJECTION = "Spectral projection"; 
    119  
    120   // class to check for each viewing option 
    121   private static final String CLASS_VISBIO = "loci.visbio.VisBio"; 
    122   private static final String CLASS_IMAGE_5D = "i5d.Image5D"; 
    123   private static final String CLASS_VIEW_5D = "View5D_"; 
    124  
    125   // enumeration for location 
    126   public static final String LOCATION_LOCAL = "Local machine"; 
    127   public static final String LOCATION_HTTP = "Internet"; 
    128   public static final String LOCATION_OME = "OME server"; 
    129   public static final String LOCATION_OMERO = "OMERO server"; 
    130   public static final String[] LOCATIONS = { 
    131     LOCATION_LOCAL, LOCATION_HTTP, LOCATION_OME, LOCATION_OMERO 
    132   }; 
    133  
    134   // keys for use in IJ_Prefs.txt 
    135   public static final String PREF_STACK = "bioformats.stackFormat"; 
    136   public static final String PREF_ORDER = "bioformats.stackOrder"; 
    137   public static final String PREF_MERGE = "bioformats.mergeChannels"; 
    138   public static final String PREF_COLORIZE = "bioformats.colorize"; 
    139   public static final String PREF_COLORIZE_CUSTOM = "bioformats.customColorize"; 
    140   public static final String PREF_SPLIT_C = "bioformats.splitWindows"; 
    141   public static final String PREF_SPLIT_Z = "bioformats.splitFocalPlanes"; 
    142   public static final String PREF_SPLIT_T = "bioformats.splitTimepoints"; 
    143   public static final String PREF_CROP = "bioformats.crop"; 
    144   public static final String PREF_METADATA = "bioformats.showMetadata"; 
    145   public static final String PREF_OME_XML = "bioformats.showOMEXML"; 
    146   public static final String PREF_GROUP = "bioformats.groupFiles"; 
    147   public static final String PREF_CONCATENATE = "bioformats.concatenate"; 
    148   public static final String PREF_RANGE = "bioformats.specifyRanges"; 
    149   public static final String PREF_AUTOSCALE = "bioformats.autoscale"; 
    150   public static final String PREF_VIRTUAL = "bioformats.virtual"; 
    151   public static final String PREF_RECORD = "bioformats.record"; 
    152   public static final String PREF_ALL_SERIES = "bioformats.openAllSeries"; 
    153   public static final String PREF_ROI = "bioformats.showROIs"; 
    154  
    155   public static final String PREF_MERGE_OPTION = "bioformats.mergeOption"; 
    156   public static final String PREF_WINDOWLESS = "bioformats.windowless"; 
    157   public static final String PREF_SERIES = "bioformats.series"; 
    158  
    159   public static final String PREF_FIRST = "bioformats.firstTime"; 
    160   public static final String PREF_THUMBNAIL = "bioformats.forceThumbnails"; 
    161   public static final String PREF_SWAP = "bioformats.swapDimensions"; 
    162  
    163   public static final String PREF_UPGRADE = "bioformats.upgradeCheck"; 
    164  
    165   // labels for user dialog; when trimmed these double as argument & macro keys 
    166   public static final String LABEL_STACK = "View stack with: "; 
    167   public static final String LABEL_ORDER = "Stack_order: "; 
    168   public static final String LABEL_MERGE = "Merge_channels to RGB"; 
    169   public static final String LABEL_COLORIZE = "RGB_colorize channels"; 
    170   public static final String LABEL_COLORIZE_CUSTOM = 
    171     "Custom_colorize channels"; 
    172   public static final String LABEL_SPLIT_C = "Split_channels"; 
    173   public static final String LABEL_SPLIT_Z = "Split_focal planes"; 
    174   public static final String LABEL_SPLIT_T = "Split_timepoints"; 
    175   public static final String LABEL_CROP = "Crop on import"; 
    176   public static final String LABEL_METADATA = 
    177     "Display_metadata in results window"; 
    178   public static final String LABEL_OME_XML = "Display_OME-XML metadata"; 
    179   public static final String LABEL_GROUP = "Group_files with similar names"; 
    180   public static final String LABEL_CONCATENATE = 
    181     "Concatenate_series when compatible"; 
    182   public static final String LABEL_RANGE = "Specify_range for each series"; 
    183   public static final String LABEL_AUTOSCALE = "Autoscale"; 
    184   public static final String LABEL_VIRTUAL = "Use_virtual_stack"; 
    185   public static final String LABEL_RECORD = 
    186     "Record_modifications_to_virtual_stack"; 
    187   public static final String LABEL_ALL_SERIES = "Open_all_series"; 
    188   public static final String LABEL_SWAP = "Swap_dimensions"; 
    189   public static final String LABEL_ROI = "Display_ROIs"; 
    190  
    191   public static final String LABEL_MERGE_OPTION = "Merging Options"; 
    192   public static final String LABEL_WINDOWLESS = "windowless"; 
    193   public static final String LABEL_SERIES = "series"; 
    194  
    195   public static final String LABEL_LOCATION = "Location: "; 
    196   public static final String LABEL_ID = "Open"; 
    197  
    198   public static final String LABEL_QUIET = "Quiet mode"; 
    199  
    200   // informative description of each option 
    201   public static final String INFO_STACK = info(LABEL_STACK) + 
    202     " - The type of image viewer to use when displaying the dataset." + 
    203     "<br><br>Possible choices are:<ul>" + 
    204     "<li><b>" + VIEW_NONE + "</b> - Display no pixels, only metadata.</li>" + 
    205     "<li><b>" + VIEW_STANDARD + "</b> - Display the pixels in a standard " + 
    206     "ImageJ window without multidimensional support.</li>" + 
    207     "<li><b>" + VIEW_HYPERSTACK + "</b> - Display the pixels in ImageJ's " + 
    208     "built-in 5D viewer. If you do not have this option, upgrade to a more " + 
    209     "recent version of ImageJ.</li>" + 
    210     "<li><b>" + VIEW_BROWSER + "</b> - Display the pixels in LOCI's " + 
    211     "multidimensional Data Browser viewer. The Data Browser has some " + 
    212     "additional features on top of the normal ImageJ hyperstack. If you do " + 
    213     "not have this option, upgrade to a more recent version of ImageJ.</li>" + 
    214     //"<li><b>" + VIEW_VISBIO + "</b> - Not yet implemented.</li>" 
    215     "<li><b>" + VIEW_IMAGE_5D + "</b> - Display the pixels in " + 
    216     "Joachim Walter's Image5D viewer. Requires the Image5D plugin.</li>" + 
    217     "<li><b>" + VIEW_VIEW_5D + "</b> - Display the pixels in " + 
    218     "Rainer Heintzmann's View5D viewer. Requires the View5D plugin.</li>" + 
    219     "</ul>"; 
    220   public static final String INFO_ORDER = info(LABEL_ORDER) + 
    221     " - Controls the rasterization order of the dataset's dimensional axes." + 
    222     "<br><br>Unless you care about the order in which the image planes " + 
    223     "appear, you probably don't need to worry too much about this option." + 
    224     "<br><br>By default, Bio-Formats reads the image planes in whatever " + 
    225     "order they are stored, which is format-dependent. However, several " + 
    226     "stack view modes require a specific rasterization order:<ul>" + 
    227     "<li>Hyperstacks must be in " + ORDER_XYCZT + " order.</li>" + 
    228     "<li>Image5D must be in " + ORDER_XYCZT + " order.</li>" + 
    229     "<li>View5D must be in " + ORDER_XYCZT + " order.</li>" + 
    230     "</ul><b>Example:</b> For a dataset in " + ORDER_XYCZT + " order with " + 
    231     "2 channels, 3 focal planes and 5 time points, the order would be:<ol>" + 
    232     "<li>C1-Z1-T1</li>" + 
    233     "<li>C2-Z1-T1</li>" + 
    234     "<li>C1-Z2-T1</li>" + 
    235     "<li>C2-Z2-T1</li>" + 
    236     "<li>C1-Z3-T1</li>" + 
    237     "<li>C2-Z3-T1</li>" + 
    238     "<li>C1-Z1-T2</li>" + 
    239     "<li>C2-Z1-T2</li>" + 
    240     "<li>etc.</li>" + 
    241     "</ol>"; 
    242   public static final String INFO_MERGE = info(LABEL_MERGE) + 
    243     " - A dataset with multiple channels will be opened and merged with " + 
    244     "channels pseudocolored in the order of the RGB color scheme; i.e., " + 
    245     "channel 1 is red, channel 2 is green, and channel 3 is blue." + 
    246     "<br><br>The bit depth will be preserved. If the dataset has more than " + 
    247     "3 channels, Bio-Formats will ask how to combine them." + 
    248     "<br><br>For example, a 12-channel image could be combined into:<ul>" + 
    249     "<li>6 planes with 2 channels each (1st channel is red, 2nd is green)" + 
    250     "</li>" + 
    251     "<li>4 planes with 3 channels each (3rd channel is blue)</li>" + 
    252     "<li>3 planes with 4 channels each (4th channel is gray)</li>" + 
    253     "<li>3 planes with 5 channels each (5th channel is cyan)</li>" + 
    254     "<li>2 planes with 6 channels each (6th channel is magenta)</li>" + 
    255     "<li>2 planes with 7 channels each (7th channel is yellow)</li>" + 
    256     "</ul>"; 
    257   public static final String INFO_COLORIZE = info(LABEL_COLORIZE) + 
    258     " - Each channel is assigned an appropriate pseudocolor table rather " + 
    259     "than the normal grayscale." + 
    260     "<br><br>The first channel is colorized red, the second channel is " + 
    261     "green, and the third channel is blue. This option is not available " + 
    262     "when " + info(LABEL_MERGE) + " or " + info(LABEL_COLORIZE_CUSTOM) + 
    263     " are set."; 
    264   public static final String INFO_COLORIZE_CUSTOM = 
    265     info(LABEL_COLORIZE_CUSTOM) + " - Each channel is assigned a pseudocolor " + 
    266     "table rather than the normal grayscale.<br><br>The color for each " + 
    267     "channel is chosen by the user. This option is not available when " + 
    268     info(LABEL_MERGE) + " or " + info(LABEL_COLORIZE) + " are set."; 
    269   public static final String INFO_SPLIT_C = info(LABEL_SPLIT_C) + 
    270     " - Each channel is opened as a separate stack." + 
    271     "<br><br>This option is especially useful if you want to merge the " + 
    272     "channels into a specific order, rather than automatically assign " + 
    273     "channels to the order of RGB. The bit depth is preserved."; 
    274   public static final String INFO_SPLIT_Z = info(LABEL_SPLIT_Z) + 
    275     " - Each focal plane is opened as a separate stack."; 
    276   public static final String INFO_SPLIT_T = info(LABEL_SPLIT_T) + 
    277     " - Timelapse data will be opened as a separate stack for each timepoint."; 
    278   public static final String INFO_CROP = info(LABEL_CROP) + 
    279     " - Image planes may be cropped during import to conserve memory." + 
    280     "<br><br>A window is opened with display of the pixel width and height " + 
    281     "of the image plane. Enter the X and Y coordinates for the upper left " + 
    282     "corner of the crop region and the width and height of the selection to " + 
    283     "be displayed, in pixels."; 
    284   public static final String INFO_METADATA = info(LABEL_METADATA) + 
    285     " - Reads metadata that may be contained within the file format and " + 
    286     "displays it. You can save it as a text file or copy it from the File " + 
    287     "and Edit menus specific to the ImageJ Results window. Readability " + 
    288     "depends upon the manner in which metadata is formatted in the data " + 
    289     "source."; 
    290   public static final String INFO_OME_XML = info(LABEL_OME_XML) + 
    291     " - Displays a tree of metadata standardized into the OME data model. " + 
    292     "This structure is the same regardless of file format, though some " + 
    293     "formats will populate more information than others." + 
    294     "<br><br><b>Examples:</b><ul>" + 
    295     "<li>The title of the dataset is listed under " + 
    296     "OME &gt; Image &gt; Name.</li>" + 
    297     "<li>The time and date when the dataset was acquired is listed under " + 
    298     "OME &gt; Image &gt; CreationDate.</li>" + 
    299     "<li>The physical pixel sizes of each plane in microns is listed under " + 
    300     "OME &gt; Image &gt; Pixels &gt; " + 
    301     "PhysicalSizeX, PhysicalSizeY, PhysicalSizeZ.</li>" + 
    302     "</ul>"; 
    303   public static final String INFO_GROUP = info(LABEL_GROUP) + 
    304     " - Parses filenames in the selected folder to open files with similar " + 
    305     "names as planes in the same dataset." + 
    306     "<br><br>The base filename and path is presented before opening for " + 
    307     "editing." + 
    308     "<br><br><b>Example:</b> Suppose you have a collection of 12 TIFF files " + 
    309     "numbered data1.tif, data2.tif, ..., data12.tif, with each file " + 
    310     "representing one timepoint, and containing the 9 focal planes at that " + 
    311     "timepoint. If you leave this option unchecked and attempt to import " + 
    312     "data1.tif, Bio-Formats will create an image stack with 9 planes. " + 
    313     "But if you enable this option, Bio-Formats will automatically detect " + 
    314     "the other similarly named files and present a confirmation dialog with " + 
    315     "the detected file pattern, which in this example would be " + 
    316     "<code>data&lt;1-12&gt;.tif</code>. You can then edit the pattern in " + 
    317     "case it is incorrect. Bio-Formats will then import all 12 x 9 = 108 " + 
    318     "planes of the dataset."; 
    319   public static final String INFO_CONCATENATE = info(LABEL_CONCATENATE) + 
    320     " - Allows multiple image series to be joined end to end." + 
    321     "<br><br><b>Example:</b> You want to join two sequential timelapse " + 
    322     "series."; 
    323   public static final String INFO_RANGE = info(LABEL_RANGE) + 
    324     " - Opens only the specified range of image planes from a dataset." + 
    325     "<br><br>After analyzing the dataset dimensional parameters, " + 
    326     "Bio-Formats will present an additional dialog box prompting for the " + 
    327     "desired range." + 
    328     "<br><br><b>Example:</b> You only want to open the range of focal " + 
    329     "planes in a z-series that actually contain structures of interest to " + 
    330     "conserve memory."; 
    331   public static final String INFO_AUTOSCALE = info(LABEL_AUTOSCALE) + 
    332     " - Stretches the histogram of the image planes to fit the data range. " + 
    333     "Does not alter underlying values in the image. If selected, histogram " + 
    334     "is stretched for each stack based upon the global minimum and maximum " + 
    335     "value throughout the stack. " + 
    336     "<br><br>Note that you can use the Brightness &amp; Contrast or " + 
    337     "Window/Level controls to adjust the contrast range regardless of " + 
    338     "whether this option is used."; 
    339   public static final String INFO_VIRTUAL = info(LABEL_VIRTUAL) + 
    340     " - Only reads one image plane into memory at a time, loading from the " + 
    341     "data source on the fly as the active image plane changes." + 
    342     "<br><br>This option is essential for datasets too large to fit into " + 
    343     "memory."; 
    344   public static final String INFO_RECORD = info(LABEL_RECORD) + 
    345     " - <i>BETA FEATURE</i> - Record and reapply changes to virtual stack " + 
    346     "planes." + 
    347     "<br><br>When viewing as a virtual stack with this option enabled, " + 
    348     "Bio-Formats will attempt to record the operations you perform. When " + 
    349     "you switch to a new image plane, Bio-Formats will \"play back\" those " + 
    350     "same operations, so that the image plane undergoes the same processing " + 
    351     "you performed previously. In this way, the image stack should behave " + 
    352     "more like a normal, fully memory-resident image stack."; 
    353   public static final String INFO_ALL_SERIES = info(LABEL_ALL_SERIES) + 
    354     " - Opens every available image series without prompting." + 
    355     "<br><br>Some datasets contain multiple distinct image series. Normally " + 
    356     "when Bio-Formats detects such data it presents a dialog box with " + 
    357     "thumbnails allowing individual selection of each available series. " + 
    358     "Checking this box instructs Bio-Formats to bypass this dialog box and " + 
    359     "instead open every available image series. Essentially, it is a " + 
    360     "shortcut for checking all the boxes in the series selector dialog box. " + 
    361     "It is also useful in a macro when the number of available image series " + 
    362     "is unknown."; 
    363   public static final String INFO_SWAP = info(LABEL_SWAP) + 
    364     " - Allows reassignment of dimensional axes (e.g., channel, Z and time)." + 
    365     "<br><br>Bio-Formats is supposed to be smart about handling " + 
    366     "multidimensional image data, but in some cases gets things wrong. " + 
    367     "For example, when stitching together a dataset from multiple files " + 
    368     "using the " + info(LABEL_GROUP) + " option, Bio-Formats may not know " + 
    369     "which dimensional axis the file numbering is supposed to represent. " + 
    370     "It will take a guess, but in case it guesses wrong, you can use " + 
    371     info(LABEL_SWAP) + " to reassign which dimensions are which."; 
    372   public static final String INFO_ROI = info(LABEL_ROI) + 
    373     " - Adds any ROIs in the file to ImageJ's ROI manager."; 
    374  
    375   public static final String INFO_DEFAULT = 
    376     "<i>Select an option for a detailed explanation. " + 
    377     "Documentation written by Glen MacDonald and Curtis Rueden.</i>"; 
    378  
    379   /** Flag indicating whether to invoke workaround for AWT refresh bug. */ 
    380   private static final boolean IS_GLITCHED = 
    381     System.getProperty("os.name").indexOf("Mac OS X") >= 0; 
    382  
    383   // -- Fields - GUI components -- 
    384  
    385   private Choice stackChoice; 
    386   private Choice orderChoice; 
    387   private Checkbox mergeBox; 
    388   private Checkbox colorizeBox; 
    389   private Checkbox customColorizeBox; 
    390   private Checkbox splitCBox; 
    391   private Checkbox splitZBox; 
    392   private Checkbox splitTBox; 
    393   private Checkbox metadataBox; 
    394   private Checkbox omexmlBox; 
    395   private Checkbox groupBox; 
    396   private Checkbox concatenateBox; 
    397   private Checkbox rangeBox; 
    398   private Checkbox autoscaleBox; 
    399   private Checkbox virtualBox; 
    400   private Checkbox recordBox; 
    401   private Checkbox allSeriesBox; 
    402   private Checkbox cropBox; 
    403   private Checkbox swapBox; 
    404   private Checkbox roiBox; 
    405  
    406   private Hashtable infoTable; 
    407   private JEditorPane infoPane; 
    408  
    409   private Choice mergeChoice; 
    410  
    411   // -- Fields - core options -- 
    412  
    413   private boolean firstTime; 
    414   private String stackFormat; 
    415   private String stackOrder; 
    416   private boolean mergeChannels; 
    417   private boolean colorize; 
    418   private boolean customColorize; 
    419   private boolean splitChannels; 
    420   private boolean splitFocalPlanes; 
    421   private boolean splitTimepoints; 
    422   private boolean crop; 
    423   private boolean showMetadata; 
    424   private boolean showOMEXML; 
    425   private boolean groupFiles; 
    426   private boolean concatenate; 
    427   private boolean specifyRanges; 
    428   private boolean autoscale; 
    429   private boolean virtual; 
    430   private boolean record; 
    431   private boolean openAllSeries; 
    432   private boolean swapDimensions; 
    433   private boolean upgradeCheck; 
    434   private boolean showROIs; 
    435  
    436   private String mergeOption; 
    437   private boolean windowless; 
    438   private String seriesString; 
    439  
    440   private boolean forceThumbnails; 
    441  
    442   private String location; 
    443   private String id; 
    444   private boolean quiet; 
    445  
    446   private Location idLoc; 
    447   private String idName; 
    448   private String idType; 
    449  
    450   // -- ImporterOptions methods - accessors -- 
    451  
    452   public boolean isFirstTime() { return firstTime; } 
    453  
    454   public String getStackFormat() { return stackFormat; } 
    455   public String getStackOrder() { return stackOrder; } 
    456   public boolean isMergeChannels() { return mergeChannels; } 
    457   public boolean isColorize() { return colorize; } 
    458   public boolean isCustomColorize() { return customColorize; } 
    459   public boolean isSplitChannels() { return splitChannels; } 
    460   public boolean isSplitFocalPlanes() { return splitFocalPlanes; } 
    461   public boolean isSplitTimepoints() { return splitTimepoints; } 
    462   public boolean isShowMetadata() { return showMetadata; } 
    463   public boolean isShowOMEXML() { return showOMEXML; } 
    464   public boolean isGroupFiles() { return groupFiles; } 
    465   public boolean isConcatenate() { return concatenate; } 
    466   public boolean isSpecifyRanges() { return specifyRanges; } 
    467   public boolean isForceThumbnails() { return forceThumbnails; } 
    468   public boolean isAutoscale() { return autoscale; } 
    469   public boolean isWindowless() { return windowless; } 
    470   public boolean isVirtual() { return virtual; } 
    471   public boolean isRecord() { return record; } 
    472   public boolean openAllSeries() { return openAllSeries; } 
    473   public boolean doCrop() { return crop; } 
    474   public boolean isSwapDimensions() { return swapDimensions; } 
    475   public boolean doUpgradeCheck() { return upgradeCheck; } 
    476   public boolean showROIs() { return showROIs; } 
    477  
    478   public String getMergeOption() { return mergeOption; } 
    479  
    480   public boolean isViewNone() { return VIEW_NONE.equals(stackFormat); } 
    481   public boolean isViewStandard() { return VIEW_STANDARD.equals(stackFormat); } 
    482   public boolean isViewHyperstack() { 
    483     return VIEW_HYPERSTACK.equals(stackFormat); 
    484   } 
    485   public boolean isViewBrowser() { return VIEW_BROWSER.equals(stackFormat); } 
    486   public boolean isViewVisBio() { return VIEW_VISBIO.equals(stackFormat); } 
    487   public boolean isViewImage5D() { return VIEW_IMAGE_5D.equals(stackFormat); } 
    488   public boolean isViewView5D() { return VIEW_VIEW_5D.equals(stackFormat); } 
    489  
    490   public String getLocation() { return location; } 
    491   public String getId() { return id; } 
    492   public boolean isQuiet() { return quiet; } 
    493  
    494   public boolean isLocal() { return LOCATION_LOCAL.equals(location); } 
    495   public boolean isHTTP() { return LOCATION_HTTP.equals(location); } 
    496   public boolean isOME() { return LOCATION_OME.equals(location); } 
    497   public boolean isOMERO() { return LOCATION_OMERO.equals(location); } 
    498  
    499   public Location getIdLocation() { return idLoc; } 
    500   public String getIdName() { return idName; } 
    501   public String getIdType() { return idType; } 
    502  
    503   // -- ImporterOptions methods - mutators -- 
    504  
    505   public void setStackFormat(String s) { stackFormat = s; } 
    506   public void setStackOrder(String s) { stackOrder = s; } 
    507   public void setMergeChannels(boolean b) { mergeChannels = b; } 
    508   public void setColorize(boolean b) { colorize = b; } 
    509   public void setCustomColorize(boolean b) { customColorize = b; } 
    510   public void setSplitChannels(boolean b) { splitChannels = b; } 
    511   public void setSplitFocalPlanes(boolean b) { splitFocalPlanes = b; } 
    512   public void setSplitTimepoints(boolean b) { splitTimepoints = b; } 
    513   public void setShowMetadata(boolean b) { showMetadata = b; } 
    514   public void setShowOMEXML(boolean b) { showOMEXML = b; } 
    515   public void setGroupFiles(boolean b) { groupFiles = b; } 
    516   public void setConcatenate(boolean b) { concatenate = b; } 
    517   public void setSpecifyRanges(boolean b) { specifyRanges = b; } 
    518   public void setForceThumbnails(boolean b) { forceThumbnails = b; } 
    519   public void setAutoscale(boolean b) { autoscale = b; } 
    520   public void setWindowless(boolean b) { windowless = b; } 
    521   public void setVirtual(boolean b) { virtual = b; } 
    522   public void setRecord(boolean b) { record = b; } 
    523   public void setOpenAllSeries(boolean b) { openAllSeries = b; } 
    524   public void setCrop(boolean b) { crop = b; } 
    525   public void setSwapDimensions(boolean b) { swapDimensions = b; } 
    526   public void setUpgradeCheck(boolean b) { upgradeCheck = b; } 
    527   public void setShowROIs(boolean b) { showROIs = b; } 
     102  public static final String ORDER_XYZCT   = "XYZCT"; 
     103  public static final String ORDER_XYZTC   = "XYZTC"; 
     104  public static final String ORDER_XYCZT   = "XYCZT"; 
     105  public static final String ORDER_XYTCZ   = "XYTCZ"; 
     106  public static final String ORDER_XYCTZ   = "XYCTZ"; 
     107  public static final String ORDER_XYTZC   = "XYTZC"; 
     108 
     109  // -- Constructor -- 
     110 
     111  public ImporterOptions() throws IOException { 
     112    super("importer-options.txt", ImporterOptions.class); 
     113    // remove unavailable stack formats 
     114    StringOption stackFormat = getStringOption(KEY_STACK_FORMAT); 
     115    if (!LibraryChecker.checkClass(CLASS_VISBIO)) { 
     116      stackFormat.removePossible(VIEW_VISBIO); 
     117    } 
     118    if (!LibraryChecker.checkClass(CLASS_IMAGE_5D)) { 
     119      stackFormat.removePossible(VIEW_IMAGE_5D); 
     120    } 
     121    if (!LibraryChecker.checkClass(CLASS_VIEW_5D)) { 
     122      stackFormat.removePossible(VIEW_VIEW_5D); 
     123    } 
     124  } 
    528125 
    529126  // -- ImporterOptions methods -- 
    530  
    531   /** Loads default option values from IJ_Prefs.txt. */ 
    532   public void loadPreferences() { 
    533     stackFormat = Prefs.get(PREF_STACK, VIEW_STANDARD); 
    534     stackOrder = Prefs.get(PREF_ORDER, ORDER_DEFAULT); 
    535     mergeChannels = Prefs.get(PREF_MERGE, false); 
    536     colorize = Prefs.get(PREF_COLORIZE, true); 
    537     customColorize = Prefs.get(PREF_COLORIZE_CUSTOM, false); 
    538     splitChannels = Prefs.get(PREF_SPLIT_C, true); 
    539     splitFocalPlanes = Prefs.get(PREF_SPLIT_Z, false); 
    540     splitTimepoints = Prefs.get(PREF_SPLIT_T, false); 
    541     crop = Prefs.get(PREF_CROP, false); 
    542     showMetadata = Prefs.get(PREF_METADATA, false); 
    543     showOMEXML = Prefs.get(PREF_OME_XML, false); 
    544     groupFiles = Prefs.get(PREF_GROUP, false); 
    545     concatenate = Prefs.get(PREF_CONCATENATE, false); 
    546     specifyRanges = Prefs.get(PREF_RANGE, false); 
    547     autoscale = Prefs.get(PREF_AUTOSCALE, true); 
    548     virtual = Prefs.get(PREF_VIRTUAL, false); 
    549     record = Prefs.get(PREF_RECORD, true); 
    550     openAllSeries = Prefs.get(PREF_ALL_SERIES, false); 
    551     swapDimensions = Prefs.get(PREF_SWAP, false); 
    552     upgradeCheck = Prefs.get(PREF_UPGRADE, false); 
    553     showROIs = Prefs.get(PREF_ROI, false); 
    554  
    555     if (Prefs.get(PREF_UPGRADE, null) == null) { 
    556       IJ.showMessage("The Bio-Formats plugin for ImageJ can automatically " + 
    557         "check for\nupgrades. By default, this feature is enabled, but you " + 
    558         "can disable\nit in the 'Upgrade' tab of the LOCI plugins " + 
    559         "configuration window."); 
    560     } 
    561  
    562     mergeOption = Prefs.get(PREF_MERGE_OPTION, MERGE_DEFAULT); 
    563     windowless = Prefs.get(PREF_WINDOWLESS, false); 
    564     seriesString = Prefs.get(PREF_SERIES, "0"); 
    565  
    566     firstTime = Prefs.get(PREF_FIRST, true); 
    567     forceThumbnails = Prefs.get(PREF_THUMBNAIL, false); 
    568   } 
    569  
    570   /** Saves option values to IJ_Prefs.txt as the new defaults. */ 
    571   public void savePreferences() { 
    572     Prefs.set(PREF_STACK, stackFormat); 
    573     Prefs.set(PREF_ORDER, stackOrder); 
    574     Prefs.set(PREF_MERGE, mergeChannels); 
    575     Prefs.set(PREF_COLORIZE, colorize); 
    576     Prefs.set(PREF_COLORIZE_CUSTOM, customColorize); 
    577     Prefs.set(PREF_SPLIT_C, splitChannels); 
    578     Prefs.set(PREF_SPLIT_Z, splitFocalPlanes); 
    579     Prefs.set(PREF_SPLIT_T, splitTimepoints); 
    580     Prefs.set(PREF_CROP, crop); 
    581     Prefs.set(PREF_METADATA, showMetadata); 
    582     Prefs.set(PREF_OME_XML, showOMEXML); 
    583     Prefs.set(PREF_GROUP, groupFiles); 
    584     Prefs.set(PREF_CONCATENATE, concatenate); 
    585     Prefs.set(PREF_RANGE, specifyRanges); 
    586     Prefs.set(PREF_AUTOSCALE, autoscale); 
    587     Prefs.set(PREF_VIRTUAL, virtual); 
    588     Prefs.set(PREF_RECORD, record); 
    589     Prefs.set(PREF_ALL_SERIES, openAllSeries); 
    590     Prefs.set(PREF_SWAP, swapDimensions); 
    591     Prefs.set(PREF_ROI, showROIs); 
    592  
    593     if (Prefs.get(PREF_UPGRADE, null) == null) upgradeCheck = true; 
    594     Prefs.set(PREF_UPGRADE, upgradeCheck); 
    595  
    596     Prefs.set(PREF_MERGE_OPTION, mergeOption); 
    597     Prefs.set(PREF_WINDOWLESS, windowless); 
    598     Prefs.set(PREF_SERIES, seriesString); 
    599  
    600     Prefs.set(PREF_FIRST, false); 
    601     //Prefs.set(PREF_THUMBNAIL, forceThumbnails); 
    602   } 
    603127 
    604128  /** Parses the plugin argument for parameter values. */ 
     
    613137      // will stop working correctly with HandleExtraFileTypes. 
    614138 
    615       location = LOCATION_LOCAL; 
    616       id = arg; 
    617       quiet = true; // suppress obnoxious error messages and such 
     139      setLocation(LOCATION_LOCAL); 
     140      setId(arg); 
     141      setQuiet(true); // suppress obnoxious error messages and such 
    618142    } 
    619143    else { 
     
    627151      // distinct behavior by calling the LociImporter plugin differently. 
    628152 
    629       stackFormat = Macro.getValue(arg, LABEL_STACK, stackFormat); 
    630       stackOrder = Macro.getValue(arg, LABEL_ORDER, stackOrder); 
    631       mergeChannels = getMacroValue(arg, LABEL_MERGE, mergeChannels); 
    632       colorize = getMacroValue(arg, LABEL_COLORIZE, colorize); 
    633       customColorize = 
    634         getMacroValue(arg, LABEL_COLORIZE_CUSTOM, customColorize); 
    635       splitChannels = getMacroValue(arg, LABEL_SPLIT_C, splitChannels); 
    636       splitFocalPlanes = getMacroValue(arg, LABEL_SPLIT_Z, splitFocalPlanes); 
    637       splitTimepoints = getMacroValue(arg, LABEL_SPLIT_T, splitTimepoints); 
    638       crop = getMacroValue(arg, LABEL_CROP, crop); 
    639       showMetadata = getMacroValue(arg, LABEL_METADATA, showMetadata); 
    640       showOMEXML = getMacroValue(arg, LABEL_OME_XML, showOMEXML); 
    641       groupFiles = getMacroValue(arg, LABEL_GROUP, groupFiles); 
    642       concatenate = getMacroValue(arg, LABEL_CONCATENATE, concatenate); 
    643       specifyRanges = getMacroValue(arg, LABEL_RANGE, specifyRanges); 
    644       autoscale = getMacroValue(arg, LABEL_AUTOSCALE, autoscale); 
    645       virtual = getMacroValue(arg, LABEL_VIRTUAL, virtual); 
    646       record = getMacroValue(arg, LABEL_RECORD, record); 
    647       openAllSeries = getMacroValue(arg, LABEL_ALL_SERIES, openAllSeries); 
    648       swapDimensions = getMacroValue(arg, LABEL_SWAP, swapDimensions); 
    649       showROIs = getMacroValue(arg, LABEL_ROI, showROIs); 
    650  
    651       mergeOption = Macro.getValue(arg, LABEL_MERGE_OPTION, mergeOption); 
    652       windowless = getMacroValue(arg, LABEL_WINDOWLESS, windowless); 
    653       seriesString = Macro.getValue(arg, LABEL_SERIES, "0"); 
    654  
    655       location = Macro.getValue(arg, LABEL_LOCATION, location); 
    656       id = Macro.getValue(arg, LABEL_ID, id); 
    657  
    658       quiet = getMacroValue(arg, LABEL_QUIET, quiet); 
    659     } 
    660   } 
    661  
    662   /** 
    663    * Gets the location (type of data source) from macro options, 
    664    * or user prompt if necessary. 
    665    * @return status of operation 
    666    */ 
    667   public int promptLocation() { 
    668     if (location == null) { 
    669       // Open a dialog asking the user what kind of dataset to handle. 
    670       // Ask only if the location was not already specified somehow. 
    671       // ImageJ will grab the value from the macro options, when possible. 
    672       GenericDialog gd = new GenericDialog("Bio-Formats Dataset Location"); 
    673       gd.addChoice(LABEL_LOCATION, LOCATIONS, LOCATION_LOCAL); 
    674       gd.showDialog(); 
    675       if (gd.wasCanceled()) return STATUS_CANCELED; 
    676       location = gd.getNextChoice(); 
    677     } 
    678  
    679     // verify that location is valid 
    680     boolean isLocal = LOCATION_LOCAL.equals(location); 
    681     boolean isHTTP = LOCATION_HTTP.equals(location); 
    682     boolean isOME = LOCATION_OME.equals(location); 
    683     boolean isOMERO = LOCATION_OMERO.equals(location); 
    684     if (!isLocal && !isHTTP && !isOME && !isOMERO) { 
    685       if (!quiet) IJ.error("Bio-Formats", "Invalid location: " + location); 
    686       return STATUS_FINISHED; 
    687     } 
    688     return STATUS_OK; 
    689   } 
    690  
    691   /** 
    692    * Gets the id (e.g., filename or URL) to open from macro options, 
    693    * or user prompt if necessary. 
    694    * @return status of operation 
    695    */ 
    696   public int promptId() { 
    697     if (isLocal()) return promptIdLocal(); 
    698     else if (isHTTP()) return promptIdHTTP(); 
    699     else return promptIdOME(); // isOME 
    700   } 
    701  
    702   /** 
    703    * Gets the filename (id) to open from macro options, 
    704    * or user prompt if necessary. 
    705    * @return status of operation 
    706    */ 
    707   public int promptIdLocal() { 
    708     if (firstTime && IJ.isMacOSX()) { 
    709       String osVersion = System.getProperty("os.version"); 
    710       if (osVersion == null || 
    711         osVersion.startsWith("10.4.") || 
    712         osVersion.startsWith("10.3.") || 
    713         osVersion.startsWith("10.2.")) 
    714       { 
    715         // present user with one-time dialog box 
    716         IJ.showMessage("Bio-Formats", 
    717           "One-time warning: There is a bug in Java on Mac OS X with the\n" + 
    718           "native file chooser that crashes ImageJ if you click on a file\n" + 
    719           "in cxd, ipw, oib or zvi format while in column view mode.\n" + 
    720           "You can work around the problem by switching to list view\n" + 
    721           "(press Command+2) or by checking the \"Use JFileChooser to\n" + 
    722           "Open/Save\" option in the Edit>Options>Input/Output... dialog."); 
    723       } 
    724     } 
    725     String ijVersion = IJ.getVersion(); 
    726     if (firstTime && (ijVersion == null || ijVersion.compareTo("1.39u") < 0)) { 
    727       // present user with one-time dialog box 
    728       if (ijVersion == null) ijVersion = "unknown"; 
    729       IJ.showMessage("Bio-Formats", 
    730         "One-time warning: Some features of Bio-Formats, such as the\n" + 
    731         "Data Browser and some color handling options, require ImageJ\n" + 
    732         "v1.39u or later. Your version is " + ijVersion + 
    733         "; you will need to upgrade\n" + 
    734         "if you wish to take advantage of these features."); 
    735     } 
    736     if (id == null) { 
    737       // prompt user for the filename (or grab from macro options) 
    738       OpenDialog od = new OpenDialog(LABEL_ID, id); 
    739       String dir = od.getDirectory(); 
    740       String name = od.getFileName(); 
    741       if (dir == null || name == null) return STATUS_CANCELED; 
    742       id = dir + name; 
    743     } 
    744  
    745     // verify that id is valid 
    746     if (id != null) idLoc = new Location(id); 
    747     if (idLoc == null || !idLoc.exists()) { 
    748       if (!quiet) { 
    749         IJ.error("Bio-Formats", idLoc == null ? 
    750           "No file was specified." : 
    751           "The specified file (" + id + ") does not exist."); 
    752       } 
    753       return STATUS_FINISHED; 
    754     } 
    755     idName = idLoc.getName(); 
    756     idType = "Filename"; 
    757     return STATUS_OK; 
    758   } 
    759  
    760   /** 
    761    * Gets the URL (id) to open from macro options, 
    762    * or user prompt if necessary. 
    763    * @return status of operation 
    764    */ 
    765   public int promptIdHTTP() { 
    766     if (id == null) { 
    767       // prompt user for the URL (or grab from macro options) 
    768       GenericDialog gd = new GenericDialog("Bio-Formats URL"); 
    769       gd.addStringField("URL: ", "http://", 30); 
    770       gd.showDialog(); 
    771       if (gd.wasCanceled()) return STATUS_CANCELED; 
    772       id = gd.getNextString(); 
    773     } 
    774  
    775     // verify that id is valid 
    776     if (id == null) { 
    777       if (!quiet) IJ.error("Bio-Formats", "No URL was specified."); 
    778       return STATUS_FINISHED; 
    779     } 
    780     idName = id; 
    781     idType = "URL"; 
    782     return STATUS_OK; 
    783   } 
    784  
    785   /** 
    786    * Gets the OME server and image (id) to open from macro options, 
    787    * or user prompt if necessary. 
    788    * @return status of operation 
    789    */ 
    790   public int promptIdOME() { 
    791     if (id == null) { 
    792       // CTR FIXME -- eliminate this kludge 
    793       IJ.runPlugIn("loci.plugins.ome.OMEPlugin", ""); 
    794       return STATUS_FINISHED; 
    795     } 
    796  
    797     idType = "OME address"; 
    798     return STATUS_OK; 
    799   } 
    800  
    801   public int promptMergeOption(int[] nums, boolean spectral) { 
    802     if (windowless) return STATUS_OK; 
    803     GenericDialog gd = new GenericDialog("Merging Options..."); 
    804  
    805     String[] options = new String[spectral ? 8 : 7]; 
    806     options[6] = MERGE_DEFAULT; 
    807     if (spectral) options[7] = MERGE_PROJECTION; 
    808     for (int i=0; i<6; i++) { 
    809       options[i] = nums[i] + " planes, " + (i + 2) + " channels per plane"; 
    810     } 
    811  
    812     gd.addMessage("How would you like to merge this data?"); 
    813     gd.addChoice(LABEL_MERGE_OPTION, options, MERGE_DEFAULT); 
    814     gd.showDialog(); 
    815     if (gd.wasCanceled()) return STATUS_CANCELED; 
    816  
    817     mergeOption = options[gd.getNextChoiceIndex()]; 
    818  
    819     return STATUS_OK; 
    820   } 
    821  
    822   /** 
    823    * Gets option values from macro options, or user prompt if necessary. 
    824    * @return status of operation 
    825    */ 
    826   public int promptOptions() { 
    827     Vector stackTypes = new Vector(); 
    828     stackTypes.add(VIEW_NONE); 
    829     stackTypes.add(VIEW_STANDARD); 
    830     if (IJ.getVersion().compareTo("1.39l") >= 0) { 
    831       stackTypes.add(VIEW_HYPERSTACK); 
    832       stackTypes.add(VIEW_BROWSER); 
    833     } 
    834     if (LibraryChecker.checkClass(CLASS_VISBIO)) stackTypes.add(VIEW_VISBIO); 
    835     if (LibraryChecker.checkClass(CLASS_IMAGE_5D)) { 
    836       stackTypes.add(VIEW_IMAGE_5D); 
    837     } 
    838     if (LibraryChecker.checkClass(CLASS_VIEW_5D)) stackTypes.add(VIEW_VIEW_5D); 
    839     final String[] stackFormats = new String[stackTypes.size()]; 
    840     stackTypes.copyInto(stackFormats); 
    841  
    842     String[] stackOrders = new String[] { 
    843       ORDER_DEFAULT, ORDER_XYZCT, ORDER_XYZTC, ORDER_XYCZT, ORDER_XYCTZ, 
    844       ORDER_XYTZC, ORDER_XYTCZ 
    845     }; 
    846  
    847     // prompt user for parameters (or grab from macro options) 
    848     GenericDialog gd = new GenericDialog("Bio-Formats Import Options"); 
    849     gd.addChoice(LABEL_STACK, stackFormats, stackFormat); 
    850     gd.addChoice(LABEL_ORDER, stackOrders, stackOrder); 
    851     gd.addCheckbox(LABEL_MERGE, mergeChannels); 
    852     gd.addCheckbox(LABEL_COLORIZE, colorize); 
    853     gd.addCheckbox(LABEL_COLORIZE_CUSTOM, customColorize); 
    854     gd.addCheckbox(LABEL_SPLIT_C, splitChannels); 
    855     gd.addCheckbox(LABEL_SPLIT_Z, splitFocalPlanes); 
    856     gd.addCheckbox(LABEL_SPLIT_T, splitTimepoints); 
    857     gd.addCheckbox(LABEL_CROP, crop); 
    858     gd.addCheckbox(LABEL_METADATA, showMetadata); 
    859     gd.addCheckbox(LABEL_OME_XML, showOMEXML); 
    860     gd.addCheckbox(LABEL_GROUP, groupFiles); 
    861     gd.addCheckbox(LABEL_CONCATENATE, concatenate); 
    862     gd.addCheckbox(LABEL_RANGE, specifyRanges); 
    863     gd.addCheckbox(LABEL_AUTOSCALE, autoscale); 
    864     gd.addCheckbox(LABEL_VIRTUAL, virtual); 
    865     gd.addCheckbox(LABEL_RECORD, record); 
    866     gd.addCheckbox(LABEL_ALL_SERIES, openAllSeries); 
    867     gd.addCheckbox(LABEL_SWAP, swapDimensions); 
    868     gd.addCheckbox(LABEL_ROI, showROIs); 
    869  
    870     gd.addCheckbox(LABEL_QUIET, quiet); // NB: invisible 
    871  
    872     // extract GUI components from dialog and add listeners 
    873  
    874     Vector labels = null; 
    875     Label stackLabel = null, orderLabel = null; 
    876     Component[] c = gd.getComponents(); 
    877     if (c != null) { 
    878       labels = new Vector(); 
    879       for (int i=0; i<c.length; i++) { 
    880         if (c[i] instanceof Label) { 
    881           Label item = (Label) c[i]; 
    882           labels.add(item); 
    883         } 
    884       } 
    885       stackLabel = (Label) labels.get(0); 
    886       orderLabel = (Label) labels.get(1); 
    887     } 
    888  
    889     Vector choices = gd.getChoices(); 
    890     if (choices != null) { 
    891       stackChoice = (Choice) choices.get(0); 
    892       orderChoice = (Choice) choices.get(1); 
    893       for (int i=0; i<choices.size(); i++) { 
    894         Choice item = (Choice) choices.get(i); 
    895         item.addFocusListener(this); 
    896         item.addItemListener(this); 
    897         item.addMouseListener(this); 
    898       } 
    899     } 
    900  
    901     Vector boxes = gd.getCheckboxes(); 
    902     if (boxes != null) { 
    903       mergeBox = (Checkbox) boxes.get(0); 
    904       colorizeBox = (Checkbox) boxes.get(1); 
    905       customColorizeBox = (Checkbox) boxes.get(2); 
    906       splitCBox = (Checkbox) boxes.get(3); 
    907       splitZBox = (Checkbox) boxes.get(4); 
    908       splitTBox = (Checkbox) boxes.get(5); 
    909       cropBox = (Checkbox) boxes.get(6); 
    910       metadataBox = (Checkbox) boxes.get(7); 
    911       omexmlBox = (Checkbox) boxes.get(8); 
    912       groupBox = (Checkbox) boxes.get(9); 
    913       concatenateBox = (Checkbox) boxes.get(10); 
    914       rangeBox = (Checkbox) boxes.get(11); 
    915       autoscaleBox = (Checkbox) boxes.get(12); 
    916       virtualBox = (Checkbox) boxes.get(13); 
    917       recordBox = (Checkbox) boxes.get(14); 
    918       allSeriesBox = (Checkbox) boxes.get(15); 
    919       swapBox = (Checkbox) boxes.get(16); 
    920       roiBox = (Checkbox) boxes.get(17); 
    921       for (int i=0; i<boxes.size(); i++) { 
    922         Checkbox item = (Checkbox) boxes.get(i); 
    923         item.addFocusListener(this); 
    924         item.addItemListener(this); 
    925         item.addMouseListener(this); 
    926       } 
    927     } 
    928  
    929     verifyOptions(null); 
    930  
    931     // associate information for each option 
    932     infoTable = new Hashtable(); 
    933     infoTable.put(stackLabel, INFO_STACK); 
    934     infoTable.put(stackChoice, INFO_STACK); 
    935     infoTable.put(orderLabel, INFO_ORDER); 
    936     infoTable.put(orderChoice, INFO_ORDER); 
    937     infoTable.put(mergeBox, INFO_MERGE); 
    938     infoTable.put(colorizeBox, INFO_COLORIZE); 
    939     infoTable.put(customColorizeBox, INFO_COLORIZE_CUSTOM); 
    940     infoTable.put(splitCBox, INFO_SPLIT_C); 
    941     infoTable.put(splitZBox, INFO_SPLIT_Z); 
    942     infoTable.put(splitTBox, INFO_SPLIT_T); 
    943     infoTable.put(cropBox, INFO_CROP); 
    944     infoTable.put(metadataBox, INFO_METADATA); 
    945     infoTable.put(omexmlBox, INFO_OME_XML); 
    946     infoTable.put(groupBox, INFO_GROUP); 
    947     infoTable.put(concatenateBox, INFO_CONCATENATE); 
    948     infoTable.put(rangeBox, INFO_RANGE); 
    949     infoTable.put(autoscaleBox, INFO_AUTOSCALE); 
    950     infoTable.put(virtualBox, INFO_VIRTUAL); 
    951     infoTable.put(recordBox, INFO_RECORD); 
    952     infoTable.put(allSeriesBox, INFO_ALL_SERIES); 
    953     infoTable.put(swapBox, INFO_SWAP); 
    954     infoTable.put(roiBox, INFO_ROI); 
    955  
    956     // rebuild dialog using FormLayout to organize things more nicely 
    957  
    958     String cols = 
    959       // first column 
    960       "pref, 3dlu, pref:grow, " + 
    961       // second column 
    962       "10dlu, pref"; 
    963  
    964     String rows = 
    965       // Stack viewing        | Metadata viewing 
    966       "pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, " + 
    967       // Dataset organization | Memory management 
    968       "9dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, " + 
    969       // Color options        | Split into separate windows 
    970       "9dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, " + 
    971       // Information 
    972       "9dlu, pref, 3dlu, fill:100dlu"; 
    973  
    974     // TODO: change "Merge channels into RGB" checkbox to 
    975     // "Channel merging" choice with options: 
    976     //   "Default", "Merge channels" or "Separate channels" 
    977  
    978     // TODO: change "Use virtual stack" and "Record modifications to virtual 
    979     // stack" checkboxes to "Stack type" choice with options: 
    980     //   "Normal", "Virtual" or "Smart virtual" 
    981  
    982     PanelBuilder builder = new PanelBuilder(new FormLayout(cols, rows)); 
    983     CellConstraints cc = new CellConstraints(); 
    984  
    985     // populate 1st column 
    986     int row = 1; 
    987     builder.addSeparator("Stack viewing", cc.xyw(1, row, 3)); 
    988     row += 2; 
    989     builder.add(stackLabel, cc.xy(1, row)); 
    990     builder.add(stackChoice, cc.xy(3, row)); 
    991     row += 2; 
    992     builder.add(orderLabel, cc.xy(1, row)); 
    993     builder.add(orderChoice, cc.xy(3, row)); 
    994     row += 4; 
    995     builder.addSeparator("Dataset organization", cc.xyw(1, row, 3)); 
    996     row += 2; 
    997     builder.add(groupBox, xyw(cc, 1, row, 3)); 
    998     row += 2; 
    999     builder.add(swapBox, xyw(cc, 1, row, 3)); 
    1000     row += 2; 
    1001     builder.add(allSeriesBox, xyw(cc, 1, row, 3)); 
    1002     row += 2; 
    1003     builder.add(concatenateBox, xyw(cc, 1, row, 3)); 
    1004     row += 2; 
    1005     builder.addSeparator("Color options", cc.xyw(1, row, 3)); 
    1006     row += 2; 
    1007     builder.add(mergeBox, xyw(cc, 1, row, 3)); 
    1008     row += 2; 
    1009     builder.add(colorizeBox, xyw(cc, 1, row, 3)); 
    1010     row += 2; 
    1011     builder.add(customColorizeBox, xyw(cc, 1, row, 3)); 
    1012     row += 2; 
    1013     builder.add(autoscaleBox, xyw(cc, 1, row, 3)); 
    1014     row += 2; 
    1015  
    1016     // populate 2nd column 
    1017     row = 1; 
    1018     builder.addSeparator("Metadata viewing", cc.xy(5, row)); 
    1019     row += 2; 
    1020     builder.add(metadataBox, xyw(cc, 5, row, 1)); 
    1021     row += 2; 
    1022     builder.add(omexmlBox, xyw(cc, 5, row, 1)); 
    1023     row += 2; 
    1024     builder.add(roiBox, xyw(cc, 5, row, 1)); 
    1025     row += 2; 
    1026     builder.addSeparator("Memory management", cc.xy(5, row)); 
    1027     row += 2; 
    1028     builder.add(virtualBox, xyw(cc, 5, row, 1)); 
    1029     row += 2; 
    1030     builder.add(recordBox, xyw(cc, 5, row, 1)); 
    1031     row += 2; 
    1032     builder.add(rangeBox, xyw(cc, 5, row, 1)); 
    1033     row += 2; 
    1034     builder.add(cropBox, xyw(cc, 5, row, 1)); 
    1035     row += 2; 
    1036     builder.addSeparator("Split into separate windows", cc.xy(5, row)); 
    1037     row += 2; 
    1038     builder.add(splitCBox, xyw(cc, 5, row, 1)); 
    1039     row += 2; 
    1040     builder.add(splitZBox, xyw(cc, 5, row, 1)); 
    1041     row += 2; 
    1042     builder.add(splitTBox, xyw(cc, 5, row, 1)); 
    1043     row += 4; 
    1044  
    1045     // information section 
    1046     builder.addSeparator("Information", cc.xyw(1, row, 5)); 
    1047     row += 2; 
    1048     infoPane = new JEditorPane(); 
    1049     infoPane.setContentType("text/html"); 
    1050     infoPane.setEditable(false); 
    1051     infoPane.setText("<html>" + INFO_DEFAULT); 
    1052     builder.add(new JScrollPane(infoPane), cc.xyw(1, row, 5)); 
    1053     row += 2; 
    1054  
    1055     gd.removeAll(); 
    1056     gd.add(builder.getPanel()); 
    1057  
    1058     // display dialog to user and harvest results 
    1059  
    1060     gd.showDialog(); 
    1061     if (gd.wasCanceled()) return STATUS_CANCELED; 
    1062  
    1063     stackFormat = stackFormats[gd.getNextChoiceIndex()]; 
    1064     stackOrder = stackOrders[gd.getNextChoiceIndex()]; 
    1065     mergeChannels = gd.getNextBoolean(); 
    1066     colorize = gd.getNextBoolean(); 
    1067     customColorize = gd.getNextBoolean(); 
    1068     splitChannels = gd.getNextBoolean(); 
    1069     splitFocalPlanes = gd.getNextBoolean(); 
    1070     splitTimepoints = gd.getNextBoolean(); 
    1071     crop = gd.getNextBoolean(); 
    1072     showMetadata = gd.getNextBoolean(); 
    1073     showOMEXML = gd.getNextBoolean(); 
    1074     groupFiles = gd.getNextBoolean(); 
    1075     concatenate = gd.getNextBoolean(); 
    1076     specifyRanges = gd.getNextBoolean(); 
    1077     autoscale = gd.getNextBoolean(); 
    1078     virtual = gd.getNextBoolean(); 
    1079     record = gd.getNextBoolean(); 
    1080     openAllSeries = gd.getNextBoolean(); 
    1081     swapDimensions = gd.getNextBoolean(); 
    1082     showROIs = gd.getNextBoolean(); 
    1083  
    1084     quiet = gd.getNextBoolean(); // NB: invisible 
    1085  
    1086     return STATUS_OK; 
    1087   } 
    1088  
    1089   /** 
    1090    * Gets file pattern from id, macro options, or user prompt if necessary. 
    1091    * @return status of operation 
    1092    */ 
    1093   public int promptFilePattern() { 
    1094     if (windowless) return STATUS_OK; 
    1095  
    1096     id = FilePattern.findPattern(idLoc); 
    1097     if (id == null) { 
    1098       IJ.showMessage("Bio-Formats", 
    1099         "Warning: Bio-Formats was unable to determine a grouping that\n" + 
    1100         "includes the file you chose. The most common reason for this\n" + 
    1101         "situation is that the folder contains extraneous files with " + 
    1102         "similar\n" + 
    1103         "names and numbers that confuse the detection algorithm.\n" + 
    1104         " \n" + 
    1105         "For example, if you have multiple datasets in the same folder\n" + 
    1106         "named series1_z*_c*.tif, series2_z*_c*.tif, etc., Bio-Formats\n" + 
    1107         "may try to group all such files into a single series.\n" + 
    1108         " \n" + 
    1109         "For best results, put each image series's files in their own " + 
    1110         "folder,\n" + 
    1111         "or type in a file pattern manually.\n"); 
    1112       id = idLoc.getAbsolutePath(); 
    1113     } 
    1114  
    1115     // prompt user to confirm file pattern (or grab from macro options) 
    1116     GenericDialog gd = new GenericDialog("Bio-Formats File Stitching"); 
    1117     int len = id.length() + 1; 
    1118     if (len > 80) len = 80; 
    1119     gd.addStringField("Pattern: ", id, len); 
    1120     gd.showDialog(); 
    1121     if (gd.wasCanceled()) return STATUS_CANCELED; 
    1122     id = gd.getNextString(); 
    1123     return STATUS_OK; 
    1124   } 
    1125  
    1126   /** 
    1127    * Gets which series to open from macro options, or user prompt if necessary. 
    1128    * @param r The reader to use for extracting details of each series. 
    1129    * @param seriesLabels Label to display to user identifying each series. 
    1130    * @param series Boolean array indicating which series to include 
    1131    *   (populated by this method). 
    1132    * @return status of operation 
    1133    */ 
    1134   public int promptSeries(IFormatReader r, 
    1135     String[] seriesLabels, boolean[] series) 
    1136   { 
    1137     if (windowless) { 
    1138       if (seriesString != null) { 
    1139         if (seriesString.startsWith("[")) { 
    1140           seriesString = seriesString.substring(1, seriesString.length() - 2); 
    1141         } 
    1142         Arrays.fill(series, false); 
    1143         StringTokenizer tokens = new StringTokenizer(seriesString, " "); 
    1144         while (tokens.hasMoreTokens()) { 
    1145           String token = tokens.nextToken().trim(); 
    1146           int n = Integer.parseInt(token); 
    1147           if (n < series.length) series[n] = true; 
    1148         } 
    1149       } 
    1150       return STATUS_OK; 
    1151     } 
    1152     int seriesCount = r.getSeriesCount(); 
    1153  
    1154     // prompt user to specify series inclusion (or grab from macro options) 
    1155     GenericDialog gd = new GenericDialog("Bio-Formats Series Options") { 
    1156       public void actionPerformed(ActionEvent e) { 
    1157         String cmd = e.getActionCommand(); 
    1158         if ("select".equals(cmd)) { 
    1159           Checkbox[] boxes = 
    1160             (Checkbox[]) getCheckboxes().toArray(new Checkbox[0]); 
    1161           for (int i=0; i<boxes.length; i++) { 
    1162             boxes[i].setState(true); 
    1163           } 
    1164         } 
    1165         else if ("deselect".equals(cmd)) { 
    1166           Checkbox[] boxes = 
    1167             (Checkbox[]) getCheckboxes().toArray(new Checkbox[0]); 
    1168           for (int i=0; i<boxes.length; i++) { 
    1169             boxes[i].setState(false); 
    1170           } 
    1171         } 
    1172         else { 
    1173           super.actionPerformed(e); 
    1174         } 
    1175       } 
    1176     }; 
    1177  
    1178     GridBagLayout gdl = (GridBagLayout) gd.getLayout(); 
    1179     GridBagConstraints gbc = new GridBagConstraints(); 
    1180     gbc.gridx = 2; 
    1181     gbc.gridwidth = GridBagConstraints.REMAINDER; 
    1182  
    1183     Panel[] p = new Panel[seriesCount]; 
    1184     for (int i=0; i<seriesCount; i++) { 
    1185       gd.addCheckbox(seriesLabels[i], series[i]); 
    1186       r.setSeries(i); 
    1187       int sx = r.getThumbSizeX() + 10; // a little extra padding 
    1188       int sy = r.getThumbSizeY(); 
    1189       p[i] = new Panel(); 
    1190       p[i].add(Box.createRigidArea(new Dimension(sx, sy))); 
    1191       gbc.gridy = i; 
    1192       if (forceThumbnails) { 
    1193         IJ.showStatus("Reading thumbnail for series #" + (i + 1)); 
    1194         int z = r.getSizeZ() / 2; 
    1195         int t = r.getSizeT() / 2; 
    1196         int ndx = r.getIndex(z, 0, t); 
    1197         try { 
    1198           BufferedImage img = r.openThumbImage(ndx); 
    1199           if (isAutoscale() && r.getPixelType() != FormatTools.FLOAT) { 
    1200             img = AWTImageTools.autoscale(img); 
    1201           } 
    1202           ImageIcon icon = new ImageIcon(img); 
    1203           p[i].removeAll(); 
    1204           p[i].add(new JLabel(icon)); 
    1205         } 
    1206         catch (Exception e) { } 
    1207       } 
    1208       gdl.setConstraints(p[i], gbc); 
    1209       gd.add(p[i]); 
    1210     } 
    1211     WindowTools.addScrollBars(gd); 
    1212  
    1213     Panel buttons = new Panel(); 
    1214  
    1215     Button select = new Button("Select All"); 
    1216     select.setActionCommand("select"); 
    1217     select.addActionListener(gd); 
    1218     Button deselect = new Button("Deselect All"); 
    1219     deselect.setActionCommand("deselect"); 
    1220     deselect.addActionListener(gd); 
    1221  
    1222     buttons.add(select); 
    1223     buttons.add(deselect); 
    1224  
    1225     gbc.gridx = 0; 
    1226     gbc.gridy = seriesCount; 
    1227     gdl.setConstraints(buttons, gbc); 
    1228     gd.add(buttons); 
    1229  
    1230     if (forceThumbnails) gd.showDialog(); 
    1231     else { 
    1232       ThumbLoader loader = new ThumbLoader(r, p, gd, isAutoscale()); 
    1233       gd.showDialog(); 
    1234       loader.stop(); 
    1235     } 
    1236     if (gd.wasCanceled()) return STATUS_CANCELED; 
    1237  
    1238     seriesString = "["; 
    1239     for (int i=0; i<seriesCount; i++) { 
    1240       series[i] = gd.getNextBoolean(); 
    1241       if (series[i]) { 
    1242         seriesString += i + " "; 
    1243       } 
    1244     } 
    1245     seriesString += "]"; 
    1246  
    1247     if (concatenate) { 
    1248       // toggle on compatible series 
    1249       // CTR FIXME -- why are we doing this? 
    1250       for (int i=0; i<seriesCount; i++) { 
    1251         if (series[i]) continue; 
    1252  
    1253         r.setSeries(i); 
    1254         int sizeX = r.getSizeX(); 
    1255         int sizeY = r.getSizeY(); 
    1256         int pixelType = r.getPixelType(); 
    1257         int sizeC = r.getSizeC(); 
    1258  
    1259         for (int j=0; j<seriesCount; j++) { 
    1260           if (j == i || !series[j]) continue; 
    1261           r.setSeries(j); 
    1262           if (sizeX == r.getSizeX() && sizeY == r.getSizeY() && 
    1263             pixelType == r.getPixelType() && sizeC == r.getSizeC()) 
    1264           { 
    1265             series[i] = true; 
    1266             break; 
    1267           } 
    1268         } 
    1269       } 
    1270     } 
    1271  
    1272     return STATUS_OK; 
    1273   } 
    1274  
    1275   public int promptCropSize(IFormatReader r, String[] labels, boolean[] series, 
    1276     Rectangle[] box) 
    1277   { 
    1278     GenericDialog gd = new GenericDialog("Bio-Formats Crop Options"); 
    1279     for (int i=0; i<series.length; i++) { 
    1280       if (!series[i]) continue; 
    1281       gd.addMessage(labels[i].replaceAll("_", " ")); 
    1282       gd.addNumericField("X_Coordinate_" + i, 0, 0); 
    1283       gd.addNumericField("Y_Coordinate_" + i, 0, 0); 
    1284       gd.addNumericField("Width_" + i, 0, 0); 
    1285       gd.addNumericField("Height_" + i, 0, 0); 
    1286     } 
    1287     WindowTools.addScrollBars(gd); 
    1288     gd.showDialog(); 
    1289     if (gd.wasCanceled()) return STATUS_CANCELED; 
    1290  
    1291     for (int i=0; i<series.length; i++) { 
    1292       if (!series[i]) continue; 
    1293       r.setSeries(i); 
    1294       box[i].x = (int) gd.getNextNumber(); 
    1295       box[i].y = (int) gd.getNextNumber(); 
    1296       box[i].width = (int) gd.getNextNumber(); 
    1297       box[i].height = (int) gd.getNextNumber(); 
    1298  
    1299       if (box[i].x < 0) box[i].x = 0; 
    1300       if (box[i].y < 0) box[i].y = 0; 
    1301       if (box[i].x >= r.getSizeX()) box[i].x = r.getSizeX() - box[i].width - 1; 
    1302       if (box[i].y >= r.getSizeY()) box[i].y = r.getSizeY() - box[i].height - 1; 
    1303       if (box[i].width < 1) box[i].width = 1; 
    1304       if (box[i].height < 1) box[i].height = 1; 
    1305       if (box[i].width + box[i].x > r.getSizeX()) { 
    1306         box[i].width = r.getSizeX() - box[i].x; 
    1307       } 
    1308       if (box[i].height + box[i].y > r.getSizeY()) { 
    1309         box[i].height = r.getSizeY() - box[i].y; 
    1310       } 
    1311     } 
    1312  
    1313     return STATUS_OK; 
    1314   } 
    1315  
    1316   /** 
    1317    * Gets the range of image planes to open from macro options, 
    1318    * or user prompt if necessary. 
    1319    * @param r The reader to use for extracting details of each series. 
    1320    * @param series Boolean array indicating the series 
    1321    *   for which ranges should be determined. 
    1322    * @param seriesLabels Label to display to user identifying each series 
    1323    * @param cBegin First C index to include (populated by this method). 
    1324    * @param cEnd Last C index to include (populated by this method). 
    1325    * @param cStep C dimension step size (populated by this method). 
    1326    * @param zBegin First Z index to include (populated by this method). 
    1327    * @param zEnd Last Z index to include (populated by this method). 
    1328    * @param zStep Z dimension step size (populated by this method). 
    1329    * @param tBegin First T index to include (populated by this method). 
    1330    * @param tEnd Last T index to include (populated by this method). 
    1331    * @param tStep T dimension step size (populated by this method). 
    1332    * @return status of operation 
    1333    */ 
    1334   public int promptRange(IFormatReader r, 
    1335     boolean[] series, String[] seriesLabels, 
    1336     int[] cBegin, int[] cEnd, int[] cStep, 
    1337     int[] zBegin, int[] zEnd, int[] zStep, 
    1338     int[] tBegin, int[] tEnd, int[] tStep) 
    1339   { 
    1340     int seriesCount = r.getSeriesCount(); 
    1341  
    1342     // prompt user to specify series ranges (or grab from macro options) 
    1343     GenericDialog gd = new GenericDialog("Bio-Formats Range Options"); 
    1344     for (int i=0; i<seriesCount; i++) { 
    1345       if (!series[i]) continue; 
    1346       r.setSeries(i); 
    1347       gd.addMessage(seriesLabels[i].replaceAll("_", " ")); 
    1348       String s = seriesCount > 1 ? "_" + (i + 1) : ""; 
    1349       //if (r.isOrderCertain()) { 
    1350       if (r.getEffectiveSizeC() > 1) { 
    1351         gd.addNumericField("C_Begin" + s, cBegin[i] + 1, 0); 
    1352         gd.addNumericField("C_End" + s, cEnd[i] + 1, 0); 
    1353         gd.addNumericField("C_Step" + s, cStep[i], 0); 
    1354       } 
    1355       if (r.getSizeZ() > 1) { 
    1356         gd.addNumericField("Z_Begin" + s, zBegin[i] + 1, 0); 
    1357         gd.addNumericField("Z_End" + s, zEnd[i] + 1, 0); 
    1358         gd.addNumericField("Z_Step" + s, zStep[i], 0); 
    1359       } 
    1360       if (r.getSizeT() > 1) { 
    1361         gd.addNumericField("T_Begin" + s, tBegin[i] + 1, 0); 
    1362         gd.addNumericField("T_End" + s, tEnd[i] + 1, 0); 
    1363         gd.addNumericField("T_Step" + s, tStep[i], 0); 
    1364       } 
    1365       //} 
    1366       //else { 
    1367       //  gd.addNumericField("Begin" + s, cBegin[i] + 1, 0); 
    1368       //  gd.addNumericField("End" + s, cEnd[i] + 1, 0); 
    1369       //  gd.addNumericField("Step" + s, cStep[i], 0); 
    1370       //} 
    1371     } 
    1372     WindowTools.addScrollBars(gd); 
    1373     gd.showDialog(); 
    1374     if (gd.wasCanceled()) return STATUS_CANCELED; 
    1375  
    1376     for (int i=0; i<seriesCount; i++) { 
    1377       if (!series[i]) continue; 
    1378       r.setSeries(i); 
    1379       int sizeC = r.getEffectiveSizeC(); 
    1380       int sizeZ = r.getSizeZ(); 
    1381       int sizeT = r.getSizeT(); 
    1382       boolean certain = r.isOrderCertain(); 
    1383  
    1384       //if (certain) { 
    1385       if (r.getEffectiveSizeC() > 1) { 
    1386         cBegin[i] = (int) gd.getNextNumber() - 1; 
    1387         cEnd[i] = (int) gd.getNextNumber() - 1; 
    1388         cStep[i] = (int) gd.getNextNumber(); 
    1389       } 
    1390       if (r.getSizeZ() > 1) { 
    1391         zBegin[i] = (int) gd.getNextNumber() - 1; 
    1392         zEnd[i] = (int) gd.getNextNumber() - 1; 
    1393         zStep[i] = (int) gd.getNextNumber(); 
    1394       } 
    1395       if (r.getSizeT() > 1) { 
    1396         tBegin[i] = (int) gd.getNextNumber() - 1; 
    1397         tEnd[i] = (int) gd.getNextNumber() - 1; 
    1398         tStep[i] = (int) gd.getNextNumber(); 
    1399       } 
    1400       //} 
    1401       //else { 
    1402       //  cBegin[i] = (int) gd.getNextNumber() - 1; 
    1403       //  cEnd[i] = (int) gd.getNextNumber() - 1; 
    1404       //  cStep[i] = (int) gd.getNextNumber(); 
    1405       //} 
    1406       int maxC = certain ? sizeC : r.getImageCount(); 
    1407       if (cBegin[i] < 0) cBegin[i] = 0; 
    1408       if (cBegin[i] >= maxC) cBegin[i] = maxC - 1; 
    1409       if (cEnd[i] < cBegin[i]) cEnd[i] = cBegin[i]; 
    1410       if (cEnd[i] >= maxC) cEnd[i] = maxC - 1; 
    1411       if (cStep[i] < 1) cStep[i] = 1; 
    1412       if (zBegin[i] < 0) zBegin[i] = 0; 
    1413       if (zBegin[i] >= sizeZ) zBegin[i] = sizeZ - 1; 
    1414       if (zEnd[i] < zBegin[i]) zEnd[i] = zBegin[i]; 
    1415       if (zEnd[i] >= sizeZ) zEnd[i] = sizeZ - 1; 
    1416       if (zStep[i] < 1) zStep[i] = 1; 
    1417       if (tBegin[i] < 0) tBegin[i] = 0; 
    1418       if (tBegin[i] >= sizeT) tBegin[i] = sizeT - 1; 
    1419       if (tEnd[i] < tBegin[i]) tEnd[i] = tBegin[i]; 
    1420       if (tEnd[i] >= sizeT) tEnd[i] = sizeT - 1; 
    1421       if (tStep[i] < 1) tStep[i] = 1; 
    1422     } 
    1423  
    1424     return STATUS_OK; 
    1425   } 
    1426  
    1427   /** Prompt for dimension swapping options. */ 
    1428   public int promptSwap(DimensionSwapper r, boolean[] series) { 
    1429     GenericDialog gd = new GenericDialog("Dimension swapping options"); 
    1430  
    1431     int oldSeries = r.getSeries(); 
    1432     String[] labels = new String[] {"Z", "C", "T"}; 
    1433     for (int n=0; n<r.getSeriesCount(); n++) { 
    1434       if (!series[n]) continue; 
    1435       r.setSeries(n); 
    1436  
    1437       gd.addMessage("Series " + n + ":\n"); 
    1438  
    1439       for (int i=0; i<labels.length; i++) { 
    1440         gd.addChoice(i + "_planes", labels, labels[i]); 
    1441       } 
    1442     } 
    1443     WindowTools.addScrollBars(gd); 
    1444     gd.showDialog(); 
    1445     if (gd.wasCanceled()) return STATUS_CANCELED; 
    1446  
    1447     for (int n=0; n<r.getSeriesCount(); n++) { 
    1448       if (!series[n]) continue; 
    1449       r.setSeries(n); 
    1450       String z = gd.getNextChoice(); 
    1451       String c = gd.getNextChoice(); 
    1452       String t = gd.getNextChoice(); 
    1453  
    1454       if (z.equals(t) || z.equals(c) || c.equals(t)) { 
    1455         IJ.error("Invalid swapping options - each axis can be used only once."); 
    1456         return promptSwap(r, series); 
    1457       } 
    1458  
    1459       String originalOrder = r.getDimensionOrder(); 
    1460       StringBuffer sb = new StringBuffer(); 
    1461       sb.append("XY"); 
    1462       for (int i=2; i<originalOrder.length(); i++) { 
    1463         if (originalOrder.charAt(i) == 'Z') sb.append(z); 
    1464         else if (originalOrder.charAt(i) == 'C') sb.append(c); 
    1465         else if (originalOrder.charAt(i) == 'T') sb.append(t); 
    1466       } 
    1467  
    1468       r.swapDimensions(sb.toString()); 
    1469     } 
    1470     r.setSeries(oldSeries); 
    1471  
    1472     return STATUS_OK; 
    1473   } 
    1474  
    1475   // -- FocusListener methods -- 
    1476  
    1477   /** Handles information pane updates when component focus changes. */ 
    1478   public void focusGained(FocusEvent e) { 
    1479     Object src = e.getSource(); 
    1480     String text = (String) infoTable.get(src); 
    1481     infoPane.setText("<html>" + text); 
    1482     infoPane.setCaretPosition(0); 
    1483   } 
    1484  
    1485   public void focusLost(FocusEvent e) { } 
    1486  
    1487   // -- ItemListener methods -- 
    1488  
    1489   /** Handles toggling of mutually exclusive options. */ 
    1490   public void itemStateChanged(ItemEvent e) { 
    1491     verifyOptions(e.getSource()); 
    1492   } 
    1493  
    1494   // -- MouseListener methods -- 
    1495  
    1496   /** Focuses the component upon mouseover. */ 
    1497   public void mouseEntered(MouseEvent e) { 
    1498     Object src = e.getSource(); 
    1499     if (src instanceof Component) { 
    1500       ((Component) src).requestFocusInWindow(); 
    1501     } 
    1502   } 
    1503  
    1504   public void mouseClicked(MouseEvent e) { } 
    1505   public void mouseExited(MouseEvent e) { } 
    1506   public void mousePressed(MouseEvent e) { } 
    1507   public void mouseReleased(MouseEvent e) { } 
    1508  
    1509   // -- Static helper methods -- 
    1510  
    1511   private static boolean getMacroValue(String options, 
    1512     String key, boolean defaultValue) 
    1513   { 
    1514     String s = Macro.getValue(options, key, null); 
    1515     return s == null ? defaultValue : s.equalsIgnoreCase("true"); 
    1516   } 
    1517  
    1518   private static String info(String label) { 
    1519     return "<b>" + label.replaceAll("[_:]", " ").trim() + "</b>"; 
    1520   } 
    1521  
    1522   private static CellConstraints xyw(CellConstraints cc, int x, int y, int w) { 
    1523     return cc.xyw(x, y, w, CellConstraints.LEFT, CellConstraints.CENTER); 
    1524   } 
    1525  
    1526   // -- Helper methods -- 
    1527  
    1528   /** Ensures that the options dialog has no mutually exclusive options. */ 
    1529   private void verifyOptions(Object src) { 
    1530     // record GUI state 
    1531  
    1532     //boolean stackEnabled = stackChoice.isEnabled(); 
    1533     boolean orderEnabled = orderChoice.isEnabled(); 
    1534     boolean mergeEnabled = mergeBox.isEnabled(); 
    1535     boolean colorizeEnabled = colorizeBox.isEnabled(); 
    1536     boolean customColorizeEnabled = customColorizeBox.isEnabled(); 
    1537     boolean splitCEnabled = splitCBox.isEnabled(); 
    1538     boolean splitZEnabled = splitZBox.isEnabled(); 
    1539     boolean splitTEnabled = splitTBox.isEnabled(); 
    1540     boolean metadataEnabled = metadataBox.isEnabled(); 
    1541     boolean omexmlEnabled = omexmlBox.isEnabled(); 
    1542     boolean groupEnabled = groupBox.isEnabled(); 
    1543     boolean concatenateEnabled = concatenateBox.isEnabled(); 
    1544     boolean rangeEnabled = rangeBox.isEnabled(); 
    1545     boolean autoscaleEnabled = autoscaleBox.isEnabled(); 
    1546     boolean virtualEnabled = virtualBox.isEnabled(); 
    1547     boolean recordEnabled = recordBox.isEnabled(); 
    1548     boolean allSeriesEnabled = allSeriesBox.isEnabled(); 
    1549     boolean cropEnabled = cropBox.isEnabled(); 
    1550     boolean swapEnabled = swapBox.isEnabled(); 
    1551  
    1552     boolean isStackNone = false; 
    1553     boolean isStackStandard = false; 
    1554     boolean isStackHyperstack = false; 
    1555     boolean isStackBrowser = false; 
    1556     boolean isStackVisBio = false; 
    1557     boolean isStackImage5D = false; 
    1558     boolean isStackView5D = false; 
    1559     String stackValue = stackChoice.getSelectedItem(); 
    1560     if (stackValue.equals(VIEW_NONE)) isStackNone = true; 
    1561     else if (stackValue.equals(VIEW_STANDARD)) isStackStandard = true; 
    1562     else if (stackValue.equals(VIEW_HYPERSTACK)) isStackHyperstack = true; 
    1563     else if (stackValue.equals(VIEW_BROWSER)) isStackBrowser = true; 
    1564     else if (stackValue.equals(VIEW_VISBIO)) isStackVisBio = true; 
    1565     else if (stackValue.equals(VIEW_IMAGE_5D)) isStackImage5D = true; 
    1566     else if (stackValue.equals(VIEW_VIEW_5D)) isStackView5D = true; 
    1567     String orderValue = orderChoice.getSelectedItem(); 
    1568     boolean isMerge = mergeBox.getState(); 
    1569     boolean isColorize = colorizeBox.getState(); 
    1570     boolean isCustomColorize = customColorizeBox.getState(); 
    1571     boolean isSplitC = splitCBox.getState(); 
    1572     boolean isSplitZ = splitZBox.getState(); 
    1573     boolean isSplitT = splitTBox.getState(); 
    1574     boolean isMetadata = metadataBox.getState(); 
    1575     boolean isOMEXML = omexmlBox.getState(); 
    1576     boolean isGroup = groupBox.getState(); 
    1577     boolean isConcatenate = concatenateBox.getState(); 
    1578     boolean isRange = rangeBox.getState(); 
    1579     boolean isAutoscale = autoscaleBox.getState(); 
    1580     boolean isVirtual = virtualBox.getState(); 
    1581     boolean isRecord = recordBox.getState(); 
    1582     boolean isAllSeries = allSeriesBox.getState(); 
    1583     boolean isCrop = cropBox.getState(); 
    1584     boolean isSwap = swapBox.getState(); 
    1585  
    1586     // toggle availability of each option based on state of earlier options 
    1587  
    1588     // NB: The order the options are examined here defines their order of 
    1589     // precedence. This ordering is necessary because it affects which 
    1590     // component states are capable of graying out other components. 
    1591  
    1592     // For example, we want to disable autoscaleBox when virtualBox is checked, 
    1593     // so the virtualBox logic must appear before the autoscaleBox logic. 
    1594  
    1595     // To make it more intuitive for the user, the order of precedence should 
    1596     // match the component layout from left to right, top to bottom, according 
    1597     // to subsection. 
    1598  
    1599     // == Stack viewing == 
    1600  
    1601     // orderChoice 
    1602     orderEnabled = isStackStandard || isStackVisBio; 
    1603     if (src == stackChoice) { 
    1604       if (isStackHyperstack || isStackBrowser || isStackImage5D) { 
    1605         orderValue = ORDER_XYCZT; 
    1606       } 
    1607       else if (isStackView5D) orderValue = ORDER_XYZCT; 
    1608       else orderValue = ORDER_DEFAULT; 
    1609     } 
    1610  
    1611     // == Metadata viewing == 
    1612  
    1613     // metadataBox 
    1614     metadataEnabled = !isStackNone; 
    1615     if (!metadataEnabled) isMetadata = true; 
    1616  
    1617     // omexmlBox 
    1618     // NB: no other options affect omexmlBox 
    1619  
    1620     // == Dataset organization == 
    1621  
    1622     // groupBox 
    1623     // NB: no other options affect groupBox 
    1624     groupEnabled = !isOME() && !isOMERO(); 
    1625     if (!groupEnabled) isGroup = false; 
    1626     else if (src == stackChoice && isStackBrowser) isGroup = true; 
    1627  
    1628     // swapBox 
    1629     // NB: no other options affect swapBox 
    1630  
    1631     // allSeriesBox 
    1632     // NB: no other options affect allSeriesBox 
    1633  
    1634     // concatenateBox 
    1635     // NB: no other options affect concatenateBox 
    1636  
    1637     // == Memory management == 
    1638  
    1639     // virtualBox 
    1640     virtualEnabled = !isStackNone && !isStackImage5D && !isStackView5D; 
    1641     if (!virtualEnabled) isVirtual = false; 
    1642     else if (src == stackChoice && isStackBrowser) isVirtual = true; 
    1643  
    1644     // recordBox 
    1645     recordEnabled = isVirtual; 
    1646     if (!recordEnabled) isRecord = false; 
    1647  
    1648     // rangeBox 
    1649     rangeEnabled = !isStackNone; 
    1650     if (!rangeEnabled) isRange = false; 
    1651  
    1652     // cropBox 
    1653     cropEnabled = !isStackNone; 
    1654     if (!cropEnabled) isCrop = false; 
    1655  
    1656     // == Color options == 
    1657  
    1658     // mergeBox 
    1659     mergeEnabled = !isStackImage5D; 
    1660     if (!mergeEnabled) isMerge = false; 
    1661  
    1662     // colorizeBox 
    1663     colorizeEnabled = !isMerge && !isStackBrowser && 
    1664       !isStackImage5D && !isStackView5D && !isCustomColorize; 
    1665     if (!colorizeEnabled) isColorize = false; 
    1666  
    1667     // customColorizeBox 
    1668     customColorizeEnabled = !isMerge && !isStackBrowser && 
    1669       !isStackImage5D && !isStackView5D && !isColorize; 
    1670     if (!customColorizeEnabled) isCustomColorize = false; 
    1671  
    1672     // autoscaleBox 
    1673     autoscaleEnabled = !isVirtual; 
    1674     if (!autoscaleEnabled) isAutoscale = false; 
    1675  
    1676     // == Split into separate windows == 
    1677  
    1678     boolean splitEnabled = !isStackNone && !isStackBrowser && 
    1679       !isStackVisBio && !isStackImage5D && !isStackView5D && !isVirtual; 
    1680     // TODO: make splitting work with Data Browser & virtual stacks 
    1681  
    1682     // splitCBox 
    1683     splitCEnabled = splitEnabled && !isMerge; 
    1684     if (!splitCEnabled) isSplitC = false; 
    1685  
    1686     // splitZBox 
    1687     splitZEnabled = splitEnabled; 
    1688     if (!splitZEnabled) isSplitZ = false; 
    1689  
    1690     // splitTBox 
    1691     splitTEnabled = splitEnabled; 
    1692     if (!splitTEnabled) isSplitT = false; 
    1693  
    1694     // update state of each option, in case anything changed 
    1695  
    1696     //stackChoice.setEnabled(stackEnabled); 
    1697     orderChoice.setEnabled(orderEnabled); 
    1698     mergeBox.setEnabled(mergeEnabled); 
    1699     colorizeBox.setEnabled(colorizeEnabled); 
    1700     customColorizeBox.setEnabled(customColorizeEnabled); 
    1701     splitCBox.setEnabled(splitCEnabled); 
    1702     splitZBox.setEnabled(splitZEnabled); 
    1703     splitTBox.setEnabled(splitTEnabled); 
    1704     metadataBox.setEnabled(metadataEnabled); 
    1705     omexmlBox.setEnabled(omexmlEnabled); 
    1706     groupBox.setEnabled(groupEnabled); 
    1707     concatenateBox.setEnabled(concatenateEnabled); 
    1708     rangeBox.setEnabled(rangeEnabled); 
    1709     autoscaleBox.setEnabled(autoscaleEnabled); 
    1710     virtualBox.setEnabled(virtualEnabled); 
    1711     recordBox.setEnabled(recordEnabled); 
    1712     allSeriesBox.setEnabled(allSeriesEnabled); 
    1713     cropBox.setEnabled(cropEnabled); 
    1714     swapBox.setEnabled(swapEnabled); 
    1715  
    1716     //stackChoice.select(stackValue); 
    1717     orderChoice.select(orderValue); 
    1718     mergeBox.setState(isMerge); 
    1719     colorizeBox.setState(isColorize); 
    1720     customColorizeBox.setState(isCustomColorize); 
    1721     splitCBox.setState(isSplitC); 
    1722     splitZBox.setState(isSplitZ); 
    1723     splitTBox.setState(isSplitT); 
    1724     metadataBox.setState(isMetadata); 
    1725     omexmlBox.setState(isOMEXML); 
    1726     groupBox.setState(isGroup); 
    1727     concatenateBox.setState(isConcatenate); 
    1728     rangeBox.setState(isRange); 
    1729     autoscaleBox.setState(isAutoscale); 
    1730     virtualBox.setState(isVirtual); 
    1731     recordBox.setState(isRecord); 
    1732     allSeriesBox.setState(isAllSeries); 
    1733     cropBox.setState(isCrop); 
    1734     swapBox.setState(isSwap); 
    1735  
    1736     if (IS_GLITCHED) { 
    1737       // HACK - workaround a Mac OS X bug where GUI components do not update 
    1738  
    1739       // list of affected components 
    1740       Component[] c = { 
    1741         stackChoice, 
    1742         orderChoice, 
    1743         mergeBox, 
    1744         colorizeBox, 
    1745         customColorizeBox, 
    1746         splitCBox, 
    1747         splitZBox, 
    1748         splitTBox, 
    1749         metadataBox, 
    1750         omexmlBox, 
    1751         groupBox, 
    1752         concatenateBox, 
    1753         rangeBox, 
    1754         autoscaleBox, 
    1755         virtualBox, 
    1756         recordBox, 
    1757         allSeriesBox, 
    1758         cropBox, 
    1759         swapBox 
    1760       }; 
    1761  
    1762       // identify currently focused component 
    1763       Component focused = null; 
    1764       for (int i=0; i<c.length; i++) { 
    1765         if (c[i].isFocusOwner()) focused = c[i]; 
    1766       } 
    1767  
    1768       // temporarily disable focus events 
    1769       for (int i=0; i<c.length; i++) c[i].removeFocusListener(this); 
    1770  
    1771       // cycle through focus on all components 
    1772       for (int i=0; i<c.length; i++) c[i].requestFocusInWindow(); 
    1773  
    1774       // clear the focus globally 
    1775       KeyboardFocusManager kfm = 
    1776         KeyboardFocusManager.getCurrentKeyboardFocusManager(); 
    1777       kfm.clearGlobalFocusOwner(); 
    1778       sleep(100); // doesn't work if this value is too small 
    1779  
    1780       // refocus the originally focused component 
    1781       if (focused != null) focused.requestFocusInWindow(); 
    1782  
    1783       // reenable focus events 
    1784       for (int i=0; i<c.length; i++) c[i].addFocusListener(this); 
    1785     } 
    1786   } 
    1787  
    1788   private void sleep(long ms) { 
    1789     try { 
    1790       Thread.sleep(ms); 
    1791     } 
    1792     catch (InterruptedException exc) { } 
    1793   } 
     153      parseOptions(arg); 
     154    } 
     155  } 
     156 
     157  // autoscale 
     158  public String getAutoscaleInfo() { return getInfo(KEY_AUTOSCALE); } 
     159  public boolean isAutoscale() { return isSet(KEY_AUTOSCALE); } 
     160  public void setAutoscale(boolean b) { setValue(KEY_AUTOSCALE, b); } 
     161 
     162  // colorize 
     163  public String getColorizeInfo() { return getInfo(KEY_COLORIZE); } 
     164  public boolean isColorize() { return isSet(KEY_COLORIZE); } 
     165  public void setColorize(boolean b) { setValue(KEY_COLORIZE, b); } 
     166 
     167  // concatenate 
     168  public String getConcatenateInfo() { return getInfo(KEY_CONCATENATE); } 
     169  public boolean isConcatenate() { return isSet(KEY_CONCATENATE); } 
     170  public void setConcatenate(boolean b) { setValue(KEY_CONCATENATE, b); } 
     171 
     172  // crop 
     173  public String getCropInfo() { return getInfo(KEY_CROP); } 
     174  public boolean doCrop() { return isSet(KEY_CROP); } 
     175  public void setCrop(boolean b) { setValue(KEY_CROP, b); } 
     176 
     177  // customColorize 
     178  public String getCustomColorizeInfo() { return getInfo(KEY_CUSTOM_COLORIZE); } 
     179  public boolean isCustomColorize() { return isSet(KEY_CUSTOM_COLORIZE); } 
     180  public void setCustomColorize(boolean b) { setValue(KEY_CUSTOM_COLORIZE, b); } 
     181 
     182  // firstTime 
     183  public String getFirstTimeInfo() { return getInfo(KEY_FIRST); } 
     184  public boolean isFirstTime() { return isSet(KEY_FIRST); } 
     185  public void setFirstTime(boolean b) { setValue(KEY_FIRST, b); } 
     186 
     187  // forceThumbnails 
     188  public String getForceThumbnailsInfo() { return getInfo(KEY_FORCE_THUMBS); } 
     189  public boolean isForceThumbnails() { return isSet(KEY_FORCE_THUMBS); } 
     190  public void setForceThumbnails(boolean b) { setValue(KEY_FORCE_THUMBS, b); } 
     191 
     192  // groupFiles 
     193  public String getGroupFilesInfo() { return getInfo(KEY_GROUP_FILES); } 
     194  public boolean isGroupFiles() { return isSet(KEY_GROUP_FILES); } 
     195  public void setGroupFiles(boolean b) { setValue(KEY_GROUP_FILES, b); } 
     196 
     197  // id 
     198  public String getIdInfo() { return getInfo(KEY_ID); } 
     199  public String getId() { return getValue(KEY_ID); } 
     200  public void setId(String s) { setValue(KEY_ID, s); } 
     201 
     202  // location 
     203  public String getLocationInfo() { return getInfo(KEY_LOCATION); } 
     204  public String getLocation() { return getValue(KEY_LOCATION); } 
     205  public String[] getLocations() { return getPossible(KEY_LOCATION); } 
     206  public boolean isLocal() { return LOCATION_LOCAL.equals(getLocation()); } 
     207  public boolean isHTTP() { return LOCATION_HTTP.equals(getLocation()); } 
     208  public boolean isOME() { return LOCATION_OME.equals(getLocation()); } 
     209  public boolean isOMERO() { return LOCATION_OMERO.equals(getLocation()); } 
     210  public void setLocation(String s) { setValue(KEY_LOCATION, s); } 
     211 
     212  // mergeChannels 
     213  public String getMergeChannelsInfo() { return getInfo(KEY_MERGE_CHANNELS); } 
     214  public boolean isMergeChannels() { return isSet(KEY_MERGE_CHANNELS); } 
     215  public void setMergeChannels(boolean b) { setValue(KEY_MERGE_CHANNELS, b); } 
     216 
     217  // mergeOption 
     218  public String getMergeOptionInfo() { return getInfo(KEY_MERGE_OPTION); } 
     219  public String getMergeOption() { return getValue(KEY_MERGE_OPTION); } 
     220  public void setMergeOption(String s) { setValue(KEY_MERGE_OPTION, s); } 
     221 
     222  // openAllSeries 
     223  public String getOpenAllSeriesInfo() { return getInfo(KEY_OPEN_ALL_SERIES); } 
     224  public boolean openAllSeries() { return isSet(KEY_OPEN_ALL_SERIES); } 
     225  public void setOpenAllSeries(boolean b) { setValue(KEY_OPEN_ALL_SERIES, b); } 
     226 
     227  // quiet 
     228  public String getQuietInfo() { return getInfo(KEY_QUIET); } 
     229  public boolean isQuiet() { return isSet(KEY_QUIET); } 
     230  public void setQuiet(boolean b) { setValue(KEY_QUIET, b); } 
     231 
     232  // record 
     233  public String getRecordInfo() { return getInfo(KEY_RECORD); } 
     234  public boolean isRecord() { return isSet(KEY_RECORD); } 
     235  public void setRecord(boolean b) { setValue(KEY_RECORD, b); } 
     236 
     237  // series 
     238  public String getSeriesInfo() { return getInfo(KEY_SERIES); } 
     239  public String getSeries() { return getValue(KEY_SERIES); } 
     240  public void setSeries(String s) { setValue(KEY_SERIES, s); } 
     241 
     242  // showMetadata 
     243  public String getShowMetadataInfo() { return getInfo(KEY_SHOW_METADATA); } 
     244  public boolean isShowMetadata() { return isSet(KEY_SHOW_METADATA); } 
     245  public void setShowMetadata(boolean b) { setValue(KEY_SHOW_METADATA, b); } 
     246 
     247  // showOMEXML 
     248  public String getShowOMEXMLInfo() { return getInfo(KEY_SHOW_OME_XML); } 
     249  public boolean isShowOMEXML() { return isSet(KEY_SHOW_OME_XML); } 
     250  public void setShowOMEXML(boolean b) { setValue(KEY_SHOW_OME_XML, b); } 
     251 
     252  // showROIs 
     253  public String getShowROIsInfo() { return getInfo(KEY_SHOW_ROIS); } 
     254  public boolean showROIs() { return isSet(KEY_SHOW_ROIS); } 
     255  public void setShowROIs(boolean b) { setValue(KEY_SHOW_ROIS, b); } 
     256 
     257  // specifyRanges 
     258  public String getSpecifyRangesInfo() { return getInfo(KEY_SPECIFY_RANGES); } 
     259  public boolean isSpecifyRanges() { return isSet(KEY_SPECIFY_RANGES); } 
     260  public void setSpecifyRanges(boolean b) { setValue(KEY_SPECIFY_RANGES, b); } 
     261 
     262  // splitFocalPlanes 
     263  public String getSplitFocalPlanesInfo() { return getInfo(KEY_SPLIT_Z); } 
     264  public boolean isSplitFocalPlanes() { return isSet(KEY_SPLIT_Z); } 
     265  public void setSplitFocalPlanes(boolean b) { setValue(KEY_SPLIT_Z, b); } 
     266 
     267  // splitTimepoints 
     268  public String getSplitTimepointsInfo() { return getInfo(KEY_SPLIT_T); } 
     269  public boolean isSplitTimepoints() { return isSet(KEY_SPLIT_T); } 
     270  public void setSplitTimepoints(boolean b) { setValue(KEY_SPLIT_T, b); } 
     271 
     272  // splitWindows 
     273  public String getSplitChannelsInfo() { return getInfo(KEY_SPLIT_C); } 
     274  public boolean isSplitChannels() { return isSet(KEY_SPLIT_C); } 
     275  public void setSplitChannels(boolean b) { setValue(KEY_SPLIT_C, b); } 
     276 
     277  // stackFormat 
     278  public String getStackFormatInfo() { return getInfo(KEY_STACK_FORMAT); } 
     279  public String getStackFormat() { return getValue(KEY_STACK_FORMAT); } 
     280  public String[] getStackFormats() { return getPossible(KEY_STACK_FORMAT); } 
     281  public boolean isViewNone() { return VIEW_NONE.equals(getStackFormat()); } 
     282  public boolean isViewStandard() { 
     283    return VIEW_STANDARD.equals(getStackFormat()); 
     284  } 
     285  public boolean isViewHyperstack() { 
     286    return VIEW_HYPERSTACK.equals(getStackFormat()); 
     287  } 
     288  public boolean isViewBrowser() { 
     289    return VIEW_BROWSER.equals(getStackFormat()); 
     290  } 
     291  public boolean isViewVisBio() { return VIEW_VISBIO.equals(getStackFormat()); } 
     292  public boolean isViewImage5D() { 
     293    return VIEW_IMAGE_5D.equals(getStackFormat()); 
     294  } 
     295  public boolean isViewView5D() { 
     296    return VIEW_VIEW_5D.equals(getStackFormat()); 
     297  } 
     298  public void setStackFormat(String s) { setValue(KEY_STACK_FORMAT, s); } 
     299 
     300  // stackOrder 
     301  public String getStackOrderInfo() { return getInfo(KEY_STACK_ORDER); } 
     302  public String getStackOrder() { return getValue(KEY_STACK_ORDER); } 
     303  public String[] getStackOrders() { return getPossible(KEY_STACK_ORDER); } 
     304  public void setStackOrder(String s) { setValue(KEY_STACK_ORDER, s); } 
     305 
     306  // swapDimensions 
     307  public String getSwapDimensionsInfo() { return getInfo(KEY_SWAP_DIMS); } 
     308  public boolean isSwapDimensions() { return isSet(KEY_SWAP_DIMS); } 
     309  public void setSwapDimensions(boolean b) { setValue(KEY_SWAP_DIMS, b); } 
     310 
     311  // upgradeCheck 
     312  public String getUpgradeCheckInfo() { return getInfo(KEY_UPGRADE_CHECK); } 
     313  public boolean doUpgradeCheck() { return isSet(KEY_UPGRADE_CHECK); } 
     314  public void setUpgradeCheck(boolean b) { setValue(KEY_UPGRADE_CHECK, b); } 
     315 
     316  // virtual 
     317  public String getVirtualInfo() { return getInfo(KEY_VIRTUAL); } 
     318  public boolean isVirtual() { return isSet(KEY_VIRTUAL); } 
     319  public void setVirtual(boolean b) { setValue(KEY_VIRTUAL, b); } 
     320 
     321  // windowless 
     322  public String getWindowlessInfo() { return getInfo(KEY_WINDOWLESS); } 
     323  public boolean isWindowless() { return isSet(KEY_WINDOWLESS); } 
     324  public void setWindowless(boolean b) { setValue(KEY_WINDOWLESS, b); } 
    1794325 
    1795326} 
  • trunk/components/loci-plugins/src/loci/plugins/importer/importer-options.txt

    r5118 r5133  
    2727type = boolean 
    2828label = Autoscale 
    29 info = \ 
     29info = <b>Autoscale</b> - \ 
    3030  Stretches the histogram of the image planes to fit the data range.    \ 
    3131  Does not alter underlying values in the image. If selected, histogram \ 
     
    3535  Window/Level controls to adjust the contrast range regardless of      \ 
    3636  whether this option is used. 
     37default = true 
    3738 
    3839[colorize] 
    3940type = boolean 
    4041label = RGB_colorize channels 
    41 info = \ 
     42info = <b>RGB colorize channels</b> - \ 
    4243  Each channel is assigned an appropriate pseudocolor table rather than the \ 
    4344  normal grayscale.                                                         \ 
     
    4546  and the third channel is blue. This option is not available when <b>Merge \ 
    4647  channels to RGB</b> or <b>Custom colorize channels</b> are set. 
     48default = true 
    4749 
    4850[concatenate] 
    4951type = boolean 
    5052label = Concatenate_series when compatible 
    51 info = \ 
     53info = <b>Concatenate series when compatible</b> - \ 
    5254  Allows multiple image series to be joined end to end.             \ 
    5355  <br><br><b>Example:</b> You want to join two sequential timelapse \ 
    5456  series. 
     57default = false 
    5558 
    5659[crop] 
    5760type = boolean 
    5861label = Crop on import 
    59 info = \ 
     62info = <b>Crop on import</b> - \ 
    6063  Image planes may be cropped during import to conserve memory.          \ 
    6164  <br><br>A window is opened with display of the pixel width and height  \ 
     
    6366  corner of the crop region and the width and height of the selection to \ 
    6467  be displayed, in pixels. 
     68default = false 
    6569 
    6670[customColorize] 
    6771type = boolean 
    6872label = Custom_colorize channels 
    69 info = \ 
     73info = <b>Custom colorize channels</b> - \ 
    7074  Each channel is assigned a pseudocolor table rather than the normal      \ 
    7175  grayscale.<br><br>The color for each channel is chosen by the user. This \ 
    7276  option is not available when <b>Merge channels to RGB</b> or <b>RGB      \ 
    7377  colorize channels</b> are set. 
     78default = false 
    7479 
    7580[firstTime] 
    7681type = boolean 
     82default = true 
    7783 
    7884[forceThumbnails] 
    7985type = boolean 
     86save = false 
     87label = Force thumbnails 
     88default = false 
    8089 
    8190[groupFiles] 
    8291type = boolean 
    8392label = Group_files with similar names 
    84 info = \ 
     93info = <b>Group files with similar names</b> - \ 
    8594  Parses filenames in the selected folder to open files with similar     \ 
    8695  names as planes in the same dataset.                                   \ 
     
    98107  case it is incorrect. Bio-Formats will then import all 12 x 9 = 108    \ 
    99108  planes of the dataset. 
     109default = false 
     110 
     111[id] 
     112type = string 
     113save = false 
     114 
     115[location] 
     116type = string 
     117save = false 
     118default = Local machine 
     119values = \ 
     120  Local machine, \ 
     121  Internet,      \ 
     122  OME server,    \ 
     123  OMERO server 
    100124 
    101125[mergeChannels] 
    102126type = boolean 
    103127label = Merge_channels to RGB 
    104 info = \ 
     128info = <b>Merge channels to RGB</b> - \ 
    105129  A dataset with multiple channels will be opened and merged with       \ 
    106130  channels pseudocolored in the order of the RGB color scheme; i.e.,    \ 
     
    117141  <li>2 planes with 7 channels each (7th channel is yellow)</li>        \ 
    118142  </ul> 
     143default = false 
    119144 
    120145[mergeOption] 
    121146type = string 
    122 label = Merging Options 
     147label = Merging options 
     148default = Do not merge 
    123149 
    124150[openAllSeries] 
    125151type = boolean 
    126152label = Open_all_series 
    127 info = \ 
     153info = <b>Open all series</b> - \ 
    128154  Opens every available image series without prompting.                  \ 
    129155  <br><br>Some datasets contain multiple distinct image series. Normally \ 
     
    135161  It is also useful in a macro when the number of available image series \ 
    136162  is unknown. 
     163default = false 
     164 
     165[quiet] 
     166type = boolean 
     167save = false 
     168label = Quiet mode 
     169default = false 
    137170 
    138171[record] 
    139172type = boolean 
    140173label = Record_modifications_to_virtual_stack 
    141 info = \ 
     174info = <b>Record modifications to virtual stack</b> - \ 
    142175  <i>BETA FEATURE</i> - Record and reapply changes to virtual stack      \ 
    143176  planes.                                                                \ 
     
    148181  you performed previously. In this way, the image stack should behave   \ 
    149182  more like a normal, fully memory-resident image stack. 
     183default = false 
    150184 
    151185[series] 
    152186type = string 
    153187label = series 
     188default = 0 
    154189 
    155190[showMetadata] 
    156191type = boolean 
    157192label = Display_metadata in results window 
    158 info = \ 
     193info = <b>Display metadata in results window</b> - \ 
    159194  Reads metadata that may be contained within the file format and      \ 
    160195  displays it. You can save it as a text file or copy it from the File \ 
     
    162197  depends upon the manner in which metadata is formatted in the data   \ 
    163198  source. 
     199default = false 
    164200 
    165201[showOMEXML] 
    166202type = boolean 
    167203label = Display_OME-XML metadata 
    168 info = \ 
     204info = <b>Display OME-XML metadata</b> - \ 
    169205  Displays a tree of metadata standardized into the OME data model.     \ 
    170206  This structure is the same regardless of file format, though some     \ 
     
    179215  PhysicalSizeX, PhysicalSizeY, PhysicalSizeZ.</li>                     \ 
    180216  </ul> 
     217default = false 
    181218 
    182219[showROIs] 
    183220type = boolean 
    184221label = Display_ROIs 
    185 info = Adds any ROIs in the file to ImageJ's ROI manager. 
     222info = <b>Display ROIs</b> - \ 
     223  Adds any ROIs in the file to ImageJ's ROI manager. 
     224default = false 
    186225 
    187226[specifyRanges] 
    188227type = boolean 
    189228label = Specify_range for each series 
    190 info = \ 
     229info = <b>Specify range for each series</b> - \ 
    191230  Opens only the specified range of image planes from a dataset.       \ 
    192231  <br><br>After analyzing the dataset dimensional parameters,          \ 
     
    196235  planes in a z-series that actually contain structures of interest to \ 
    197236  conserve memory. 
     237default = false 
    198238 
    199239[splitFocalPlanes] 
    200240type = boolean 
    201241label = Split_focal planes 
    202 info = Each focal plane is opened as a separate stack. 
     242info = <b>Split focal planes</b> - \ 
     243  Each focal plane is opened as a separate stack. 
     244default = false 
    203245 
    204246[splitTimepoints] 
    205247type = boolean 
    206248label = Split_timepoints 
    207 info = Timelapse data will be opened as a separate stack for each timepoint. 
     249info = <b>Split timepoints</b> - \ 
     250  Timelapse data will be opened as a separate stack for each timepoint. 
     251default = false 
    208252 
    209253[splitWindows] 
    210254type = boolean 
    211255label = Split_channels 
    212 info = \ 
     256info = <b>Split channels</b> - \ 
    213257  Each channel is opened as a separate stack.                       \ 
    214258  <br><br>This option is especially useful if you want to merge the \ 
    215259  channels into a specific order, rather than automatically assign  \ 
    216260  channels to the order of RGB. The bit depth is preserved. 
     261default = true 
    217262 
    218263[stackFormat] 
    219264type = string 
    220265label = View stack with: 
    221 info = \ 
     266info = <b>View stack with</b> - \ 
    222267  The type of image viewer to use when displaying the dataset.           \ 
    223268  <br><br>Possible choices are:<ul>                                      \ 
    224   <li><b>" + VIEW_NONE + "</b> - Display no pixels, only metadata.</li>  \ 
    225   <li><b>" + VIEW_STANDARD + "</b> - Display the pixels in a standard    \ 
     269  <li><b>Metadata only</b> - Display no pixels, only metadata.</li>      \ 
     270  <li><b>Standard ImageJ</b> - Display the pixels in a standard          \ 
    226271  ImageJ window without multidimensional support.</li>                   \ 
    227   <li><b>" + VIEW_HYPERSTACK + "</b> - Display the pixels in ImageJ's    \ 
     272  <li><b>Hyperstack</b> - Display the pixels in ImageJ's                 \ 
    228273  built-in 5D viewer. If you do not have this option, upgrade to a more  \ 
    229274  recent version of ImageJ.</li>                                         \ 
    230   <li><b>" + VIEW_BROWSER + "</b> - Display the pixels in LOCI's         \ 
     275  <li><b>Data Browser</b> - Display the pixels in LOCI's                 \ 
    231276  multidimensional Data Browser viewer. The Data Browser has some        \ 
    232277  additional features on top of the normal ImageJ hyperstack. If you do  \ 
    233278  not have this option, upgrade to a more recent version of ImageJ.</li> \ 
    234   /"<li><b>" + VIEW_VISBIO + "</b> - Not yet implemented.</li>           \ 
    235   <li><b>" + VIEW_IMAGE_5D + "</b> - Display the pixels in               \ 
     279  <li><b>VisBio</b> - Not yet implemented.</li>                          \ 
     280  <li><b>Image5D</b> - Display the pixels in                             \ 
    236281  Joachim Walter's Image5D viewer. Requires the Image5D plugin.</li>     \ 
    237   <li><b>" + VIEW_VIEW_5D + "</b> - Display the pixels in                \ 
     282  <li><b>View5D</b> - Display the pixels in                              \ 
    238283  Rainer Heintzmann's View5D viewer. Requires the View5D plugin.</li>    \ 
    239284  </ul> 
     285default = Hyperstack 
     286values = \ 
     287  Metadata only,   \ 
     288  Standard ImageJ, \ 
     289  Hyperstack,      \ 
     290  Data Browser,    \ 
     291  VisBio,          \ 
     292  Image5D,         \ 
     293  View5D 
    240294 
    241295[stackOrder] 
    242296type = string 
    243297label = Stack_order: 
    244 info = \ 
     298info = <b>Stack order</b> - \ 
    245299  Controls the rasterization order of the dataset's dimensional axes.   \ 
    246300  <br><br>Unless you care about the order in which the image planes     \ 
     
    249303  order they are stored, which is format-dependent. However, several    \ 
    250304  stack view modes require a specific rasterization order:<ul>          \ 
    251   <li>Hyperstacks must be in " + ORDER_XYCZT + " order.</li>            \ 
    252   <li>Image5D must be in " + ORDER_XYCZT + " order.</li>                \ 
    253   <li>View5D must be in " + ORDER_XYCZT + " order.</li>                 \ 
    254   </ul><b>Example:</b> For a dataset in " + ORDER_XYCZT + " order with  \ 
    255   2 channels, 3 focal planes and 5 time points, the order would be:<ol> \ 
     305  <li>Hyperstacks must be in XYCZT order.</li>                          \ 
     306  <li>Image5D must be in XYCZT order.</li>                              \ 
     307  <li>View5D must be in XYCZT order.</li>                               \ 
     308  </ul><b>Example:</b> For a dataset in XYCZT order with 2 channels,    \ 
     309  3 focal planes and 5 time points, the order would be:<ol>            \ 
    256310  <li>C1-Z1-T1</li>                                                     \ 
    257311  <li>C2-Z1-T1</li>                                                     \ 
     
    264318  <li>etc.</li>                                                         \ 
    265319  </ol> 
     320default = Default 
     321values = \ 
     322  Default, \ 
     323  XYZCT,   \ 
     324  XYZTC,   \ 
     325  XYCZT,   \ 
     326  XYTCZ,   \ 
     327  XYCTZ,   \ 
     328  XYTZC 
    266329 
    267330[swapDimensions] 
    268331type = boolean 
    269332label = Swap_dimensions 
    270 info = \ 
     333info = <b>Swap dimensions</b> - \ 
    271334  Allows reassignment of dimensional axes (e.g., channel, Z and time).        \ 
    272335  <br><br>Bio-Formats is supposed to be smart about handling multidimensional \ 
     
    277340  in case it guesses wrong, you can use <b>Swap dimensions</b> to reassign    \ 
    278341  which dimensions are which. 
     342default = false 
    279343 
    280344[upgradeCheck] 
     
    285349type = boolean 
    286350label = Use_virtual_stack 
    287 info = \ 
     351info = <b>Use virtual stack</b> - \ 
    288352  Only reads one image plane into memory at a time, loading from the  \ 
    289353  data source on the fly as the active image plane changes.           \ 
    290354  <br><br>This option is essential for datasets too large to fit into \ 
    291355  memory. 
     356default = false 
    292357 
    293358[windowless] 
    294359type = boolean 
    295360label = windowless 
     361default = false 
  • trunk/components/loci-plugins/src/loci/plugins/macro/MacroFunctions.java

    r5093 r5133  
    3737import java.lang.reflect.Method; 
    3838 
     39import loci.plugins.util.LibraryChecker; 
     40 
    3941/** 
    4042 * Convenience class that simplifies implemention of ImageJ macro extensions. 
     
    5759 
    5860  public void run(String arg) { 
    59     if (IJ.versionLessThan("1.39c")) return; 
     61    if (!LibraryChecker.checkImageJ()) return; 
    6062    if (!IJ.macroRunning()) { 
    6163      IJ.error("Cannot install extensions from outside a macro."); 
  • trunk/components/loci-plugins/src/loci/plugins/prefs/BooleanOption.java

    r5111 r5133  
    2626package loci.plugins.prefs; 
    2727 
     28import ij.Macro; 
    2829import ij.Prefs; 
    2930 
     
    5152  /** Constructs a boolean option with the parameters from the given map. */ 
    5253  public BooleanOption(HashMap<String, String> entry) { 
    53     this(entry.get(INI_KEY), entry.get(INI_LABEL), 
    54       entry.get(INI_INFO), "true".equals(entry.get(INI_DEFAULT))); 
     54    this(entry.get(INI_KEY), 
     55      "true".equals(entry.get(INI_SAVE)), 
     56      entry.get(INI_LABEL), 
     57      entry.get(INI_INFO), 
     58      "true".equals(entry.get(INI_DEFAULT))); 
    5559  } 
    5660 
    5761  /** Constructs a boolean option with the given parameters. */ 
    58   public BooleanOption(String key, String label, String info, 
    59     boolean defaultValue) 
     62  public BooleanOption(String key, boolean save, String label, 
     63    String info, boolean defaultValue) 
    6064  { 
    61     super(key, label, info); 
     65    super(key, save, label, info); 
    6266    this.defaultValue = defaultValue; 
     67    this.value = defaultValue; 
    6368  } 
    6469 
     
    7580  } 
    7681 
     82  /** Sets the current value of the option. */ 
     83  public void setValue(boolean value) { 
     84    this.value = value; 
     85  } 
     86 
    7787  // -- Option methods -- 
     88 
     89  /* @see Option#parseOption(String arg) */ 
     90  public void parseOption(String arg) { 
     91    String s = Macro.getValue(arg, key, null); 
     92    if (s != null) value = s.equalsIgnoreCase("true"); 
     93  } 
    7894 
    7995  /* @see Option#loadOption() */ 
     
    84100  /* @see Option#saveOption() */ 
    85101  public void saveOption() { 
    86     Prefs.set(KEY_PREFIX + key, value); 
     102    if (save) Prefs.set(KEY_PREFIX + key, value); 
    87103  } 
    88104 
  • trunk/components/loci-plugins/src/loci/plugins/prefs/Option.java

    r5118 r5133  
    4545  public static final String INI_KEY = IniParser.HEADER_KEY; 
    4646 
     47  /** INI key indicating whether option should be saved to prefs file. */ 
     48  public static final String INI_SAVE = "save"; 
     49 
    4750  /** INI key indicating option's label. */ 
    4851  public static final String INI_LABEL = "label"; 
     
    5962  protected String key; 
    6063 
     64  /** Whether option state should be saved to ImageJ preferences file. */ 
     65  protected boolean save; 
     66 
    6167  /** 
    6268   * Label describing the option, for use with ImageJ dialogs. 
     
    7177 
    7278  /** Constructs an option with the given parameters. */ 
    73   public Option(String key, String label, String info) { 
     79  public Option(String key, boolean save, String label, String info) { 
    7480    this.key = key; 
    7581    if (key == null) throw new IllegalArgumentException("Null key"); 
     82    this.save = save; 
    7683    this.label = label; 
    7784    this.info = info; 
     
    8390  public String getKey() { 
    8491    return key; 
     92  } 
     93 
     94  /** Gets whether option should be saved to ImageJ preferences file. */ 
     95  public boolean isSaved() { 
     96    return save; 
    8597  } 
    8698 
     
    97109  // -- Abstract Option methods -- 
    98110 
     111  /** Parses the option's value from the given argument string. */ 
     112  public abstract void parseOption(String arg); 
     113 
    99114  /** Loads the option's value from the ImageJ preferences file. */ 
    100115  public abstract void loadOption(); 
  • trunk/components/loci-plugins/src/loci/plugins/prefs/OptionsList.java

    r5118 r5133  
    2626package loci.plugins.prefs; 
    2727 
    28 import ij.Prefs; 
    29  
    3028import java.io.IOException; 
    3129import java.util.HashMap; 
     30import java.util.List; 
    3231import java.util.Vector; 
    3332 
     
    5655  // -- Fields -- 
    5756 
    58   /** List of options defining this set of preferences. */ 
    59   protected Vector<Option> options; 
     57  /** Table of options defining this set of preferences. */ 
     58  protected HashMap<String, Option> options; 
    6059 
    6160  // -- Constructor -- 
    6261 
    63   public OptionsList(String path) throws IOException { 
    64     this(new IniParser().parseINI(path)); 
     62  public OptionsList(String path, Class c) throws IOException { 
     63    this(new IniParser().parseINI(path, c)); 
    6564  } 
    6665 
    6766  public OptionsList(Vector<HashMap<String, String>> ini) { 
    68     options = new Vector<Option>(); 
     67    options = new HashMap<String, Option>(); 
    6968    for (HashMap<String, String> entry : ini) { 
    7069      String type = entry.get(INI_TYPE); 
    71       if (type.equals(TYPE_BOOLEAN)) { 
    72         options.add(new BooleanOption(entry)); 
    73       } 
    74       else if (type.equals(TYPE_STRING)) { 
    75         options.add(new StringOption(entry)); 
    76       } 
     70      Option o; 
     71      if (type.equals(TYPE_BOOLEAN)) o = new BooleanOption(entry); 
     72      else if (type.equals(TYPE_STRING)) o = new StringOption(entry); 
    7773      else throw new IllegalArgumentException("Unknown type: " + type); 
     74      options.put(o.getKey(), o); 
    7875    } 
    7976  } 
     
    8178  // -- OptionsList methods -- 
    8279 
     80  /** Parses option values from the given argument string. */ 
     81  public void parseOptions(String arg) { 
     82    for (Option o : options.values()) o.parseOption(arg); 
     83  } 
     84 
    8385  /** Loads option values from the ImageJ preferences file. */ 
    8486  public void loadOptions() { 
    85     for (Option o : options) o.loadOption(); 
     87    for (Option o : options.values()) o.loadOption(); 
    8688  } 
    8789 
    8890  /** Saves option values to the ImageJ preferences file. */ 
    8991  public void saveOptions() { 
    90     for (Option o : options) o.saveOption(); 
     92    for (Option o : options.values()) o.saveOption(); 
     93  } 
     94 
     95  /** 
     96   * Gets whether the option with the given key 
     97   * is saved to the ImageJ preferences file. 
     98   */ 
     99  public boolean isSaved(String key) { return options.get(key).isSaved(); } 
     100 
     101  /** Gets the label for the option with the given key. */ 
     102  public String getLabel(String key) { return options.get(key).getLabel(); } 
     103 
     104  /** Gets the documentation for the option with the given key. */ 
     105  public String getInfo(String key) { return options.get(key).getInfo(); } 
     106 
     107  /** Gets the possible values for the string option with the given key. */ 
     108  public String[] getPossible(String key) { 
     109    Option o = options.get(key); 
     110    if (o instanceof StringOption) { 
     111      List<String> possible = ((StringOption) o).getPossible(); 
     112      return possible.toArray(new String[0]); 
     113    } 
     114    throw new IllegalArgumentException("Not a string key: " + key); 
     115  } 
     116 
     117  /** 
     118   * Gets whether the specified value is a possible one 
     119   * for the string option with the given key. 
     120   */ 
     121  public boolean isPossible(String key, String value) { 
     122    Option o = options.get(key); 
     123    if (o instanceof StringOption) { 
     124      List<String> possible = ((StringOption) o).getPossible(); 
     125      return possible.contains(value); 
     126    } 
     127    throw new IllegalArgumentException("Not a string key: " + key); 
     128  } 
     129 
     130  /** Gets the default value of the boolean option with the given key. */ 
     131  public boolean isSetByDefault(String key) { 
     132    Option o = options.get(key); 
     133    if (o instanceof BooleanOption) return ((BooleanOption) o).getDefault(); 
     134    throw new IllegalArgumentException("Not a boolean key: " + key); 
     135  } 
     136 
     137  /** Gets the default value of the string option with the given key. */ 
     138  public String getDefaultValue(String key) { 
     139    Option o = options.get(key); 
     140    if (o instanceof StringOption) return ((StringOption) o).getDefault(); 
     141    throw new IllegalArgumentException("Not a string key: " + key); 
     142  } 
     143 
     144  /** Gets the value of the boolean option with the given key. */ 
     145  public boolean isSet(String key) { 
     146    Option o = options.get(key); 
     147    if (o instanceof BooleanOption) return ((BooleanOption) o).getValue(); 
     148    throw new IllegalArgumentException("Not a boolean key: " + key); 
     149  } 
     150 
     151  /** Gets the value of the string option with the given key. */ 
     152  public String getValue(String key) { 
     153    Option o = options.get(key); 
     154    if (o instanceof StringOption) return ((StringOption) o).getValue(); 
     155    throw new IllegalArgumentException("Not a string key: " + key); 
     156  } 
     157 
     158  /** Sets the value of the boolean option with the given key. */ 
     159  public void setValue(String key, boolean value) { 
     160    Option o = options.get(key); 
     161    if (o instanceof BooleanOption) ((BooleanOption) o).setValue(value); 
     162    else throw new IllegalArgumentException("Not a boolean key: " + key); 
     163  } 
     164 
     165  /** Sets the value of the string option with the given key. */ 
     166  public void setValue(String key, String value) { 
     167    Option o = options.get(key); 
     168    if (o instanceof StringOption) ((StringOption) o).setValue(value); 
     169    else throw new IllegalArgumentException("Not a string key: " + key); 
     170  } 
     171 
     172  /** Gets the option with the given key. */ 
     173  public Option getOption(String key) { 
     174    return options.get(key); 
     175  } 
     176 
     177  /** Gets the boolean option with the given key. */ 
     178  public BooleanOption getBooleanOption(String key) { 
     179    Option o = options.get(key); 
     180    if (o instanceof BooleanOption) return (BooleanOption) o; 
     181    throw new IllegalArgumentException("Not a boolean key: " + key); 
     182  } 
     183 
     184  /** Gets the string option with the given key. */ 
     185  public StringOption getStringOption(String key) { 
     186    Option o = options.get(key); 
     187    if (o instanceof StringOption) return (StringOption) o; 
     188    throw new IllegalArgumentException("Not a string key: " + key); 
    91189  } 
    92190 
  • trunk/components/loci-plugins/src/loci/plugins/prefs/StringOption.java

    r5111 r5133  
    2626package loci.plugins.prefs; 
    2727 
     28import ij.Macro; 
    2829import ij.Prefs; 
    2930 
     
    4849  // -- Fields -- 
    4950 
     51  /** The option's default value. */ 
     52  protected String defaultValue; 
     53 
    5054  /** List of possible values. */ 
    5155  protected List<String> possibleValues; 
    52  
    53   /** The option's default value. */ 
    54   protected String defaultValue; 
    5556 
    5657  /** The option's current value. */ 
     
    7172  /** Constructs a string option with the parameters from the given map. */ 
    7273  public StringOption(HashMap<String, String> entry) { 
    73     this(entry.get(INI_KEY), entry.get(INI_LABEL), entry.get(INI_INFO), 
    74       entry.get(INI_DEFAULT), parseList(entry.get(INI_POSSIBLE))); 
     74    this(entry.get(INI_KEY), 
     75      "true".equals(entry.get(INI_SAVE)), 
     76      entry.get(INI_LABEL), 
     77      entry.get(INI_INFO), 
     78      entry.get(INI_DEFAULT), 
     79      parseList(entry.get(INI_POSSIBLE))); 
    7580  } 
    7681 
     
    7984   * If possible values list is null, any string value is allowed. 
    8085   */ 
    81   public StringOption(String key, String label, String info, 
    82     String defaultValue, List<String> possibleValues) 
     86  public StringOption(String key, boolean save, String label, 
     87    String info, String defaultValue, List<String> possibleValues) 
    8388  { 
    84     super(key, label, info); 
     89    super(key, save, label, info); 
    8590    this.defaultValue = defaultValue; 
    8691    this.possibleValues = possibleValues; 
     92    this.value = defaultValue; 
    8793  } 
    8894 
     
    114120  } 
    115121 
     122  /** Sets the current value of the option. */ 
     123  public void setValue(String value) { 
     124    if (possibleValues == null) this.value = value; 
     125    else { 
     126      for (String p : possibleValues) { 
     127        if (p.equals(value)) { 
     128          this.value = value; 
     129          return; 
     130        } 
     131      } 
     132      throw new IllegalArgumentException("'" + 
     133        value + "' is not a possible value"); 
     134    } 
     135  } 
     136 
    116137  // -- Option methods -- 
     138 
     139  /* @see Option#parseOption(String arg) */ 
     140  public void parseOption(String arg) { 
     141    value = Macro.getValue(arg, key, value); 
     142  } 
    117143 
    118144  /* @see Option#loadOption() */ 
     
    123149  /* @see Option#saveOption() */ 
    124150  public void saveOption() { 
    125     Prefs.set(KEY_PREFIX + key, value); 
     151    if (save) Prefs.set(KEY_PREFIX + key, value); 
    126152  } 
    127153 
  • trunk/components/loci-plugins/src/loci/plugins/util/ImagePlusTools.java

    r5093 r5133  
    2626package loci.plugins.util; 
    2727 
    28 import ij.IJ; 
     28import ij.CompositeImage; 
    2929import ij.ImagePlus; 
    3030import ij.ImageStack; 
     
    3535import ij.process.ImageProcessor; 
    3636import ij.process.ShortProcessor; 
    37  
    38 import java.io.ByteArrayOutputStream; 
    39 import java.io.PrintStream; 
    40  
    41 import loci.common.ReflectException; 
    42 import loci.common.ReflectedUniverse; 
    4337import loci.formats.FormatTools; 
    4438import loci.formats.meta.MetadataRetrieve; 
     
    111105      imp = new ImagePlus(title, cp); 
    112106    } 
    113     else if (p.length <= 7 && LibraryChecker.checkComposite()) { 
     107    else if (p.length <= 7) { 
    114108      ImageStack tmpStack = new ImageStack(width, height); 
    115       for (int i=0; i<p.length; i++) { 
    116         tmpStack.addSlice("", p[i]); 
    117       } 
    118       try { 
    119         ReflectedUniverse r = new ReflectedUniverse(); 
    120         r.exec("import ij.CompositeImage"); 
    121         ImagePlus ii = new ImagePlus(title, tmpStack); 
    122         r.setVar("ii", ii); 
    123         r.exec("imp = new CompositeImage(ii, CompositeImage.COMPOSITE)"); 
    124         imp = (ImagePlus) r.getVar("imp"); 
    125       } 
    126       catch (ReflectException e) { 
    127         ByteArrayOutputStream s = new ByteArrayOutputStream(); 
    128         e.printStackTrace(new PrintStream(s)); 
    129         IJ.error(s.toString()); 
    130       } 
     109      for (int i=0; i<p.length; i++) tmpStack.addSlice("", p[i]); 
     110 
     111      ImagePlus ii = new ImagePlus(title, tmpStack); 
     112      imp = new CompositeImage(ii, CompositeImage.COMPOSITE); 
    131113    } 
    132114 
  • trunk/components/loci-plugins/src/loci/plugins/util/LibraryChecker.java

    r5093 r5133  
    5151  } 
    5252 
    53   /** Minimum version of ImageJ necessary for CompositeImage. */ 
    54   public static final String IMAGEJ_VERSION = "1.34"; 
     53  /** Minimum version of ImageJ necessary for LOCI plugins. */ 
     54  public static final String IMAGEJ_VERSION = "1.40"; 
    5555 
    5656  /** Message to be displayed if ImageJ is too old for LOCI plugins. */ 
    5757  public static final String IMAGEJ_MSG = 
    5858    "Sorry, the LOCI plugins require ImageJ v" + IMAGEJ_VERSION + " or later."; 
    59  
    60   /** Minimum version of ImageJ necessary for LOCI plugins. */ 
    61   public static final String COMPOSITE_VERSION = "1.39l"; 
    62  
    63   /** Message to be displayed if ImageJ is too old for CompositeImage. */ 
    64   public static final String COMPOSITE_MSG = "ImageJ " + COMPOSITE_VERSION + 
    65     " or later is required to merge >8 bit or >3 channel data"; 
    6659 
    6760  // -- Constructor -- 
     
    138131  } 
    139132 
    140   /** Checks whether ImageJ is new enough for CompositeImages. */ 
    141   public static boolean checkComposite() { 
    142     return checkImageJ(COMPOSITE_VERSION, COMPOSITE_MSG); 
    143   } 
    144  
    145133  /** 
    146134   * Returns true the current ImageJ version is greater than or equal to the 
  • trunk/components/loci-plugins/src/loci/plugins/util/WindowTools.java

    r5093 r5133  
    2828import ij.IJ; 
    2929import ij.ImageJ; 
    30 import ij.text.TextWindow; 
    31 import ij.util.Tools; 
    3230 
    3331import java.awt.BorderLayout; 
     
    4442import java.awt.Toolkit; 
    4543import java.awt.Window; 
    46 import java.io.CharArrayWriter; 
    47 import java.io.PrintWriter; 
     44import java.io.ByteArrayOutputStream; 
     45import java.io.PrintStream; 
     46import java.util.StringTokenizer; 
    4847 
    4948/** 
     
    165164  } 
    166165 
    167   /** Reports an exception in an ImageJ text window. */ 
     166  /** Reports the given exception with stack trace in an ImageJ error dialog. */ 
    168167  public static void reportException(Throwable t) { 
    169     // stolen from IJ.Executor.run() 
     168        reportException(t, false, null); 
     169  } 
     170   
     171  /** Reports the given exception with stack trace in an ImageJ error dialog. */ 
     172  public static void reportException(Throwable t, boolean quiet, String msg) { 
    170173    IJ.showStatus(""); 
    171     IJ.showProgress(1.0); 
    172     CharArrayWriter caw = new CharArrayWriter(); 
    173     PrintWriter pw = new PrintWriter(caw); 
    174     t.printStackTrace(pw); 
    175     String s = caw.toString(); 
    176     if (IJ.isMacintosh()) { 
    177       if (s.indexOf("ThreadDeath") > 0) return; 
    178       s = Tools.fixNewLines(s); 
     174    if (!quiet) { 
     175      if (t != null) { 
     176        ByteArrayOutputStream buf = new ByteArrayOutputStream(); 
     177        t.printStackTrace(new PrintStream(buf)); 
     178        String s = new String(buf.toByteArray()); 
     179        StringTokenizer st = new StringTokenizer(s, "\n\r"); 
     180        while (st.hasMoreTokens()) IJ.write(st.nextToken()); 
     181      } 
     182      if (msg != null) IJ.error("Bio-Formats Importer", msg); 
    179183    } 
    180     if (IJ.getInstance() != null) new TextWindow("Exception", s, 350, 250); 
    181     else IJ.log(s); 
    182184  } 
    183185 
Note: See TracChangeset for help on using the changeset viewer.