Skip to content

Commit

Permalink
Make eager I/O plugins work with File > Open
Browse files Browse the repository at this point in the history
The interceptFileOpen hook runs *before* any dialogs are shown when
invoked via File > Open. When new-style I/O is enabled, a suitable
file opener dialog is displayed by running the GetPath command.
But when new-style I/O is *not* enabled, the path is simply null,
and when handed to the getEagerHandler method, triggers a
NullPointerException in the abstract I/O service infrastructure.

The fix in this patch is to *always* respond to a null initial path by
running the GetPath command, even if new-style I/O is disabled. This
change means that the original ImageJ's file chooser dialog will never
be shown directly anymore, which feels a bit strange. But in practice,
the modified behavior very closely resembles the old behavior, so
hopefully this fix will not cause any problems downstream.

And it makes the eager I/O plugins work as intended with File > Open.
  • Loading branch information
ctrueden committed Oct 18, 2023
1 parent df8b210 commit cc00483
Showing 1 changed file with 55 additions and 48 deletions.
103 changes: 55 additions & 48 deletions src/main/java/net/imagej/legacy/plugin/DefaultLegacyOpener.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,71 +120,78 @@ public Object open(String path, final int planeIndex,
final boolean newStyleIO =
optionsService.getOptions(ImageJ2Options.class).isSciJavaIO();

if (!newStyleIO) {
// Before giving up, let's give the IOService's *eager* IOPlugins
// a chance to handle it, before the original ImageJ kicks in.
// An eager plugin is an IOPlugin with attrs = { @Attr("eager") }.
// This concept is distinct from a high-priority I/O plugin,
// because it partitions the list of IOPlugins into two parts:
// those allowed to run here, before the original ImageJ logic,
// and those which are not allowed to do so (the default).
Object data = null;
try {
IOPlugin<?> io = getEagerHandler(path);

if (io == null) {
logService.debug("No appropriate eager format found: " + path);
return null; // Pass through to original ImageJ.
}
data = io.open(path);
if (data == null) {
logService.debug("Eager format '" + io.getClass().getName() + "' opened nothing.");
return null; // Pass through to original ImageJ.
}
return handleData(c, data, path, displayResult);
}
catch (final IOException exc) {
legacyService.handleException(exc);
}

// No eager plugin handled this path, so we give up.
return null; // Pass through to original ImageJ.
}

// Ensure path is not null.
if (path == null) {
// Display a file chooser dialog for the user to select a path.
// This dialog replaces the original ImageJ's file chooser, which
// normally happens later in the case of the File > Open code path.
final CommandInfo command = commandService.getCommand(GetPath.class);
final String[] selectedPath = new String[1];
final Future<Module> result =
moduleService.run(command, true, "path", selectedPath);
final Module module = moduleService.waitFor(result);
// Check if the module failed
if (module == null) return null;
// Check if the module was canceled
if (Cancelable.class.isAssignableFrom(module.getClass())) {
if (((Cancelable)module).isCanceled()) {
return Boolean.TRUE;
}
// Check if the module failed.
if (module == null) return null; // fall back to original ImageJ
// Check if the module was canceled.
if (module instanceof Cancelable && //
(((Cancelable) module).isCanceled()))
{
return Boolean.TRUE; // cancel the operation
}

path = selectedPath[0];
}
if (path == null) return Boolean.TRUE; // cancel the operation

Object data = null;
// And now it's time to open the path to get the data!
final Object data;
try {
final IOPlugin<?> opener = ioService.getOpener(path);
if (opener == null) {
logService.warn("No appropriate format found: " + path);
return path;
if (newStyleIO) {
// With ImageJ2-style I/O enabled, we ask the SciJava I/O
// service to open the data using any available I/O plugin.
final IOPlugin<?> opener = ioService.getOpener(path);
if (opener == null) {
logService.warn("No appropriate format found: " + path);
return path;
}
data = opener.open(path);
if (data == null) {
logService.warn("Opening was canceled.");
return path;
}
}
data = opener.open(path);
if (data == null) {
logService.warn("Opening was canceled.");
return path;
else {
// With ImageJ2-style I/O disabled, we let the original ImageJ
// operate on the file path the way it normally would... EXCEPT:
// before falling back, we give the IOService's *eager* IOPlugins
// a chance to handle it, before the original ImageJ kicks in.
// An eager plugin is an IOPlugin with attrs = { @Attr("eager") }.
// This concept is distinct from a high-priority I/O plugin,
// because it partitions the list of IOPlugins into two parts:
// those allowed to run here, before the original ImageJ logic,
// and those which are not allowed to do so (the default).
try {
final IOPlugin<?> io = getEagerHandler(path);
if (io == null) {
logService.debug("No appropriate eager I/O plugin found: " + path);
return path; // fall back to original ImageJ
}
data = io.open(path);
if (data == null) {
logService.debug("Eager I/O plugin '" + io.getClass().getName() + "' opened nothing.");
return path; // fall back to original ImageJ
}
}
catch (final IOException exc) {
legacyService.handleException(exc);
return path; // fall back to original ImageJ
}
}
}
catch (final IOException exc) {
legacyService.handleException(exc);
return path; // fall back to original ImageJ
}

return handleData(c, data, path, displayResult);
}

Expand Down

0 comments on commit cc00483

Please sign in to comment.