Skip to content

Commit 36e90a9

Browse files
stefanhahmannclaude
andcommitted
Let "Open Current OME-Zarr Image in BigDataViewer" also open several OME-Zarr images at once.
The command previously opened only the active OME-Zarr. With more than one open, in ImageJ or BDV, it now asks which to show, via OmeZarrImagesChooser, and shows them in one new BDV window, like BigDataViewer's own "Open Current Image" does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 8d10929 commit 36e90a9

2 files changed

Lines changed: 106 additions & 5 deletions

File tree

‎ome-zarr-fiji-ui/src/main/java/ome/zarr/fijiui/plugin/command/tools/OpenInBDVCommand.java‎

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
package ome.zarr.fijiui.plugin.command.tools;
3030

3131
import java.lang.invoke.MethodHandles;
32+
import java.util.Collections;
33+
import java.util.List;
3234

3335
import org.scijava.command.Command;
3436
import org.scijava.plugin.Parameter;
@@ -43,7 +45,9 @@
4345
import ome.zarr.fiji.PyramidalBdv;
4446
import ome.zarr.fiji.plugins.PyramidalService;
4547
import ome.zarr.fiji.util.BdvUtils;
48+
import ome.zarr.fiji.util.OmeZarrImagesChooser;
4649
import ome.zarr.fijiui.open.OmeZarrDropListener;
50+
import ome.zarr.imglib2.PyramidContents;
4751

4852
@Plugin( type = Command.class, menuPath = "Plugins > OME-Zarr > Open Current OME-Zarr Image in BigDataViewer" )
4953
public class OpenInBDVCommand implements Command
@@ -72,8 +76,25 @@ public void run()
7276
logger.warn( message );
7377
return;
7478
}
75-
final PyramidalBdv< ? > pyramidalBdv = new PyramidalBdv<>( this.pyramidal.getContext(), this.pyramidal.getPyramidContents() );
76-
final BdvHandle bdvHandle = BdvUtils.show( pyramidalBdv, pyramidalService );
77-
OmeZarrDropListener.install( bdvHandle, this.pyramidal.getContext() );
79+
BdvHandle bdvHandle = null;
80+
for ( final PyramidContents< ? > selected : selectContents() )
81+
bdvHandle = BdvUtils.show( new PyramidalBdv<>( this.pyramidal.getContext(), selected ), bdvHandle, pyramidalService );
82+
if ( bdvHandle != null )
83+
OmeZarrDropListener.install( bdvHandle, this.pyramidal.getContext() );
84+
}
85+
86+
/**
87+
* The OME-Zarrs to show in one BDV window: just the active one, unless more than one
88+
* is open, in ImageJ or BigDataViewer. Each is listed once, however many windows show it.
89+
*/
90+
private List< PyramidContents< ? > > selectContents()
91+
{
92+
final List< PyramidContents< ? > > open = pyramidalService.getPyramidContents();
93+
if ( open.isEmpty() )
94+
return Collections.emptyList();
95+
// for one OME-Zarr, this.pyramidal's contents should be the same as open.get( 0 )
96+
if ( open.size() == 1 || uiService.isHeadless() )
97+
return Collections.singletonList( this.pyramidal.getPyramidContents() );
98+
return OmeZarrImagesChooser.choose( open, this.pyramidal.getPyramidContents() ); // NB: the active one is pre-selected
7899
}
79100
}

‎ome-zarr-fiji-ui/src/test/java/ome/zarr/fijiui/plugin/command/tools/OpenInBDVCommandTest.java‎

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
* %%
77
* Redistribution and use in source and binary forms, with or without
88
* modification, are permitted provided that the following conditions are met:
9-
*
9+
*
1010
* 1. Redistributions of source code must retain the above copyright notice,
1111
* this list of conditions and the following disclaimer.
1212
* 2. Redistributions in binary form must reproduce the above copyright notice,
1313
* this list of conditions and the following disclaimer in the documentation
1414
* and/or other materials provided with the distribution.
15-
*
15+
*
1616
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1717
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1818
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -32,13 +32,21 @@
3232
import static org.junit.jupiter.api.Assertions.assertNotSame;
3333
import static org.junit.jupiter.api.Assertions.assertSame;
3434

35+
import java.awt.AWTEvent;
36+
import java.awt.Toolkit;
3537
import java.awt.Window;
38+
import java.awt.event.AWTEventListener;
39+
import java.awt.event.WindowEvent;
3640
import java.lang.reflect.InvocationTargetException;
3741
import java.net.URISyntaxException;
3842
import java.nio.file.Path;
3943
import java.util.List;
44+
import java.util.stream.Collectors;
4045
import java.util.concurrent.ExecutionException;
4146

47+
import javax.swing.JCheckBox;
48+
import javax.swing.JDialog;
49+
import javax.swing.JOptionPane;
4250
import javax.swing.SwingUtilities;
4351

