Skip to content

Commit f5230f6

Browse files
committed
De-duplicate widget inputs by String comparison
When populating potential items for an input widget, we now prefer existing objects of a given input type to potentially convertiable types. Further, for convertibles we now avoid considering them if they share a toString with any other potential input. Candidates are prioritized in order returned by ConvertService.getCompatibleInputs. This mitigates the potential for duplicate entries in input harvesters when multiple input instances are convertible to the same effective output instance.
1 parent 0d95340 commit f5230f6

File tree

1 file changed

+21
-5
lines changed

1 file changed

+21
-5
lines changed

src/main/java/org/scijava/widget/AbstractInputHarvester.java

+21-5
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
package org.scijava.widget;
3131

3232
import java.util.ArrayList;
33-
import java.util.HashSet;
33+
import java.util.Collection;
3434
import java.util.List;
3535
import java.util.Set;
36+
import java.util.stream.Collectors;
3637

3738
import org.scijava.AbstractContextual;
3839
import org.scijava.convert.ConvertService;
@@ -129,9 +130,24 @@ private <T> WidgetModel addInput(final InputPanel<P, W> inputPanel,
129130

130131
/** Asks the object service and convert service for valid choices */
131132
private List<Object> getObjects(final Class<?> type) {
132-
Set<Object> compatibleInputs =
133-
new HashSet<>(convertService.getCompatibleInputs(type));
134-
compatibleInputs.addAll(objectService.getObjects(type));
135-
return new ArrayList<>(compatibleInputs);
133+
// Start with the known, unconverted objects of the desired type
134+
List<Object> objects = new ArrayList<>(objectService.getObjects(type));
135+
136+
// Get all the known objects that can be converted to the destination type
137+
Collection<Object> compatibleInputs = convertService.getCompatibleInputs(type);
138+
139+
// HACK: Add each convertible object that doesn't share a name with any other object
140+
// Our goal here is to de-duplicate by avoiding similar inputs that could be converted
141+
// to the same effective output (e.g. an ImageDisplay and a Dataset that map to the same
142+
// ImgPlus)
143+
Set<String> knownNames = objects.stream().map(Object::toString).collect(Collectors.toSet());
144+
for (Object o : compatibleInputs) {
145+
final String s = o.toString();
146+
if (!knownNames.contains(s)) {
147+
objects.add(o);
148+
knownNames.add(s);
149+
}
150+
}
151+
return objects;
136152
}
137153
}

0 commit comments

Comments
 (0)