Repository: mobie/mobie-viewer-fiji (language: python)

Issue:
"showAsBoundaries" no longer works
Hi,

with the updated specs, "showAsBoundaries" no longer works when initiated from a view (CLEM project).
When I activate it through the context menu, it comes back.





Discussion / hints:

Fix patch:
diff --git a/pom.xml b/pom.xml
index f46824030..3e0fb4ec9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,6 +11,7 @@
 	<artifactId>mobie-viewer-fiji</artifactId>
 	<version>2.1.9-SNAPSHOT</version>
 
+
 	<!-- mvn clean compile -Dmaven.test.skip=true -->
 	<!-- mvn clean install -Dscijava.app.directory=/Users/tischer/Desktop/Fiji/Fiji-MoBIE-beta.app -->
 	<!-- mvn clean install -Dmaven.test.skip=true -Dscijava.app.directory=/Users/tischer/Desktop/Fiji/Fiji-MoBIE-beta.app -->
@@ -202,6 +203,7 @@
             <artifactId>trove</artifactId>
             <version>1.0.2</version>
         </dependency>
+		<!--  https://forum.image.sc/t/icy-crashes-when-clicking-3d-view-macos-catalina/40628/21 -->
 		<dependency>
 			<groupId>org.jogamp.jogl</groupId>
 			<artifactId>jogl-all</artifactId>
@@ -223,6 +225,13 @@
 			<scope>system</scope>
 			<systemPath>${project.basedir}/src/main/resources/jogl-all-natives-windows-amd64.jar</systemPath>
 		</dependency>
+		<dependency>
+			<groupId>org.jogamp.jogl</groupId>
+			<artifactId>jogl-all-natives-linux-amd64</artifactId>
+			<version>2.4.0-rc-20200307</version>
+			<scope>system</scope>
+			<systemPath>${project.basedir}/src/main/resources/jogl-all-natives-linux-amd64.jar</systemPath>
+		</dependency>
 		<dependency>
 			<groupId>org.jogamp.gluegen</groupId>
 			<artifactId>gluegen-rt</artifactId>
@@ -244,6 +253,13 @@
 			<scope>system</scope>
 			<systemPath>${project.basedir}/src/main/resources/gluegen-rt-natives-windows-amd64.jar</systemPath>
 		</dependency>
+		<dependency>
+			<groupId>org.jogamp.gluegen</groupId>
+			<artifactId>gluegen-rt-natives-linux-amd64</artifactId>
+			<version>2.4.0-rc-20200307</version>
+			<scope>system</scope>
+			<systemPath>${project.basedir}/src/main/resources/gluegen-rt-natives-linux-amd64.jar</systemPath>
+		</dependency>
 		<dependency>
 			<groupId>org.junit.jupiter</groupId>
 			<artifactId>junit-jupiter-api</artifactId>
diff --git a/src/main/java/org/embl/mobie/viewer/MoBIE.java b/src/main/java/org/embl/mobie/viewer/MoBIE.java
index be9c1587c..793869439 100644
--- a/src/main/java/org/embl/mobie/viewer/MoBIE.java
+++ b/src/main/java/org/embl/mobie/viewer/MoBIE.java
@@ -63,7 +63,7 @@ public class MoBIE
 	private String imageRoot;
 	private String tableRoot;
 	private HashMap< String, ImgLoader > sourceNameToImgLoader;
-	private Map< String, SourceAndConverter< ? > > sourceNameToTransformedSourceAndConverter;
+	private Map< String, SourceAndConverter< ? > > sourceNameToSourceAndConverter;
 	private ArrayList< String > projectCommands = new ArrayList<>();;
 	public static int minLogTimeMillis = 100;
 
