From f2fc5300b42512113465f5793c119f8a06e15730 Mon Sep 17 00:00:00 2001 From: Jan Eglinger Date: Sun, 1 Nov 2020 15:39:07 +0100 Subject: [PATCH 1/4] Bump parent to pom-scijava 29.2.1 --- pom.xml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index e5d64f4..092811a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.scijava pom-scijava - 28.0.0 + 29.2.1 @@ -107,9 +107,6 @@ 1.3.2 0.1 - - 5.2 - 0.1.7 From 5da4cd501d9f4773bb68c57cb5d9ff083a184706 Mon Sep 17 00:00:00 2001 From: Jan Eglinger Date: Sun, 1 Nov 2020 15:33:26 +0100 Subject: [PATCH 2/4] Add SwingNumberWidgetDemo --- .../swing/widget/SwingNumberWidgetDemo.java | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/test/java/org/scijava/ui/swing/widget/SwingNumberWidgetDemo.java diff --git a/src/test/java/org/scijava/ui/swing/widget/SwingNumberWidgetDemo.java b/src/test/java/org/scijava/ui/swing/widget/SwingNumberWidgetDemo.java new file mode 100644 index 0000000..45b6c88 --- /dev/null +++ b/src/test/java/org/scijava/ui/swing/widget/SwingNumberWidgetDemo.java @@ -0,0 +1,69 @@ +package org.scijava.ui.swing.widget; + +import org.scijava.Context; +import org.scijava.command.Command; +import org.scijava.command.CommandService; +import org.scijava.plugin.Parameter; +import org.scijava.ui.UIService; + +public class SwingNumberWidgetDemo implements Command { + + @Parameter(persist = false) + private Double a = 0.0000123; + + @Parameter(persist = false) + private Double b = 0.000123; + + @Parameter(persist = false) + private Double c = 0.00123; + + @Parameter(persist = false) + private Double d = 0.0123; + + @Parameter(persist = false) + private Double e = 0.123; + + @Parameter(persist = false) + private Double f = 1.23; + + @Parameter(persist = false) + private Double g = 123d; + + @Parameter(min = "0.0", max = "10.0", stepSize = "0.001", persist = false) + private Double h = 1d; + + @Parameter(style = "format:#.##", persist = false) + private Double i = 0.0123; + + @Parameter(style = "format:#.00", persist = false) + private Double j = 0.0123; + + @Parameter(style = "format:#####.#####", persist = false) + private Double k = 123.45; + + @Parameter(style = "format:00000.00000", persist = false) + private Double l = 123.45; + + @Parameter(style = "slider", min = "0", max = "10", stepSize = "0.001", persist = false) + private Double m = 1d; + + @Parameter(style = "slider,format:0.0000", min = "0", max = "10", stepSize = "0.001", persist = false) + private Double n = 1d; + + @Parameter(style = "scroll bar", min = "0", max = "10", stepSize = "0.001", persist = false) + private Double o = 1d; + + @Parameter(style = "scroll bar,format:0.0000", min = "0", max = "10", stepSize = "0.001", persist = false) + private Double p = 1d; + + @Override + public void run() { + // Nothing to do. + } + + public static void main(final String... args) throws Exception { + Context context = new Context(); + context.service(UIService.class).showUI(); + context.service(CommandService.class).run(SwingNumberWidgetDemo.class, true); + } +} From f66283ca1209ad4622e7864d3d33289e8a53219b Mon Sep 17 00:00:00 2001 From: Boudewijn van Langerak Date: Sun, 18 Oct 2020 07:30:54 +0200 Subject: [PATCH 3/4] Using the style to format number in the swing UI. --- .../ui/swing/widget/SwingNumberWidget.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/org/scijava/ui/swing/widget/SwingNumberWidget.java b/src/main/java/org/scijava/ui/swing/widget/SwingNumberWidget.java index e833419..8a881a2 100644 --- a/src/main/java/org/scijava/ui/swing/widget/SwingNumberWidget.java +++ b/src/main/java/org/scijava/ui/swing/widget/SwingNumberWidget.java @@ -119,6 +119,11 @@ else if (model.isStyle(NumberWidget.SLIDER_STYLE)) { final SpinnerNumberModel spinnerModel = new SpinnerNumberModelFactory().createModel(value, min, max, stepSize); spinner = new JSpinner(spinnerModel); + String format = getFormat(model); + if (format != null) { + spinner.setEditor(new JSpinner.NumberEditor(spinner, format)); + } + Dimension spinnerSize = spinner.getSize(); spinnerSize.width = 50; spinner.setPreferredSize(spinnerSize); @@ -132,6 +137,17 @@ else if (model.isStyle(NumberWidget.SLIDER_STYLE)) { syncSliders(); } + private String getFormat(WidgetModel model) { + final String widgetStyle = model.getItem().getWidgetStyle(); + String format = null; + for (final String s : widgetStyle.split(",")) { + if (s.startsWith("format:")) { + format = s.substring(s.indexOf(":") + 1).trim(); + } + } + return format; + } + // -- Typed methods -- @Override From d89b7c959ba86d8cc37d3cc9ca1a6416d997fd90 Mon Sep 17 00:00:00 2001 From: Jan Eglinger Date: Sat, 31 Oct 2020 19:06:41 +0100 Subject: [PATCH 4/4] Adjust default format for SwingNumberWidget This depends scijava-common 2.87.0 --- pom.xml | 13 +- .../ui/swing/widget/SwingNumberWidget.java | 35 +++-- .../swing/widget/SwingNumberWidgetTest.java | 148 ++++++++++++++++++ 3 files changed, 180 insertions(+), 16 deletions(-) create mode 100644 src/test/java/org/scijava/ui/swing/widget/SwingNumberWidgetTest.java diff --git a/pom.xml b/pom.xml index 092811a..f76072a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.scijava pom-scijava - 29.2.1 + 30.0.0 @@ -107,6 +107,8 @@ 1.3.2 0.1 + + 2.87.0 @@ -144,7 +146,6 @@ com.miglayout miglayout-swing - ${miglayout-swing.version} net.sourceforge.jdatepicker @@ -158,5 +159,13 @@ junit test + + + org.scijava + scijava-common + tests + test + + diff --git a/src/main/java/org/scijava/ui/swing/widget/SwingNumberWidget.java b/src/main/java/org/scijava/ui/swing/widget/SwingNumberWidget.java index 8a881a2..999cf39 100644 --- a/src/main/java/org/scijava/ui/swing/widget/SwingNumberWidget.java +++ b/src/main/java/org/scijava/ui/swing/widget/SwingNumberWidget.java @@ -41,6 +41,8 @@ import java.math.BigInteger; import java.text.DecimalFormat; import java.text.ParsePosition; +import java.util.Arrays; +import java.util.Collections; import java.util.Hashtable; import javax.swing.JComponent; @@ -62,6 +64,7 @@ import org.scijava.widget.InputWidget; import org.scijava.widget.NumberWidget; import org.scijava.widget.WidgetModel; +import org.scijava.widget.WidgetStyle; /** * Swing implementation of number chooser widget. @@ -119,10 +122,11 @@ else if (model.isStyle(NumberWidget.SLIDER_STYLE)) { final SpinnerNumberModel spinnerModel = new SpinnerNumberModelFactory().createModel(value, min, max, stepSize); spinner = new JSpinner(spinnerModel); - String format = getFormat(model); - if (format != null) { - spinner.setEditor(new JSpinner.NumberEditor(spinner, format)); + String format = WidgetStyle.getStyleModifier(model.getItem().getWidgetStyle(), "format"); + if (format == null) { + format = suitableFormat(value, stepSize, min, max); } + spinner.setEditor(new JSpinner.NumberEditor(spinner, format)); Dimension spinnerSize = spinner.getSize(); spinnerSize.width = 50; @@ -137,17 +141,6 @@ else if (model.isStyle(NumberWidget.SLIDER_STYLE)) { syncSliders(); } - private String getFormat(WidgetModel model) { - final String widgetStyle = model.getItem().getWidgetStyle(); - String format = null; - for (final String s : widgetStyle.split(",")) { - if (s.startsWith("format:")) { - format = s.substring(s.indexOf(":") + 1).trim(); - } - } - return format; - } - // -- Typed methods -- @Override @@ -345,6 +338,20 @@ private void syncSliders() { } } + /** Generate a suitable format pattern. */ + private String suitableFormat(Number... values) { + Integer maxScale = Arrays.stream(values) + .map(n -> new BigDecimal("" + n.doubleValue()).stripTrailingZeros().scale()).max(Integer::compare) + .get(); + return formatForScale(maxScale); + } + + /** Generate a format pattern with sufficient number of decimals. */ + private String formatForScale(int scale) { + if (scale <= 0) return "0"; + return "0." + String.join("", Collections.nCopies(scale, "0")); + } + // -- AbstractUIInputWidget methods --- @Override diff --git a/src/test/java/org/scijava/ui/swing/widget/SwingNumberWidgetTest.java b/src/test/java/org/scijava/ui/swing/widget/SwingNumberWidgetTest.java new file mode 100644 index 0000000..500aaa7 --- /dev/null +++ b/src/test/java/org/scijava/ui/swing/widget/SwingNumberWidgetTest.java @@ -0,0 +1,148 @@ +/*- + * #%L + * SciJava UI components for Java Swing. + * %% + * Copyright (C) 2010 - 2020 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package org.scijava.ui.swing.widget; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.StringReader; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; + +import javax.swing.JSpinner; +import javax.swing.JSpinner.NumberEditor; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.module.Module; +import org.scijava.module.ModuleException; +import org.scijava.module.ModuleItem; +import org.scijava.module.ModuleService; +import org.scijava.script.ScriptInfo; +import org.scijava.script.ScriptService; +import org.scijava.util.ListUtils; +import org.scijava.widget.InputWidget; +import org.scijava.widget.WidgetModel; +import org.scijava.widget.WidgetService; + +public class SwingNumberWidgetTest { + + private Context context; + private ModuleService moduleService; + private WidgetService widgetService; + + @Before + public void setUp() { + context = new Context(); + moduleService = context.service(ModuleService.class); + widgetService = context.service(WidgetService.class); + } + + @After + public void tearDown() { + context.dispose(); + } + + @Test + public void test() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, ModuleException { + String[] expecteds = getExpectedValues(); + Field spinnerField = SwingNumberWidget.class.getDeclaredField("spinner"); + spinnerField.setAccessible(true); + + String script = createScript(); + ScriptInfo info = new ScriptInfo(context, ".bsizes", new StringReader(script)); + //System.err.println(moduleService); + Module module = moduleService.createModule(info); + //Module module = info.createModule(); + Iterable> inputs = info.inputs(); + SwingInputPanel inputPanel = new SwingInputPanel(); + int i = 0; + for (ModuleItem item : inputs) { + WidgetModel model = widgetService.createModel(inputPanel, module, item, Collections.EMPTY_LIST); + InputWidget inputWidget = widgetService.create(model); + assertTrue(inputWidget instanceof SwingNumberWidget); + + JSpinner spinner = (JSpinner) spinnerField.get(inputWidget); + NumberEditor editor = (NumberEditor) spinner.getEditor(); + assertEquals("Format (index " + i + ")", expecteds[i++], editor.getTextField().getText()); + } + } + + private String[] getExpectedValues() { + return new String[] { + "0.0000123", + "0.000123", + "0.00123", + "0.0123", + "0.123", + "1.23", + "123", + "1.000", + "0.01", + ".01", + "123.45", + "00123.45000", + "1.000", + "1.0000", + "1.000", + "1.0000" + }; + } + + private String createScript() { + final String script = "// Automatically generated format\n" + + "#@ Double (value=0.0000123, persist=false) a\n" + + "#@ Double (value=0.000123, persist=false) b\n" + + "#@ Double (value=0.00123, persist=false) c\n" + + "#@ Double (value=0.0123, persist=false) d\n" + + "#@ Double (value=0.123, persist=false) e\n" + + "#@ Double (value=1.23, persist=false) f\n" + + "#@ Double (value=123, persist=false) g\n" + + "#@ Double (value=1, min=0.0, max=10.0, stepSize=0.001, persist=false) h\n" + + "\n" + + "// Specified format\n" + + "#@ Double (value=0.0123, persist=false, style=\"format:#.##\") i\n" + + "#@ Double (value=0.0123, persist=false, style=\"format:#.00\") j\n" + + "#@ Double (value=123.45, persist=false, style=\"format:#####.#####\") k\n" + + "#@ Double (value=123.45, persist=false, style=\"format:00000.00000\") l\n" + + "\n" + + "// Sliders and scroll bars\n" + + "#@ Double (value=1, min=0, max=10, stepSize=0.001, persist=false, style=slider) m\n" + + "#@ Double (value=1, min=0, max=10, stepSize=0.001, persist=false, style=\"slider,format:0.0000\") n\n" + + "#@ Double (value=1, min=0, max=10, stepSize=0.001, persist=false, style=\"scroll bar\") o\n" + + "#@ Double (value=1, min=0, max=10, stepSize=0.001, persist=false, style=\"scroll bar,format:0.0000\") p\n" + + ""; + return script; + } + +}