From 5ec5380c4310fdbc75b4fd0836bf65a1c5be1af5 Mon Sep 17 00:00:00 2001 From: Matthias Arzt <arzt@mpi-cbg.de> Date: Fri, 4 Sep 2020 16:54:40 +0200 Subject: [PATCH] BdvDefaultCards: fix memory leak Using KeybordFocusManager.addPropertyChangeListener(...) adds a permanent listener, that want be garbage collected until it is removed. The listener in BdvDefaultCards now uses weak references and removes itself if no longer needed. --- src/main/java/bdv/ui/BdvDefaultCards.java | 121 ++++++++++++++-------- 1 file changed, 78 insertions(+), 43 deletions(-) diff --git a/src/main/java/bdv/ui/BdvDefaultCards.java b/src/main/java/bdv/ui/BdvDefaultCards.java index f0d1ab1c..3bbc9c57 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; @@ -104,64 +105,98 @@ public class BdvDefaultCards 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 currentKeyboardFocusManager; + + 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( JPanel tablePanel, SourceTable table, JPanel treePanel, 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 ); + currentKeyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + currentKeyboardFocusManager.addPropertyChangeListener( "focusOwner", this ); + } - void focusTable( boolean focus ) + void focusTable( final boolean focus ) + { + if ( focus != tableFocused ) { - if ( focus != tableFocused ) - { - tableFocused = focus; + tableFocused = focus; + 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; + SourceGroupTree tree = this.tree.get(); + if ( tree != null ) tree.setSelectionBackground( focus ); - } + } + } + + @Override + public void propertyChange( final PropertyChangeEvent evt ) + { + if ( tablePanel.get() == null && treePanel.get() == null ) + { + currentKeyboardFocusManager.removePropertyChangeListener( "focusOwner", this ); + return; } - @Override - public void propertyChange( final PropertyChangeEvent evt ) + if ( evt.getNewValue() instanceof JComponent ) { - if ( evt.getNewValue() instanceof JComponent ) + 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 ) + Container parent = component.getParent(); + if ( !( parent instanceof JComponent ) ) + break; + + if ( component == treePanel.get() ) + { + focusTable( false ); + focusTree( true ); + return; + } + else if ( component == tablePanel.get() ) { - 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 ) ); + } } } -- GitLab