2828 */
2929package org .mastodon .mamut .clustering .ui ;
3030
31- import net .miginfocom .swing .MigLayout ;
32- import org .mastodon .mamut .clustering .util .HierarchicalClusteringResult ;
33- import org .mastodon .mamut .model .Model ;
34- import org .mastodon .model .tag .TagSetModel ;
35- import org .mastodon .model .tag .TagSetStructure ;
36- import org .mastodon .ui .util .ExtensionFileFilter ;
37- import org .mastodon .ui .util .FileChooser ;
38- import org .scijava .prefs .PrefService ;
39- import org .slf4j .Logger ;
40- import org .slf4j .LoggerFactory ;
31+ import java .awt .Color ;
32+ import java .awt .Desktop ;
33+ import java .awt .Dimension ;
34+ import java .awt .Toolkit ;
35+ import java .awt .event .ActionListener ;
36+ import java .awt .event .WindowAdapter ;
37+ import java .awt .event .WindowEvent ;
38+ import java .io .File ;
39+ import java .io .IOException ;
40+ import java .lang .invoke .MethodHandles ;
41+ import java .util .ArrayList ;
42+ import java .util .List ;
43+ import java .util .function .ObjIntConsumer ;
4144
4245import javax .swing .BorderFactory ;
4346import javax .swing .JButton ;
5053import javax .swing .JPopupMenu ;
5154import javax .swing .JScrollPane ;
5255import javax .swing .WindowConstants ;
53- import java .awt .Color ;
54- import java .awt .Desktop ;
55- import java .awt .Dimension ;
56- import java .awt .Toolkit ;
57- import java .awt .event .ActionListener ;
58- import java .io .File ;
59- import java .io .IOException ;
60- import java .lang .invoke .MethodHandles ;
61- import java .util .ArrayList ;
62- import java .util .List ;
63- import java .util .function .ObjIntConsumer ;
56+
57+ import net .miginfocom .swing .MigLayout ;
58+
59+ import org .mastodon .mamut .clustering .util .HierarchicalClusteringResult ;
60+ import org .mastodon .mamut .model .Model ;
61+ import org .mastodon .model .tag .TagSetModel ;
62+ import org .mastodon .model .tag .TagSetStructure ;
63+ import org .mastodon .ui .util .ExtensionFileFilter ;
64+ import org .mastodon .ui .util .FileChooser ;
65+ import org .scijava .prefs .PrefService ;
66+ import org .slf4j .Logger ;
67+ import org .slf4j .LoggerFactory ;
6468
6569/**
6670 * A class that represents a UI view of a dendrogram.<br>
6771 * It encapsulates a {@link HierarchicalClusteringResult} object and a headline that write the parameters that were used for it.
6872 * @param <T> the type of the objects that are clustered
6973 */
70- public class DendrogramView < T > implements TagSetModel .TagSetModelListener
74+ public class DendrogramView < T > extends JFrame implements TagSetModel .TagSetModelListener
7175{
7276 private static final Logger logger = LoggerFactory .getLogger ( MethodHandles .lookup ().lookupClass () );
7377
@@ -93,8 +97,6 @@ public class DendrogramView< T > implements TagSetModel.TagSetModelListener
9397
9498 private final PrefService prefs ;
9599
96- private final JFrame frame ;
97-
98100 private final JPanel canvas = new JPanel ( new MigLayout ( "fill" ) );
99101
100102 private final JCheckBox showThresholdCheckBox = new JCheckBox ( "Show clustering threshold" );
@@ -126,21 +128,23 @@ public DendrogramView( final HierarchicalClusteringResult< T > hierarchicalClust
126128 final PrefService prefs ,
127129 final String projectName )
128130 {
131+ super ( "Hierarchical clustering of lineage trees" );
132+
129133 this .hierarchicalClusteringResult = hierarchicalClusteringResult ;
130134 this .model = model ;
131135 this .prefs = prefs ;
132136 this .projectName = projectName ;
133137
134- frame = new JFrame ( "Hierarchical clustering of lineage trees" );
135- frame .setDefaultCloseOperation ( WindowConstants .DISPOSE_ON_CLOSE );
138+
136139 int minHeight = 50 ;
137140 int initialDendrogramHeight = hierarchicalClusteringResult == null ? minHeight
138141 : ( hierarchicalClusteringResult .getObjectCount () ) * getDefaultFontHeight () + DendrogramPanel .DENDROGRAM_VERTICAL_OFFSET ;
139142 initialDendrogramHeight += 200 ;
140143 initialDendrogramHeight = Math .min ( initialDendrogramHeight , 1000 );
141- frame .setSize ( 1000 , initialDendrogramHeight );
142- frame .setLayout ( new MigLayout ( "insets 10, fill" ) );
143- frame .add ( canvas , "grow" );
144+ setSize ( 1000 , initialDendrogramHeight );
145+ setLayout ( new MigLayout ( "insets 10, fill" ) );
146+ add ( canvas , "grow" );
147+ setDefaultCloseOperation ( WindowConstants .DISPOSE_ON_CLOSE );
144148
145149 headlineLabel = new JLabel ( headline );
146150 dendrogramPanel = new DendrogramPanel <>( hierarchicalClusteringResult );
@@ -153,14 +157,6 @@ public DendrogramView( final HierarchicalClusteringResult< T > hierarchicalClust
153157 this .model .getTagSetModel ().listeners ().add ( this );
154158 }
155159
156- /**
157- * Sets the visibility of the frame to {@code true}.
158- */
159- public void show ()
160- {
161- frame .setVisible ( true );
162- }
163-
164160 public JPanel getCanvas ()
165161 {
166162 return canvas ;
@@ -214,8 +210,10 @@ private void initSettings()
214210
215211 private void initBehavior ()
216212 {
217- showThresholdCheckBox .addActionListener ( ignore -> showThreshold ( showThresholdCheckBox .isSelected () ) );
218- showMedianCheckBox .addActionListener ( ignore -> showMedian ( showMedianCheckBox .isSelected () ) );
213+ ActionListener showThresholdListener = ignore -> showThreshold ( showThresholdCheckBox .isSelected () );
214+ showThresholdCheckBox .addActionListener ( showThresholdListener );
215+ ActionListener showMedianListener = ignore -> showMedian ( showMedianCheckBox .isSelected () );
216+ showMedianCheckBox .addActionListener ( showMedianListener );
219217 ActionListener tagSetListener = event -> {
220218 selectedTagSet =
221219 tagSetComboBox .getSelectedItem () == null ? null : ( ( TagSetElement ) tagSetComboBox .getSelectedItem () ).tagSet ;
@@ -225,7 +223,24 @@ private void initBehavior()
225223 showTagLabelsCheckBox .addActionListener ( tagSetListener );
226224 tagSetComboBox .addActionListener ( tagSetListener );
227225 JPopupMenu popupMenu = new PopupMenu ();
228- menuButton .addActionListener ( event -> popupMenu .show ( menuButton , 0 , menuButton .getHeight () ) );
226+ ActionListener menuListener = event -> popupMenu .show ( menuButton , 0 , menuButton .getHeight () );
227+ menuButton .addActionListener ( menuListener );
228+
229+ addWindowListener ( new WindowAdapter ()
230+ {
231+ @ Override
232+ public void windowClosing ( WindowEvent windowEvent )
233+ {
234+ showThresholdCheckBox .removeActionListener ( showThresholdListener );
235+ showMedianCheckBox .removeActionListener ( showMedianListener );
236+ showRootLabelsCheckBox .removeActionListener ( tagSetListener );
237+ showTagLabelsCheckBox .removeActionListener ( tagSetListener );
238+ tagSetComboBox .removeActionListener ( tagSetListener );
239+ menuButton .removeActionListener ( menuListener );
240+ if ( null != model )
241+ model .getTagSetModel ().listeners ().remove ( DendrogramView .this );
242+ }
243+ } );
229244 }
230245
231246 private void showThreshold ( final boolean showThreshold )
@@ -333,7 +348,7 @@ private PopupMenu()
333348
334349 private void chooseFileAndExport ( final String extension , final String fileName , final ObjIntConsumer < File > exportFunction )
335350 {
336- File chosenFile = FileChooser .chooseFile ( frame , fileName + '.' + extension ,
351+ File chosenFile = FileChooser .chooseFile ( this , fileName + '.' + extension ,
337352 new ExtensionFileFilter ( extension ), "Save dendrogram to " + extension , FileChooser .DialogType .SAVE );
338353 if ( chosenFile != null )
339354 {
0 commit comments