4452
import net.imagej.Dataset;
@@ -49,9 +57,11 @@
4957
import org.junit.jupiter.api.Test;
5058
import org.scijava.Context;
5159
import org.scijava.command.CommandService;
60+
import org.scijava.ui.UIService;
5261

5362
import ome.zarr.fijiui.open.OmeZarrOpenActions;
5463
import ome.zarr.fiji.Pyramidal;
64+
import ome.zarr.fiji.PyramidalBdv;
5565
import ome.zarr.fiji.plugins.PyramidalService;
5666
import ome.zarr.ZarrTestUtils;
5767

@@ -76,6 +86,10 @@ private static void flushEventQueue() throws InterruptedException
7686
}
7787
}
7888

89+
private static final String SPOTS = "ome/zarr/testdata/bdv_testing/logo_spots.ome.zarr";
90+
91+
private static final String LABELS = "ome/zarr/testdata/bdv_testing/logo_labels.ome.zarr";
92+
7993
// 2 resolution levels: level 0 = 64x64x16, level 1 = 32x32x8
8094
private static final String PYRAMID_RESOURCE = "ome/zarr/testdata/5d_testing/5d_dataset_v5.ome.zarr";
8195

@@ -146,4 +160,70 @@ void runAfterBdvOpenCreatesSecondBdvDataset() throws URISyntaxException, Executi
146160
assertSame( firstBdvPyramidal.getPyramidContents(), secondBdvPyramidal.getPyramidContents() );
147161
}
148162
}
163+
164+
/**
165+
* With two OME-Zarrs open in ImageJ, ticking both in the dialog shows them in one new BDV window.
166+
*/
167+
@Test
168+
void runWithTwoOpenShowsTheTickedOnesInOneWindow() throws Exception
169+
{
170+
try (Context context = new Context())
171+
{
172+
new OmeZarrOpenActions( ZarrTestUtils.resourcePath( SPOTS ).toUri(), context ).showInImageJ();
173+
new OmeZarrOpenActions( ZarrTestUtils.resourcePath( LABELS ).toUri(), context ).showInImageJ();
174+
flushEventQueue();
175+
176+
AWTEventListener user = event -> {
177+
if ( event.getID() != WindowEvent.WINDOW_OPENED || !( event.getSource() instanceof JDialog ) )
178+
return;
179+
JOptionPane pane = ( JOptionPane ) ( ( JDialog ) event.getSource() ).getContentPane().getComponent( 0 );
180+
for ( Object checkbox : ( Object[] ) pane.getMessage() )
181+
( ( JCheckBox ) checkbox ).setSelected( true ); // tick both
182+
SwingUtilities.invokeLater( () -> pane.setValue( JOptionPane.OK_OPTION ) ); // press OK
183+
};
184+
Toolkit.getDefaultToolkit().addAWTEventListener( user, AWTEvent.WINDOW_EVENT_MASK );
185+
try
186+
{
187+
context.getService( CommandService.class ).run( OpenInBDVCommand.class, true ).get();
188+
}
189+
finally
190+
{
191+
Toolkit.getDefaultToolkit().removeAWTEventListener( user );
192+
}
193+
194+
List< PyramidalBdv< ? > > shown = bdvPyramidals( context );
195+
assertEquals( 2, shown.size() );
196+
assertSame( shown.get( 0 ).getBdvHandle(), shown.get( 1 ).getBdvHandle() );
197+
}
198+
}
199+
200+
/**
201+
* Headless, there is no dialog: with two OME-Zarrs open, only the active one is shown.
202+
*/
203+
@Test
204+
void runHeadlessWithTwoOpenShowsOnlyTheActiveOne() throws Exception
205+
{
206+
try (Context context = new Context())
207+
{
208+
new OmeZarrOpenActions( ZarrTestUtils.resourcePath( SPOTS ).toUri(), context ).showInImageJ();
209+
new OmeZarrOpenActions( ZarrTestUtils.resourcePath( LABELS ).toUri(), context ).showInImageJ();
210+
flushEventQueue();
211+
Pyramidal active = context.getService( PyramidalService.class ).getActivePyramidal();
212+
context.getService( UIService.class ).setHeadless( true );
213+
214+
context.getService( CommandService.class ).run( OpenInBDVCommand.class, true ).get();
215+
216+
List< PyramidalBdv< ? > > shown = bdvPyramidals( context );
217+
assertEquals( 1, shown.size() );
218+
assertSame( active.getPyramidContents(), shown.get( 0 ).getPyramidContents() );
219+
}
220+
}
221+
222+
private static List< PyramidalBdv< ? > > bdvPyramidals( final Context context )
223+
{
224+
return context.getService( PyramidalService.class ).getPyramidals().stream()
225+
.filter( PyramidalBdv.class::isInstance )
226+
.map( pyramidal -> ( PyramidalBdv< ? > ) pyramidal )
227+
.collect( Collectors.toList() );
228+
}
149229
}

0 commit comments

Comments
 (0)