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