Skip to content

Commit 3b51400

Browse files
committed
WIP: Adjust default format for SwingNumberWidget
This depends on scijava/scijava-common#405
1 parent 791030e commit 3b51400

File tree

3 files changed

+180
-15
lines changed

3 files changed

+180
-15
lines changed

Diff for: pom.xml

+11-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@
107107

108108
<jdatepicker.version>1.3.2</jdatepicker.version>
109109
<object-inspector.version>0.1</object-inspector.version>
110+
111+
<scijava-common.version>999</scijava-common.version>
110112
</properties>
111113

112114
<repositories>
@@ -144,7 +146,6 @@
144146
<dependency>
145147
<groupId>com.miglayout</groupId>
146148
<artifactId>miglayout-swing</artifactId>
147-
<version>${miglayout-swing.version}</version>
148149
</dependency>
149150
<dependency>
150151
<groupId>net.sourceforge.jdatepicker</groupId>
@@ -158,5 +159,14 @@
158159
<artifactId>junit</artifactId>
159160
<scope>test</scope>
160161
</dependency>
162+
<!-- NB: inherit the BindingSizes script engine from scijava-common -->
163+
<dependency>
164+
<groupId>org.scijava</groupId>
165+
<artifactId>scijava-common</artifactId>
166+
<version>${scijava-common.version}</version>
167+
<classifier>tests</classifier>
168+
<scope>test</scope>
169+
</dependency>
170+
161171
</dependencies>
162172
</project>

Diff for: src/main/java/org/scijava/ui/swing/widget/SwingNumberWidget.java

+21-14
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import java.math.BigInteger;
4242
import java.text.DecimalFormat;
4343
import java.text.ParsePosition;
44+
import java.util.Arrays;
45+
import java.util.Collections;
4446
import java.util.Hashtable;
4547

4648
import javax.swing.JComponent;
@@ -62,6 +64,7 @@
6264
import org.scijava.widget.InputWidget;
6365
import org.scijava.widget.NumberWidget;
6466
import org.scijava.widget.WidgetModel;
67+
import org.scijava.widget.WidgetStyle;
6568

6669
/**
6770
* Swing implementation of number chooser widget.
@@ -119,10 +122,11 @@ else if (model.isStyle(NumberWidget.SLIDER_STYLE)) {
119122
final SpinnerNumberModel spinnerModel =
120123
new SpinnerNumberModelFactory().createModel(value, min, max, stepSize);
121124
spinner = new JSpinner(spinnerModel);
122-
String format = getFormat(model);
123-
if (format != null) {
124-
spinner.setEditor(new JSpinner.NumberEditor(spinner, format));
125+
String format = WidgetStyle.getStyleModifier(model.getItem().getWidgetStyle(), "format");
126+
if (format == null) {
127+
format = suitableFormat(value, stepSize, min, max);
125128
}
129+
spinner.setEditor(new JSpinner.NumberEditor(spinner, format));
126130

127131
Dimension spinnerSize = spinner.getSize();
128132
spinnerSize.width = 50;
@@ -137,17 +141,6 @@ else if (model.isStyle(NumberWidget.SLIDER_STYLE)) {
137141
syncSliders();
138142
}
139143

140-
private String getFormat(WidgetModel model) {
141-
final String widgetStyle = model.getItem().getWidgetStyle();
142-
String format = null;
143-
for (final String s : widgetStyle.split(",")) {
144-
if (s.startsWith("format:")) {
145-
format = s.substring(s.indexOf(":") + 1).trim();
146-
}
147-
}
148-
return format;
149-
}
150-
151144
// -- Typed methods --
152145

153146
@Override
@@ -345,6 +338,20 @@ private void syncSliders() {
345338
}
346339
}
347340

341+
/** Generate a suitable format pattern. */
342+
private String suitableFormat(Number... values) {
343+
Integer maxScale = Arrays.stream(values)
344+
.map(n -> new BigDecimal("" + n.doubleValue()).stripTrailingZeros().scale()).max(Integer::compare)
345+
.get();
346+
return formatForScale(maxScale);
347+
}
348+
349+
/** Generate a format pattern with sufficient number of decimals. */
350+
private String formatForScale(int scale) {
351+
if (scale <= 0) return "0";
352+
return "0." + String.join("", Collections.nCopies(scale, "0"));
353+
}
354+
348355
// -- AbstractUIInputWidget methods ---
349356

