fmtUri = N5Factory.StorageFormat.parseUri(n5UriOrPath);
+ final StorageFormat format = fmtUri.getA();
+
+ final N5URI n5uri = from(fmtUri.getB().toString());
+ // add the format prefix back if it was present
+ rootPath = format == null ? n5uri.getContainerPath() : format.toString().toLowerCase() + ":" + n5uri.getContainerPath();
} catch (URISyntaxException e) {}
}
@@ -877,6 +887,42 @@ public N5Reader apply(final String n5UriOrPath) {
}
}
+ /**
+ * Generate an {@link N5URI} from a String.
+ *
+ * @param uriOrPath
+ * a string representation of a uri or a path string.
+ * @return the {@link N5URI}
+ */
+ private static N5URI from(final String uriOrPath) {
+
+ try {
+ return new N5URI(new URI(uriOrPath));
+ } catch (Throwable ignore) {}
+
+ try {
+ final String[] split = uriOrPath.split("\\?");
+ final URI tmp = Paths.get(split[0]).toUri();
+ if (split.length == 1)
+ return new N5URI(tmp);
+ else {
+ StringBuffer buildUri = new StringBuffer();
+ buildUri.append(tmp.toString());
+ buildUri.append("?");
+ for (int i = 1; i < split.length; i++)
+ buildUri.append(split[i]);
+
+ return new N5URI(new URI(buildUri.toString()));
+ }
+ } catch (Throwable ignore) {}
+
+ try {
+ return new N5URI(N5URI.encodeAsUri(uriOrPath));
+ } catch (URISyntaxException e) {
+ throw new N5Exception(e);
+ }
+ }
+
private static String upToLastExtension(final String path) {
final int i = path.lastIndexOf('.');
diff --git a/src/main/java/org/janelia/saalfeldlab/n5/ij/N5ScalePyramidExporter.java b/src/main/java/org/janelia/saalfeldlab/n5/ij/N5ScalePyramidExporter.java
index 651c9e0..6e7694b 100644
--- a/src/main/java/org/janelia/saalfeldlab/n5/ij/N5ScalePyramidExporter.java
+++ b/src/main/java/org/janelia/saalfeldlab/n5/ij/N5ScalePyramidExporter.java
@@ -1487,9 +1487,6 @@ private static class DetailedOverwriteWarningDialog extends JDialog {
public DetailedOverwriteWarningDialog(final Frame parent, final String root, final String dataset) {
super(parent,"WARNING", true);
initComponents(root, dataset);
- final Dimension dims = new Dimension(600, 250);
- setSize(dims);
- setPreferredSize(dims);
setResizable(false);
setLocationRelativeTo(null);
}
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 041043e..1cef8af 100644
--- a/src/main/java/org/janelia/saalfeldlab/n5/ui/DatasetSelectorDialog.java
+++ b/src/main/java/org/janelia/saalfeldlab/n5/ui/DatasetSelectorDialog.java
@@ -50,13 +50,13 @@
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
+import javax.swing.JFormattedTextField.AbstractFormatter;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
-import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
@@ -72,7 +72,11 @@
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.io.File;
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.text.Collator;
+import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -105,7 +109,7 @@ public class DatasetSelectorDialog {
private JFrame dialog;
- private JTextField containerPathText;
+ private ImprovedFormattedTextField containerPathText;
private JCheckBox virtualBox;
@@ -366,8 +370,7 @@ private JFrame buildDialog() {
tabs.addTab("Metadata Translation", translationPanel.buildPanel());
tabs.addTab("Translation Result", translationResultPanel.buildPanel());
- containerPathText = new JTextField();
- containerPathText.setText(initialContainerPath);
+ containerPathText = new ImprovedFormattedTextField(new UriValidator(), initialContainerPath);
containerPathText.setPreferredSize(new Dimension(frameSizeX / 3, containerPathText.getPreferredSize().height));
containerPathText.addActionListener(e -> openContainer(n5Fun, () -> getN5RootPath(), pathFun));
@@ -934,4 +937,38 @@ private static boolean pathsEqual(final String a, final String b) {
return normalDatasetName(a, "/").equals(normalDatasetName(b, "/"));
}
+ protected static class UriValidator extends AbstractFormatter {
+
+ private static final long serialVersionUID = 6765664180035018335L;
+
+ @Override
+ public Object stringToValue(String input) throws ParseException {
+
+ if (input == null || input.isEmpty())
+ return null;
+
+ try {
+ final URI uri = new URI(input);
+ if (uri.isAbsolute())
+ return uri;
+ } catch (Throwable ignore) {}
+
+ try {
+ return Paths.get(input).toUri();
+ } catch (Throwable ignore) {}
+
+ throw new ParseException("input " + input + " not a valid URI", 0);
+ }
+
+ @Override
+ public String valueToString(Object arg) throws ParseException {
+
+ if( arg instanceof URI )
+ return ((URI)arg).toString().replaceFirst("^file://", "");
+ else
+ throw new ParseException("input " + arg + " not a valid URI", 0);
+ }
+
+ }
+
}
diff --git a/src/main/java/org/janelia/saalfeldlab/n5/ui/ImprovedFormattedTextField.java b/src/main/java/org/janelia/saalfeldlab/n5/ui/ImprovedFormattedTextField.java
new file mode 100644
index 0000000..f5999af
--- /dev/null
+++ b/src/main/java/org/janelia/saalfeldlab/n5/ui/ImprovedFormattedTextField.java
@@ -0,0 +1,263 @@
+package org.janelia.saalfeldlab.n5.ui;
+
+import javax.swing.JFormattedTextField;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import java.awt.Color;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyEvent;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+
+/**
+ *
+ * Extension of {@code JFormattedTextField} which solves some of the usability
+ * issues
+ *
+ *
+ *
+ * from
+ * https://stackoverflow.com/questions/1313390/is-there-any-way-to-accept-only-numeric-values-in-a-jtextfield?answertab=scoredesc#tab-top
+ *
+ */
+public class ImprovedFormattedTextField extends JFormattedTextField {
+
+ private static final long serialVersionUID = 6986337989217402465L;
+
+ private static final Color ERROR_BACKGROUND_COLOR = new Color(255, 215, 215);
+
+ private static final Color ERROR_FOREGROUND_COLOR = null;
+
+ private Color fBackground, fForeground;
+
+ private Runnable updateCallback;
+
+ private boolean runCallback;
+
+ public ImprovedFormattedTextField(AbstractFormatter formatter) {
+
+ super(formatter);
+ setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT);
+ updateBackgroundOnEachUpdate();
+
+ // improve the caret behavior
+ // see also
+ // http://tips4java.wordpress.com/2010/02/21/formatted-text-field-tips/
+ addFocusListener(new MousePositionCorrectorListener());
+ addFocusListener(new ContainerTextUpdateOnFocus(this));
+ runCallback = true;
+ }
+
+ /**
+ * Create a new {@code ImprovedFormattedTextField} instance which will use
+ * {@code aFormat} for the validation of the user input. The field will be
+ * initialized with {@code aValue}.
+ *
+ * @param formatter
+ * The formatter. May not be {@code null}
+ * @param aValue
+ * The initial value
+ */
+ public ImprovedFormattedTextField(AbstractFormatter formatter, Object aValue) {
+
+ this(formatter);
+ try {
+ setValue(new URI(""));
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setCallback(final Runnable updateCallback) {
+
+ this.updateCallback = updateCallback;
+ }
+
+ private void updateBackgroundOnEachUpdate() {
+
+ getDocument().addDocumentListener(new DocumentListener() {
+
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+
+ update();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+
+ update();
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+
+ update();
+ }
+
+ public void update() {
+
+ updateBackground();
+ if (runCallback && updateCallback != null)
+ updateCallback.run();
+ }
+ });
+ }
+
+ /**
+ * Update the background color depending on the valid state of the current
+ * input. This provides visual feedback to the user
+ */
+ private void updateBackground() {
+
+ final boolean valid = validContent();
+ if (ERROR_BACKGROUND_COLOR != null) {
+ setBackground(valid ? fBackground : ERROR_BACKGROUND_COLOR);
+ }
+ if (ERROR_FOREGROUND_COLOR != null) {
+ setForeground(valid ? fForeground : ERROR_FOREGROUND_COLOR);
+ }
+ }
+
+ @Override
+ public void updateUI() {
+
+ super.updateUI();
+ fBackground = getBackground();
+ fForeground = getForeground();
+ }
+
+ private boolean validContent() {
+
+ final AbstractFormatter formatter = getFormatter();
+ if (formatter != null) {
+ try {
+ formatter.stringToValue(getText());
+ return true;
+ } catch (final ParseException e) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public void setValue(Object value, boolean callback, boolean validate) {
+
+ boolean validValue = true;
+ // before setting the value, parse it by using the format
+ try {
+ final AbstractFormatter formatter = getFormatter();
+ if (formatter != null && validate ) {
+ formatter.stringToValue(getText());
+ }
+ } catch (final ParseException e) {
+ validValue = false;
+ updateBackground();
+ }
+ // only set the value when valid
+ if (validValue) {
+ final int old_caret_position = getCaretPosition();
+
+ final boolean before = runCallback;
+ runCallback = callback;
+ super.setValue(value);
+ runCallback = before;
+
+ setCaretPosition(Math.min(old_caret_position, getText().length()));
+ }
+ }
+
+ public void setValue(Object value, boolean callback) {
+
+ setValue(value, callback, true);
+ }
+
+ public void setValueNoCallback(Object value) {
+
+ setValue(value, false);
+ }
+
+ @Override
+ public void setValue(Object value) {
+
+ setValue(value, true);
+ }
+
+ @Override
+ protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
+
+ // do not let the formatted text field consume the enters. This allows
+ // to trigger an OK button by
+ // pressing enter from within the formatted text field
+ if (validContent()) {
+ return super.processKeyBinding(ks, e, condition, pressed) && ks != KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
+ } else {
+ return super.processKeyBinding(ks, e, condition, pressed);
+ }
+ }
+
+ private static class MousePositionCorrectorListener extends FocusAdapter {
+
+ @Override
+ public void focusGained(FocusEvent e) {
+
+ /*
+ * After a formatted text field gains focus, it replaces its text
+ * with its current value, formatted appropriately of course. It
+ * does this after any focus listeners are notified. We want to make
+ * sure that the caret is placed in the correct position rather than
+ * the dumb default that is before the 1st character !
+ */
+ final JTextField field = (JTextField)e.getSource();
+ final int dot = field.getCaret().getDot();
+ final int mark = field.getCaret().getMark();
+ if (field.isEnabled() && field.isEditable()) {
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ // Only set the caret if the textfield hasn't got a
+ // selection on it
+ if (dot == mark) {
+ field.getCaret().setDot(dot);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ private static class ContainerTextUpdateOnFocus extends FocusAdapter {
+
+ private final ImprovedFormattedTextField field;
+
+ public ContainerTextUpdateOnFocus(ImprovedFormattedTextField field) {
+
+ this.field = field;
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+
+ final AbstractFormatter formatter = field.getFormatter();
+ if (formatter != null) {
+ try {
+ Object result = formatter.stringToValue((String)field.getText());
+ field.setValue((URI)result, false, false); // no callback, no validation
+ } catch (ParseException ignore) {
+ ignore.printStackTrace();
+ }
+ }
+
+ }
+ }
+
+}
diff --git a/src/test/java/org/janelia/saalfeldlab/n5/ij/MacroTests.java b/src/test/java/org/janelia/saalfeldlab/n5/ij/MacroTests.java
index 0af5293..ac08ab1 100644
--- a/src/test/java/org/janelia/saalfeldlab/n5/ij/MacroTests.java
+++ b/src/test/java/org/janelia/saalfeldlab/n5/ij/MacroTests.java
@@ -5,13 +5,13 @@
import java.io.File;
import java.io.IOException;
-import java.net.URL;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.util.List;
-import org.janelia.saalfeldlab.n5.N5Exception;
-import org.janelia.saalfeldlab.n5.N5Reader;
import org.janelia.saalfeldlab.n5.N5Writer;
-import org.janelia.saalfeldlab.n5.RunImportExportTest;
import org.janelia.saalfeldlab.n5.TestExportImports;
import org.janelia.saalfeldlab.n5.universe.N5Factory;
import org.junit.After;
@@ -30,9 +30,11 @@
public class MacroTests {
- private File n5rootF;
+ private URI containerDir;
- private File containerDir;
+ private URI n5rootF;
+
+ private String dataset;
private ImagePlus imp;
@@ -40,19 +42,18 @@ public class MacroTests {
public void before() {
System.setProperty("java.awt.headless", "true");
- final String n5Root = "src/test/resources/test.n5";
- n5rootF = new File(n5Root);
+ try {
+ containerDir = new File(tempN5PathName()).getCanonicalFile().toURI();
+ } catch (IOException e) {}
- final URL configUrl = RunImportExportTest.class.getResource( "/plugins.config" );
- final File baseDir = new File( configUrl.getFile() ).getParentFile();
- containerDir = new File( baseDir, "macrotest.n5" );
- System.out.println( containerDir.getAbsolutePath() );
+ n5rootF = Paths.get("src", "test", "resources", "test.n5").toUri();
+ dataset = "dataset";
imp = NewImage.createImage("test", 8, 7, 9, 16, NewImage.FILL_NOISE);
- final String format = N5ScalePyramidExporter.AUTO_FORMAT;
+ final String format = N5ScalePyramidExporter.N5_FORMAT;
final N5ScalePyramidExporter writer = new N5ScalePyramidExporter();
- writer.setOptions( imp, containerDir.getAbsolutePath(), "dataset", format, "16,16,16", false,
+ writer.setOptions( imp, containerDir.toString(), dataset, format, "16,16,16", false,
N5ScalePyramidExporter.NONE, N5ScalePyramidExporter.DOWN_SAMPLE, N5ScalePyramidExporter.RAW_COMPRESSION);
writer.run(); // run() closes the n5 writer
}
@@ -60,25 +61,44 @@ public void before() {
@After
public void after() {
- final N5Writer n5 = new N5Factory().openWriter(containerDir.getAbsolutePath());
+ N5Writer n5 = new N5Factory().openWriter(containerDir.toString());
n5.remove();
}
+ private static String tempN5PathName() {
+
+ try {
+ final File tmpFile = Files.createTempDirectory("n5-ij-macro-test-").toFile();
+ tmpFile.deleteOnExit();
+ return tmpFile.getCanonicalPath();
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected String tempN5Location() throws URISyntaxException {
+
+ final String basePath = new File(tempN5PathName()).toURI().normalize().getPath();
+ return new URI("file", null, basePath, null).toString();
+ }
+
@Test
- public void testMacroContentPath() {
+ public void testMacroContentPath() throws IOException {
testMacroContentHelper("url=%s/%s");
}
@Test
- public void testMacroContentUri() {
- testMacroContentHelper("url=%s?%s");
+ public void testMacroContentUri() throws IOException {
+ System.out.println("testMacroContent URI style skip windows");
+ final String os = System.getProperty("os.name").toLowerCase();
+ if( !os.startsWith("windows"))
+ testMacroContentHelper("url=%s?%s");
}
- public void testMacroContentHelper( String urlFormat ) {
+ public void testMacroContentHelper( String urlFormat ) throws IOException {
- // URL
final N5Importer plugin = (N5Importer)IJ.runPlugIn("org.janelia.saalfeldlab.n5.ij.N5Importer",
- String.format( urlFormat + " hide", containerDir.getAbsolutePath(), "dataset" ));
+ String.format( urlFormat + " hide", containerDir.toString(), dataset ));
final List res = plugin.getResult();
final ImagePlus imgImported = res.get(0);
@@ -86,7 +106,7 @@ public void testMacroContentHelper( String urlFormat ) {
final N5Importer pluginCrop = (N5Importer)IJ.runPlugIn("org.janelia.saalfeldlab.n5.ij.N5Importer",
String.format( urlFormat + " hide min=0,1,2 max=5,5,5",
- containerDir.getAbsolutePath(), "dataset" ));
+ containerDir.toString(), "dataset" ));
final List resCrop = pluginCrop.getResult();
final ImagePlus imgImportedCrop = resCrop.get(0);
@@ -97,54 +117,55 @@ public void testMacroContentHelper( String urlFormat ) {
final ImagePlus impCrop = ImageJFunctions.wrap(imgCrop, "imgCrop");
impCrop.setDimensions(1, 4, 1);
- assertEquals( " cont crop w", impCrop.getWidth(), imgImportedCrop.getWidth());
- assertEquals( " cont crop h", impCrop.getHeight(), imgImportedCrop.getHeight());
- assertEquals( " cont crop d", impCrop.getNSlices(), imgImportedCrop.getNSlices());
- assertTrue( "equal content crop", TestExportImports.equal(impCrop, imgImportedCrop));
+ assertEquals("cont crop w", impCrop.getWidth(), imgImportedCrop.getWidth());
+ assertEquals("cont crop h", impCrop.getHeight(), imgImportedCrop.getHeight());
+ assertEquals("cont crop d", impCrop.getNSlices(), imgImportedCrop.getNSlices());
+ assertTrue("equal content crop", TestExportImports.equal(impCrop, imgImportedCrop));
}
@Test
public void testMacro() {
final N5Importer plugin = (N5Importer)IJ.runPlugIn("org.janelia.saalfeldlab.n5.ij.N5Importer",
- String.format("url=%s/%s hide", n5rootF.getAbsolutePath(), "cosem" ));
+ String.format("url=%s" + File.separator + "%s hide", n5rootF.toString(), "cosem" ));
final List res = plugin.getResult();
- assertEquals(" crop num", 1, res.size());
+ assertEquals("crop num", 1, res.size());
final ImagePlus img = res.get(0);
- assertEquals(" crop w", 256, img.getWidth());
- assertEquals(" crop h", 256, img.getHeight());
- assertEquals(" crop d", 129, img.getNSlices() );
+ assertEquals("crop w", 256, img.getWidth());
+ assertEquals("crop h", 256, img.getHeight());
+ assertEquals("crop d", 129, img.getNSlices());
}
@Test
public void testMacroVirtual() {
+
final N5Importer plugin = (N5Importer)IJ.runPlugIn("org.janelia.saalfeldlab.n5.ij.N5Importer",
- String.format("url=%s/%s hide virtual", n5rootF.getAbsolutePath(), "cosem" ));
+ String.format("url=%s" + File.separator + "%s hide virtual", n5rootF.toString(), "cosem" ));
final List res = plugin.getResult();
- assertEquals(" crop num", 1, res.size());
+ assertEquals("crop num", 1, res.size());
final ImagePlus img = res.get(0);
- assertTrue( " is virtual", (img.getStack() instanceof ImageJVirtualStack) );
+ assertTrue( "is virtual", (img.getStack() instanceof ImageJVirtualStack) );
}
@Test
public void testMacroCrop() {
+
final String minString = "100,100,50";
final String maxString = "250,250,120";
-
final N5Importer plugin = (N5Importer)IJ.runPlugIn("org.janelia.saalfeldlab.n5.ij.N5Importer",
- String.format("url=%s/%s hide min=%s max=%s",
- n5rootF.getAbsolutePath(), "cosem", minString, maxString ));
+ String.format("url=%s" + File.separator + "%s hide min=%s max=%s",
+ n5rootF.toString(), "cosem", minString, maxString ));
final List res = plugin.getResult();
assertEquals(" crop num", 1, res.size());
final ImagePlus img = res.get(0);
- assertEquals(" crop w", 151, img.getWidth());
- assertEquals(" crop h", 151, img.getHeight());
- assertEquals(" crop d", 71, img.getNSlices() );
+ assertEquals("crop w", 151, img.getWidth());
+ assertEquals("crop h", 151, img.getHeight());
+ assertEquals("crop d", 71, img.getNSlices() );
}
}
diff --git a/src/test/java/org/janelia/saalfeldlab/n5/metadata/ome/ngff/v04/WriteAxesTests.java b/src/test/java/org/janelia/saalfeldlab/n5/metadata/ome/ngff/v04/WriteAxesTests.java
index f263048..9574055 100644
--- a/src/test/java/org/janelia/saalfeldlab/n5/metadata/ome/ngff/v04/WriteAxesTests.java
+++ b/src/test/java/org/janelia/saalfeldlab/n5/metadata/ome/ngff/v04/WriteAxesTests.java
@@ -1,10 +1,13 @@
package org.janelia.saalfeldlab.n5.metadata.ome.ngff.v04;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Collections;
@@ -14,6 +17,7 @@
import java.util.concurrent.Executors;
import org.janelia.saalfeldlab.n5.N5Reader;
+import org.janelia.saalfeldlab.n5.N5Writer;
import org.janelia.saalfeldlab.n5.TestExportImports;
import org.janelia.saalfeldlab.n5.ij.N5Importer;
import org.janelia.saalfeldlab.n5.ij.N5ScalePyramidExporter;
@@ -27,6 +31,7 @@
import org.janelia.saalfeldlab.n5.universe.N5DatasetDiscoverer;
import org.janelia.saalfeldlab.n5.universe.N5Factory;
import org.janelia.saalfeldlab.n5.universe.N5TreeNode;
+import org.janelia.saalfeldlab.n5.universe.N5Factory.StorageFormat;
import org.janelia.saalfeldlab.n5.universe.metadata.N5CosemMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.N5DatasetMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.N5GenericSingleScaleMetadataParser;
@@ -38,11 +43,15 @@
import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.NgffSingleScaleAxesMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.OmeNgffMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.OmeNgffMetadataParser;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import com.google.gson.JsonElement;
+
import ij.ImagePlus;
import ij.gui.NewImage;
+import net.imglib2.util.Pair;
public class WriteAxesTests {
@@ -80,27 +89,36 @@ private static HashMap, ImageplusMetadata>> defaultImagePlusMetadataW
public void before() {
/* To explicitly test headless */
-// System.setProperty("java.awt.headless", "true");
+ System.setProperty("java.awt.headless", "true");
+
impWriters = defaultImagePlusMetadataWriters();
}
+ private void remove(final String rootLocation) {
+
+ final N5Writer zarr = new N5Factory().openWriter(rootLocation);
+ zarr.remove();
+ }
+
@Test
public void testXYZ() throws IOException, InterruptedException, ExecutionException {
final int nc = 1;
final int nz = 6;
final int nt = 1;
+ final String dataset = "";
final ImagePlus imp = createImage( nc, nz, nt );
- final String rootLocation = createDataset("xyz.zarr", imp );
+ final String rootLocation = createDataset("xyz.zarr", dataset, imp );
- final OmeNgffMetadata ngffMeta = readMetadata(rootLocation);
+ final OmeNgffMetadata ngffMeta = readMetadata(rootLocation, dataset);
assertTrue(Arrays.stream(ngffMeta.multiscales[0].axes).allMatch(x -> x.getUnit().equals(UNIT)));
assertEquals(3, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.SPACE)).count());
assertEquals(0, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.CHANNEL)).count());
assertEquals(0, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.TIME)).count());
- final ImagePlus impRead = readImage( rootLocation );
- assertTrue( TestExportImports.equal(imp, impRead));
+ final ImagePlus impRead = readImage(rootLocation);
+ assertTrue(TestExportImports.equal(imp, impRead));
+ remove(rootLocation);
}
@Test
@@ -109,16 +127,18 @@ public void testXYC() throws IOException, InterruptedException, ExecutionExcepti
final int nc = 6;
final int nz = 1;
final int nt = 1;
- final ImagePlus imp = createImage( nc, nz, nt );
- final String rootLocation = createDataset("xyc.zarr", imp );
+ final String dataset = "";
+ final ImagePlus imp = createImage(nc, nz, nt);
+ final String rootLocation = createDataset("xyc.zarr", dataset, imp);
- final OmeNgffMetadata ngffMeta = readMetadata(rootLocation);
+ final OmeNgffMetadata ngffMeta = readMetadata(rootLocation, dataset);
assertEquals(2, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.SPACE)).count());
assertEquals(1, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.CHANNEL)).count());
assertEquals(0, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.TIME)).count());
- final ImagePlus impRead = readImage( rootLocation );
- assertTrue( TestExportImports.equal(imp, impRead));
+ final ImagePlus impRead = readImage(rootLocation);
+ assertTrue(TestExportImports.equal(imp, impRead));
+ remove(rootLocation);
}
@Test
@@ -127,16 +147,18 @@ public void testXYT() throws IOException, InterruptedException, ExecutionExcepti
final int nc = 1;
final int nz = 1;
final int nt = 6;
- final ImagePlus imp = createImage( nc, nz, nt );
- final String rootLocation = createDataset("xyt.zarr", imp );
+ final String dataset = "";
+ final ImagePlus imp = createImage(nc, nz, nt);
+ final String rootLocation = createDataset("xyt.zarr", dataset, imp);
- final OmeNgffMetadata ngffMeta = readMetadata(rootLocation);
+ final OmeNgffMetadata ngffMeta = readMetadata(rootLocation, dataset);
assertEquals(2, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.SPACE)).count());
assertEquals(0, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.CHANNEL)).count());
assertEquals(1, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.TIME)).count());
- final ImagePlus impRead = readImage( rootLocation );
- assertTrue( TestExportImports.equal(imp, impRead));
+ final ImagePlus impRead = readImage(rootLocation);
+ assertTrue(TestExportImports.equal(imp, impRead));
+ remove(rootLocation);
}
@Test
@@ -145,16 +167,18 @@ public void testXYCZ() throws IOException, InterruptedException, ExecutionExcept
final int nc = 3;
final int nz = 2;
final int nt = 1;
- final ImagePlus imp = createImage( nc, nz, nt );
- final String rootLocation = createDataset("xycz.zarr", imp );
+ final String dataset = "";
+ final ImagePlus imp = createImage(nc, nz, nt);
+ final String rootLocation = createDataset("xycz.zarr", dataset, imp);
- final OmeNgffMetadata ngffMeta = readMetadata(rootLocation);
+ final OmeNgffMetadata ngffMeta = readMetadata(rootLocation, dataset);
assertEquals(3, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.SPACE)).count());
assertEquals(1, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.CHANNEL)).count());
assertEquals(0, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.TIME)).count());
- final ImagePlus impRead = readImage( rootLocation );
- assertTrue( TestExportImports.equal(imp, impRead));
+ final ImagePlus impRead = readImage(rootLocation);
+ assertTrue(TestExportImports.equal(imp, impRead));
+ remove(rootLocation);
}
@Test
@@ -163,16 +187,18 @@ public void testCZYX() throws IOException, InterruptedException, ExecutionExcept
final int nc = 3;
final int nz = 2;
final int nt = 1;
- final ImagePlus imp = createImage( nc, nz, nt );
- final String rootLocation = createDataset("czyx.zarr", imp);
+ final String dataset = "";
+ final ImagePlus imp = createImage(nc, nz, nt);
+ final String rootLocation = createDataset("czyx.zarr", dataset, imp);
- final OmeNgffMetadata ngffMeta = readMetadata(rootLocation);
+ final OmeNgffMetadata ngffMeta = readMetadata(rootLocation, dataset);
assertEquals(3, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.SPACE)).count());
assertEquals(1, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.CHANNEL)).count());
assertEquals(0, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.TIME)).count());
- final ImagePlus impRead = readImage( rootLocation );
- assertTrue( TestExportImports.equal(imp, impRead));
+ final ImagePlus impRead = readImage(rootLocation);
+ assertTrue(TestExportImports.equal(imp, impRead));
+ remove(rootLocation);
// TODO other checks?
}
@@ -182,45 +208,59 @@ public void testXYCZT() throws IOException, InterruptedException, ExecutionExcep
final int nc = 4;
final int nz = 3;
final int nt = 2;
- final ImagePlus imp = createImage( nc, nz, nt );
- final String rootLocation = createDataset("xyczt.zarr", imp);
+ final String dataset = "";
+ final ImagePlus imp = createImage(nc, nz, nt);
+ final String rootLocation = createDataset("xyczt.zarr", dataset, imp);
- final OmeNgffMetadata ngffMeta = readMetadata(rootLocation);
+ final OmeNgffMetadata ngffMeta = readMetadata(rootLocation, dataset);
assertEquals(3, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.SPACE)).count());
assertEquals(1, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.CHANNEL)).count());
assertEquals(1, Arrays.stream(ngffMeta.multiscales[0].axes).filter(x -> x.getType().equals(Axis.TIME)).count());
+ remove(rootLocation);
}
- private ImagePlus createImage( final int nc, final int nz, final int nt ) {
+ private ImagePlus createImage(final int nc, final int nz, final int nt) {
+
final ImagePlus imp = NewImage.createImage("test", nx, ny, nc * nz * nt, 8, NewImage.FILL_NOISE);
imp.setDimensions(nc, nz, nt);
imp.getCalibration().setUnit(UNIT);
return imp;
}
- private String createDataset(final String containerName, final ImagePlus imp )
+ private String createDataset(final String containerName, final String dataset, final ImagePlus imp)
throws IOException, InterruptedException, ExecutionException {
final String rootLocation = tempPathName() + File.separator + containerName;
- final String dataset = "/";
final String blockSizeArg = "32,32,32";
final String compression = N5ScalePyramidExporter.GZIP_COMPRESSION;
final N5ScalePyramidExporter writer = new N5ScalePyramidExporter();
- writer.setOptions( imp, rootLocation, dataset, N5ScalePyramidExporter.AUTO_FORMAT, blockSizeArg, false,
+ writer.setOptions(imp, rootLocation, dataset, N5ScalePyramidExporter.ZARR_FORMAT, blockSizeArg, false,
N5ScalePyramidExporter.DOWN_SAMPLE, N5Importer.MetadataOmeZarrKey, compression);
writer.run(); // run() closes the n5 writer
return rootLocation;
}
- private OmeNgffMetadata readMetadata(final String rootLocation ) {
+ private OmeNgffMetadata readMetadata(final String rootLocation, final String dataset) {
final N5Reader zarr = new N5Factory().openReader(rootLocation);
- final N5TreeNode node = N5DatasetDiscoverer.discover(zarr, Collections.singletonList(new N5GenericSingleScaleMetadataParser()),
+ final String prefix = String.format("%s - %s", rootLocation, dataset);
+
+ assertNotNull(prefix + " reader null", zarr);
+ assertTrue(prefix + " root exists", zarr.exists(""));
+
+ final N5TreeNode node = N5DatasetDiscoverer.discover(zarr,
+ Collections.singletonList(new N5GenericSingleScaleMetadataParser()),
Collections.singletonList(new OmeNgffMetadataParser()));
+ assertNotNull(prefix + " node null", node);
+ assertNotNull( zarr.getAttribute(dataset, "", JsonElement.class).getAsJsonObject().get("multiscales"));
+ assertTrue(prefix + " is not group", zarr.exists(dataset));
+
final N5Metadata meta = node.getMetadata();
+ assertNotNull(prefix + " metadata null", meta);
+ assertTrue(prefix + " metadata not OmeNgff", (meta instanceof OmeNgffMetadata));
if( meta instanceof OmeNgffMetadata ) {
return (OmeNgffMetadata) meta;
}
diff --git a/src/test/java/org/janelia/saalfeldlab/n5/ui/TestUriValidation.java b/src/test/java/org/janelia/saalfeldlab/n5/ui/TestUriValidation.java
new file mode 100644
index 0000000..79c92b9
--- /dev/null
+++ b/src/test/java/org/janelia/saalfeldlab/n5/ui/TestUriValidation.java
@@ -0,0 +1,89 @@
+package org.janelia.saalfeldlab.n5.ui;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.ParseException;
+
+import org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.UriValidator;
+import org.junit.Test;
+
+public class TestUriValidation {
+
+ @Test
+ public void testUriValidator() throws ParseException {
+
+ final UriValidator urival = new UriValidator();
+
+ final String os = System.getProperty("os.name").toLowerCase();
+
+ final String[] names = new String[] {"b", "c"};
+ final Path p = Paths.get("a", names);
+
+ if (os.contains("windows")) {
+ // windows only
+
+ assertThrows(ParseException.class, () -> {
+ urival.stringToValue(p.toString() + "?d/e");
+ });
+ assertThrows(ParseException.class, () -> {
+ urival.stringToValue(p.toString() + "?d/e#/f/g");
+ });
+ }
+ else {
+ // not windows
+
+ // test some weird strings that can technically be interpreted as paths or uris
+ assertNotNull(urival.stringToValue("."));
+ assertNotNull(urival.stringToValue("/.."));
+ assertNotNull(urival.stringToValue("\\\\"));
+ assertNotNull(urival.stringToValue("::"));
+ assertNotNull(urival.stringToValue("/a/\\//b").toString());
+ assertNotNull(urival.stringToValue("://////").toString());
+ assertNotNull(urival.stringToValue("..").toString());
+
+ assertNotNull(urival.stringToValue("/a/b/c"));
+ assertNotNull(urival.stringToValue("/a/b/c?d/e"));
+ assertNotNull(urival.stringToValue("/a/b/c?d/e#f/g"));
+ }
+
+ // both windows and not
+ assertNotNull(urival.stringToValue(p.toString()));
+ assertNotNull(urival.stringToValue(p.toUri().toString()));
+ assertNotNull(urival.stringToValue(p.toUri().toString() + "?d/e"));
+ assertNotNull(urival.stringToValue(p.toUri().toString() + "?d/e#f/g"));
+
+ assertNotNull(urival.stringToValue("file:///a/b/c"));
+ assertNotNull(urival.stringToValue("file:///a/b/c?d/e"));
+ assertNotNull(urival.stringToValue("file:///a/b/c?d/e#f/g"));
+
+ assertNotNull(urival.stringToValue("s3:///a/b/c"));
+ assertNotNull(urival.stringToValue("s3:///a/b/c?d/e"));
+ assertNotNull(urival.stringToValue("s3:///a/b/c?d/e#f/g"));
+
+ assertNotNull(urival.stringToValue("https://s3.us-east-1.amazonaws.com/a/b/c"));
+ assertNotNull(urival.stringToValue("https://s3.us-east-1.amazonaws.com/a/b/c?d/e"));
+ assertNotNull(urival.stringToValue("https://s3.us-east-1.amazonaws.com/a/b/c?d/e#f/g"));
+
+ assertNotNull(urival.stringToValue("gs://storage.googleapis.com/a/b"));
+ assertNotNull(urival.stringToValue("gs://storage.googleapis.com/a/b/c?d/e"));
+ assertNotNull(urival.stringToValue("gs://storage.googleapis.com/a/b/c?d/e#f/g"));
+
+ assertNotNull(urival.stringToValue("https://storage.googleapis.com/a/b"));
+ assertNotNull(urival.stringToValue("https://storage.googleapis.com/a/b/c?d/e"));
+ assertNotNull(urival.stringToValue("https://storage.googleapis.com/a/b/c?d/e#f/g"));
+
+ assertNotNull(urival.stringToValue("zarr:/a/b/c"));
+ assertNotNull(urival.stringToValue("zarr:/a/b/c?d/e"));
+ assertNotNull(urival.stringToValue("zarr:/a/b/c?d/e#f/g"));
+
+ assertNotNull(urival.stringToValue("zarr:file:///a/b/c"));
+ assertNotNull(urival.stringToValue("zarr:file:///a/b/c?d/e"));
+ assertNotNull(urival.stringToValue("zarr:file:///a/b/c?d/e#f/g"));
+
+ }
+
+}