diff --git a/src/main/java/bdv/tools/HelpDialog.java b/src/main/java/bdv/tools/HelpDialog.java index e056c40bd56ef990baa1a3c6224ae8005168f59a..61edcb7ed41fdb417c49f216def1d1f7fa9b5a6b 100644 --- a/src/main/java/bdv/tools/HelpDialog.java +++ b/src/main/java/bdv/tools/HelpDialog.java @@ -28,6 +28,8 @@ */ package bdv.tools; +import bdv.util.DelayedPackDialog; + import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Frame; @@ -42,14 +44,12 @@ import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.InputMap; import javax.swing.JComponent; -import javax.swing.JDialog; import javax.swing.JEditorPane; import javax.swing.JScrollPane; import javax.swing.KeyStroke; import javax.swing.ScrollPaneConstants; -import javax.swing.WindowConstants; -public class HelpDialog extends JDialog +public class HelpDialog extends DelayedPackDialog { private static final long serialVersionUID = 1L; @@ -100,7 +100,6 @@ public class HelpDialog extends JDialog am.put( hideKey, hideAction ); pack(); - setDefaultCloseOperation( WindowConstants.HIDE_ON_CLOSE ); } catch ( final IOException e ) { diff --git a/src/main/java/bdv/tools/RecordMaxProjectionDialog.java b/src/main/java/bdv/tools/RecordMaxProjectionDialog.java index d2b076638596892417775eb2879c09fcd123ee0e..3ec543035640a7494229a28b3e862ba33cc40d46 100644 --- a/src/main/java/bdv/tools/RecordMaxProjectionDialog.java +++ b/src/main/java/bdv/tools/RecordMaxProjectionDialog.java @@ -30,6 +30,7 @@ package bdv.tools; import bdv.cache.CacheControl; import bdv.export.ProgressWriter; +import bdv.util.DelayedPackDialog; import bdv.util.Prefs; import bdv.viewer.BasicViewerState; import bdv.viewer.ViewerPanel; @@ -56,7 +57,6 @@ import javax.swing.BoxLayout; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComponent; -import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JPanel; @@ -64,7 +64,6 @@ import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SpinnerNumberModel; -import javax.swing.WindowConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.imglib2.Cursor; @@ -77,7 +76,7 @@ import bdv.viewer.OverlayRenderer; import bdv.viewer.render.RenderTarget; import net.imglib2.util.LinAlgHelpers; -public class RecordMaxProjectionDialog extends JDialog implements OverlayRenderer +public class RecordMaxProjectionDialog extends DelayedPackDialog implements OverlayRenderer { private static final long serialVersionUID = 1L; @@ -275,7 +274,6 @@ public class RecordMaxProjectionDialog extends JDialog implements OverlayRendere am.put( hideKey, hideAction ); pack(); - setDefaultCloseOperation( WindowConstants.HIDE_ON_CLOSE ); } /** diff --git a/src/main/java/bdv/tools/RecordMovieDialog.java b/src/main/java/bdv/tools/RecordMovieDialog.java index 9ae851aa1bcd269c953521ebcd1ff63f0987ca5c..cf35bcbd141638108ea1cde6d74bec026dd63084 100644 --- a/src/main/java/bdv/tools/RecordMovieDialog.java +++ b/src/main/java/bdv/tools/RecordMovieDialog.java @@ -30,6 +30,7 @@ package bdv.tools; import bdv.cache.CacheControl; import bdv.export.ProgressWriter; +import bdv.util.DelayedPackDialog; import bdv.util.Prefs; import bdv.viewer.BasicViewerState; import bdv.viewer.ViewerPanel; @@ -55,7 +56,6 @@ import javax.swing.BoxLayout; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComponent; -import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JPanel; @@ -63,14 +63,13 @@ import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SpinnerNumberModel; -import javax.swing.WindowConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.imglib2.realtransform.AffineTransform3D; import bdv.viewer.OverlayRenderer; import bdv.viewer.render.RenderTarget; -public class RecordMovieDialog extends JDialog implements OverlayRenderer +public class RecordMovieDialog extends DelayedPackDialog implements OverlayRenderer { private static final long serialVersionUID = 1L; @@ -248,7 +247,6 @@ public class RecordMovieDialog extends JDialog implements OverlayRenderer am.put( hideKey, hideAction ); pack(); - setDefaultCloseOperation( WindowConstants.HIDE_ON_CLOSE ); } public void recordMovie( final int width, final int height, final int minTimepointIndex, final int maxTimepointIndex, final File dir ) throws IOException diff --git a/src/main/java/bdv/tools/VisibilityAndGroupingDialog.java b/src/main/java/bdv/tools/VisibilityAndGroupingDialog.java index b4a42dca5980fff34b6b93abacda8e8eb0ad09f1..b1da27e26f79a5bd9cfe80c2da58c2047b44cbee 100644 --- a/src/main/java/bdv/tools/VisibilityAndGroupingDialog.java +++ b/src/main/java/bdv/tools/VisibilityAndGroupingDialog.java @@ -28,6 +28,7 @@ */ package bdv.tools; +import bdv.util.DelayedPackDialog; import bdv.viewer.SourceAndConverter; import bdv.viewer.ViewerState; import bdv.viewer.VisibilityAndGrouping; @@ -61,19 +62,17 @@ import javax.swing.ButtonGroup; import javax.swing.InputMap; import javax.swing.JCheckBox; import javax.swing.JComponent; -import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; -import javax.swing.WindowConstants; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @Deprecated -public class VisibilityAndGroupingDialog extends JDialog +public class VisibilityAndGroupingDialog extends DelayedPackDialog { private static final long serialVersionUID = 1L; @@ -117,7 +116,7 @@ public class VisibilityAndGroupingDialog extends JDialog content.add( visibilityPanel ); content.add( groupingPanel ); content.add( modePanel ); - getContentPane().add( content, BorderLayout.NORTH ); + add( content, BorderLayout.NORTH ); final ActionMap am = getRootPane().getActionMap(); final InputMap im = getRootPane().getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); @@ -147,7 +146,6 @@ public class VisibilityAndGroupingDialog extends JDialog } ); pack(); - setDefaultCloseOperation( WindowConstants.HIDE_ON_CLOSE ); } public void update() diff --git a/src/main/java/bdv/tools/brightness/BrightnessDialog.java b/src/main/java/bdv/tools/brightness/BrightnessDialog.java index 1e71f960cdaec7ba438f14de6c7fe35903ae15c1..ce98337f48a7fe79259fc397cb4b68e5892fb93e 100644 --- a/src/main/java/bdv/tools/brightness/BrightnessDialog.java +++ b/src/main/java/bdv/tools/brightness/BrightnessDialog.java @@ -60,11 +60,11 @@ import javax.swing.JSpinner; import javax.swing.KeyStroke; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; -import javax.swing.WindowConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import bdv.util.InvokeOnEDT; +import bdv.util.DelayedPackDialog; import mpicbg.spim.data.generic.sequence.BasicViewSetup; import net.imglib2.type.numeric.ARGBType; @@ -75,7 +75,7 @@ import net.imglib2.type.numeric.ARGBType; * @author Tobias Pietzsch <tobias.pietzsch@gmail.com> */ @Deprecated -public class BrightnessDialog extends JDialog +public class BrightnessDialog extends DelayedPackDialog { public BrightnessDialog( final Frame owner, final SetupAssignments setupAssignments ) { @@ -148,7 +148,6 @@ public class BrightnessDialog extends JDialog } ); pack(); - setDefaultCloseOperation( WindowConstants.HIDE_ON_CLOSE ); } public static class ColorsPanel extends JPanel diff --git a/src/main/java/bdv/ui/BdvDefaultCards.java b/src/main/java/bdv/ui/BdvDefaultCards.java index f0d1ab1c6b13201c9440b48b0e3629f08a04b5d4..403dd1fcf45d9d2751da5347a4c0a3332ca04301 100644 --- a/src/main/java/bdv/ui/BdvDefaultCards.java +++ b/src/main/java/bdv/ui/BdvDefaultCards.java @@ -42,6 +42,7 @@ import java.awt.Insets; import java.awt.KeyboardFocusManager; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.lang.ref.WeakReference; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -85,7 +86,7 @@ public class BdvDefaultCards tablePanel.setPreferredSize( new Dimension( 300, 245 ) ); // -- Groups tree -- - SourceGroupTree tree = new SourceGroupTree( state, viewer.getOptionValues().getInputTriggerConfig() ); + final SourceGroupTree tree = new SourceGroupTree( state, viewer.getOptionValues().getInputTriggerConfig() ); // tree.setPreferredSize( new Dimension( 300, 200 ) ); tree.setVisibleRowCount( 10 ); tree.setEditable( true ); @@ -103,65 +104,95 @@ public class BdvDefaultCards treePanel.add( editPanelTree, BorderLayout.SOUTH ); treePanel.setPreferredSize( new Dimension( 300, 225 ) ); - // -- handle focus -- - KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener( "focusOwner", new PropertyChangeListener() + new FocusListener( tablePanel, table, treePanel, tree ); + + cards.addCard( DEFAULT_VIEWERMODES_CARD, "Display Modes", new DisplaySettingsPanel( viewer.state() ), true, new Insets( 0, 4, 4, 0 ) ); + cards.addCard( DEFAULT_SOURCES_CARD, "Sources", tablePanel, true, new Insets( 0, 4, 0, 0 ) ); + cards.addCard( DEFAULT_SOURCEGROUPS_CARD, "Groups", treePanel, true, new Insets( 0, 4, 0, 0 ) ); + } + + private static class FocusListener implements PropertyChangeListener + { + private final KeyboardFocusManager keyboardFocusManager; + + private final WeakReference< JPanel > tablePanel; + private final WeakReference< SourceTable > table; + private final WeakReference< JPanel > treePanel; + private final WeakReference< SourceGroupTree > tree; + + static final int MAX_DEPTH = 8; + boolean tableFocused; + boolean treeFocused; + + FocusListener( final JPanel tablePanel, final SourceTable table, final JPanel treePanel, final SourceGroupTree tree ) { - static final int MAX_DEPTH = 8; - boolean tableFocused; - boolean treeFocused; + this.tablePanel = new WeakReference<>( tablePanel ); + this.table = new WeakReference<>( table ); + this.treePanel = new WeakReference<>( treePanel ); + this.tree = new WeakReference<>( tree ); + + keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + keyboardFocusManager.addPropertyChangeListener( "focusOwner", this ); + } - void focusTable( boolean focus ) + void focusTable( final boolean focus ) + { + if ( focus != tableFocused ) { - if ( focus != tableFocused ) - { - tableFocused = focus; + tableFocused = focus; + final SourceTable table = this.table.get(); + if ( table != null ) table.setSelectionBackground( focus ); - } } + } - void focusTree( boolean focus ) + void focusTree( final boolean focus ) + { + if ( focus != treeFocused ) { - if ( focus != treeFocused ) - { - treeFocused = focus; + treeFocused = focus; + final SourceGroupTree tree = this.tree.get(); + if ( tree != null ) tree.setSelectionBackground( focus ); - } + } + } + + @Override + public void propertyChange( final PropertyChangeEvent evt ) + { + final JPanel tablePanel = this.tablePanel.get(); + final JPanel treePanel = this.treePanel.get(); + if ( tablePanel == null && treePanel == null ) + { + keyboardFocusManager.removePropertyChangeListener( "focusOwner", this ); + return; } - @Override - public void propertyChange( final PropertyChangeEvent evt ) + if ( evt.getNewValue() instanceof JComponent ) { - if ( evt.getNewValue() instanceof JComponent ) + final JComponent component = ( JComponent ) evt.getNewValue(); + for ( int i = 0; i < MAX_DEPTH; ++i ) { - JComponent component = ( JComponent ) evt.getNewValue(); - for ( int i = 0; i < MAX_DEPTH; ++i ) + final Container parent = component.getParent(); + if ( !( parent instanceof JComponent ) ) + break; + + if ( component == treePanel ) + { + focusTable( false ); + focusTree( true ); + return; + } + else if ( component == tablePanel ) { - Container parent = component.getParent(); - if ( ! ( parent instanceof JComponent ) ) - break; - - component = ( JComponent ) parent; - if ( component == treePanel ) - { - focusTable( false ); - focusTree( true ); - return; - } - else if ( component == tablePanel ) - { - focusTable( true ); - focusTree( false ); - return; - } + focusTable( true ); + focusTree( false ); + return; } - focusTable( false ); - focusTree( false ); } + focusTable( false ); + focusTree( false ); } - } ); - - cards.addCard( DEFAULT_VIEWERMODES_CARD, "Display Modes", new DisplaySettingsPanel( viewer.state() ), true, new Insets( 0, 4, 4, 0 ) ); - cards.addCard( DEFAULT_SOURCES_CARD, "Sources", tablePanel, true, new Insets( 0, 4, 0, 0 ) ); - cards.addCard( DEFAULT_SOURCEGROUPS_CARD, "Groups", treePanel, true, new Insets( 0, 4, 0, 0 ) ); + } } } diff --git a/src/main/java/bdv/util/DelayedPackDialog.java b/src/main/java/bdv/util/DelayedPackDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..3d3d178758cbb8635f8df5488f2e473366da556a --- /dev/null +++ b/src/main/java/bdv/util/DelayedPackDialog.java @@ -0,0 +1,40 @@ +package bdv.util; + +import javax.swing.*; +import java.awt.*; + +/** + * A {@code JDialog} that delays {@code pack()} calls until the dialog is made visible. + */ +public class DelayedPackDialog extends JDialog +{ + private volatile boolean packIsPending = false; + + public DelayedPackDialog( Frame owner, String title, boolean modal ) + { + super( owner, title, modal ); + } + + @Override + public void pack() + { + if ( isVisible() ) + { + packIsPending = false; + super.pack(); + } + else + packIsPending = true; + } + + @Override + public void setVisible( boolean visible ) + { + if ( visible && packIsPending ) + { + packIsPending = false; + super.pack(); + } + super.setVisible( visible ); + } +} diff --git a/src/main/java/bdv/viewer/ViewerPanel.java b/src/main/java/bdv/viewer/ViewerPanel.java index 612592832ad6f0b45712c57da4e6b5b673e28cbb..39bc9a54847fe633dd6451fd708e4ffc58bda556 100644 --- a/src/main/java/bdv/viewer/ViewerPanel.java +++ b/src/main/java/bdv/viewer/ViewerPanel.java @@ -260,7 +260,7 @@ public class ViewerPanel extends JPanel implements OverlayRenderer, PainterThrea renderingExecutorService = Executors.newFixedThreadPool( options.getNumRenderingThreads(), - new RenderThreadFactory() ); + new RenderThreadFactory( threadGroup ) ); imageRenderer = new MultiResolutionRenderer( renderTarget, painterThread, options.getScreenScales(), @@ -1153,14 +1153,21 @@ public class ViewerPanel extends JPanel implements OverlayRenderer, PainterThrea protected static final AtomicInteger panelNumber = new AtomicInteger( 1 ); - protected class RenderThreadFactory implements ThreadFactory + protected static class RenderThreadFactory implements ThreadFactory { + private final ThreadGroup threadGroup; + private final String threadNameFormat = String.format( "bdv-panel-%d-thread-%%d", panelNumber.getAndIncrement() ); private final AtomicInteger threadNumber = new AtomicInteger( 1 ); + protected RenderThreadFactory( final ThreadGroup threadGroup ) + { + this.threadGroup = threadGroup; + } + @Override public Thread newThread( final Runnable r ) {