Merge branch 'releases/Release_2_11_3_Branch'
[jalview.git] / src / jalview / gui / AnnotationColumnChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21
22 package jalview.gui;
23
24 import java.awt.BorderLayout;
25 import java.awt.CardLayout;
26 import java.awt.Color;
27 import java.awt.Dimension;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.awt.event.FocusAdapter;
31 import java.awt.event.FocusEvent;
32 import java.awt.event.ItemEvent;
33 import java.awt.event.ItemListener;
34 import java.awt.event.KeyEvent;
35
36 import javax.swing.ButtonGroup;
37 import javax.swing.JCheckBox;
38 import javax.swing.JComboBox;
39 import javax.swing.JInternalFrame;
40 import javax.swing.JLayeredPane;
41 import javax.swing.JPanel;
42 import javax.swing.JRadioButton;
43 import javax.swing.border.TitledBorder;
44
45 import jalview.bin.Console;
46 import jalview.datamodel.AlignmentAnnotation;
47 import jalview.datamodel.HiddenColumns;
48 import jalview.io.cache.JvCacheableInputBox;
49 import jalview.schemes.AnnotationColourGradient;
50 import jalview.util.MessageManager;
51 import jalview.util.Platform;
52 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
53 import net.miginfocom.swing.MigLayout;
54
55 @SuppressWarnings("serial")
56 public class AnnotationColumnChooser extends AnnotationRowFilter
57         implements ItemListener
58 {
59   private JPanel switchableViewsPanel = new JPanel(new CardLayout());
60
61   private JPanel annotationComboBoxPanel = new JPanel();
62
63   private StructureFilterPanel gStructureFilterPanel;
64
65   private StructureFilterPanel ngStructureFilterPanel;
66
67   private StructureFilterPanel currentStructureFilterPanel;
68
69   private SearchPanel currentSearchPanel;
70
71   private SearchPanel gSearchPanel;
72
73   private SearchPanel ngSearchPanel;
74
75   private FurtherActionPanel currentFurtherActionPanel;
76
77   private FurtherActionPanel gFurtherActionPanel;
78
79   private FurtherActionPanel ngFurtherActionPanel;
80
81   public static final int ACTION_OPTION_SELECT = 1;
82
83   public static int ACTION_OPTION_HIDE = 2;
84
85   public static String NO_GRAPH_VIEW = "0";
86
87   public static String GRAPH_VIEW = "1";
88
89   private int actionOption = ACTION_OPTION_SELECT;
90
91   private HiddenColumns oldHiddenColumns;
92
93   protected static int MIN_WIDTH = (Platform.isJS() ? 370 : 420);
94
95   protected static int MIN_HEIGHT = (Platform.isJS() ? 370 : 430);
96
97   public AnnotationColumnChooser(AlignViewport av, final AlignmentPanel ap)
98   {
99     this(av, ap, null);
100   }
101
102   public AnnotationColumnChooser(AlignViewport av, final AlignmentPanel ap,
103           AlignmentAnnotation selectedAnnotation)
104   {
105     super(av, ap);
106     frame = new JInternalFrame();
107     frame.setFrameIcon(null);
108     frame.setContentPane(this);
109     frame.setLayer(JLayeredPane.PALETTE_LAYER);
110     Desktop.addInternalFrame(frame,
111             MessageManager.getString("label.select_by_annotation"), 0, 0);
112     // BH note: MIGLayout ignores this completely,
113     // possibly creating a frame smaller than specified:
114     frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
115
116     addSliderChangeListener();
117     addSliderMouseListeners();
118
119     if (av.getAlignment().getAlignmentAnnotation() == null)
120     {
121       return;
122     }
123     setOldHiddenColumns(av.getAlignment().getHiddenColumns());
124     adjusting = true;
125
126     setAnnotations(new JComboBox<>(getAnnotationItems(false)));
127     populateThresholdComboBox(threshold);
128     AnnotationColumnChooser lastChooser = av
129             .getAnnotationColumnSelectionState();
130     // restore Object state from the previous session if one exists
131     if (lastChooser != null)
132     {
133       currentSearchPanel = lastChooser.getCurrentSearchPanel();
134       currentStructureFilterPanel = lastChooser
135               .getCurrentStructureFilterPanel();
136       annotations.setSelectedIndex(
137               lastChooser.getAnnotations().getSelectedIndex());
138       threshold.setSelectedIndex(
139               lastChooser.getThreshold().getSelectedIndex());
140       actionOption = lastChooser.getActionOption();
141       percentThreshold
142               .setSelected(lastChooser.percentThreshold.isSelected());
143     }
144     if (selectedAnnotation != null)
145     {
146       try
147       {
148         setCurrentAnnotation(selectedAnnotation);
149         annotations.setSelectedItem(
150                 getAnnotationMenuLabel(selectedAnnotation));
151       } catch (Exception x)
152       {
153         Console.error("Couldn't select annotation in column chooser", x);
154       }
155     }
156
157     try
158     {
159       jbInit();
160     } catch (Exception ex)
161     {
162     }
163     adjusting = false;
164
165     updateView();
166     frame.invalidate();
167     frame.pack();
168   }
169
170   @Override
171   protected void jbInit()
172   {
173     super.jbInit();
174
175     JPanel thresholdPanel = new JPanel();
176     thresholdPanel.setBorder(new TitledBorder(
177             MessageManager.getString("label.threshold_filter")));
178     thresholdPanel.setBackground(Color.white);
179     thresholdPanel.setFont(JvSwingUtils.getLabelFont());
180     thresholdPanel.setLayout(new MigLayout("", "[left][right]", "[][]"));
181
182     percentThreshold.setBackground(Color.white);
183     percentThreshold.setFont(JvSwingUtils.getLabelFont());
184
185     JPanel actionPanel = new JPanel();
186     actionPanel.setBackground(Color.white);
187     actionPanel.setFont(JvSwingUtils.getLabelFont());
188
189     JPanel graphFilterView = new JPanel();
190     graphFilterView.setLayout(new MigLayout("", "[left][right]", "[][]"));
191     graphFilterView.setBackground(Color.white);
192
193     JPanel noGraphFilterView = new JPanel();
194     noGraphFilterView.setLayout(new MigLayout("", "[left][right]", "[][]"));
195     noGraphFilterView.setBackground(Color.white);
196
197     annotationComboBoxPanel.setBackground(Color.white);
198     annotationComboBoxPanel.setFont(JvSwingUtils.getLabelFont());
199
200     gSearchPanel = new SearchPanel(this);
201     ngSearchPanel = new SearchPanel(this);
202     gFurtherActionPanel = new FurtherActionPanel(this);
203     ngFurtherActionPanel = new FurtherActionPanel(this);
204     gStructureFilterPanel = new StructureFilterPanel(this);
205     ngStructureFilterPanel = new StructureFilterPanel(this);
206
207     thresholdPanel.add(getThreshold());
208     thresholdPanel.add(percentThreshold, "wrap");
209     thresholdPanel.add(slider, "grow");
210     thresholdPanel.add(thresholdValue, "span, wrap");
211
212     actionPanel.add(ok);
213     actionPanel.add(cancel);
214
215     graphFilterView.add(gSearchPanel, "grow, span, wrap");
216     graphFilterView.add(gStructureFilterPanel, "grow, span, wrap");
217     graphFilterView.add(thresholdPanel, "grow, span, wrap");
218     graphFilterView.add(gFurtherActionPanel);
219
220     noGraphFilterView.add(ngSearchPanel, "grow, span, wrap");
221     noGraphFilterView.add(ngStructureFilterPanel, "grow, span, wrap");
222     noGraphFilterView.add(ngFurtherActionPanel);
223
224     annotationComboBoxPanel.add(getAnnotations());
225     switchableViewsPanel.add(noGraphFilterView,
226             AnnotationColumnChooser.NO_GRAPH_VIEW);
227     switchableViewsPanel.add(graphFilterView,
228             AnnotationColumnChooser.GRAPH_VIEW);
229     this.setLayout(new BorderLayout());
230     this.add(annotationComboBoxPanel, java.awt.BorderLayout.PAGE_START);
231     this.add(switchableViewsPanel, java.awt.BorderLayout.CENTER);
232     this.add(actionPanel, java.awt.BorderLayout.SOUTH);
233
234     selectedAnnotationChanged();
235     updateThresholdPanelToolTip();
236     this.validate();
237   }
238
239   protected void updateThresholdPanelToolTip()
240   {
241     thresholdValue.setToolTipText("");
242     slider.setToolTipText("");
243
244     String defaultTtip = MessageManager
245             .getString("info.change_threshold_mode_to_enable");
246
247     String thresh = getThreshold().getSelectedItem().toString();
248     if (thresh.equalsIgnoreCase("No Threshold"))
249     {
250       thresholdValue.setToolTipText(defaultTtip);
251       slider.setToolTipText(defaultTtip);
252     }
253   }
254
255   @Override
256   protected void reset()
257   {
258     if (this.getOldHiddenColumns() != null)
259     {
260       av.getColumnSelection().clear();
261
262       if (av.getAnnotationColumnSelectionState() != null)
263       {
264         HiddenColumns oldHidden = av.getAnnotationColumnSelectionState()
265                 .getOldHiddenColumns();
266         av.getAlignment().setHiddenColumns(oldHidden);
267       }
268       av.sendSelection();
269       ap.paintAlignment(true, true);
270     }
271   }
272
273   @Override
274   public void valueChanged(boolean updateAllAnnotation)
275   {
276     if (slider.isEnabled())
277     {
278       getCurrentAnnotation().threshold.value = getSliderValue();
279       updateView();
280       propagateSeqAssociatedThreshold(updateAllAnnotation,
281               getCurrentAnnotation());
282       ap.paintAlignment(false, false);
283     }
284   }
285
286   @Override
287   public void updateView()
288   {
289     // Check if combobox is still adjusting
290     if (adjusting)
291     {
292       return;
293     }
294
295     AnnotationFilterParameter filterParams = new AnnotationFilterParameter();
296
297     setCurrentAnnotation(av.getAlignment()
298             .getAlignmentAnnotation()[annmap[getAnnotations()
299                     .getSelectedIndex()]]);
300
301     int selectedThresholdItem = getSelectedThresholdItem(
302             getThreshold().getSelectedIndex());
303
304     slider.setEnabled(true);
305     thresholdValue.setEnabled(true);
306     percentThreshold.setEnabled(true);
307
308     final AlignmentAnnotation currentAnnotation = getCurrentAnnotation();
309     if (selectedThresholdItem == AnnotationColourGradient.NO_THRESHOLD)
310     {
311       slider.setEnabled(false);
312       thresholdValue.setEnabled(false);
313       thresholdValue.setText("");
314       percentThreshold.setEnabled(false);
315       // build filter params
316     }
317     else if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD)
318     {
319       if (currentAnnotation.threshold == null)
320       {
321         currentAnnotation.setThreshold(new jalview.datamodel.GraphLine(
322                 (currentAnnotation.graphMax - currentAnnotation.graphMin)
323                         / 2f,
324                 "Threshold", Color.black));
325       }
326
327       adjusting = true;
328
329       setSliderModel(currentAnnotation.graphMin, currentAnnotation.graphMax,
330               currentAnnotation.threshold.value);
331
332       setThresholdValueText();
333
334       slider.setEnabled(true);
335       thresholdValue.setEnabled(true);
336       adjusting = false;
337
338       // build filter params
339       filterParams.setThresholdType(
340               AnnotationFilterParameter.ThresholdType.NO_THRESHOLD);
341       if (currentAnnotation.isQuantitative())
342       {
343         filterParams.setThresholdValue(currentAnnotation.threshold.value);
344
345         if (selectedThresholdItem == AnnotationColourGradient.ABOVE_THRESHOLD)
346         {
347           filterParams.setThresholdType(
348                   AnnotationFilterParameter.ThresholdType.ABOVE_THRESHOLD);
349         }
350         else if (selectedThresholdItem == AnnotationColourGradient.BELOW_THRESHOLD)
351         {
352           filterParams.setThresholdType(
353                   AnnotationFilterParameter.ThresholdType.BELOW_THRESHOLD);
354         }
355       }
356     }
357
358     updateThresholdPanelToolTip();
359     if (currentStructureFilterPanel != null)
360     {
361       if (currentStructureFilterPanel.alphaHelix.isSelected())
362       {
363         filterParams.setFilterAlphaHelix(true);
364       }
365       if (currentStructureFilterPanel.betaStrand.isSelected())
366       {
367         filterParams.setFilterBetaSheet(true);
368       }
369       if (currentStructureFilterPanel.turn.isSelected())
370       {
371         filterParams.setFilterTurn(true);
372       }
373     }
374
375     if (currentSearchPanel != null)
376     {
377       if (!currentSearchPanel.searchBox.getUserInput().isEmpty())
378       {
379         filterParams.setRegexString(
380                 currentSearchPanel.searchBox.getUserInput());
381         if (currentSearchPanel.displayName.isSelected())
382         {
383           filterParams.addRegexSearchField(
384                   AnnotationFilterParameter.SearchableAnnotationField.DISPLAY_STRING);
385         }
386         if (currentSearchPanel.description.isSelected())
387         {
388           filterParams.addRegexSearchField(
389                   AnnotationFilterParameter.SearchableAnnotationField.DESCRIPTION);
390         }
391       }
392     }
393
394     // show hidden columns here, before changing the column selection in
395     // filterAnnotations, because showing hidden columns has the side effect of
396     // adding them to the selection
397     av.showAllHiddenColumns();
398     av.getColumnSelection().filterAnnotations(currentAnnotation,
399             filterParams);
400
401     boolean hideCols = getActionOption() == ACTION_OPTION_HIDE;
402     if (hideCols)
403     {
404       av.hideSelectedColumns();
405     }
406     av.sendSelection();
407
408     filterParams = null;
409     av.setAnnotationColumnSelectionState(this);
410     // only update overview and structures if columns were hidden
411     ap.paintAlignment(hideCols, hideCols);
412   }
413
414   public HiddenColumns getOldHiddenColumns()
415   {
416     return oldHiddenColumns;
417   }
418
419   public void setOldHiddenColumns(HiddenColumns currentHiddenColumns)
420   {
421     if (currentHiddenColumns != null)
422     {
423       this.oldHiddenColumns = new HiddenColumns(currentHiddenColumns);
424     }
425   }
426
427   public FurtherActionPanel getCurrentFutherActionPanel()
428   {
429     return currentFurtherActionPanel;
430   }
431
432   public void setCurrentFutherActionPanel(
433           FurtherActionPanel currentFutherActionPanel)
434   {
435     this.currentFurtherActionPanel = currentFutherActionPanel;
436   }
437
438   public SearchPanel getCurrentSearchPanel()
439   {
440     return currentSearchPanel;
441   }
442
443   public void setCurrentSearchPanel(SearchPanel currentSearchPanel)
444   {
445     this.currentSearchPanel = currentSearchPanel;
446   }
447
448   public int getActionOption()
449   {
450     return actionOption;
451   }
452
453   public void setActionOption(int actionOption)
454   {
455     this.actionOption = actionOption;
456   }
457
458   public StructureFilterPanel getCurrentStructureFilterPanel()
459   {
460     return currentStructureFilterPanel;
461   }
462
463   public void setCurrentStructureFilterPanel(
464           StructureFilterPanel currentStructureFilterPanel)
465   {
466     this.currentStructureFilterPanel = currentStructureFilterPanel;
467   }
468
469   public void select_action(ActionEvent actionEvent)
470   {
471     JRadioButton radioButton = (JRadioButton) actionEvent.getSource();
472     if (radioButton.isSelected())
473     {
474       setActionOption(ACTION_OPTION_SELECT);
475       updateView();
476     }
477   }
478
479   public void hide_action(ActionEvent actionEvent)
480   {
481     JRadioButton radioButton = (JRadioButton) actionEvent.getSource();
482     if (radioButton.isSelected())
483     {
484       setActionOption(ACTION_OPTION_HIDE);
485       updateView();
486     }
487   }
488
489   @Override
490   public void itemStateChanged(ItemEvent e)
491   {
492     selectedAnnotationChanged();
493   }
494
495   @Override
496   public void selectedAnnotationChanged()
497   {
498     String currentView = AnnotationColumnChooser.NO_GRAPH_VIEW;
499     if (av.getAlignment().getAlignmentAnnotation()[annmap[getAnnotations()
500             .getSelectedIndex()]].isQuantitative())
501     {
502       currentView = AnnotationColumnChooser.GRAPH_VIEW;
503     }
504     saveCache();
505     gSearchPanel.syncState();
506     gFurtherActionPanel.syncState();
507     gStructureFilterPanel.syncState();
508
509     ngSearchPanel.syncState();
510     ngFurtherActionPanel.syncState();
511     ngStructureFilterPanel.syncState();
512
513     CardLayout switchableViewsLayout = (CardLayout) switchableViewsPanel
514             .getLayout();
515     switchableViewsLayout.show(switchableViewsPanel, currentView);
516     updateView();
517   }
518
519   public class FurtherActionPanel extends JPanel
520   {
521     private AnnotationColumnChooser aColChooser;
522
523     private JRadioButton hideOption = new JRadioButton();
524
525     private JRadioButton selectOption = new JRadioButton();
526
527     private ButtonGroup optionsGroup = new ButtonGroup();
528
529     public FurtherActionPanel(AnnotationColumnChooser aColChooser)
530     {
531       this.aColChooser = aColChooser;
532       JvSwingUtils.jvInitComponent(selectOption, "action.select");
533       selectOption.addActionListener(new ActionListener()
534       {
535         @Override
536         public void actionPerformed(ActionEvent actionEvent)
537         {
538           selectRadioAction(actionEvent);
539         }
540       });
541
542       JvSwingUtils.jvInitComponent(hideOption, "action.hide");
543       hideOption.addActionListener(new ActionListener()
544       {
545         @Override
546         public void actionPerformed(ActionEvent actionEvent)
547         {
548           hideRadioAction(actionEvent);
549         }
550       });
551
552       optionsGroup.add(selectOption);
553       optionsGroup.add(hideOption);
554       optionsGroup.setSelected(selectOption.getModel(), true);
555
556       JvSwingUtils.jvInitComponent(this);
557       syncState();
558
559       this.add(selectOption);
560       this.add(hideOption);
561     }
562
563     public void selectRadioAction(ActionEvent actionEvent)
564     {
565       aColChooser.setCurrentFutherActionPanel(this);
566       aColChooser.select_action(actionEvent);
567     }
568
569     public void hideRadioAction(ActionEvent actionEvent)
570     {
571       aColChooser.setCurrentFutherActionPanel(this);
572       aColChooser.hide_action(actionEvent);
573     }
574
575     public void syncState()
576     {
577       if (aColChooser
578               .getActionOption() == AnnotationColumnChooser.ACTION_OPTION_HIDE)
579       {
580         this.optionsGroup.setSelected(this.hideOption.getModel(), true);
581       }
582       else
583       {
584         this.optionsGroup.setSelected(this.selectOption.getModel(), true);
585       }
586     }
587   }
588
589   public class StructureFilterPanel extends JPanel
590   {
591     private AnnotationColumnChooser aColChooser;
592
593     private JCheckBox alphaHelix = new JCheckBox();
594
595     private JCheckBox betaStrand = new JCheckBox();
596
597     private JCheckBox turn = new JCheckBox();
598
599     private JCheckBox all = new JCheckBox();
600
601     public StructureFilterPanel(AnnotationColumnChooser aColChooser)
602     {
603       this.aColChooser = aColChooser;
604
605       JvSwingUtils.jvInitComponent(alphaHelix, "label.alpha_helix");
606       alphaHelix.addActionListener(new ActionListener()
607       {
608         @Override
609         public void actionPerformed(ActionEvent actionEvent)
610         {
611           alphaHelix_actionPerformed();
612         }
613       });
614
615       JvSwingUtils.jvInitComponent(betaStrand, "label.beta_strand");
616       betaStrand.addActionListener(new ActionListener()
617       {
618         @Override
619         public void actionPerformed(ActionEvent actionEvent)
620         {
621           betaStrand_actionPerformed();
622         }
623       });
624
625       JvSwingUtils.jvInitComponent(turn, "label.turn");
626       turn.addActionListener(new ActionListener()
627       {
628         @Override
629         public void actionPerformed(ActionEvent actionEvent)
630         {
631           turn_actionPerformed();
632         }
633       });
634
635       JvSwingUtils.jvInitComponent(all, "label.select_all");
636       all.addActionListener(new ActionListener()
637       {
638         @Override
639         public void actionPerformed(ActionEvent actionEvent)
640         {
641           all_actionPerformed();
642         }
643       });
644
645       this.setBorder(new TitledBorder(
646               MessageManager.getString("label.structures_filter")));
647       JvSwingUtils.jvInitComponent(this);
648
649       this.add(all);
650       this.add(alphaHelix);
651       this.add(betaStrand);
652       this.add(turn);
653     }
654
655     public void alphaHelix_actionPerformed()
656     {
657       updateSelectAllState();
658       aColChooser.setCurrentStructureFilterPanel(this);
659       aColChooser.updateView();
660     }
661
662     public void betaStrand_actionPerformed()
663     {
664       updateSelectAllState();
665       aColChooser.setCurrentStructureFilterPanel(this);
666       aColChooser.updateView();
667     }
668
669     public void turn_actionPerformed()
670     {
671       updateSelectAllState();
672       aColChooser.setCurrentStructureFilterPanel(this);
673       aColChooser.updateView();
674     }
675
676     public void all_actionPerformed()
677     {
678       if (all.isSelected())
679       {
680         alphaHelix.setSelected(true);
681         betaStrand.setSelected(true);
682         turn.setSelected(true);
683       }
684       else
685       {
686         alphaHelix.setSelected(false);
687         betaStrand.setSelected(false);
688         turn.setSelected(false);
689       }
690       aColChooser.setCurrentStructureFilterPanel(this);
691       aColChooser.updateView();
692     }
693
694     public void updateSelectAllState()
695     {
696       if (alphaHelix.isSelected() && betaStrand.isSelected()
697               && turn.isSelected())
698       {
699         all.setSelected(true);
700       }
701       else
702       {
703         all.setSelected(false);
704       }
705     }
706
707     public void syncState()
708     {
709       StructureFilterPanel sfp = aColChooser
710               .getCurrentStructureFilterPanel();
711       if (sfp != null)
712       {
713         alphaHelix.setSelected(sfp.alphaHelix.isSelected());
714         betaStrand.setSelected(sfp.betaStrand.isSelected());
715         turn.setSelected(sfp.turn.isSelected());
716         if (sfp.all.isSelected())
717         {
718           all.setSelected(true);
719           alphaHelix.setSelected(true);
720           betaStrand.setSelected(true);
721           turn.setSelected(true);
722         }
723       }
724
725     }
726   }
727
728   public class SearchPanel extends JPanel
729   {
730     private AnnotationColumnChooser aColChooser;
731
732     private JCheckBox displayName = new JCheckBox();
733
734     private JCheckBox description = new JCheckBox();
735
736     private static final String FILTER_BY_ANN_CACHE_KEY = "CACHE.SELECT_FILTER_BY_ANNOT";
737
738     public JvCacheableInputBox<String> searchBox = new JvCacheableInputBox<>(
739             FILTER_BY_ANN_CACHE_KEY, 23);
740
741     public SearchPanel(AnnotationColumnChooser aColChooser)
742     {
743
744       this.aColChooser = aColChooser;
745       JvSwingUtils.jvInitComponent(this);
746       this.setBorder(new TitledBorder(
747               MessageManager.getString("label.search_filter")));
748
749       searchBox.getComponent().setToolTipText(
750               MessageManager.getString("info.enter_search_text_here"));
751       searchBox.addKeyListener(new java.awt.event.KeyAdapter()
752       {
753         @Override
754         public void keyPressed(KeyEvent e)
755         {
756           if (e.getKeyCode() == KeyEvent.VK_ENTER)
757           {
758             e.consume();
759             searchStringAction();
760           }
761         }
762       });
763       searchBox.addFocusListener(new FocusAdapter()
764       {
765         @Override
766         public void focusLost(FocusEvent e)
767         {
768           searchStringAction();
769         }
770       });
771
772       JvSwingUtils.jvInitComponent(displayName, "label.label");
773       displayName.addActionListener(new ActionListener()
774       {
775         @Override
776         public void actionPerformed(ActionEvent actionEvent)
777         {
778           displayNameCheckboxAction();
779         }
780       });
781
782       JvSwingUtils.jvInitComponent(description, "label.description");
783       description.addActionListener(new ActionListener()
784       {
785         @Override
786         public void actionPerformed(ActionEvent actionEvent)
787         {
788           descriptionCheckboxAction();
789         }
790       });
791
792       syncState();
793       this.add(searchBox.getComponent());
794       this.add(displayName);
795       this.add(description);
796     }
797
798     public void displayNameCheckboxAction()
799     {
800       aColChooser.setCurrentSearchPanel(this);
801       aColChooser.updateView();
802     }
803
804     public void descriptionCheckboxAction()
805     {
806       aColChooser.setCurrentSearchPanel(this);
807       aColChooser.updateView();
808     }
809
810     public void searchStringAction()
811     {
812       aColChooser.setCurrentSearchPanel(this);
813       aColChooser.updateView();
814       updateSearchPanelToolTips();
815       searchBox.updateCache();
816     }
817
818     public void syncState()
819     {
820       SearchPanel sp = aColChooser.getCurrentSearchPanel();
821       if (sp != null)
822       {
823         description.setEnabled(sp.description.isEnabled());
824         description.setSelected(sp.description.isSelected());
825
826         displayName.setEnabled(sp.displayName.isEnabled());
827         displayName.setSelected(sp.displayName.isSelected());
828
829         searchBox.setSelectedItem(sp.searchBox.getUserInput());
830       }
831       updateSearchPanelToolTips();
832     }
833
834     public void updateSearchPanelToolTips()
835     {
836       String defaultTtip = MessageManager
837               .getString("info.enter_search_text_to_enable");
838       String labelTtip = MessageManager.formatMessage(
839               "info.search_in_annotation_label",
840               annotations.getSelectedItem().toString());
841       String descTtip = MessageManager.formatMessage(
842               "info.search_in_annotation_description",
843               annotations.getSelectedItem().toString());
844       displayName.setToolTipText(
845               displayName.isEnabled() ? labelTtip : defaultTtip);
846       description.setToolTipText(
847               description.isEnabled() ? descTtip : defaultTtip);
848     }
849   }
850
851   @Override
852   public void ok_actionPerformed()
853   {
854     saveCache();
855     super.ok_actionPerformed();
856   }
857
858   @Override
859   public void cancel_actionPerformed()
860   {
861     saveCache();
862     super.cancel_actionPerformed();
863   }
864
865   private void saveCache()
866   {
867     gSearchPanel.searchBox.persistCache();
868     ngSearchPanel.searchBox.persistCache();
869     gSearchPanel.searchBox.updateCache();
870     ngSearchPanel.searchBox.updateCache();
871   }
872
873   public static void displayFor(AlignViewport av, AlignmentPanel ap,
874           AlignmentAnnotation alignmentAnnotation)
875   {
876     AnnotationColumnChooser colchooser = new AnnotationColumnChooser(av, ap,
877             alignmentAnnotation);
878   }
879 }