Skip to content

Commit

Permalink
De-duplicate widget inputs by String comparison
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hinerm committed Sep 10, 2024
1 parent 0d95340 commit f5230f6
Showing 1 changed file with 21 additions and 5 deletions.
26 changes: 21 additions & 5 deletions src/main/java/org/scijava/widget/AbstractInputHarvester.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@
package org.scijava.widget;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

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

/** Asks the object service and convert service for valid choices */
private List<Object> getObjects(final Class<?> type) {
Set<Object> compatibleInputs =
new HashSet<>(convertService.getCompatibleInputs(type));
compatibleInputs.addAll(objectService.getObjects(type));
return new ArrayList<>(compatibleInputs);
// Start with the known, unconverted objects of the desired type
List<Object> objects = new ArrayList<>(objectService.getObjects(type));

// Get all the known objects that can be converted to the destination type
Collection<Object> compatibleInputs = convertService.getCompatibleInputs(type);

// HACK: Add each convertible object that doesn't share a name with any other object
// Our goal here is to de-duplicate by avoiding similar inputs that could be converted
// to the same effective output (e.g. an ImageDisplay and a Dataset that map to the same
// ImgPlus)
Set<String> knownNames = objects.stream().map(Object::toString).collect(Collectors.toSet());
for (Object o : compatibleInputs) {
final String s = o.toString();
if (!knownNames.contains(s)) {
objects.add(o);
knownNames.add(s);
}
}
return objects;
}
}

0 comments on commit f5230f6

Please sign in to comment.