@@ -275,18 +275,13 @@ private void openDataset( String datasetName ) throws IOException
 	{
 		IJ.log("Opening dataset: " + datasetName );
 		sourceNameToImgLoader = new HashMap<>();
-		sourceNameToTransformedSourceAndConverter = new ConcurrentHashMap<>();
+		sourceNameToSourceAndConverter = new ConcurrentHashMap<>();
 		setDatasetName( datasetName );
 		dataset = new DatasetJsonParser().parseDataset( getDatasetPath( "dataset.json" ) );
 		userInterface = new UserInterface( this );
 		viewManager = new ViewManager( this, userInterface, dataset.is2D, dataset.timepoints );
 		final View view = dataset.views.get( settings.values.getView() );
 		view.setName( settings.values.getView() );
-
-		System.out.println("# Views");
-		for ( String viewName : dataset.views.keySet() )
-			System.out.println( viewName );
-
 		IJ.log( "Opening view: " + view.getName() + "\n" );
 		final long startTime = System.currentTimeMillis();
 		viewManager.show( view );
@@ -352,10 +347,17 @@ public List< String > getDatasets()
 
 	public void close()
 	{
-		// TODO
-//		sourcesDisplayManager.removeAllSourcesFromViewers();
-//		sourcesDisplayManager.getBdv().close();
-//		userInterface.dispose();
+		try
+		{
+			IJ.log( "Closing MoBIE..." );
+			viewManager.close();
+		}
+		catch ( Exception e )
+		{
+			IJ.log( "[ERROR] Could not fully close MoBIE!" );
+			e.printStackTrace();
+		}
+		IJ.log( "MoBIE closed." );
 	}
 
 	public synchronized ImageSource getSource( String sourceName )
@@ -524,9 +526,9 @@ private List< Map< String, List< String > > > loadAdditionalTables( List<String>
 		return additionalTables;
 	}
 
-	public Map< String, SourceAndConverter< ? > > getSourceNameToTransformedSourceAndConverter()
+	public Map< String, SourceAndConverter< ? > > sourceNameToSourceAndConverter()
 	{
-		return sourceNameToTransformedSourceAndConverter;
+		return sourceNameToSourceAndConverter;
 	}
 
 	private Collection< List< TableRowImageSegment > > loadPrimarySegmentsTables( SegmentationDisplay segmentationDisplay, String tableName )
@@ -537,7 +539,7 @@ private Collection< List< TableRowImageSegment > > loadPrimarySegmentsTables( Se
 		for ( String sourceName : segmentationDisplaySources )
 		{
 			Set< Source< ? > > rootSources = ConcurrentHashMap.newKeySet();
-			MoBIEHelper.fetchRootSources( getTransformedSourceAndConverter( sourceName ).getSpimSource(), rootSources );
+			MoBIEHelper.fetchRootSources( sourceNameToSourceAndConverter.get( sourceName ).getSpimSource(), rootSources );
 			sourceNameToRootSources.put( sourceName, rootSources );
 		}
 
@@ -669,7 +671,7 @@ public List< AnnotatedMaskTableRow > loadAnnotatedMaskTables( RegionDisplay anno
 		// create primary AnnotatedMaskTableRow table
 		final Map< String, List< String > > referenceTable = tables.get( 0 );
 		// TODO: The AnnotatedMaskCreator does not need the sources, but just the source's real intervals
-		final AnnotatedMaskCreator annotatedMaskCreator = new AnnotatedMaskCreator( referenceTable, annotationDisplay.getAnnotationIdToSources(), (String sourceName ) -> getTransformedSourceAndConverter( sourceName )  );
+		final AnnotatedMaskCreator annotatedMaskCreator = new AnnotatedMaskCreator( referenceTable, annotationDisplay.getAnnotationIdToSources(), (String sourceName ) -> sourceNameToSourceAndConverter.get( sourceName )  );
 		final List< AnnotatedMaskTableRow > intervalTableRows = annotatedMaskCreator.getAnnotatedMaskTableRows();
 
 		final List< Map< String, List< String > > > additionalTables = tables.subList( 1, tables.size() );
@@ -693,13 +695,15 @@ public void closeSourceAndConverter( SourceAndConverter< ? > sourceAndConverter,
 			if ( imgLoader instanceof N5ImageLoader )
 			{
 				( ( N5ImageLoader ) imgLoader ).close();
-			} else if ( imgLoader instanceof N5OMEZarrImageLoader )
+			}
+			else if ( imgLoader instanceof N5OMEZarrImageLoader )
 			{
 				( ( N5OMEZarrImageLoader ) imgLoader ).close();
 			}
 		}
 
 		sourceNameToImgLoader.remove( sourceName );
+		sourceNameToSourceAndConverter.remove( sourceName );
 		SourceAndConverterServices.getSourceAndConverterService().remove( sourceAndConverter );
 	}
 
@@ -723,12 +727,7 @@ public synchronized String getImagePath(ImageSource source, ImageDataFormat imag
 
 	public void addTransformedSourceAndConverters( Map< String, SourceAndConverter< ? > > sourceNameToSourceAndConverters )
 	{
-		sourceNameToTransformedSourceAndConverter.putAll( sourceNameToSourceAndConverters );
-	}
-
-	public SourceAndConverter< ? > getTransformedSourceAndConverter( String sourceName )
-	{
-		return sourceNameToTransformedSourceAndConverter.get( sourceName );
+		sourceNameToSourceAndConverter.putAll( sourceNameToSourceAndConverters );
 	}
 
 	public ArrayList< String > getProjectCommands()
diff --git a/src/main/java/org/embl/mobie/viewer/annotate/AnnotatedMaskCreator.java b/src/main/java/org/embl/mobie/viewer/annotate/AnnotatedMaskCreator.java
index c65fd8381..0ba160dc2 100644
--- a/src/main/java/org/embl/mobie/viewer/annotate/AnnotatedMaskCreator.java
+++ b/src/main/java/org/embl/mobie/viewer/annotate/AnnotatedMaskCreator.java
@@ -43,9 +43,9 @@ private void createAnnotatedMasks()
 			final List< ? extends Source< ? > > sources = annotationIdToSources.get( annotationId ).stream().map( name -> sourceAndConverterSupplier.apply( name ).getSpimSource() ).collect( Collectors.toList() );
 
 			final RealMaskRealInterval mask = MoBIEHelper.unionRealMask( sources );
-			System.out.println( annotationId );
-			System.out.println( sources.size() );
-			System.out.println( Arrays.toString( mask.minAsDoubleArray() ));
+			//System.out.println( annotationId );
+			//System.out.println( sources.size() );
+			//System.out.println( Arrays.toString( mask.minAsDoubleArray() ));
 
 			annotatedMaskTableRows.add(
 					new DefaultAnnotatedMaskTableRow(
diff --git a/src/main/java/org/embl/mobie/viewer/bdv/view/AnnotationSliceView.java b/src/main/java/org/embl/mobie/viewer/bdv/view/AnnotationSliceView.java
index 37195ac13..a0bdbebe3 100644
--- a/src/main/java/org/embl/mobie/viewer/bdv/view/AnnotationSliceView.java
+++ b/src/main/java/org/embl/mobie/viewer/bdv/view/AnnotationSliceView.java
@@ -31,9 +31,7 @@ public AnnotationSliceView( MoBIE moBIE, AnnotationDisplay< T > display )
 	protected void show( SourceAndConverter< ? > sourceAndConverter )
 	{
 		configureLabelRendering( sourceAndConverter );
-
 		display.sliceViewer.show( sourceAndConverter, display );
-
 		getSliceViewer().getBdvHandle().getViewerPanel().addTimePointListener( ( TimePointListener ) sourceAndConverter.getConverter() );
 	}
 
diff --git a/src/main/java/org/embl/mobie/viewer/bdv/view/ImageSliceView.java b/src/main/java/org/embl/mobie/viewer/bdv/view/ImageSliceView.java
index e0728972d..8e53ac0e4 100644
--- a/src/main/java/org/embl/mobie/viewer/bdv/view/ImageSliceView.java
+++ b/src/main/java/org/embl/mobie/viewer/bdv/view/ImageSliceView.java
@@ -39,7 +39,7 @@ private void show( )
 	{
 		Map< String, SourceAndConverter< ? > > sourceNameToSourceAndConverter = new HashMap<>();
 		for ( String name : display.getSources() ) {
-			sourceNameToSourceAndConverter.put( name, moBIE.getTransformedSourceAndConverter( name ) );
+			sourceNameToSourceAndConverter.put( name, moBIE.sourceNameToSourceAndConverter().get( name ) );
 		}
 
 		for ( String name : sourceNameToSourceAndConverter.keySet() )
diff --git a/src/main/java/org/embl/mobie/viewer/bdv/view/RegionSliceView.java b/src/main/java/org/embl/mobie/viewer/bdv/view/RegionSliceView.java
index 4618c8443..ba5f1a2bc 100644
--- a/src/main/java/org/embl/mobie/viewer/bdv/view/RegionSliceView.java
+++ b/src/main/java/org/embl/mobie/viewer/bdv/view/RegionSliceView.java
@@ -19,9 +19,9 @@ public RegionSliceView( MoBIE moBIE, RegionDisplay display )
 	{
 		super( moBIE, display );
 
-		final SourceAndConverter< IntType > sourceAndConverter = createSourceAndConverter();
+		final SourceAndConverter< IntType > regionSourceAndConverter = createSourceAndConverter();
 
-		display.sliceViewer.show( sourceAndConverter, display );
+		show( regionSourceAndConverter );
 	}
 
 	private SourceAndConverter< IntType > createSourceAndConverter()
diff --git a/src/main/java/org/embl/mobie/viewer/bdv/view/SegmentationSliceView.java b/src/main/java/org/embl/mobie/viewer/bdv/view/SegmentationSliceView.java
index 1fb99aa1f..7ecaae1a1 100644
--- a/src/main/java/org/embl/mobie/viewer/bdv/view/SegmentationSliceView.java
+++ b/src/main/java/org/embl/mobie/viewer/bdv/view/SegmentationSliceView.java
@@ -23,7 +23,7 @@ public SegmentationSliceView( MoBIE moBIE, SegmentationDisplay display )
 
 		for ( String name : display.getSources() )
 		{
-			final SourceAndConverter< ? > sourceAndConverter = moBIE.getTransformedSourceAndConverter( name );
+			final SourceAndConverter< ? > sourceAndConverter = moBIE.sourceNameToSourceAndConverter().get( name );
 
 			SourceAndConverter< ? > labelSourceAndConverter = asLabelSourceAndConverter( display, sourceAndConverter );
 
@@ -98,7 +98,7 @@ public synchronized void focusEvent( TableRowImageSegment selection, Object init
 	private void adaptPosition( double[] position, String sourceName )
 	{
 		// get source transform
-		final SourceAndConverter< ? > sourceAndConverter = moBIE.getTransformedSourceAndConverter( sourceName );
+		final SourceAndConverter< ? > sourceAndConverter = moBIE.sourceNameToSourceAndConverter().get( sourceName );
 		AffineTransform3D sourceTransform = new AffineTransform3D();
 		sourceAndConverter.getSpimSource().getSourceTransform( 0,0, sourceTransform );
 
diff --git a/src/main/java/org/embl/mobie/viewer/bdv/view/SliceViewer.java b/src/main/java/org/embl/mobie/viewer/bdv/view/SliceViewer.java
index d79d1fe37..5034d556a 100644
--- a/src/main/java/org/embl/mobie/viewer/bdv/view/SliceViewer.java
+++ b/src/main/java/org/embl/mobie/viewer/bdv/view/SliceViewer.java
@@ -2,6 +2,7 @@
 
 import bdv.util.BdvHandle;
 import bdv.viewer.SourceAndConverter;
+import org.embl.mobie.viewer.MoBIE;
 import org.embl.mobie.viewer.bdv.MobieBdvSupplier;
 import org.embl.mobie.viewer.bdv.MobieSerializableBdvOptions;
 import org.embl.mobie.viewer.bdv.SourcesAtMousePositionSupplier;
@@ -38,12 +39,12 @@
 public class SliceViewer
 {
 	public static final String UNDO_SEGMENT_SELECTIONS = "Undo Segment Selections [ Ctrl Shift N ]";
-	public static final String CHANGE_RANDOM_COLOR_SEED = "Change Random Color Seed";
 	public static final String LOAD_ADDITIONAL_VIEWS = "Load Additional Views";
 	public static final String SAVE_CURRENT_SETTINGS_AS_VIEW = "Save Current View";
 	protected static final String FRAME_TITLE = "MoBIE - BigDataViewer";
 	private final SourceAndConverterBdvDisplayService sacDisplayService;
 	private BdvHandle bdvHandle;
+	private final MoBIE moBIE;
 	private final boolean is2D;
 	private final ViewManager viewManager;
 	private final int timepoints;
@@ -52,12 +53,13 @@ public class SliceViewer
 	private SourceAndConverterContextMenuClickBehaviour contextMenu;
 	private final SourceAndConverterService sacService;
 
-	public SliceViewer( boolean is2D, ViewManager viewManager, int timepoints, ArrayList< String > projectCommands )
+	public SliceViewer( MoBIE moBIE, boolean is2D, int timepoints )
 	{
+		this.moBIE = moBIE;
 		this.is2D = is2D;
-		this.viewManager = viewManager;
+		this.viewManager = moBIE.getViewManager();
 		this.timepoints = timepoints;
-		this.projectCommands = projectCommands;
+		this.projectCommands = moBIE.getProjectCommands();
 
 		sacService = ( SourceAndConverterService ) SourceAndConverterServices.getSourceAndConverterService();
 		sacDisplayService = SourceAndConverterServices.getBdvDisplayService();
@@ -171,6 +173,8 @@ public void show( SourceAndConverter< ? > sourceAndConverter, AbstractSourceDisp
 	{
 		// register
 		SourceAndConverterServices.getSourceAndConverterService().register( sourceAndConverter );
+		display.sourceNameToSourceAndConverter.put( sourceAndConverter.getSpimSource().getName(), sourceAndConverter );
+		moBIE.sourceNameToSourceAndConverter().put( sourceAndConverter.getSpimSource().getName(), sourceAndConverter );
 
 		// blending mode
 		SourceAndConverterServices.getSourceAndConverterService().setMetadata( sourceAndConverter, BlendingMode.BLENDING_MODE, display.getBlendingMode() );
@@ -180,6 +184,6 @@ public void show( SourceAndConverter< ? > sourceAndConverter, AbstractSourceDisp
 
 		SourceAndConverterServices.getBdvDisplayService().show( bdvHandle, display.isVisible(), sourceAndConverter );
 
-		display.sourceNameToSourceAndConverter.put( sourceAndConverter.getSpimSource().getName(), sourceAndConverter );
+
 	}
 }
diff --git a/src/main/java/org/embl/mobie/viewer/display/RegionDisplay.java b/src/main/java/org/embl/mobie/viewer/display/RegionDisplay.java
index 3a489bd72..32f913e9a 100644
--- a/src/main/java/org/embl/mobie/viewer/display/RegionDisplay.java
+++ b/src/main/java/org/embl/mobie/viewer/display/RegionDisplay.java
@@ -56,8 +56,8 @@ public List< String > getSources()
 	// Needed for Gson
 	public RegionDisplay() {}
 
-	// TODO: Looks like we do not need it? Maybe for the interactive grid view?
-	public RegionDisplay( String name, double opacity, Map< String, List< String > > sources, String lut, String colorByColumn, Double[] valueLimits, List< String > selectedSegmentIds, boolean showScatterPlot, String[] scatterPlotAxes, List< String > tables )
+	// Needed for Gson
+	public RegionDisplay( String name, double opacity, Map< String, List< String > > sources, String lut, String colorByColumn, Double[] valueLimits, List< String > selectedSegmentIds, boolean showScatterPlot, String[] scatterPlotAxes, List< String > tables, boolean showAsBoundaries )
 	{
 		this.name = name;
 		this.opacity = opacity;
@@ -69,6 +69,7 @@ public RegionDisplay( String name, double opacity, Map< String, List< String > >
 		this.showScatterPlot = showScatterPlot;
 		this.scatterPlotAxes = scatterPlotAxes;
 		this.tables = tables;
+		this.showAsBoundaries = showAsBoundaries;
 	}
 
 	/**
diff --git a/src/main/java/org/embl/mobie/viewer/display/SegmentationDisplay.java b/src/main/java/org/embl/mobie/viewer/display/SegmentationDisplay.java
index d861d77bc..113704535 100644
--- a/src/main/java/org/embl/mobie/viewer/display/SegmentationDisplay.java
+++ b/src/main/java/org/embl/mobie/viewer/display/SegmentationDisplay.java
@@ -85,7 +85,7 @@ public SegmentationDisplay( SegmentationDisplay segmentationDisplay )
 
 		if ( segmentationDisplay.segmentsVolumeViewer != null )
 		{
-			this.showSelectedSegmentsIn3d = segmentationDisplay.segmentsVolumeViewer.getShowSegments();
+			this.showSelectedSegmentsIn3d = segmentationDisplay.segmentsVolumeViewer.isShowSegments();
 
 			double[] voxelSpacing = segmentationDisplay.segmentsVolumeViewer.getVoxelSpacing();
 			if ( voxelSpacing != null ) {
diff --git a/src/main/java/org/embl/mobie/viewer/ui/UserInterfaceHelper.java b/src/main/java/org/embl/mobie/viewer/ui/UserInterfaceHelper.java
index 87bfbe15c..5b6102169 100644
--- a/src/main/java/org/embl/mobie/viewer/ui/UserInterfaceHelper.java
+++ b/src/main/java/org/embl/mobie/viewer/ui/UserInterfaceHelper.java
@@ -460,7 +460,7 @@ private JPanel createRemoveAllViewsPanel( MoBIE moBIE )
 			{
 				new Thread( () ->
 				{
-					moBIE.getViewManager().removeAllSourceDisplays();
+					moBIE.getViewManager().removeAllSourceDisplays( true );
 				}).start();
 			} );
 		} );
diff --git a/src/main/java/org/embl/mobie/viewer/view/ViewManager.java b/src/main/java/org/embl/mobie/viewer/view/ViewManager.java
index 7225ad6da..1d51f8b42 100644
--- a/src/main/java/org/embl/mobie/viewer/view/ViewManager.java
+++ b/src/main/java/org/embl/mobie/viewer/view/ViewManager.java
@@ -69,7 +69,7 @@ public ViewManager( MoBIE moBIE, UserInterface userInterface, boolean is2D, int
 		this.userInterface = userInterface;
 		currentSourceDisplays = new ArrayList<>();
 		currentSourceTransformers = new ArrayList<>();
-		sliceViewer = new SliceViewer( is2D, this, timepoints, moBIE.getProjectCommands() );
+		sliceViewer = new SliceViewer( moBIE, is2D, timepoints );
 		universeManager = new UniverseManager();
 		additionalViewsLoader = new AdditionalViewsLoader( moBIE );
 		viewSaver = new ViewSaver( moBIE );
@@ -242,7 +242,7 @@ public synchronized void show( View view )
 	{
 		if ( view.isExclusive() )
 		{
-			removeAllSourceDisplays();
+			removeAllSourceDisplays( true );
 		}
 
 		openAndTransformSources( view );
@@ -348,7 +348,7 @@ else if ( sourceDisplay instanceof RegionDisplay )
 		currentSourceDisplays.add( sourceDisplay );
 	}
 
-	public synchronized void removeAllSourceDisplays()
+	public synchronized void removeAllSourceDisplays( boolean closeImgLoader )
 	{
 		// create a copy of the currently shown displays...
 		final ArrayList< SourceDisplay > currentSourceDisplays = new ArrayList<>( this.currentSourceDisplays ) ;
@@ -360,7 +360,7 @@ public synchronized void removeAllSourceDisplays()
 			// removes display from all viewers and
 			// also from the list of currently shown sourceDisplays
 			// also close all ImgLoaders to free the cache
-			removeSourceDisplay( sourceDisplay, true );
+			removeSourceDisplay( sourceDisplay, closeImgLoader );
 		}
 	}
 
@@ -572,7 +572,7 @@ public Collection< AnnotationDisplay > getAnnotatedRegionDisplays()
 
 	public void close()
 	{
-		removeAllSourceDisplays();
+		removeAllSourceDisplays( true );
 		sliceViewer.getBdvHandle().close();
 		universeManager.close();
 	}
diff --git a/src/main/java/org/embl/mobie/viewer/volume/SegmentsVolumeViewer.java b/src/main/java/org/embl/mobie/viewer/volume/SegmentsVolumeViewer.java
index 1f269bcba..37a729409 100644
--- a/src/main/java/org/embl/mobie/viewer/volume/SegmentsVolumeViewer.java
+++ b/src/main/java/org/embl/mobie/viewer/volume/SegmentsVolumeViewer.java
@@ -278,11 +278,11 @@ public void windowClosing( WindowEvent ev )
 		}
 	}
 
-	public boolean getShowSegments() {
+	public boolean isShowSegments() {
 		return showSegments;
 	}
 
-	private void setShowSegments(boolean b )
+	private void setShowSegments( boolean b )
 	{
 		this.showSegments = b;
 	}
@@ -451,7 +451,7 @@ public void coloringChanged()
 	@Override
 	public synchronized void selectionChanged()
 	{
-		if ( ! showSegments ) return;
+		if ( !showSegments ) return;
 
 		updateView( false );
 	}
@@ -459,7 +459,7 @@ public synchronized void selectionChanged()
 	@Override
 	public synchronized void focusEvent( S selection, Object initiator )
 	{
-		if ( ! showSegments ) return;
+		if ( !showSegments ) return;
 
 		if ( selection.timePoint() != currentTimePoint )
 		{
diff --git a/src/main/resources/gluegen-rt-natives-linux-amd64.jar b/src/main/resources/gluegen-rt-natives-linux-amd64.jar
new file mode 100644
index 000000000..826d6d6fa
Binary files /dev/null and b/src/main/resources/gluegen-rt-natives-linux-amd64.jar differ
diff --git a/src/main/resources/jogl-all-natives-linux-amd64.jar b/src/main/resources/jogl-all-natives-linux-amd64.jar
new file mode 100644
index 000000000..55953e236
Binary files /dev/null and b/src/main/resources/jogl-all-natives-linux-amd64.jar differ


Test patch:
diff --git a/src/test/java/commands/OpenOMEZARRCommand.java b/src/test/java/commands/OpenOMEZARRCommand.java
deleted file mode 100644
index 7b462e874..000000000
--- a/src/test/java/commands/OpenOMEZARRCommand.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package commands;
-
-import mpicbg.spim.data.SpimData;
-import org.embl.mobie.io.ome.zarr.openers.OMEZarrOpener;
-import org.embl.mobie.OMEZarrViewer;
-
-import java.io.IOException;
-
-public class OpenOMEZARRCommand
-{
-    private static void openAndShow( String filePath ) throws IOException
-    {
-        SpimData spimData = OMEZarrOpener.openFile( filePath );
-        final OMEZarrViewer viewer = new OMEZarrViewer( spimData );
-        viewer.show();
-    }
-
-    public static void main( String[] args )
-    {
-        try {
-            openAndShow( "/home/katerina/Documents/data/v0.3/zyx.ome.zarr" );
-        } catch ( IOException e ) {
-            e.printStackTrace();
-        }
-    }
-}
diff --git a/src/test/java/commands/OpenOMEZARRFromS3AdvancedCommand.java b/src/test/java/commands/OpenOMEZARRFromS3AdvancedCommand.java
deleted file mode 100644
index e1143359d..000000000
--- a/src/test/java/commands/OpenOMEZARRFromS3AdvancedCommand.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package commands;
-
-import net.imagej.ImageJ;
-
-import java.io.IOException;
-
-public class OpenOMEZARRFromS3AdvancedCommand
-{
-
-    public static void main( String[] args ) throws IOException
-    {
-        final ImageJ imageJ = new ImageJ();
-        imageJ.ui().showUI();
-
-//		OMEZarrS3Reader.setLogChunkLoading( true );
-//
-//		// SpimData spimData = OMEZarrS3Reader.readURL( "https://s3.embl.de/i2k-2020/em-raw.ome.zarr" );
-//		SpimData spimData = OMEZarrS3Reader.readURL( "https://s3.embassy.ebi.ac.uk/idr/zarr/v0.1/4495402.zarr" );
-//
-//		final OMEZarrViewer viewer = new OMEZarrViewer( spimData );
-//		viewer.show();
-    }
-}
diff --git a/src/test/java/commands/OpenOMEZARRFromS3Command.java b/src/test/java/commands/OpenOMEZARRFromS3Command.java
deleted file mode 100644
index df3308631..000000000
--- a/src/test/java/commands/OpenOMEZARRFromS3Command.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package commands;
-
-import mpicbg.spim.data.SpimData;
-import org.embl.mobie.io.ome.zarr.openers.OMEZarrS3Opener;
-import org.embl.mobie.OMEZarrViewer;
-
-import java.io.IOException;
-
-public class OpenOMEZARRFromS3Command
-{
-    protected static void openAndShow( String s3URL ) throws IOException
-    {
-        SpimData spimData = OMEZarrS3Opener.readURL( s3URL );
-        final OMEZarrViewer viewer = new OMEZarrViewer( spimData );
-        viewer.show();
-    }
-
-    public static void main( String[] args ) throws IOException
-    {
-        try {
-            openAndShow( "https://s3.embl.de/i2k-2020/em-raw.ome.zarr" );
-        } catch ( IOException e ) {
-            e.printStackTrace();
-        }
-    }
-}
diff --git a/src/test/java/debug/Debug3DImageUniverse.java b/src/test/java/debug/Debug3DImageUniverse.java
deleted file mode 100644
index 7f8f63b08..000000000
--- a/src/test/java/debug/Debug3DImageUniverse.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package debug;
-
-import ij3d.Image3DUniverse;
-
-public class Debug3DImageUniverse
-{
-	public static void main( String[] args )
-	{
-		Image3DUniverse universe = new Image3DUniverse();
-		universe.show();
-	}
-}
diff --git a/src/test/java/debug/DebugCorruptChunkLoadingFromN5.java b/src/test/java/debug/DebugCorruptChunkLoadingFromN5.java
deleted file mode 100644
index 7a65eb906..000000000
--- a/src/test/java/debug/DebugCorruptChunkLoadingFromN5.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package debug;
-
-import bdv.util.BdvFunctions;
-import mpicbg.spim.data.SpimData;
-import mpicbg.spim.data.SpimDataException;
-import mpicbg.spim.data.XmlIoSpimData;
-import net.imagej.ImageJ;
-
-public class DebugCorruptChunkLoadingFromN5
-{
-	public static void main( String[] args ) throws SpimDataException
-	{
-		new ImageJ(  ).ui().showUI();
-		final SpimData spimData = new XmlIoSpimData().load( "/Users/tischer/Desktop/test_data_corruted_s3.xml" );
-		BdvFunctions.show( spimData );
-	}
-}
diff --git a/src/test/java/debug/DebugMultiThreadedIOCovidIF.java b/src/test/java/debug/DebugMultiThreadedIOCovidIF.java
deleted file mode 100644
index b8eb7f197..000000000
--- a/src/test/java/debug/DebugMultiThreadedIOCovidIF.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package debug;
-
-import net.imagej.ImageJ;
-import org.embl.mobie.io.ImageDataFormat;
-import org.embl.mobie.viewer.MoBIE;
-import org.embl.mobie.viewer.MoBIESettings;
-import org.embl.mobie.viewer.MultiThreading;
-
-import java.io.IOException;
-
-public class DebugMultiThreadedIOCovidIF
-{
-	public static void main( String[] args )
-	{
-		final ImageJ imageJ = new ImageJ();
-		imageJ.ui().showUI();
-
-		try {
-			run();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-	}
-
-	private static void run() throws IOException
-	{
-		MultiThreading.setNumIoThreads( 16 );
-		new MoBIE( "https://github.com/mobie/covid-if-project", MoBIESettings.settings().gitProjectBranch( "main" ).imageDataFormat( ImageDataFormat.OmeZarrS3 ).view( "boundary-segment-test" ) ).close();
-		//"default_transform_grid_with_tables_with_segmentations_without_segmentation_tables"
-	}
-}
diff --git a/src/test/java/demo/DemoOpenOMEZARRFromS3WithCredentialsCommand.java b/src/test/java/develop/DemoOpenOMEZARRFromS3WithCredentialsCommand.java
similarity index 96%
rename from src/test/java/demo/DemoOpenOMEZARRFromS3WithCredentialsCommand.java
rename to src/test/java/develop/DemoOpenOMEZARRFromS3WithCredentialsCommand.java
index b7d8c338b..7b976d0c0 100644
--- a/src/test/java/demo/DemoOpenOMEZARRFromS3WithCredentialsCommand.java
+++ b/src/test/java/develop/DemoOpenOMEZARRFromS3WithCredentialsCommand.java
@@ -1,4 +1,4 @@
-package demo;
+package develop;
 
 import org.embl.mobie.viewer.command.OpenOMEZARRFromS3WithCredentialsCommand;
 
diff --git a/src/test/java/org/embl/mobie/viewer/MoBIEViewerTest.java b/src/test/java/org/embl/mobie/viewer/MoBIEViewerTest.java
new file mode 100644
index 000000000..30b8988eb
--- /dev/null
+++ b/src/test/java/org/embl/mobie/viewer/MoBIEViewerTest.java
@@ -0,0 +1,118 @@
+package org.embl.mobie.viewer;
+
+import bdv.viewer.SourceAndConverter;
+import net.imagej.ImageJ;
+import net.imagej.patcher.LegacyInjector;
+import org.embl.mobie.viewer.display.AnnotationDisplay;
+import org.embl.mobie.viewer.display.SegmentationDisplay;
+import org.embl.mobie.viewer.display.SourceDisplay;
+import org.embl.mobie.viewer.source.LabelSource;
+import org.embl.mobie.viewer.source.SourceHelper;
+import org.embl.mobie.viewer.view.View;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+public class MoBIEViewerTest
+{
+	static {
+		LegacyInjector.preinit();
+	}
+
+	private MoBIE moBIE;
+
+	@BeforeAll
+	public static void initIJ() throws IOException
+	{
+		final ImageJ imageJ = new ImageJ();
+		imageJ.ui().showUI();
+	}
+
+	@Test
+	public void testCLEMFigure2a() throws IOException
+	{
+		// Open
+		moBIE = new MoBIE( "https://github.com/mobie/clem-example-project", MoBIESettings.settings().view( "Figure2a" ) );
+
+		// Test
+		moBIE.sourceNameToSourceAndConverter().keySet().stream().forEach( s -> System.out.println( s ) );
+		final SourceAndConverter< ? > sourceAndConverter = moBIE.sourceNameToSourceAndConverter().get( "fluorescence-annotations" );
+		final LabelSource< ? > labelSource = SourceHelper.getLabelSource( sourceAndConverter );
+		final boolean showAsBoundaries = labelSource.isShowAsBoundaries();
+		assertTrue( showAsBoundaries );
+	}
+
+	@Test
+	public void testCovidIFDefault() throws IOException
+	{
+		moBIE = new MoBIE( "https://github.com/mobie/covid-if-project" );
+	}
+
+	@Test
+	public void testCellPublicationFigure2C() throws IOException
+	{
+		moBIE = new MoBIE( "https://github.com/mobie/platybrowser-datasets", MoBIESettings.settings().view( "Figure 2C: Muscle segmentation" ) );
+	}
+
+	//@Test
+	public void testSubmissionFigure1c() throws IOException
+	{
+		// Open
+		moBIE = new MoBIE( "https://github.com/mobie/platybrowser-datasets", MoBIESettings.settings().view( "Figure1c" ) );
+
+		// The second display should be of the segmented cells.
+		final List< SourceDisplay > displays = moBIE.getViewManager().getCurrentSourceDisplays();
+		final SegmentationDisplay segmentationDisplay = ( SegmentationDisplay ) displays.get( 1 );
+		System.out.println( segmentationDisplay.getName() );
+
+		// Both scatter plot and segment volume rendering
+		// should be enabled.
+		final boolean scatterPlotViewerVisible = segmentationDisplay.scatterPlotViewer.isVisible();
+		final boolean volumeViewerShowSegments = segmentationDisplay.segmentsVolumeViewer.isShowSegments();
+		assertTrue( scatterPlotViewerVisible );
+		assertTrue( volumeViewerShowSegments );
+	}
+
+	@Test
+	public void testAllOnS3() throws IOException
+	{
+		// This is special as it does not go via github but
+		// all information is on S3
+		moBIE = new MoBIE("https://s3.embl.de/plankton-fibsem", MoBIESettings.settings());
+
+		// Check all views
+		final Map< String, View > views = moBIE.getViews();
+		for ( View view : views.values() )
+		{
+			moBIE.getViewManager().show( view );
+		}
+	}
+
+	@Test
+	public void testZebraFishSmallGridView() throws IOException
+	{
+		// Open
+		moBIE = new MoBIE( "https://github.com/mobie/zebrafish-lm-datasets", MoBIESettings.settings().gitProjectBranch( "main" ).view( "small-grid-view" ) );
+
+		// Select some image segments
+		final AnnotationDisplay display = moBIE.getViewManager().getAnnotatedRegionDisplays().iterator().next();
+		display.selectionModel.setSelected( display.tableRows.get( 0 ), true );
+		display.selectionModel.focus( display.tableRows.get( 0 ), this );
+		display.selectionModel.setSelected( display.tableRows.get( 1 ), true );
+		display.selectionModel.focus( display.tableRows.get( 1 ), this );
+
+		// Show in 3D
+		(( SegmentationDisplay ) display).segmentsVolumeViewer.showSegments( true );
+	}
+
+	@AfterEach
+	public void closeMoBIE()
+	{
+		moBIE.close();
+	}
+}
diff --git a/src/test/java/run/RunOpenCustomBrowserCommand.java b/src/test/java/run/RunOpenCustomBrowserCommand.java
deleted file mode 100644
index 1f9787a41..000000000
--- a/src/test/java/run/RunOpenCustomBrowserCommand.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package run;
-
-import org.embl.mobie.viewer.command.OpenMoBIEProjectCommand;
-import net.imagej.ImageJ;
-
-public class RunOpenCustomBrowserCommand
-{
-	public static void main(final String... args)
-	{
-		final ImageJ ij = new ImageJ();
-		ij.ui().showUI();
-
-		ij.command().run( OpenMoBIEProjectCommand.class, true );
-	}
-}
diff --git a/src/test/java/run/RunOpenPlatyBrowserCommand.java b/src/test/java/run/RunOpenPlatyBrowserCommand.java
deleted file mode 100644
index efb3ded45..000000000
--- a/src/test/java/run/RunOpenPlatyBrowserCommand.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package run;
-
-import org.embl.mobie.viewer.command.OpenPlatyBrowserCommand;
-import net.imagej.ImageJ;
-
-public class RunOpenPlatyBrowserCommand
-{
-	public static void main(final String... args)
-	{
-		final ImageJ ij = new ImageJ();
-		ij.ui().showUI();
-
-		ij.command().run( OpenPlatyBrowserCommand.class, true );
-	}
-}
diff --git a/src/test/java/tests/TestCovidIF.java b/src/test/java/tests/TestCovidIF.java
deleted file mode 100644
index 54f0f122f..000000000
--- a/src/test/java/tests/TestCovidIF.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package tests;
-
-import java.io.IOException;
-
-public class TestCovidIF
-{
-	public static void main( String[] args ) throws IOException
-	{
-		new TestCovidIF().test();
-	}
-
-	//@Test
-	public void test() throws IOException
-	{
-		// TODO: Bug loading the multi-scales
-//		final ImageJ imageJ = new ImageJ();
-//		imageJ.ui().showUI();
-//		final MoBIE moBIE = new MoBIE( "https://github.com/mobie/covid-if-project", MoBIESettings.settings().gitProjectBranch( "main" ).imageDataFormat( ImageDataFormat.OmeZarr ) );
-	}
-}
diff --git a/src/test/java/tests/TestOpenAdvancedProject.java b/src/test/java/tests/TestOpenAdvancedProject.java
deleted file mode 100644
index a11feb1eb..000000000
--- a/src/test/java/tests/TestOpenAdvancedProject.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package tests;
-
-import net.imagej.ImageJ;
-import org.embl.mobie.io.ImageDataFormat;
-import org.embl.mobie.viewer.MoBIE;
-import org.embl.mobie.viewer.MoBIESettings;
-
-import java.io.IOException;
-
-public class TestOpenAdvancedProject
-{
-	// TODO: Make a proper test from this code
-	public static void main(final String... args)
-	{
-		final ImageJ ij = new ImageJ();
-		ij.ui().showUI();
-
-		/**
-		 * Project location (github or local): "https://github.com/mobie/platybrowser-datasets"
-		 * Project branch (for github): "xray"
-		 * Load image data from: choice: local
-		 * Image data root path (for local): "/g/arendt/EM_6dpf_segmentation/platy-browser-data"
-		 * Table data location (github or local): "https://github.com/mobie/platy-browser-data"
-		 * Table data branch (for github): "xray"
-		 */
-
-		try {
-			new MoBIE(
-					"https://github.com/mobie/platybrowser-datasets",
-					MoBIESettings.settings()
-							.gitProjectBranch( "xray" )
-							.imageDataFormat( ImageDataFormat.BdvN5 )
-							.imageDataLocation( "/g/arendt/EM_6dpf_segmentation/platy-browser-data" )
-							.tableDataLocation( "https://github.com/mobie/platy-browser-data" )
-							.gitTablesBranch( "xray" ) );
-		} catch ( IOException e) {
-			e.printStackTrace();
-		}
-	}
-}
diff --git a/src/test/java/tests/TestRemotePlanktonS3.java b/src/test/java/tests/TestRemotePlanktonS3.java
deleted file mode 100644
index 01bf845b6..000000000
--- a/src/test/java/tests/TestRemotePlanktonS3.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package tests;
-
-import net.imagej.ImageJ;
-import org.embl.mobie.viewer.MoBIE;
-import org.embl.mobie.viewer.MoBIESettings;
-import org.embl.mobie.viewer.view.View;
-import org.junit.jupiter.api.Test;
-
-import java.io.IOException;
-import java.util.Map;
-
-public class TestRemotePlanktonS3
-{
-	public static void main( String[] args ) throws IOException
-	{
-		new TestRemotePlanktonS3().run();
-	}
-
-	@Test
-	public void run() throws IOException
-	{
-		final ImageJ imageJ = new ImageJ();
-		imageJ.ui().showUI();
-
-		// This is special as it does not go via github but
-		// all information is on S3
-		final MoBIE moBIE = new MoBIE("https://s3.embl.de/plankton-fibsem", MoBIESettings.settings());
-
-		// Check all views
-		final Map< String, View > views = moBIE.getViews();
-		for ( View view : views.values() )
-		{
-			moBIE.getViewManager().show( view );
-		}
-	}
-}
diff --git a/src/test/java/tests/TestRemoteZebrafish.java b/src/test/java/tests/TestRemoteZebrafish.java
deleted file mode 100644
index a3874a2b7..000000000
--- a/src/test/java/tests/TestRemoteZebrafish.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package tests;
-
-import net.imagej.ImageJ;
-import org.embl.mobie.io.ImageDataFormat;
-import org.embl.mobie.viewer.MoBIE;
-import org.embl.mobie.viewer.MoBIESettings;
-import org.embl.mobie.viewer.display.AnnotationDisplay;
-import org.embl.mobie.viewer.display.SegmentationDisplay;
-import org.embl.mobie.viewer.view.AdditionalViewsLoader;
-import org.junit.jupiter.api.Test;
-
-import javax.swing.*;
-import java.io.IOException;
-
-public class TestRemoteZebrafish
-{
-	public static void main( String[] args ) throws IOException
-	{
-		new TestRemoteZebrafish().testSmallGridView();
-		new TestRemoteZebrafish().testTransformedGridView();
-	}
-
-	@Test
-	public void testSmallGridView() throws IOException
-	{
-		final ImageJ imageJ = new ImageJ();
-		imageJ.ui().showUI();
-
-		final MoBIE moBIE = new MoBIE( "https://github.com/mobie/zebrafish-lm-datasets", MoBIESettings.settings().gitProjectBranch( "main" ).imageDataFormat( ImageDataFormat.BdvN5S3 ) );
-
-		moBIE.getViewManager().show( "small-grid-view" );
-
-		// select some image segments
-		final AnnotationDisplay display = moBIE.getViewManager().getAnnotatedRegionDisplays().iterator().next();
-		display.selectionModel.setSelected( display.tableRows.get( 0 ), true );
-		display.selectionModel.focus( display.tableRows.get( 0 ), this );
-		display.selectionModel.setSelected( display.tableRows.get( 1 ), true );
-		display.selectionModel.focus( display.tableRows.get( 1 ), this );
-
-		// show in 3D
-		new Thread( () -> { (( SegmentationDisplay ) display).segmentsVolumeViewer.showSegments( true ); } ).start();
-		//(( SegmentationDisplay ) display).segmentsVolumeViewer.showSegments( true );
-	}
-
-	@Test
-	public void testTransformedGridView() throws IOException
-	{
-		final ImageJ imageJ = new ImageJ();
-		imageJ.ui().showUI();
-		final MoBIE moBIE = new MoBIE( "https://github.com/mobie/zebrafish-lm-datasets", MoBIESettings.settings().gitProjectBranch( "main" ).imageDataFormat( ImageDataFormat.BdvN5S3 ) );
-
-		// TODO: does not show the sources
-		final AdditionalViewsLoader viewsLoader = new AdditionalViewsLoader( moBIE );
-		viewsLoader.loadViews( "https://raw.githubusercontent.com/mobie/zebrafish-lm-datasets/main/data/membrane/misc/views/test_views.json" );
-		moBIE.getViewManager().show( "test-transformed-grid" );
-
-		// select some image segments
-		final AnnotationDisplay display = moBIE.getViewManager().getAnnotatedRegionDisplays().iterator().next();
-		display.selectionModel.setSelected( display.tableRows.get( 0 ), true );
-		display.selectionModel.focus( display.tableRows.get( 0 ), this );
-	}
-}
diff --git a/src/test/java/create/CreateRafaelProject.java b/src/test/java/users/rafael/CreateRafaelProject.java
similarity index 99%
rename from src/test/java/create/CreateRafaelProject.java
rename to src/test/java/users/rafael/CreateRafaelProject.java
index d7f806ce5..cbc38f8e7 100644
--- a/src/test/java/create/CreateRafaelProject.java
+++ b/src/test/java/users/rafael/CreateRafaelProject.java
@@ -1,4 +1,4 @@
-package create;
+package users.rafael;
 
 import ij.IJ;
 import ij.ImagePlus;