350357
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*-
2+
* #%L
3+
* SciJava UI components for Java Swing.
4+
* %%
5+
* Copyright (C) 2010 - 2020 SciJava developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
package org.scijava.ui.swing.widget;
30+
31+
import static org.junit.Assert.assertEquals;
32+
import static org.junit.Assert.assertTrue;
33+
34+
import java.io.StringReader;
35+
import java.lang.reflect.Field;
36+
import java.util.ArrayList;
37+
import java.util.Collections;
38+
39+
import javax.swing.JSpinner;
40+
import javax.swing.JSpinner.NumberEditor;
41+
42+
import org.junit.After;
43+
import org.junit.Before;
44+
import org.junit.Ignore;
45+
import org.junit.Test;
46+
import org.scijava.Context;
47+
import org.scijava.module.Module;
48+
import org.scijava.module.ModuleException;
49+
import org.scijava.module.ModuleItem;
50+
import org.scijava.module.ModuleService;
51+
import org.scijava.script.ScriptInfo;
52+
import org.scijava.script.ScriptService;
53+
import org.scijava.util.ListUtils;
54+
import org.scijava.widget.InputWidget;
55+
import org.scijava.widget.WidgetModel;
56+
import org.scijava.widget.WidgetService;
57+
58+
public class SwingNumberWidgetTest {
59+
60+
private Context context;
61+
private ModuleService moduleService;
62+
private WidgetService widgetService;
63+
64+
@Before
65+
public void setUp() {
66+
context = new Context();
67+
moduleService = context.service(ModuleService.class);
68+
widgetService = context.service(WidgetService.class);
69+
}
70+
71+
@After
72+
public void tearDown() {
73+
context.dispose();
74+
}
75+
76+
@Test
77+
public void test() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, ModuleException {
78+
String[] expecteds = getExpectedValues();
79+
Field spinnerField = SwingNumberWidget.class.getDeclaredField("spinner");
80+
spinnerField.setAccessible(true);
81+
82+
String script = createScript();
83+
ScriptInfo info = new ScriptInfo(context, ".bsizes", new StringReader(script));
84+
//System.err.println(moduleService);
85+
Module module = moduleService.createModule(info);
86+
//Module module = info.createModule();
87+
Iterable<ModuleItem<?>> inputs = info.inputs();
88+
SwingInputPanel inputPanel = new SwingInputPanel();
89+
int i = 0;
90+
for (ModuleItem<?> item : inputs) {
91+
WidgetModel model = widgetService.createModel(inputPanel, module, item, Collections.EMPTY_LIST);
92+
InputWidget<?, ?> inputWidget = widgetService.create(model);
93+
assertTrue(inputWidget instanceof SwingNumberWidget);
94+
95+
JSpinner spinner = (JSpinner) spinnerField.get(inputWidget);
96+
NumberEditor editor = (NumberEditor) spinner.getEditor();
97+
assertEquals("Format (index " + i + ")", expecteds[i++], editor.getTextField().getText());
98+
}
99+
}
100+
101+
private String[] getExpectedValues() {
102+
return new String[] {
103+
"0.0000123",
104+
"0.000123",
105+
"0.00123",
106+
"0.0123",
107+
"0.123",
108+
"1.23",
109+
"123",
110+
"1.000",
111+
"0.01",
112+
".01",
113+
"123.45",
114+
"00123.45000",
115+
"1.000",
116+
"1.0000",
117+
"1.000",
118+
"1.0000"
119+
};
120+
}
121+
122+
private String createScript() {
123+
final String script = "// Automatically generated format\n" +
124+
"#@ Double (value=0.0000123, persist=false) a\n" +
125+
"#@ Double (value=0.000123, persist=false) b\n" +
126+
"#@ Double (value=0.00123, persist=false) c\n" +
127+
"#@ Double (value=0.0123, persist=false) d\n" +
128+
"#@ Double (value=0.123, persist=false) e\n" +
129+
"#@ Double (value=1.23, persist=false) f\n" +
130+
"#@ Double (value=123, persist=false) g\n" +
131+
"#@ Double (value=1, min=0.0, max=10.0, stepSize=0.001, persist=false) h\n" +
132+
"\n" +
133+
"// Specified format\n" +
134+
"#@ Double (value=0.0123, persist=false, style=\"format:#.##\") i\n" +
135+
"#@ Double (value=0.0123, persist=false, style=\"format:#.00\") j\n" +
136+
"#@ Double (value=123.45, persist=false, style=\"format:#####.#####\") k\n" +
137+
"#@ Double (value=123.45, persist=false, style=\"format:00000.00000\") l\n" +
138+
"\n" +
139+
"// Sliders and scroll bars\n" +
140+
"#@ Double (value=1, min=0, max=10, stepSize=0.001, persist=false, style=slider) m\n" +
141+
"#@ Double (value=1, min=0, max=10, stepSize=0.001, persist=false, style=\"slider,format:0.0000\") n\n" +
142+
"#@ Double (value=1, min=0, max=10, stepSize=0.001, persist=false, style=\"scroll bar\") o\n" +
143+
"#@ Double (value=1, min=0, max=10, stepSize=0.001, persist=false, style=\"scroll bar,format:0.0000\") p\n" +
144+
"";
145+
return script;
146+
}
147+
148+
}

0 commit comments

Comments
 (0)