From d6e2cc5da12ef1ee0a462fa9d6e5cba85f46defc Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 16 Oct 2023 14:40:14 -0400 Subject: [PATCH] fix/style: detect datasets in zarrs * format DatasetSelectorDialog --- .../janelia/saalfeldlab/n5/ij/N5Importer.java | 25 +- .../n5/ui/DatasetSelectorDialog.java | 1231 +++++++++-------- .../n5/ui/N5MetadataTranslationPanel.java | 5 +- .../n5/ui/N5SpatialKeySpecDialog.java | 12 +- 4 files changed, 666 insertions(+), 607 deletions(-) diff --git a/src/main/java/org/janelia/saalfeldlab/n5/ij/N5Importer.java b/src/main/java/org/janelia/saalfeldlab/n5/ij/N5Importer.java index c5626a4e..9951868a 100644 --- a/src/main/java/org/janelia/saalfeldlab/n5/ij/N5Importer.java +++ b/src/main/java/org/janelia/saalfeldlab/n5/ij/N5Importer.java @@ -336,12 +336,14 @@ public void run(final String args) { Recorder.record = initialRecorderState; final N5Reader n5ForThisDataset = new N5ViewerReaderFun().apply(n5Path); + final String root = n5ForThisDataset.getURI().toString(); + final String dset = new N5BasePathFun().apply(n5Path); N5Metadata meta; final N5DatasetDiscoverer discoverer = new N5DatasetDiscoverer(n5ForThisDataset, N5DatasetDiscoverer.fromParsers(PARSERS), null); - meta = discoverer.parse("").getMetadata(); + meta = discoverer.parse(dset).getMetadata(); if (meta instanceof N5DatasetMetadata) - lastResult = process(n5ForThisDataset, n5Path, exec, Collections.singletonList((N5DatasetMetadata)meta), openAsVirtual, thisDatasetCropInterval, + lastResult = process(n5ForThisDataset, root, exec, Collections.singletonList((N5DatasetMetadata)meta), openAsVirtual, thisDatasetCropInterval, show, impMetaWriterTypes); else System.err.println("not a dataset : " + n5Path); @@ -743,14 +745,7 @@ public N5Reader apply(final String n5PathIn) { if (n5PathIn == null || n5PathIn.isEmpty()) return null; - final String rootPath; - if (n5PathIn.contains(".h5") || n5PathIn.contains(".hdf5")) - rootPath = h5DatasetPath(n5PathIn, true); - else if (lastExtension(n5PathIn).startsWith(".zarr")) - rootPath = upToLastExtension(n5PathIn); - else - rootPath = n5PathIn; - + final String rootPath = upToLastExtension(n5PathIn); final N5Factory factory = new N5Factory().cacheAttributes(true).s3RetryWithCredentials(); try { n5 = factory.openReader(rootPath); @@ -783,9 +778,9 @@ private static String afterLastExtension(final String path) { if (j >= 0) return path.substring(i + j); else - return path; + return ""; } else - return path; + return ""; } private static String lastExtension(final String path) { @@ -804,12 +799,10 @@ public static class N5BasePathFun implements Function { @Override public String apply(final String n5Path) { - if (n5Path.contains(".h5") || n5Path.contains(".hdf5")) + if (n5Path.contains(".h5") || n5Path.contains(".hdf5") || n5Path.contains(".hdf")) return h5DatasetPath(n5Path); - else if (lastExtension(n5Path).startsWith(".zarr")) - return afterLastExtension(n5Path); else - return ""; + return afterLastExtension(n5Path); } } diff --git a/src/main/java/org/janelia/saalfeldlab/n5/ui/DatasetSelectorDialog.java b/src/main/java/org/janelia/saalfeldlab/n5/ui/DatasetSelectorDialog.java index 6fd11972..7f01200d 100644 --- a/src/main/java/org/janelia/saalfeldlab/n5/ui/DatasetSelectorDialog.java +++ b/src/main/java/org/janelia/saalfeldlab/n5/ui/DatasetSelectorDialog.java @@ -90,753 +90,816 @@ public class DatasetSelectorDialog { - /** - * The dataset/group discoverer that takes a list of metadata parsers. - *

- * Currently, there is only one parser for N5 Viewer-style metadata (that comes from the previous version of this plugin). - *

- * To add more parsers, add a new class that implements {@link N5MetadataParser} - * and pass an instance of it to the {@link N5DatasetDiscoverer} constructor here. - */ - private N5DatasetDiscoverer datasetDiscoverer; + /** + * The dataset/group discoverer that takes a list of metadata parsers. + *

+ * Currently, there is only one parser for N5 Viewer-style metadata (that + * comes from the previous version of this plugin). + *

+ * To add more parsers, add a new class that implements + * {@link N5MetadataParser} and pass an instance of it to the + * {@link N5DatasetDiscoverer} constructor here. + */ + private N5DatasetDiscoverer datasetDiscoverer; - private Consumer okCallback; + private Consumer okCallback; - private JFrame dialog; + private JFrame dialog; - private JTextField containerPathText; + private JTextField containerPathText; - private JCheckBox virtualBox; + private JCheckBox virtualBox; - private JCheckBox cropBox; + private JCheckBox cropBox; - private JTree containerTree; + private JTree containerTree; - // private JLabel loadingIcon; + // private JLabel loadingIcon; - private JButton browseBtn; + private JButton browseBtn; - private JButton detectBtn; + private JButton detectBtn; - private JLabel messageLabel; + private JLabel messageLabel; - private JButton okBtn; + private JButton okBtn; - private JButton cancelBtn; + private JButton cancelBtn; - private DefaultTreeModel treeModel; + private DefaultTreeModel treeModel; - private String lastBrowsePath; + private String lastBrowsePath; - private Function n5Fun; + private Function n5Fun; - private final Function pathFun; + private final Function pathFun; - private N5Reader n5; + private N5Reader n5; - private boolean virtualOption = false; + private boolean virtualOption = false; - private boolean cropOption = false; + private boolean cropOption = false; - private Thread loaderThread; + private Thread loaderThread; - private ExecutorService loaderExecutor; + private ExecutorService loaderExecutor; - private Future parserFuture; + private Future parserFuture; - private final String initialContainerPath; + private final String initialContainerPath; - private Consumer containerPathUpdateCallback; + private Consumer containerPathUpdateCallback; - private Consumer cancelCallback; + private Consumer cancelCallback; - private Predicate n5NodeFilter; + private Predicate n5NodeFilter; - private TreeCellRenderer treeRenderer; + private TreeCellRenderer treeRenderer; - private final N5MetadataParser[] groupParsers; + private final N5MetadataParser[] groupParsers; - private final N5MetadataParser[] parsers; + private final N5MetadataParser[] parsers; - private N5SwingTreeNode rootNode; + private N5SwingTreeNode rootNode; - private N5SpatialKeySpecDialog spatialMetaSpec; + private N5SpatialKeySpecDialog spatialMetaSpec; - private N5MetadataTranslationPanel translationPanel; + private N5MetadataTranslationPanel translationPanel; - private TranslationResultPanel translationResultPanel; + private TranslationResultPanel translationResultPanel; - private ExecutorService parseExec; + private ExecutorService parseExec; - private ProgressBar ijProgressBar; + private ProgressBar ijProgressBar; - private final AlphanumericComparator comp = new AlphanumericComparator(Collator.getInstance()); + private final AlphanumericComparator comp = new AlphanumericComparator(Collator.getInstance()); - public DatasetSelectorDialog( - final Function n5Fun, - final Function pathFun, - final String initialContainerPath, - final N5MetadataParser[] groupParsers, - final N5MetadataParser... parsers) { + public DatasetSelectorDialog( + final Function n5Fun, + final Function pathFun, + final String initialContainerPath, + final N5MetadataParser[] groupParsers, + final N5MetadataParser... parsers) { - this.n5Fun = n5Fun; - this.pathFun = pathFun; - this.initialContainerPath = initialContainerPath; + this.n5Fun = n5Fun; + this.pathFun = pathFun; + this.initialContainerPath = initialContainerPath; - this.parsers = parsers; - this.groupParsers = groupParsers; + this.parsers = parsers; + this.groupParsers = groupParsers; - spatialMetaSpec = new N5SpatialKeySpecDialog(); - translationPanel = new N5MetadataTranslationPanel(); - translationResultPanel = new TranslationResultPanel(); + spatialMetaSpec = new N5SpatialKeySpecDialog(); + translationPanel = new N5MetadataTranslationPanel(); + translationResultPanel = new TranslationResultPanel(); - final ImageJ ij = IJ.getInstance(); - if( ij != null ) - ijProgressBar = ij.getProgressBar(); - } + final ImageJ ij = IJ.getInstance(); + if (ij != null) + ijProgressBar = ij.getProgressBar(); + } - public DatasetSelectorDialog( - final Function n5Fun, - final Function pathFun, - final N5MetadataParser[] groupParsers, - final N5MetadataParser... parsers) { + public DatasetSelectorDialog( + final Function n5Fun, + final Function pathFun, + final N5MetadataParser[] groupParsers, + final N5MetadataParser... parsers) { - this(n5Fun, pathFun, "", groupParsers, parsers); - } + this(n5Fun, pathFun, "", groupParsers, parsers); + } - public DatasetSelectorDialog( - final Function n5Fun, - final N5MetadataParser[] groupParsers, - final N5MetadataParser... parsers) { + public DatasetSelectorDialog( + final Function n5Fun, + final N5MetadataParser[] groupParsers, + final N5MetadataParser... parsers) { - this(n5Fun, x -> "", groupParsers, parsers); - } + this(n5Fun, x -> "", groupParsers, parsers); + } - public DatasetSelectorDialog( - final N5Reader n5, - final N5MetadataParser[] groupParsers, - final N5MetadataParser... parsers) { + public DatasetSelectorDialog( + final N5Reader n5, + final N5MetadataParser[] groupParsers, + final N5MetadataParser... parsers) { - this.n5 = n5; - this.pathFun = x -> ""; - this.initialContainerPath = ""; + this.n5 = n5; + this.pathFun = x -> ""; + this.initialContainerPath = ""; - this.parsers = parsers; - this.groupParsers = groupParsers; + this.parsers = parsers; + this.groupParsers = groupParsers; - final ImageJ ij = IJ.getInstance(); - if( ij != null ) - ijProgressBar = ij.getProgressBar(); - } + final ImageJ ij = IJ.getInstance(); + if (ij != null) + ijProgressBar = ij.getProgressBar(); + } public N5MetadataTranslationPanel getTranslationPanel() { + return translationPanel; } public TranslationResultPanel getTranslationResultPanel() { + return translationResultPanel; } - public void setLoaderExecutor(final ExecutorService loaderExecutor) { - - this.loaderExecutor = loaderExecutor; - } + public void setLoaderExecutor(final ExecutorService loaderExecutor) { - public N5DatasetDiscoverer getDatasetDiscoverer() { + this.loaderExecutor = loaderExecutor; + } - return datasetDiscoverer; - } + public void setTreeRenderer(final TreeCellRenderer treeRenderer) { - public void setTreeRenderer(final TreeCellRenderer treeRenderer) { + this.treeRenderer = treeRenderer; + } - this.treeRenderer = treeRenderer; - } + public void setRecursiveFilterCallback(final Predicate n5NodeFilter) { - public void setRecursiveFilterCallback(final Predicate n5NodeFilter) { + this.n5NodeFilter = n5NodeFilter; + } - this.n5NodeFilter = n5NodeFilter; - } + public void setCancelCallback(final Consumer cancelCallback) { - public void setCancelCallback(final Consumer cancelCallback) { + this.cancelCallback = cancelCallback; + } - this.cancelCallback = cancelCallback; - } + public void setContainerPathUpdateCallback(final Consumer containerPathUpdateCallback) { - public void setContainerPathUpdateCallback(final Consumer containerPathUpdateCallback) { + this.containerPathUpdateCallback = containerPathUpdateCallback; + } - this.containerPathUpdateCallback = containerPathUpdateCallback; - } + public void setMessage(final String message) { - public void setMessage(final String message) { + messageLabel.setText(message); + } - messageLabel.setText(message); - } + public void setVirtualOption(final boolean arg) { - public void setVirtualOption(final boolean arg) { + virtualOption = arg; + } - virtualOption = arg; - } + public void setCropOption(final boolean arg) { - public void setCropOption(final boolean arg) { + this.cropOption = arg; + } - this.cropOption = arg; - } + public boolean getCropOption() { - public boolean getCropOption() { + return cropOption; + } - return cropOption; - } + public boolean isCropSelected() { - public boolean isCropSelected() { + return cropOption && cropBox.isSelected(); + } - return cropOption && cropBox.isSelected(); - } + public boolean isVirtual() { - public boolean isVirtual() { + return (virtualBox != null) && virtualBox.isSelected(); + } - return (virtualBox != null) && virtualBox.isSelected(); - } + public String getN5RootPath() { - public String getN5RootPath() { + return containerPathText.getText().trim(); + } - return containerPathText.getText().trim(); - } + public void setLoaderThread(final Thread loaderThread) { - public void setLoaderThread(final Thread loaderThread) { + this.loaderThread = loaderThread; + } - this.loaderThread = loaderThread; - } + public void run(final Consumer okCallback) { - public void run(final Consumer okCallback) { + this.okCallback = okCallback; + dialog = buildDialog(); - this.okCallback = okCallback; - dialog = buildDialog(); + if (n5 == null) { + browseBtn.addActionListener(e -> openContainer(n5Fun, this::openBrowseDialog)); + detectBtn.addActionListener(e -> openContainer(n5Fun, () -> getN5RootPath(), pathFun)); + } - if (n5 == null) { - browseBtn.addActionListener(e -> openContainer(n5Fun, this::openBrowseDialog)); - detectBtn.addActionListener(e -> openContainer(n5Fun, () -> getN5RootPath(), pathFun)); + // ok and cancel buttons + okBtn.addActionListener(e -> ok()); + cancelBtn.addActionListener(e -> cancel()); + dialog.setVisible(true); } - // ok and cancel buttons - okBtn.addActionListener(e -> ok()); - cancelBtn.addActionListener(e -> cancel()); - dialog.setVisible(true); - } - - private static final int DEFAULT_OUTER_PAD = 8; - private static final int DEFAULT_BUTTON_PAD = 3; - private static final int DEFAULT_MID_PAD = 5; + private static final int DEFAULT_OUTER_PAD = 8; + private static final int DEFAULT_BUTTON_PAD = 3; + private static final int DEFAULT_MID_PAD = 5; + + private JFrame buildDialog() { + + final int OUTER_PAD = DEFAULT_OUTER_PAD; + final int BUTTON_PAD = DEFAULT_BUTTON_PAD; + final int MID_PAD = DEFAULT_MID_PAD; + + final int frameSizeX = UIScale.scale(600); + final int frameSizeY = UIScale.scale(400); + + dialog = new JFrame("Open N5"); + dialog.setPreferredSize(new Dimension(frameSizeX, frameSizeY)); + dialog.setMinimumSize(dialog.getPreferredSize()); + + final Container pane = dialog.getContentPane(); + final JTabbedPane tabs = new JTabbedPane(); + pane.add(tabs); + + final JPanel panel = new JPanel(false); + panel.setLayout(new GridBagLayout()); + tabs.addTab("Main", panel); + tabs.addTab("Spatial Metadata", spatialMetaSpec.buildPanel()); + tabs.addTab("Metadata Translation", translationPanel.buildPanel()); + tabs.addTab("Translation Result", translationResultPanel.buildPanel()); + + containerPathText = new JTextField(); + containerPathText.setText(initialContainerPath); + containerPathText.setPreferredSize(new Dimension(frameSizeX / 3, containerPathText.getPreferredSize().height)); + containerPathText.addActionListener(e -> openContainer(n5Fun, () -> getN5RootPath(), pathFun)); + + final GridBagConstraints ctxt = new GridBagConstraints(); + ctxt.gridx = 0; + ctxt.gridy = 0; + ctxt.gridwidth = 3; + ctxt.gridheight = 1; + ctxt.weightx = 1.0; + ctxt.weighty = 0.0; + ctxt.fill = GridBagConstraints.HORIZONTAL; + ctxt.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); + panel.add(containerPathText, ctxt); + + browseBtn = new JButton("Browse"); + final GridBagConstraints cbrowse = new GridBagConstraints(); + cbrowse.gridx = 3; + cbrowse.gridy = 0; + cbrowse.gridwidth = 1; + cbrowse.gridheight = 1; + cbrowse.weightx = 0.0; + cbrowse.weighty = 0.0; + cbrowse.fill = GridBagConstraints.HORIZONTAL; + cbrowse.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); + panel.add(browseBtn, cbrowse); + + detectBtn = new JButton("Detect datasets"); + final GridBagConstraints cdetect = new GridBagConstraints(); + cdetect.gridx = 4; + cdetect.gridy = 0; + cdetect.gridwidth = 2; + cdetect.gridheight = 1; + cdetect.weightx = 0.0; + cdetect.weighty = 0.0; + cdetect.fill = GridBagConstraints.HORIZONTAL; + cdetect.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, OUTER_PAD); + panel.add(detectBtn, cdetect); + + final GridBagConstraints ctree = new GridBagConstraints(); + ctree.gridx = 0; + ctree.gridy = 1; + ctree.gridwidth = 6; + ctree.gridheight = 3; + ctree.weightx = 1.0; + ctree.weighty = 1.0; + ctree.ipadx = 0; + ctree.ipady = 0; + ctree.insets = new Insets(0, OUTER_PAD, 0, OUTER_PAD); + ctree.fill = GridBagConstraints.BOTH; + + treeModel = new DefaultTreeModel(null); + containerTree = new JTree(treeModel); + containerTree.setMinimumSize(new Dimension(550, 230)); + + containerTree.getSelectionModel().setSelectionMode( + TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); + + // disable selection of nodes that are not open-able + containerTree.addTreeSelectionListener( + new N5IjTreeSelectionListener(containerTree.getSelectionModel())); + + // By default leaf nodes (datasets) are displayed as files. This changes + // the default behavior to display them as folders + // final DefaultTreeCellRenderer treeCellRenderer = + // (DefaultTreeCellRenderer) containerTree.getCellRenderer(); + if (treeRenderer != null) + containerTree.setCellRenderer(treeRenderer); + + final JScrollPane treeScroller = new JScrollPane(containerTree); + treeScroller.setViewportView(containerTree); + treeScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + panel.add(treeScroller, ctree); + + // bottom button + final GridBagConstraints cbot = new GridBagConstraints(); + cbot.gridx = 0; + cbot.gridy = 4; + cbot.gridwidth = 1; + cbot.gridheight = 1; + cbot.weightx = 0.0; + cbot.weighty = 0.0; + cbot.insets = new Insets(OUTER_PAD, OUTER_PAD, OUTER_PAD, OUTER_PAD); + cbot.anchor = GridBagConstraints.CENTER; + + if (virtualOption) { + final JPanel virtPanel = new JPanel(); + virtualBox = new JCheckBox(); + final JLabel virtLabel = new JLabel("Open as virtual"); + virtPanel.add(virtualBox); + virtPanel.add(virtLabel); + panel.add(virtPanel, cbot); + } - private JFrame buildDialog() { + if (cropOption) { + final JPanel cropPanel = new JPanel(); + cropBox = new JCheckBox(); + final JLabel cropLabel = new JLabel("Crop"); + cbot.gridx = 1; + cbot.anchor = GridBagConstraints.WEST; + cropPanel.add(cropBox); + cropPanel.add(cropLabel); + panel.add(cropPanel, cbot); + } - final int OUTER_PAD = DEFAULT_OUTER_PAD; - final int BUTTON_PAD = DEFAULT_BUTTON_PAD; - final int MID_PAD = DEFAULT_MID_PAD; + messageLabel = new JLabel(""); + messageLabel.setVisible(false); + cbot.gridx = 2; + cbot.anchor = GridBagConstraints.CENTER; + panel.add(messageLabel, cbot); + + okBtn = new JButton("OK"); + cbot.gridx = 4; + cbot.ipadx = 20; + cbot.anchor = GridBagConstraints.EAST; + cbot.fill = GridBagConstraints.HORIZONTAL; + cbot.insets = new Insets(MID_PAD, OUTER_PAD, OUTER_PAD, BUTTON_PAD); + panel.add(okBtn, cbot); + + cancelBtn = new JButton("Cancel"); + cbot.gridx = 5; + cbot.ipadx = 0; + cbot.anchor = GridBagConstraints.EAST; + cbot.fill = GridBagConstraints.HORIZONTAL; + cbot.insets = new Insets(MID_PAD, BUTTON_PAD, OUTER_PAD, OUTER_PAD); + panel.add(cancelBtn, cbot); + + containerTree.addMouseListener(new NodePopupMenu(this).getPopupListener()); + + dialog.pack(); + return dialog; + } - final int frameSizeX = UIScale.scale( 600 ); - final int frameSizeY = UIScale.scale( 400 ); + public JTree getJTree() { - dialog = new JFrame("Open N5"); - dialog.setPreferredSize(new Dimension(frameSizeX, frameSizeY)); - dialog.setMinimumSize(dialog.getPreferredSize()); + return containerTree; + } - final Container pane = dialog.getContentPane(); - final JTabbedPane tabs = new JTabbedPane(); - pane.add( tabs ); + private String openBrowseDialog() { + + final JFileChooser fileChooser = new JFileChooser(); + /* + * Need to allow files so h5 containers can be opened, and directories + * so that filesystem n5's and zarrs can be opened. + */ + fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); + + if (lastBrowsePath != null && !lastBrowsePath.isEmpty()) + fileChooser.setCurrentDirectory(new File(lastBrowsePath)); + else if (initialContainerPath != null && !initialContainerPath.isEmpty()) + fileChooser.setCurrentDirectory(new File(initialContainerPath)); + else if (IJ.getInstance() != null) { + File f = null; + + final String currDir = IJ.getDirectory("current"); + final String homeDir = IJ.getDirectory("home"); + if (currDir != null) + f = new File(currDir); + else if (homeDir != null) + f = new File(homeDir); + + fileChooser.setCurrentDirectory(f); + } - final JPanel panel = new JPanel(false); - panel.setLayout(new GridBagLayout()); - tabs.addTab("Main", panel); - tabs.addTab("Spatial Metadata", spatialMetaSpec.buildPanel() ); - tabs.addTab("Metadata Translation", translationPanel.buildPanel()); - tabs.addTab("Translation Result", translationResultPanel.buildPanel()); - - containerPathText = new JTextField(); - containerPathText.setText(initialContainerPath); - containerPathText.setPreferredSize(new Dimension(frameSizeX / 3, containerPathText.getPreferredSize().height)); - containerPathText.addActionListener(e -> openContainer(n5Fun, () -> getN5RootPath(), pathFun)); - - final GridBagConstraints ctxt = new GridBagConstraints(); - ctxt.gridx = 0; - ctxt.gridy = 0; - ctxt.gridwidth = 3; - ctxt.gridheight = 1; - ctxt.weightx = 1.0; - ctxt.weighty = 0.0; - ctxt.fill = GridBagConstraints.HORIZONTAL; - ctxt.insets = new Insets(OUTER_PAD, OUTER_PAD, MID_PAD, BUTTON_PAD); - panel.add(containerPathText, ctxt); - - browseBtn = new JButton("Browse"); - final GridBagConstraints cbrowse = new GridBagConstraints(); - cbrowse.gridx = 3; - cbrowse.gridy = 0; - cbrowse.gridwidth = 1; - cbrowse.gridheight = 1; - cbrowse.weightx = 0.0; - cbrowse.weighty = 0.0; - cbrowse.fill = GridBagConstraints.HORIZONTAL; - cbrowse.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, BUTTON_PAD); - panel.add(browseBtn, cbrowse); - - detectBtn = new JButton("Detect datasets"); - final GridBagConstraints cdetect = new GridBagConstraints(); - cdetect.gridx = 4; - cdetect.gridy = 0; - cdetect.gridwidth = 2; - cdetect.gridheight = 1; - cdetect.weightx = 0.0; - cdetect.weighty = 0.0; - cdetect.fill = GridBagConstraints.HORIZONTAL; - cdetect.insets = new Insets(OUTER_PAD, BUTTON_PAD, MID_PAD, OUTER_PAD); - panel.add(detectBtn, cdetect); - - final GridBagConstraints ctree = new GridBagConstraints(); - ctree.gridx = 0; - ctree.gridy = 1; - ctree.gridwidth = 6; - ctree.gridheight = 3; - ctree.weightx = 1.0; - ctree.weighty = 1.0; - ctree.ipadx = 0; - ctree.ipady = 0; - ctree.insets = new Insets(0, OUTER_PAD, 0, OUTER_PAD); - ctree.fill = GridBagConstraints.BOTH; - - treeModel = new DefaultTreeModel(null); - containerTree = new JTree(treeModel); - containerTree.setMinimumSize(new Dimension(550, 230)); - - containerTree.getSelectionModel().setSelectionMode( - TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); - - // disable selection of nodes that are not open-able - containerTree.addTreeSelectionListener( - new N5IjTreeSelectionListener(containerTree.getSelectionModel())); - - // By default leaf nodes (datasets) are displayed as files. This changes the default behavior to display them as folders - // final DefaultTreeCellRenderer treeCellRenderer = (DefaultTreeCellRenderer) containerTree.getCellRenderer(); - if (treeRenderer != null) - containerTree.setCellRenderer(treeRenderer); - - final JScrollPane treeScroller = new JScrollPane(containerTree); - treeScroller.setViewportView(containerTree); - treeScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - panel.add(treeScroller, ctree); - - // bottom button - final GridBagConstraints cbot = new GridBagConstraints(); - cbot.gridx = 0; - cbot.gridy = 4; - cbot.gridwidth = 1; - cbot.gridheight = 1; - cbot.weightx = 0.0; - cbot.weighty = 0.0; - cbot.insets = new Insets(OUTER_PAD, OUTER_PAD, OUTER_PAD, OUTER_PAD); - cbot.anchor = GridBagConstraints.CENTER; - - if (virtualOption) { - final JPanel virtPanel = new JPanel(); - virtualBox = new JCheckBox(); - final JLabel virtLabel = new JLabel("Open as virtual"); - virtPanel.add(virtualBox); - virtPanel.add(virtLabel); - panel.add(virtPanel, cbot); - } - - if (cropOption) { - final JPanel cropPanel = new JPanel(); - cropBox = new JCheckBox(); - final JLabel cropLabel = new JLabel("Crop"); - cbot.gridx = 1; - cbot.anchor = GridBagConstraints.WEST; - cropPanel.add(cropBox); - cropPanel.add(cropLabel); - panel.add(cropPanel, cbot); - } - - messageLabel = new JLabel(""); - messageLabel.setVisible(false); - cbot.gridx = 2; - cbot.anchor = GridBagConstraints.CENTER; - panel.add(messageLabel, cbot); - - okBtn = new JButton("OK"); - cbot.gridx = 4; - cbot.ipadx = 20; - cbot.anchor = GridBagConstraints.EAST; - cbot.fill = GridBagConstraints.HORIZONTAL; - cbot.insets = new Insets(MID_PAD, OUTER_PAD, OUTER_PAD, BUTTON_PAD); - panel.add(okBtn, cbot); - - cancelBtn = new JButton("Cancel"); - cbot.gridx = 5; - cbot.ipadx = 0; - cbot.anchor = GridBagConstraints.EAST; - cbot.fill = GridBagConstraints.HORIZONTAL; - cbot.insets = new Insets(MID_PAD, BUTTON_PAD, OUTER_PAD, OUTER_PAD); - panel.add(cancelBtn, cbot); - - containerTree.addMouseListener( new NodePopupMenu(this).getPopupListener() ); - - dialog.pack(); - return dialog; - } - - public JTree getJTree() { - return containerTree; - } - - private String openBrowseDialog() { - - final JFileChooser fileChooser = new JFileChooser(); - /* - * Need to allow files so h5 containers can be opened, - * and directories so that filesystem n5's and zarrs can be opened. - */ - fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); + final int ret = fileChooser.showOpenDialog(dialog); + if (ret != JFileChooser.APPROVE_OPTION) + return null; - if (lastBrowsePath != null && !lastBrowsePath.isEmpty()) - fileChooser.setCurrentDirectory(new File(lastBrowsePath)); - else if (initialContainerPath != null && !initialContainerPath.isEmpty()) - fileChooser.setCurrentDirectory(new File(initialContainerPath)); - else if (IJ.getInstance() != null) { - File f = null; + final String path = fileChooser.getSelectedFile().getAbsolutePath(); + containerPathText.setText(path); + lastBrowsePath = path; - final String currDir = IJ.getDirectory("current"); - final String homeDir = IJ.getDirectory("home"); - if( currDir != null ) - f = new File( currDir ); - else if( homeDir != null ) - f = new File( homeDir ); + // callback after browse as well + containerPathUpdateCallback.accept(path); - fileChooser.setCurrentDirectory(f); + return path; } - final int ret = fileChooser.showOpenDialog(dialog); - if (ret != JFileChooser.APPROVE_OPTION) - return null; - - final String path = fileChooser.getSelectedFile().getAbsolutePath(); - containerPathText.setText(path); - lastBrowsePath = path; + private N5DatasetDiscoverer makeDiscoverer() { - // callback after browse as well - containerPathUpdateCallback.accept(path); + // copy list + final ArrayList> parserList = new ArrayList<>(); - return path; - } + // add custom metadata parser into the first position in the list if it + // exists + final Optional parserOptional = spatialMetaSpec.getParserOptional(); + if (parserOptional.isPresent()) { + parserList.add(parserOptional.get()); + parserList.addAll(Arrays.asList(parsers)); + } else + parserList.addAll(Arrays.asList(parsers)); - private void openContainer(final Function n5Fun, final Supplier opener) { + final List> groupParserList = Arrays.asList(groupParsers); + datasetDiscoverer = new N5DatasetDiscoverer(n5, loaderExecutor, n5NodeFilter, + parserList, groupParserList); - openContainer(n5Fun, opener, pathFun); - } + return datasetDiscoverer; + } - private void openContainer(final Function n5Fun, final Supplier opener, - final Function pathToRoot) { + private N5Reader makeN5(final String n5Path) { - if( ijProgressBar != null ) - ijProgressBar.show( 0.1 ); + n5 = n5Fun.apply(n5Path); + if (n5 == null) { + messageLabel.setVisible(false); + dialog.repaint(); + return null; + } - SwingUtilities.invokeLater(() -> { - messageLabel.setText("Building reader..."); - messageLabel.setVisible(true); - messageLabel.repaint(); - }); + // copy list + final ArrayList> parserList = new ArrayList<>(); + + final Gson gson; + if (n5 instanceof CachedGsonKeyValueN5Reader) + gson = ((CachedGsonKeyValueN5Reader)n5).getGson(); + else { + final GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(DataType.class, new DataType.JsonAdapter()); + gsonBuilder.registerTypeHierarchyAdapter(Compression.class, CompressionAdapter.getJsonAdapter()); + gsonBuilder.disableHtmlEscaping(); + gson = gsonBuilder.create(); + } - final String n5Path = opener.get(); - containerPathUpdateCallback.accept(n5Path); + boolean isTranslated = false; + final Optional translatedN5 = translationPanel.getTranslatedN5Optional(n5, gson); + if (translatedN5.isPresent()) { + n5 = translatedN5.get(); + isTranslated = true; + } - if (n5Path == null) { - messageLabel.setVisible(false); - dialog.repaint(); - return; + return n5; } - n5 = n5Fun.apply(n5Path); - final String rootPath = pathToRoot.apply(n5Path); + private void openContainer(final Function n5Fun, final Supplier opener) { - if (n5 == null) { - messageLabel.setVisible(false); - dialog.repaint(); - return; + openContainer(n5Fun, opener, pathFun); } - if (loaderExecutor == null) { - loaderExecutor = Executors.newCachedThreadPool(); - } + private void openContainer(final Function n5Fun, final Supplier opener, + final Function pathToRoot) { - // copy list - final ArrayList> parserList = new ArrayList<>(); + if (ijProgressBar != null) + ijProgressBar.show(0.1); - // add custom metadata parser into the first position in the list if it exists - final Optional parserOptional = spatialMetaSpec.getParserOptional(); - if( parserOptional.isPresent() ) { - parserList.add(parserOptional.get()); - parserList.addAll(Arrays.asList(parsers)); - } - else - parserList.addAll(Arrays.asList(parsers)); + SwingUtilities.invokeLater(() -> { + messageLabel.setText("Building reader..."); + messageLabel.setVisible(true); + messageLabel.repaint(); + }); - final Gson gson; - if( n5 instanceof CachedGsonKeyValueN5Reader ) - gson = ((CachedGsonKeyValueN5Reader) n5).getGson(); - else - { - final GsonBuilder gsonBuilder = new GsonBuilder(); - gsonBuilder.registerTypeAdapter(DataType.class, new DataType.JsonAdapter()); - gsonBuilder.registerTypeHierarchyAdapter(Compression.class, CompressionAdapter.getJsonAdapter()); - gsonBuilder.disableHtmlEscaping(); - gson = gsonBuilder.create(); - } + final String n5Path = opener.get(); + containerPathUpdateCallback.accept(n5Path); - boolean isTranslated = false; - final Optional translatedN5 = translationPanel.getTranslatedN5Optional(n5, gson); - if( translatedN5.isPresent() ) - { - n5 = translatedN5.get(); - isTranslated = true; - } + if (n5Path == null) { + messageLabel.setVisible(false); + dialog.repaint(); + return; + } - final List> groupParserList = Arrays.asList(groupParsers); - datasetDiscoverer = new N5DatasetDiscoverer(n5, loaderExecutor, n5NodeFilter, - parserList, groupParserList ); + if (loaderExecutor == null) { + loaderExecutor = Executors.newCachedThreadPool(); + } - final String[] pathParts = n5Path.split( n5.getGroupSeparator() ); + n5 = n5Fun.apply(n5Path); + final String rootPath = pathToRoot.apply(n5Path); + System.out.println("rootPath: " + rootPath); - final String rootName = pathParts[ pathParts.length - 1 ]; - if( treeRenderer != null && treeRenderer instanceof N5DatasetTreeCellRenderer ) - ((N5DatasetTreeCellRenderer)treeRenderer ).setRootName(rootName); + if (n5 == null) { + messageLabel.setVisible(false); + dialog.repaint(); + return; + } - final N5TreeNode tmpRootNode = new N5TreeNode( rootPath ); - rootNode = new N5SwingTreeNode( rootPath, treeModel ); - treeModel.setRoot(rootNode); - containerTree.setEnabled(true); - containerTree.repaint(); + // copy list + final ArrayList> parserList = new ArrayList<>(); - if( ijProgressBar != null ) - ijProgressBar.show( 0.3 ); + final Gson gson; + if (n5 instanceof CachedGsonKeyValueN5Reader) + gson = ((CachedGsonKeyValueN5Reader)n5).getGson(); + else { + final GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(DataType.class, new DataType.JsonAdapter()); + gsonBuilder.registerTypeHierarchyAdapter(Compression.class, CompressionAdapter.getJsonAdapter()); + gsonBuilder.disableHtmlEscaping(); + gson = gsonBuilder.create(); + } - final Consumer callback = (x) -> { - SwingUtilities.invokeLater(() -> { - if( x.getMetadata() != null ) - { - // get the node at the requested path, or add it if not present - final N5SwingTreeNode node = (N5SwingTreeNode) rootNode.getDescendants( y -> pathsEqual( y.getPath(), x.getPath() )).findFirst() - .orElse( rootNode.addPath( x.getPath() )); - - // update the node's metadata - if( node != null ) - { - // set metadata, update ui - node.setMetadata( x.getMetadata() ); - - // sort children, update ui - final N5SwingTreeNode parent = (N5SwingTreeNode) node.getParent(); - sortRecursive( parent ); - - treeModel.nodeChanged(node); - } - } - else - { - final Optional< N5TreeNode > desc = rootNode.getDescendant( x.getNodeName() ); - if( desc.isPresent() ) - { - final N5SwingTreeNode node = (N5SwingTreeNode)desc.get(); - if( node.getParent() != null && node.getChildCount() == 0 ) - { - treeModel.removeNodeFromParent( node ); + boolean isTranslated = false; + final Optional translatedN5 = translationPanel.getTranslatedN5Optional(n5, gson); + if (translatedN5.isPresent()) { + n5 = translatedN5.get(); + isTranslated = true; + } + +// // add custom metadata parser into the first position in the list if it +// // exists +// final Optional parserOptional = spatialMetaSpec.getParserOptional(); +// if (parserOptional.isPresent()) { +// parserList.add(parserOptional.get()); +// parserList.addAll(Arrays.asList(parsers)); +// } else +// parserList.addAll(Arrays.asList(parsers)); +// +// +// final List> groupParserList = Arrays.asList(groupParsers); +// datasetDiscoverer = new N5DatasetDiscoverer(n5, loaderExecutor, n5NodeFilter, +// parserList, groupParserList); + + datasetDiscoverer = makeDiscoverer(); + + final String[] pathParts = n5Path.split(n5.getGroupSeparator()); + + final String rootName = pathParts[pathParts.length - 1]; + if (treeRenderer != null && treeRenderer instanceof N5DatasetTreeCellRenderer) + ((N5DatasetTreeCellRenderer)treeRenderer).setRootName(rootName); + + final N5TreeNode tmpRootNode = new N5TreeNode(rootPath); + rootNode = new N5SwingTreeNode(rootPath, treeModel); + treeModel.setRoot(rootNode); + + containerTree.setEnabled(true); + containerTree.repaint(); + + if (ijProgressBar != null) + ijProgressBar.show(0.3); + + final Consumer callback = (x) -> { + SwingUtilities.invokeLater(() -> { + if (x.getMetadata() != null) { + // get the node at the requested path, or add it if not + // present + final N5SwingTreeNode node = (N5SwingTreeNode)rootNode.getDescendants(y -> pathsEqual(y.getPath(), x.getPath())).findFirst() + .orElse(rootNode.addPath(x.getPath())); + + // update the node's metadata + if (node != null) { + // set metadata, update ui + node.setMetadata(x.getMetadata()); + + // sort children, update ui + final N5SwingTreeNode parent = (N5SwingTreeNode)node.getParent(); + sortRecursive(parent); + + treeModel.nodeChanged(node); + } + } else { + final Optional desc = rootNode.getDescendant(x.getNodeName()); + if (desc.isPresent()) { + final N5SwingTreeNode node = (N5SwingTreeNode)desc.get(); + if (node.getParent() != null && node.getChildCount() == 0) { + treeModel.removeNodeFromParent(node); + } } } - } - }); - }; + }); + }; - parseExec = Executors.newSingleThreadExecutor(); - parseExec.submit(() -> { - try { - String[] datasetPaths; + parseExec = Executors.newSingleThreadExecutor(); + parseExec.submit(() -> { try { + String[] datasetPaths; + try { + + if (ijProgressBar != null) + ijProgressBar.show(0.3); + + SwingUtilities.invokeLater(() -> { + messageLabel.setText("Listing..."); + messageLabel.repaint(); + }); + + // build a temporary tree + datasetPaths = n5.deepList(rootPath, loaderExecutor); + N5SwingTreeNode.fromFlatList(tmpRootNode, datasetPaths, "/"); + for (final String p : datasetPaths) + rootNode.addPath(p); + + sortRecursive(rootNode); + containerTree.expandRow(0); + + if (ijProgressBar != null) + ijProgressBar.show(0.5); + + SwingUtilities.invokeLater(() -> { + messageLabel.setText("Parsing..."); + messageLabel.repaint(); + }); + + // callback copies values from temporary tree into the ui + // when metadata is parsed + datasetDiscoverer.parseMetadataRecursive(tmpRootNode, callback); + + if (ijProgressBar != null) + ijProgressBar.show(0.8); + + SwingUtilities.invokeLater(() -> { + messageLabel.setText("Done"); + messageLabel.repaint(); + }); + + if (ijProgressBar != null) + ijProgressBar.show(1.0); + + Thread.sleep(1000); + SwingUtilities.invokeLater(() -> { + messageLabel.setText(""); + messageLabel.setVisible(false); + messageLabel.repaint(); + }); + } catch (final InterruptedException e) { + e.printStackTrace(); + } catch (final ExecutionException e) { + e.printStackTrace(); + } + } catch (final N5Exception e) { + e.printStackTrace(); + } - if( ijProgressBar != null ) - ijProgressBar.show( 0.3 ); - - SwingUtilities.invokeLater(() -> { - messageLabel.setText("Listing..."); - messageLabel.repaint(); - }); - - // build a temporary tree - datasetPaths = n5.deepList(rootPath, loaderExecutor); - N5SwingTreeNode.fromFlatList(tmpRootNode, datasetPaths, "/" ); - for( final String p : datasetPaths ) - rootNode.addPath( p ); + }); - sortRecursive( rootNode ); - containerTree.expandRow( 0 ); + if (isTranslated) { + final TranslatedN5Reader xlatedN5 = (TranslatedN5Reader)n5; + translationResultPanel.set( + xlatedN5.getGson(), + xlatedN5.getTranslation().getOrig(), + xlatedN5.getTranslation().getTranslated()); + } + } - if( ijProgressBar != null ) - ijProgressBar.show( 0.5 ); + public void ok() { - SwingUtilities.invokeLater(() -> { - messageLabel.setText("Parsing..."); - messageLabel.repaint(); - }); + // stop parsing things + if (parseExec != null) + parseExec.shutdownNow(); - // callback copies values from temporary tree into the ui - // when metadata is parsed - datasetDiscoverer.parseMetadataRecursive( tmpRootNode, callback ); + final ArrayList selectedMetadata = new ArrayList<>(); - if( ijProgressBar != null ) - ijProgressBar.show( 0.8 ); + // check if we can skip explicit dataset detection + if (containerTree.getSelectionCount() == 0) { + final String n5Path = getN5RootPath(); + containerPathUpdateCallback.accept(getN5RootPath()); - SwingUtilities.invokeLater(() -> { - messageLabel.setText("Done"); - messageLabel.repaint(); - }); + if( n5== null ) + n5 = makeN5(n5Path); - if( ijProgressBar != null ) - ijProgressBar.show( 1.0 ); + if( datasetDiscoverer == null ) + datasetDiscoverer = makeDiscoverer(); - Thread.sleep(1000); - SwingUtilities.invokeLater(() -> { - messageLabel.setText(""); - messageLabel.setVisible(false); - messageLabel.repaint(); - }); + final String dataset = pathFun.apply(n5Path); + N5TreeNode node = null; + try { + node = datasetDiscoverer.parse(dataset); + if (node.isDataset() && node.getMetadata() != null) + selectedMetadata.add(node.getMetadata()); + } catch (final Exception e) {} + + if (node == null || !node.isDataset() || node.getMetadata() == null) { + JOptionPane.showMessageDialog(null, "Could not find a dataset / metadata at the provided path."); + return; } - catch (final InterruptedException e) { } - catch (final ExecutionException e) { } - } catch (final N5Exception e) { } - - }); - - if( isTranslated ) { - final TranslatedN5Reader xlatedN5 = (TranslatedN5Reader)n5; - translationResultPanel.set( - xlatedN5.getGson(), - xlatedN5.getTranslation().getOrig(), - xlatedN5.getTranslation().getTranslated()); + } else { + // datasets were selected by the user + for (final TreePath path : containerTree.getSelectionPaths()) + selectedMetadata.add(((N5SwingTreeNode)path.getLastPathComponent()).getMetadata()); + } + okCallback.accept(new DataSelection(n5, selectedMetadata)); + dialog.setVisible(false); + dialog.dispose(); } - } - public void ok() { + public void cancel() { - // stop parsing things - if( parseExec != null ) - parseExec.shutdownNow(); + // stop parsing things + if (parseExec != null) + parseExec.shutdownNow(); - final ArrayList selectedMetadata = new ArrayList<>(); + dialog.setVisible(false); + dialog.dispose(); - // check if we can skip explicit dataset detection - if (containerTree.getSelectionCount() == 0) { - final String n5Path = getN5RootPath(); - containerPathUpdateCallback.accept(getN5RootPath()); + if (loaderThread != null) + loaderThread.interrupt(); - n5 = n5Fun.apply(n5Path); - final String dataset = pathFun.apply(n5Path); - N5TreeNode node = null; - try { - node = datasetDiscoverer.parse(dataset); - if (node.isDataset() && node.getMetadata() != null) - selectedMetadata.add(node.getMetadata()); - } catch (final Exception e) { - } + if (parserFuture != null) { + parserFuture.cancel(true); + } - if (node == null || !node.isDataset() || node.getMetadata() == null) { - JOptionPane.showMessageDialog(null, "Could not find a dataset / metadata at the provided path."); - return; - } - } else { - // datasets were selected by the user - for (final TreePath path : containerTree.getSelectionPaths()) - selectedMetadata.add(((N5SwingTreeNode)path.getLastPathComponent()).getMetadata()); + if (cancelCallback != null) + cancelCallback.accept(null); } - okCallback.accept(new DataSelection(n5, selectedMetadata)); - dialog.setVisible(false); - dialog.dispose(); - } - - public void cancel() { - // stop parsing things - if( parseExec != null ) - parseExec.shutdownNow(); + public void detectDatasets() { - dialog.setVisible(false); - dialog.dispose(); - - if (loaderThread != null) - loaderThread.interrupt(); - - if (parserFuture != null) { - parserFuture.cancel(true); + openContainer(n5Fun, () -> getN5RootPath(), pathFun); } - if (cancelCallback != null) - cancelCallback.accept(null); - } + /** + * Removes selected nodes that do not have metadata, and are therefore not + * openable. + */ + public static class N5IjTreeSelectionListener implements TreeSelectionListener { - public void detectDatasets() { - openContainer(n5Fun, () -> getN5RootPath(), pathFun); - } + private final TreeSelectionModel selectionModel; - /** - * Removes selected nodes that do not have metadata, and are therefore not openable. - */ - public static class N5IjTreeSelectionListener implements TreeSelectionListener { + public N5IjTreeSelectionListener(final TreeSelectionModel selectionModel) { - private final TreeSelectionModel selectionModel; + this.selectionModel = selectionModel; + } - public N5IjTreeSelectionListener(final TreeSelectionModel selectionModel) { + @Override + public void valueChanged(final TreeSelectionEvent sel) { - this.selectionModel = selectionModel; - } + int i = 0; + for (final TreePath path : sel.getPaths()) { + if (!sel.isAddedPath(i)) + continue; - @Override - public void valueChanged(final TreeSelectionEvent sel) { + final Object last = path.getLastPathComponent(); + if (last instanceof N5SwingTreeNode) { + final N5SwingTreeNode node = ((N5SwingTreeNode)last); + if (node.getMetadata() == null) { + selectionModel.removeSelectionPath(path); + } + } + i++; + } + } + } - int i = 0; - for (final TreePath path : sel.getPaths()) { - if (!sel.isAddedPath(i)) - continue; + private void sortRecursive(final N5SwingTreeNode node) { - final Object last = path.getLastPathComponent(); - if (last instanceof N5SwingTreeNode) { - final N5SwingTreeNode node = ((N5SwingTreeNode)last); - if (node.getMetadata() == null) { - selectionModel.removeSelectionPath(path); - } - } - i++; - } - } - } - - private void sortRecursive( final N5SwingTreeNode node ) - { - if( node != null ) { - final List children = node.childrenList(); - if( !children.isEmpty()) - { - children.sort(Comparator.comparing(N5TreeNode::toString, comp)); + if (node != null) { + final List children = node.childrenList(); + if (!children.isEmpty()) { + children.sort(Comparator.comparing(N5TreeNode::toString, comp)); + } + treeModel.nodeStructureChanged(node); + for (final N5TreeNode child : children) + sortRecursive((N5SwingTreeNode)child); } - treeModel.nodeStructureChanged(node); - for( final N5TreeNode child : children ) - sortRecursive( (N5SwingTreeNode)child ); } - } - private static String normalDatasetName(final String fullPath, final String groupSeparator) { + private static String normalDatasetName(final String fullPath, final String groupSeparator) { - return fullPath.replaceAll("(^" + groupSeparator + "*)|(" + groupSeparator + "*$)", ""); - } + return fullPath.replaceAll("(^" + groupSeparator + "*)|(" + groupSeparator + "*$)", ""); + } - private static boolean pathsEqual( final String a, final String b ) - { - return normalDatasetName( a, "/" ).equals( normalDatasetName( b, "/" ) ); - } + private static boolean pathsEqual(final String a, final String b) { + + return normalDatasetName(a, "/").equals(normalDatasetName(b, "/")); + } } diff --git a/src/main/java/org/janelia/saalfeldlab/n5/ui/N5MetadataTranslationPanel.java b/src/main/java/org/janelia/saalfeldlab/n5/ui/N5MetadataTranslationPanel.java index 4f33ca3a..6a2ba566 100644 --- a/src/main/java/org/janelia/saalfeldlab/n5/ui/N5MetadataTranslationPanel.java +++ b/src/main/java/org/janelia/saalfeldlab/n5/ui/N5MetadataTranslationPanel.java @@ -86,8 +86,11 @@ public Optional getTranslatedN5Optional( final N5Reader n5, public boolean isTranslationProvided() { + if( textArea == null ) + return false; + final String txt = textArea.getText(); - boolean textSet = !( txt.isEmpty() || txt.equals(DEFAULT_TEXT)); + final boolean textSet = !( txt.isEmpty() || txt.equals(DEFAULT_TEXT)); return textSet; // if( textSet ) { // return TranslatedTreeMetadataParser.testTranslation( txt ); diff --git a/src/main/java/org/janelia/saalfeldlab/n5/ui/N5SpatialKeySpecDialog.java b/src/main/java/org/janelia/saalfeldlab/n5/ui/N5SpatialKeySpecDialog.java index 27005b3d..8b328f7c 100644 --- a/src/main/java/org/janelia/saalfeldlab/n5/ui/N5SpatialKeySpecDialog.java +++ b/src/main/java/org/janelia/saalfeldlab/n5/ui/N5SpatialKeySpecDialog.java @@ -55,7 +55,7 @@ public N5GenericSingleScaleMetadataParser getParser() { /** * Returns an optional containing the parser if any fields are non empty. - * + * * @return the parser optional */ public Optional getParserOptional() { @@ -68,11 +68,11 @@ public Optional getParserOptional() { public boolean anyNonEmptyFields() { - return !resolutionField.getText().isEmpty() || - !offsetField.getText().isEmpty() || - !downsamplingFactorsField.getText().isEmpty() || - !minIntensityField.getText().isEmpty() || - !maxIntensityField.getText().isEmpty(); + return (resolutionField != null && !resolutionField.getText().isEmpty() ) || + (offsetField != null && !offsetField.getText().isEmpty()) || + (downsamplingFactorsField != null && !downsamplingFactorsField.getText().isEmpty()) || + (minIntensityField != null && !minIntensityField.getText().isEmpty()) || + (maxIntensityField != null && !maxIntensityField.getText().isEmpty()); } public JPanel buildPanel()