Merge branch 'features/JAL-2360colourSchemeApplicability' into
[jalview.git] / src / jalview / appletgui / APopupMenu.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 package jalview.appletgui;
22
23 import jalview.analysis.AAFrequency;
24 import jalview.analysis.AlignmentAnnotationUtils;
25 import jalview.analysis.AlignmentUtils;
26 import jalview.analysis.Conservation;
27 import jalview.bin.JalviewLite;
28 import jalview.commands.ChangeCaseCommand;
29 import jalview.commands.EditCommand;
30 import jalview.commands.EditCommand.Action;
31 import jalview.datamodel.AlignmentAnnotation;
32 import jalview.datamodel.AlignmentI;
33 import jalview.datamodel.PDBEntry;
34 import jalview.datamodel.SequenceFeature;
35 import jalview.datamodel.SequenceGroup;
36 import jalview.datamodel.SequenceI;
37 import jalview.io.AppletFormatAdapter;
38 import jalview.io.DataSourceType;
39 import jalview.io.FileFormatI;
40 import jalview.io.FileFormats;
41 import jalview.io.SequenceAnnotationReport;
42 import jalview.schemes.Blosum62ColourScheme;
43 import jalview.schemes.BuriedColourScheme;
44 import jalview.schemes.ClustalxColourScheme;
45 import jalview.schemes.CollectionColourScheme;
46 import jalview.schemes.CollectionColourSchemeI;
47 import jalview.schemes.HelixColourScheme;
48 import jalview.schemes.HydrophobicColourScheme;
49 import jalview.schemes.JalviewColourScheme;
50 import jalview.schemes.NucleotideColourScheme;
51 import jalview.schemes.PIDColourScheme;
52 import jalview.schemes.PurinePyrimidineColourScheme;
53 import jalview.schemes.StrandColourScheme;
54 import jalview.schemes.TaylorColourScheme;
55 import jalview.schemes.TurnColourScheme;
56 import jalview.schemes.ZappoColourScheme;
57 import jalview.util.MessageManager;
58 import jalview.util.UrlLink;
59
60 import java.awt.CheckboxMenuItem;
61 import java.awt.Frame;
62 import java.awt.Menu;
63 import java.awt.MenuItem;
64 import java.awt.event.ActionEvent;
65 import java.awt.event.ActionListener;
66 import java.awt.event.ItemEvent;
67 import java.awt.event.ItemListener;
68 import java.util.Arrays;
69 import java.util.Collection;
70 import java.util.Collections;
71 import java.util.LinkedHashMap;
72 import java.util.List;
73 import java.util.Map;
74 import java.util.SortedMap;
75 import java.util.TreeMap;
76 import java.util.Vector;
77
78 public class APopupMenu extends java.awt.PopupMenu implements
79         ActionListener, ItemListener
80 {
81   Menu groupMenu = new Menu();
82
83   MenuItem editGroupName = new MenuItem();
84
85   CheckboxMenuItem noColour = new CheckboxMenuItem();
86
87   protected CheckboxMenuItem clustalColour = new CheckboxMenuItem();
88
89   protected CheckboxMenuItem zappoColour = new CheckboxMenuItem();
90
91   protected CheckboxMenuItem taylorColour = new CheckboxMenuItem();
92
93   protected CheckboxMenuItem hydrophobicityColour = new CheckboxMenuItem();
94
95   protected CheckboxMenuItem helixColour = new CheckboxMenuItem();
96
97   protected CheckboxMenuItem strandColour = new CheckboxMenuItem();
98
99   protected CheckboxMenuItem turnColour = new CheckboxMenuItem();
100
101   protected CheckboxMenuItem buriedColour = new CheckboxMenuItem();
102
103   protected CheckboxMenuItem PIDColour = new CheckboxMenuItem();
104
105   protected CheckboxMenuItem BLOSUM62Colour = new CheckboxMenuItem();
106
107   CheckboxMenuItem nucleotideColour = new CheckboxMenuItem();
108
109   CheckboxMenuItem purinePyrimidineColour = new CheckboxMenuItem();
110
111   protected MenuItem userDefinedColour = new MenuItem();
112
113   protected CheckboxMenuItem abovePIDColour = new CheckboxMenuItem();
114
115   MenuItem modifyPID = new MenuItem();
116
117   protected CheckboxMenuItem conservationColour = new CheckboxMenuItem();
118
119   MenuItem modifyConservation = new MenuItem();
120
121   MenuItem noColourmenuItem = new MenuItem();
122
123   final AlignmentPanel ap;
124
125   MenuItem unGroupMenuItem = new MenuItem();
126
127   MenuItem createGroupMenuItem = new MenuItem();
128
129   Menu colourMenu = new Menu();
130
131   CheckboxMenuItem showBoxes = new CheckboxMenuItem();
132
133   CheckboxMenuItem showText = new CheckboxMenuItem();
134
135   CheckboxMenuItem showColourText = new CheckboxMenuItem();
136
137   CheckboxMenuItem displayNonconserved = new CheckboxMenuItem();
138
139   Menu seqShowAnnotationsMenu = new Menu(
140           MessageManager.getString("label.show_annotations"));
141
142   Menu seqHideAnnotationsMenu = new Menu(
143           MessageManager.getString("label.hide_annotations"));
144
145   MenuItem seqAddReferenceAnnotations = new MenuItem(
146           MessageManager.getString("label.add_reference_annotations"));
147
148   Menu groupShowAnnotationsMenu = new Menu(
149           MessageManager.getString("label.show_annotations"));
150
151   Menu groupHideAnnotationsMenu = new Menu(
152           MessageManager.getString("label.hide_annotations"));
153
154   MenuItem groupAddReferenceAnnotations = new MenuItem(
155           MessageManager.getString("label.add_reference_annotations"));
156
157   Menu editMenu = new Menu(MessageManager.getString("action.edit"));
158
159   MenuItem copy = new MenuItem(MessageManager.getString("action.copy"));
160
161   MenuItem cut = new MenuItem(MessageManager.getString("action.cut"));
162
163   MenuItem toUpper = new MenuItem(
164           MessageManager.getString("label.to_upper_case"));
165
166   MenuItem toLower = new MenuItem(
167           MessageManager.getString("label.to_lower_case"));
168
169   MenuItem toggleCase = new MenuItem(
170           MessageManager.getString("label.toggle_case"));
171
172   Menu outputmenu = new Menu();
173
174   Menu seqMenu = new Menu();
175
176   MenuItem pdb = new MenuItem();
177
178   MenuItem hideSeqs = new MenuItem();
179
180   MenuItem repGroup = new MenuItem();
181
182   MenuItem sequenceName = new MenuItem(
183           MessageManager.getString("label.edit_name_description"));
184
185   MenuItem sequenceFeature = new MenuItem(
186           MessageManager.getString("label.create_sequence_feature"));
187
188   MenuItem editSequence = new MenuItem(
189           MessageManager.getString("label.edit_sequence"));
190
191   MenuItem sequenceDetails = new MenuItem(
192           MessageManager.getString("label.sequence_details"));
193
194   MenuItem selSeqDetails = new MenuItem(
195           MessageManager.getString("label.sequence_details"));
196
197   MenuItem makeReferenceSeq = new MenuItem();
198
199   SequenceI seq;
200
201   MenuItem revealAll = new MenuItem();
202
203   MenuItem revealSeq = new MenuItem();
204
205   /**
206    * index of sequence to be revealed
207    */
208   int revealSeq_index = -1;
209
210   Menu menu1 = new Menu();
211
212   public APopupMenu(AlignmentPanel apanel, final SequenceI seq,
213           Vector<String> links)
214   {
215     // /////////////////////////////////////////////////////////
216     // If this is activated from the sequence panel, the user may want to
217     // edit or annotate a particular residue. Therefore display the residue menu
218     //
219     // If from the IDPanel, we must display the sequence menu
220     // ////////////////////////////////////////////////////////
221
222     this.ap = apanel;
223     this.seq = seq;
224
225     try
226     {
227       jbInit();
228     } catch (Exception e)
229     {
230       e.printStackTrace();
231     }
232
233     for (String ff : FileFormats.getInstance().getWritableFormats(true))
234     {
235       MenuItem item = new MenuItem(ff);
236
237       item.addActionListener(this);
238       outputmenu.add(item);
239     }
240
241     buildAnnotationSubmenus();
242
243     SequenceGroup sg = ap.av.getSelectionGroup();
244     if (sg != null && sg.getSize() > 0)
245     {
246       editGroupName.setLabel(MessageManager.formatMessage(
247               "label.name_param", new Object[] { sg.getName() }));
248       showText.setState(sg.getDisplayText());
249       showColourText.setState(sg.getColourText());
250       showBoxes.setState(sg.getDisplayBoxes());
251       displayNonconserved.setState(sg.getShowNonconserved());
252       if (!ap.av.getAlignment().getGroups().contains(sg))
253       {
254         menu1.setLabel(MessageManager.getString("action.edit_new_group"));
255         groupMenu.remove(unGroupMenuItem);
256       }
257       else
258       {
259         menu1.setLabel(MessageManager.getString("action.edit_group"));
260         groupMenu.remove(createGroupMenuItem);
261         if (sg.cs != null)
262         {
263           abovePIDColour.setState(sg.cs.getThreshold() > 0);
264           conservationColour.setState(sg.cs.conservationApplied());
265           modifyPID.setEnabled(abovePIDColour.getState());
266           modifyConservation.setEnabled(conservationColour.getState());
267         }
268       }
269       setSelectedColour(sg.cs);
270     }
271     else
272     {
273       remove(hideSeqs);
274       remove(groupMenu);
275     }
276
277     if (links != null && links.size() > 0)
278     {
279       addFeatureLinks(seq, links);
280     }
281
282     // TODO: add group link menu entry here
283     if (seq != null)
284     {
285       seqMenu.setLabel(seq.getName());
286       if (seq == ap.av.getAlignment().getSeqrep())
287       {
288         makeReferenceSeq.setLabel(MessageManager
289                 .getString("action.unmark_as_reference"));// Unmark
290                                                           // representative");
291       }
292       else
293       {
294         makeReferenceSeq.setLabel(MessageManager
295                 .getString("action.set_as_reference")); // );
296       }
297       repGroup.setLabel(MessageManager.formatMessage(
298               "label.represent_group_with", new Object[] { seq.getName() }));
299     }
300     else
301     {
302       remove(seqMenu);
303     }
304
305     if (!ap.av.hasHiddenRows())
306     {
307       remove(revealAll);
308       remove(revealSeq);
309     }
310     else
311     {
312       final int index = ap.av.getAlignment().findIndex(seq);
313
314       if (ap.av.adjustForHiddenSeqs(index)
315               - ap.av.adjustForHiddenSeqs(index - 1) > 1)
316       {
317         revealSeq_index = index;
318       }
319       else
320       {
321         remove(revealSeq);
322       }
323     }
324   }
325
326   /**
327    * Select the menu item (if any) matching the current colour scheme. This
328    * works by matching the menu item name (not display text) to the canonical
329    * name of the colour scheme.
330    * 
331    * @param cs
332    */
333   protected void setSelectedColour(CollectionColourSchemeI cs)
334   {
335     if (cs == null || cs.getColourScheme() == null)
336     {
337       noColour.setState(true);
338     }
339     else
340     {
341       String name = cs.getColourScheme().getSchemeName();
342       for (int i = 0; i < colourMenu.getItemCount(); i++)
343       {
344         MenuItem item = colourMenu.getItem(i);
345         if (item instanceof CheckboxMenuItem)
346         {
347           if (name.equals(item.getName()))
348           {
349             ((CheckboxMenuItem) item).setState(true);
350           }
351         }
352       }
353     }
354   }
355
356   /**
357    * Adds a 'Link' menu item with a sub-menu item for each hyperlink provided.
358    * 
359    * @param seq
360    * @param links
361    */
362   void addFeatureLinks(final SequenceI seq, List<String> links)
363   {
364     Menu linkMenu = new Menu(MessageManager.getString("action.link"));
365     Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
366
367     for (String link : links)
368     {
369       UrlLink urlLink = null;
370       try
371       {
372         urlLink = new UrlLink(link);
373       } catch (Exception foo)
374       {
375         System.err.println("Exception for URLLink '" + link + "': "
376                 + foo.getMessage());
377         continue;
378       }
379
380       if (!urlLink.isValid())
381       {
382         System.err.println(urlLink.getInvalidMessage());
383         continue;
384       }
385
386       urlLink.createLinksFromSeq(seq, linkset);
387     }
388
389     addshowLinks(linkMenu, linkset.values());
390
391     // disable link menu if there are no valid entries
392     if (linkMenu.getItemCount() > 0)
393     {
394       linkMenu.setEnabled(true);
395     }
396     else
397     {
398       linkMenu.setEnabled(false);
399     }
400
401     if (seq != null)
402     {
403       seqMenu.add(linkMenu);
404     }
405     else
406     {
407       add(linkMenu);
408     }
409
410   }
411
412   private void addshowLinks(Menu linkMenu, Collection<List<String>> linkset)
413   {
414     for (List<String> linkstrset : linkset)
415     {
416       // split linkstr into label and url
417       addshowLink(linkMenu, linkstrset.get(1), linkstrset.get(3));
418     }
419   }
420
421   /**
422    * Build menus for annotation types that may be shown or hidden, and for
423    * 'reference annotations' that may be added to the alignment.
424    */
425   private void buildAnnotationSubmenus()
426   {
427     /*
428      * First for the currently selected sequence (if there is one):
429      */
430     final List<SequenceI> selectedSequence = (seq == null ? Collections
431             .<SequenceI> emptyList() : Arrays.asList(seq));
432     buildAnnotationTypesMenus(seqShowAnnotationsMenu,
433             seqHideAnnotationsMenu, selectedSequence);
434     configureReferenceAnnotationsMenu(seqAddReferenceAnnotations,
435             selectedSequence);
436
437     /*
438      * and repeat for the current selection group (if there is one):
439      */
440     final List<SequenceI> selectedGroup = (ap.av.getSelectionGroup() == null ? Collections
441             .<SequenceI> emptyList() : ap.av.getSelectionGroup()
442             .getSequences());
443     buildAnnotationTypesMenus(groupShowAnnotationsMenu,
444             groupHideAnnotationsMenu, selectedGroup);
445     configureReferenceAnnotationsMenu(groupAddReferenceAnnotations,
446             selectedGroup);
447   }
448
449   /**
450    * Determine whether or not to enable 'add reference annotations' menu item.
451    * It is enable if there are any annotations, on any of the selected
452    * sequences, which are not yet on the alignment (visible or not).
453    * 
454    * @param menu
455    * @param forSequences
456    */
457   private void configureReferenceAnnotationsMenu(MenuItem menuItem,
458           List<SequenceI> forSequences)
459   {
460     menuItem.setEnabled(false);
461
462     /*
463      * Temporary store to hold distinct calcId / type pairs for the tooltip.
464      * Using TreeMap means calcIds are shown in alphabetical order.
465      */
466     SortedMap<String, String> tipEntries = new TreeMap<String, String>();
467     final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
468     AlignmentI al = this.ap.av.getAlignment();
469     AlignmentUtils.findAddableReferenceAnnotations(forSequences,
470             tipEntries, candidates, al);
471     if (!candidates.isEmpty())
472     {
473       StringBuilder tooltip = new StringBuilder(64);
474       tooltip.append(MessageManager.getString("label.add_annotations_for"));
475
476       /*
477        * Found annotations that could be added. Enable the menu item, and
478        * configure its action.
479        */
480       menuItem.setEnabled(true);
481
482       menuItem.addActionListener(new ActionListener()
483       {
484         @Override
485         public void actionPerformed(ActionEvent e)
486         {
487           addReferenceAnnotations_actionPerformed(candidates);
488         }
489       });
490     }
491   }
492
493   /**
494    * Add annotations to the sequences and to the alignment.
495    * 
496    * @param candidates
497    *          a map whose keys are sequences on the alignment, and values a list
498    *          of annotations to add to each sequence
499    */
500   protected void addReferenceAnnotations_actionPerformed(
501           Map<SequenceI, List<AlignmentAnnotation>> candidates)
502   {
503     final SequenceGroup selectionGroup = this.ap.av.getSelectionGroup();
504     final AlignmentI alignment = this.ap.getAlignment();
505     AlignmentUtils.addReferenceAnnotations(candidates, alignment,
506             selectionGroup);
507     refresh();
508   }
509
510   /**
511    * add a show URL menu item to the given linkMenu
512    * 
513    * @param linkMenu
514    * @param target
515    *          - menu label string
516    * @param url
517    *          - url to open
518    */
519   private void addshowLink(Menu linkMenu, final String target,
520           final String url)
521   {
522     addshowLink(linkMenu, target, target, url);
523   }
524
525   /**
526    * add a show URL menu item to the given linkMenu
527    * 
528    * @param linkMenu
529    * @param target
530    *          - URL target window
531    * @param label
532    *          - menu label string
533    * @param url
534    *          - url to open
535    */
536   private void addshowLink(Menu linkMenu, final String target,
537           final String label, final String url)
538   {
539     MenuItem item = new MenuItem(label);
540     item.addActionListener(new java.awt.event.ActionListener()
541     {
542       @Override
543       public void actionPerformed(ActionEvent e)
544       {
545         ap.alignFrame.showURL(url, target);
546       }
547     });
548     linkMenu.add(item);
549   }
550
551   /**
552    * Actions on selecting / unselecting a checkbox menu item
553    */
554   @Override
555   public void itemStateChanged(ItemEvent evt)
556   {
557     Object source = evt.getSource();
558     if (source == noColour)
559     {
560       noColourmenuItem_actionPerformed();
561     }
562     else if (source == clustalColour)
563     {
564       clustalColour_actionPerformed();
565     }
566     else if (source == BLOSUM62Colour)
567     {
568       BLOSUM62Colour_actionPerformed();
569     }
570     else if (evt.getSource() == PIDColour)
571     {
572       PIDColour_actionPerformed();
573     }
574     else if (source == zappoColour)
575     {
576       zappoColour_actionPerformed();
577     }
578     else if (source == taylorColour)
579     {
580       taylorColour_actionPerformed();
581     }
582     else if (source == hydrophobicityColour)
583     {
584       hydrophobicityColour_actionPerformed();
585     }
586     else if (source == helixColour)
587     {
588       helixColour_actionPerformed();
589     }
590     else if (source == strandColour)
591     {
592       strandColour_actionPerformed();
593     }
594     else if (source == turnColour)
595     {
596       turnColour_actionPerformed();
597     }
598     else if (source == buriedColour)
599     {
600       buriedColour_actionPerformed();
601     }
602     else if (source == nucleotideColour)
603     {
604       nucleotideMenuItem_actionPerformed();
605     }
606     else if (source == purinePyrimidineColour)
607     {
608       purinePyrimidineColour_actionPerformed();
609     }
610     else if (source == abovePIDColour)
611     {
612       abovePIDColour_itemStateChanged();
613     }
614     else if (source == conservationColour)
615     {
616       conservationMenuItem_itemStateChanged();
617     }
618     else if (source == showColourText)
619     {
620       showColourText_itemStateChanged();
621     }
622     else if (source == showText)
623     {
624       showText_itemStateChanged();
625     }
626     else if (source == showBoxes)
627     {
628       showBoxes_itemStateChanged();
629     }
630     else if (source == displayNonconserved)
631     {
632       this.showNonconserved_itemStateChanged();
633     }
634   }
635
636   /**
637    * Actions on clicking a menu item
638    */
639   @Override
640   public void actionPerformed(ActionEvent evt)
641   {
642     Object source = evt.getSource();
643     if (source == userDefinedColour)
644     {
645       userDefinedColour_actionPerformed();
646     }
647     else if (source == modifyConservation)
648     {
649       conservationMenuItem_itemStateChanged();
650     }
651     else if (source == modifyPID)
652     {
653       abovePIDColour_itemStateChanged();
654     }
655     else if (source == unGroupMenuItem)
656     {
657       unGroupMenuItem_actionPerformed();
658     }
659
660     else if (source == createGroupMenuItem)
661     {
662       createGroupMenuItem_actionPerformed();
663     }
664
665     else if (source == sequenceName)
666     {
667       editName();
668     }
669     else if (source == makeReferenceSeq)
670     {
671       makeReferenceSeq_actionPerformed();
672     }
673     else if (source == sequenceDetails)
674     {
675       showSequenceDetails();
676     }
677     else if (source == selSeqDetails)
678     {
679       showSequenceSelectionDetails();
680     }
681     else if (source == pdb)
682     {
683       addPDB();
684     }
685     else if (source == hideSeqs)
686     {
687       hideSequences(false);
688     }
689     else if (source == repGroup)
690     {
691       hideSequences(true);
692     }
693     else if (source == revealSeq)
694     {
695       ap.av.showSequence(revealSeq_index);
696     }
697     else if (source == revealAll)
698     {
699       ap.av.showAllHiddenSeqs();
700     }
701
702     else if (source == editGroupName)
703     {
704       EditNameDialog dialog = new EditNameDialog(getGroup().getName(),
705               getGroup().getDescription(), "       Group Name",
706               "Group Description", ap.alignFrame,
707               "Edit Group Name / Description", 500, 100, true);
708
709       if (dialog.accept)
710       {
711         getGroup().setName(dialog.getName().replace(' ', '_'));
712         getGroup().setDescription(dialog.getDescription());
713       }
714
715     }
716     else if (source == copy)
717     {
718       ap.alignFrame.copy_actionPerformed();
719     }
720     else if (source == cut)
721     {
722       ap.alignFrame.cut_actionPerformed();
723     }
724     else if (source == editSequence)
725     {
726       SequenceGroup sg = ap.av.getSelectionGroup();
727
728       if (sg != null)
729       {
730         if (seq == null)
731         {
732           seq = sg.getSequenceAt(0);
733         }
734
735         EditNameDialog dialog = new EditNameDialog(seq.getSequenceAsString(
736                 sg.getStartRes(), sg.getEndRes() + 1), null,
737                 "Edit Sequence ", null,
738
739                 ap.alignFrame, "Edit Sequence", 500, 100, true);
740
741         if (dialog.accept)
742         {
743           EditCommand editCommand = new EditCommand(
744                   MessageManager.getString("label.edit_sequences"),
745                   Action.REPLACE, dialog.getName().replace(' ',
746                           ap.av.getGapCharacter()),
747                   sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
748                   sg.getStartRes(), sg.getEndRes() + 1,
749                   ap.av.getAlignment());
750
751           ap.alignFrame.addHistoryItem(editCommand);
752
753           ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
754                   .getSequences());
755         }
756       }
757     }
758     else if (source == toUpper || source == toLower || source == toggleCase)
759     {
760       SequenceGroup sg = ap.av.getSelectionGroup();
761       if (sg != null)
762       {
763         List<int[]> startEnd = ap.av.getVisibleRegionBoundaries(
764                 sg.getStartRes(), sg.getEndRes() + 1);
765
766         String description;
767         int caseChange;
768
769         if (source == toggleCase)
770         {
771           description = "Toggle Case";
772           caseChange = ChangeCaseCommand.TOGGLE_CASE;
773         }
774         else if (source == toUpper)
775         {
776           description = "To Upper Case";
777           caseChange = ChangeCaseCommand.TO_UPPER;
778         }
779         else
780         {
781           description = "To Lower Case";
782           caseChange = ChangeCaseCommand.TO_LOWER;
783         }
784
785         ChangeCaseCommand caseCommand = new ChangeCaseCommand(description,
786                 sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
787                 startEnd, caseChange);
788
789         ap.alignFrame.addHistoryItem(caseCommand);
790
791         ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
792                 .getSequences());
793
794       }
795     }
796     else if (source == sequenceFeature)
797     {
798       SequenceGroup sg = ap.av.getSelectionGroup();
799       if (sg == null)
800       {
801         return;
802       }
803
804       int rsize = 0, gSize = sg.getSize();
805       SequenceI[] rseqs, seqs = new SequenceI[gSize];
806       SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
807
808       for (int i = 0; i < gSize; i++)
809       {
810         int start = sg.getSequenceAt(i).findPosition(sg.getStartRes());
811         int end = sg.findEndRes(sg.getSequenceAt(i));
812         if (start <= end)
813         {
814           seqs[rsize] = sg.getSequenceAt(i);
815           features[rsize] = new SequenceFeature(null, null, null, start,
816                   end, "Jalview");
817           rsize++;
818         }
819       }
820       rseqs = new SequenceI[rsize];
821       tfeatures = new SequenceFeature[rsize];
822       System.arraycopy(seqs, 0, rseqs, 0, rsize);
823       System.arraycopy(features, 0, tfeatures, 0, rsize);
824       features = tfeatures;
825       seqs = rseqs;
826
827       if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
828               features, true, ap))
829       {
830         ap.alignFrame.sequenceFeatures.setState(true);
831         ap.av.setShowSequenceFeatures(true);
832         ;
833         ap.highlightSearchResults(null);
834       }
835     }
836     else
837     {
838       outputText(evt);
839     }
840
841   }
842
843   void outputText(ActionEvent e)
844   {
845     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, ap.alignFrame);
846
847     Frame frame = new Frame();
848     frame.add(cap);
849     JalviewLite.addFrame(frame, MessageManager.formatMessage(
850             "label.selection_output_command",
851             new Object[] { e.getActionCommand() }), 600, 500);
852     // JBPNote: getSelectionAsNewSequence behaviour has changed - this method
853     // now returns a full copy of sequence data
854     // TODO consider using getSequenceSelection instead here
855
856     FileFormatI fileFormat = FileFormats.getInstance().forName(
857             e.getActionCommand());
858     cap.setText(new AppletFormatAdapter().formatSequences(fileFormat,
859             ap.av.getShowJVSuffix(), ap, true));
860
861   }
862
863   protected void showSequenceSelectionDetails()
864   {
865     createSequenceDetailsReport(ap.av.getSequenceSelection());
866   }
867
868   protected void showSequenceDetails()
869   {
870     createSequenceDetailsReport(new SequenceI[] { seq });
871   }
872
873   public void createSequenceDetailsReport(SequenceI[] sequences)
874   {
875
876     CutAndPasteTransfer cap = new CutAndPasteTransfer(false, ap.alignFrame);
877
878     StringBuilder contents = new StringBuilder(128);
879     for (SequenceI seq : sequences)
880     {
881       contents.append(MessageManager.formatMessage(
882               "label.annotation_for_displayid",
883               new Object[] { seq.getDisplayId(true) }));
884       new SequenceAnnotationReport(null).createSequenceAnnotationReport(
885               contents,
886               seq,
887               true,
888               true,
889               (ap.seqPanel.seqCanvas.fr != null) ? ap.seqPanel.seqCanvas.fr
890                       .getMinMax() : null);
891       contents.append("</p>");
892     }
893     Frame frame = new Frame();
894     frame.add(cap);
895     jalview.bin.JalviewLite.addFrame(frame, "Sequence Details for "
896             + (sequences.length == 1 ? sequences[0].getDisplayId(true)
897                     : "Selection"), 600, 500);
898     cap.setText(MessageManager.formatMessage("label.html_content",
899             new Object[] { contents.toString() }));
900   }
901
902   void editName()
903   {
904     EditNameDialog dialog = new EditNameDialog(seq.getName(),
905             seq.getDescription(), "       Sequence Name",
906             "Sequence Description", ap.alignFrame,
907             "Edit Sequence Name / Description", 500, 100, true);
908
909     if (dialog.accept)
910     {
911       seq.setName(dialog.getName());
912       seq.setDescription(dialog.getDescription());
913       ap.paintAlignment(false);
914     }
915   }
916
917   void addPDB()
918   {
919     Vector<PDBEntry> pdbs = seq.getAllPDBEntries();
920     if (pdbs != null && !pdbs.isEmpty())
921     {
922       PDBEntry entry = pdbs.firstElement();
923
924       if (ap.av.applet.jmolAvailable)
925       {
926         new AppletJmol(entry, new SequenceI[] { seq }, null, ap,
927                 DataSourceType.URL);
928       }
929       else
930       {
931         new MCview.AppletPDBViewer(entry, new SequenceI[] { seq }, null,
932                 ap, DataSourceType.URL);
933       }
934
935     }
936     else
937     {
938       CutAndPasteTransfer cap = new CutAndPasteTransfer(true, ap.alignFrame);
939       cap.setText(MessageManager.getString("label.paste_pdb_file"));
940       cap.setPDBImport(seq);
941       Frame frame = new Frame();
942       frame.add(cap);
943       JalviewLite.addFrame(frame, MessageManager.formatMessage(
944               "label.paste_pdb_file_for_sequence",
945               new Object[] { seq.getName() }), 400, 300);
946     }
947   }
948
949   private void jbInit() throws Exception
950   {
951     groupMenu.setLabel(MessageManager.getString("label.selection"));
952     sequenceFeature.addActionListener(this);
953
954     editGroupName.addActionListener(this);
955     unGroupMenuItem.setLabel(MessageManager
956             .getString("action.remove_group"));
957     unGroupMenuItem.addActionListener(this);
958
959     createGroupMenuItem.setLabel(MessageManager
960             .getString("action.create_group"));
961     createGroupMenuItem.addActionListener(this);
962
963     modifyPID.setEnabled(abovePIDColour.getState());
964     modifyConservation.setEnabled(conservationColour.getState());
965     colourMenu.setLabel(MessageManager.getString("label.group_colour"));
966     showBoxes.setLabel(MessageManager.getString("action.boxes"));
967     showBoxes.setState(true);
968     showBoxes.addItemListener(this);
969     sequenceName.addActionListener(this);
970     sequenceDetails.addActionListener(this);
971     selSeqDetails.addActionListener(this);
972     displayNonconserved.setLabel(MessageManager
973             .getString("label.show_non_conserved"));
974     displayNonconserved.setState(false);
975     displayNonconserved.addItemListener(this);
976     showText.setLabel(MessageManager.getString("action.text"));
977     showText.addItemListener(this);
978     showColourText.setLabel(MessageManager.getString("label.colour_text"));
979     showColourText.addItemListener(this);
980     outputmenu.setLabel(MessageManager.getString("label.out_to_textbox"));
981     seqMenu.setLabel(MessageManager.getString("label.sequence"));
982     pdb.setLabel(MessageManager.getString("label.view_pdb_structure"));
983     hideSeqs.setLabel(MessageManager.getString("action.hide_sequences"));
984     repGroup.setLabel(MessageManager.formatMessage(
985             "label.represent_group_with", new Object[] { "" }));
986     revealAll.setLabel(MessageManager.getString("action.reveal_all"));
987     revealSeq.setLabel(MessageManager.getString("action.reveal_sequences"));
988     menu1.setLabel(MessageManager.getString("label.group:"));
989     add(groupMenu);
990     this.add(seqMenu);
991     this.add(hideSeqs);
992     this.add(revealSeq);
993     this.add(revealAll);
994     // groupMenu.add(selSeqDetails);
995     groupMenu.add(groupShowAnnotationsMenu);
996     groupMenu.add(groupHideAnnotationsMenu);
997     groupMenu.add(groupAddReferenceAnnotations);
998     groupMenu.add(editMenu);
999     groupMenu.add(outputmenu);
1000     groupMenu.add(sequenceFeature);
1001     groupMenu.add(createGroupMenuItem);
1002     groupMenu.add(unGroupMenuItem);
1003     groupMenu.add(menu1);
1004
1005     colourMenu.add(noColour);
1006     colourMenu.add(clustalColour);
1007     colourMenu.add(BLOSUM62Colour);
1008     colourMenu.add(PIDColour);
1009     colourMenu.add(zappoColour);
1010     colourMenu.add(taylorColour);
1011     colourMenu.add(hydrophobicityColour);
1012     colourMenu.add(helixColour);
1013     colourMenu.add(strandColour);
1014     colourMenu.add(turnColour);
1015     colourMenu.add(buriedColour);
1016     colourMenu.add(nucleotideColour);
1017     colourMenu.add(purinePyrimidineColour);
1018     colourMenu.add(userDefinedColour);
1019     colourMenu.addSeparator();
1020     colourMenu.add(conservationColour);
1021     colourMenu.add(modifyConservation);
1022     colourMenu.add(abovePIDColour);
1023     colourMenu.add(modifyPID);
1024
1025     noColour.setLabel(MessageManager.getString("label.none"));
1026     noColour.addItemListener(this);
1027
1028     /*
1029      * setName allows setSelectedColour to do its thing
1030      */
1031     clustalColour.setLabel(MessageManager
1032             .getString("label.colourScheme_clustal"));
1033     clustalColour.setName(JalviewColourScheme.Clustal.toString());
1034     clustalColour.addItemListener(this);
1035     BLOSUM62Colour.setLabel(MessageManager
1036             .getString("label.colourScheme_blosum62"));
1037     BLOSUM62Colour.setName(JalviewColourScheme.Blosum62.toString());
1038     BLOSUM62Colour.addItemListener(this);
1039     PIDColour.setLabel(MessageManager
1040             .getString("label.colourScheme_%_identity"));
1041     PIDColour.setName(JalviewColourScheme.PID.toString());
1042     PIDColour.addItemListener(this);
1043     zappoColour.setLabel(MessageManager
1044             .getString("label.colourScheme_zappo"));
1045     zappoColour.setName(JalviewColourScheme.Zappo.toString());
1046     zappoColour.addItemListener(this);
1047     taylorColour.setLabel(MessageManager
1048             .getString("label.colourScheme_taylor"));
1049     taylorColour.setName(JalviewColourScheme.Taylor.toString());
1050     taylorColour.addItemListener(this);
1051     hydrophobicityColour.setLabel(MessageManager
1052             .getString("label.colourScheme_hydrophobic"));
1053     hydrophobicityColour
1054             .setName(JalviewColourScheme.Hydrophobic.toString());
1055     hydrophobicityColour.addItemListener(this);
1056     helixColour.setLabel(MessageManager
1057             .getString("label.colourScheme_helix_propensity"));
1058     helixColour.setName(JalviewColourScheme.Helix.toString());
1059     helixColour.addItemListener(this);
1060     strandColour.setLabel(MessageManager
1061             .getString("label.colourScheme_strand_propensity"));
1062     strandColour.setName(JalviewColourScheme.Strand.toString());
1063     strandColour.addItemListener(this);
1064     turnColour.setLabel(MessageManager
1065             .getString("label.colourScheme_turn_propensity"));
1066     turnColour.setName(JalviewColourScheme.Turn.toString());
1067     turnColour.addItemListener(this);
1068     buriedColour.setLabel(MessageManager
1069             .getString("label.colourScheme_buried_index"));
1070     buriedColour.setName(JalviewColourScheme.Buried.toString());
1071     buriedColour.addItemListener(this);
1072     nucleotideColour.setLabel(MessageManager
1073             .getString("label.colourScheme_nucleotide"));
1074     nucleotideColour.setName(JalviewColourScheme.Nucleotide.toString());
1075     nucleotideColour.addItemListener(this);
1076     purinePyrimidineColour.setLabel(MessageManager
1077             .getString("label.colourScheme_purine/pyrimidine"));
1078     purinePyrimidineColour.setName(JalviewColourScheme.PurinePyrimidine
1079             .toString());
1080     purinePyrimidineColour.addItemListener(this);
1081
1082     userDefinedColour.setLabel(MessageManager
1083             .getString("action.user_defined"));
1084     userDefinedColour.addActionListener(this);
1085
1086     abovePIDColour.setLabel(MessageManager
1087             .getString("label.above_identity_threshold"));
1088     abovePIDColour.addItemListener(this);
1089     modifyPID.setLabel(MessageManager
1090             .getString("label.modify_identity_threshold"));
1091     modifyPID.addActionListener(this);
1092     conservationColour.setLabel(MessageManager
1093             .getString("action.by_conservation"));
1094     conservationColour.addItemListener(this);
1095     modifyConservation.setLabel(MessageManager
1096             .getString("label.modify_conservation_threshold"));
1097     modifyConservation.addActionListener(this);
1098
1099     PIDColour.addActionListener(this);
1100     BLOSUM62Colour.addActionListener(this);
1101
1102     editMenu.add(copy);
1103     copy.addActionListener(this);
1104     editMenu.add(cut);
1105     cut.addActionListener(this);
1106
1107     editMenu.add(editSequence);
1108     editSequence.addActionListener(this);
1109
1110     editMenu.add(toUpper);
1111     toUpper.addActionListener(this);
1112     editMenu.add(toLower);
1113     toLower.addActionListener(this);
1114     editMenu.add(toggleCase);
1115     seqMenu.add(seqShowAnnotationsMenu);
1116     seqMenu.add(seqHideAnnotationsMenu);
1117     seqMenu.add(seqAddReferenceAnnotations);
1118     seqMenu.add(sequenceName);
1119     seqMenu.add(makeReferenceSeq);
1120     // seqMenu.add(sequenceDetails);
1121
1122     if (!ap.av.applet.useXtrnalSviewer)
1123     {
1124       seqMenu.add(pdb);
1125     }
1126     seqMenu.add(repGroup);
1127     menu1.add(editGroupName);
1128     menu1.add(colourMenu);
1129     menu1.add(showBoxes);
1130     menu1.add(showText);
1131     menu1.add(showColourText);
1132     menu1.add(displayNonconserved);
1133     toggleCase.addActionListener(this);
1134     pdb.addActionListener(this);
1135     hideSeqs.addActionListener(this);
1136     repGroup.addActionListener(this);
1137     revealAll.addActionListener(this);
1138     revealSeq.addActionListener(this);
1139     makeReferenceSeq.addActionListener(this);
1140   }
1141
1142   void refresh()
1143   {
1144     ap.paintAlignment(true);
1145   }
1146
1147   protected void clustalColour_actionPerformed()
1148   {
1149     SequenceGroup sg = getGroup();
1150     sg.cs = new CollectionColourScheme(new ClustalxColourScheme(sg,
1151             ap.av.getHiddenRepSequences()));
1152     refresh();
1153   }
1154
1155   protected void zappoColour_actionPerformed()
1156   {
1157     getGroup().cs = new CollectionColourScheme(new ZappoColourScheme());
1158     refresh();
1159   }
1160
1161   protected void taylorColour_actionPerformed()
1162   {
1163     getGroup().cs = new CollectionColourScheme(new TaylorColourScheme());
1164     refresh();
1165   }
1166
1167   protected void hydrophobicityColour_actionPerformed()
1168   {
1169     getGroup().cs = new CollectionColourScheme(new HydrophobicColourScheme());
1170     refresh();
1171   }
1172
1173   protected void helixColour_actionPerformed()
1174   {
1175     getGroup().cs = new CollectionColourScheme(new HelixColourScheme());
1176     refresh();
1177   }
1178
1179   protected void strandColour_actionPerformed()
1180   {
1181     getGroup().cs = new CollectionColourScheme(new StrandColourScheme());
1182     refresh();
1183   }
1184
1185   protected void turnColour_actionPerformed()
1186   {
1187     getGroup().cs = new CollectionColourScheme(new TurnColourScheme());
1188     refresh();
1189   }
1190
1191   protected void buriedColour_actionPerformed()
1192   {
1193     getGroup().cs = new CollectionColourScheme(new BuriedColourScheme());
1194     refresh();
1195   }
1196
1197   public void nucleotideMenuItem_actionPerformed()
1198   {
1199     getGroup().cs = new CollectionColourScheme(new NucleotideColourScheme());
1200     refresh();
1201   }
1202
1203   public void purinePyrimidineColour_actionPerformed()
1204   {
1205     getGroup().cs = new CollectionColourScheme(
1206             new PurinePyrimidineColourScheme());
1207     refresh();
1208   }
1209
1210   protected void abovePIDColour_itemStateChanged()
1211   {
1212     SequenceGroup sg = getGroup();
1213     if (sg.cs == null)
1214     {
1215       return;
1216     }
1217
1218     if (abovePIDColour.getState())
1219     {
1220       sg.cs.setConsensus(AAFrequency.calculate(sg.getSequences(ap.av
1221               .getHiddenRepSequences()), 0, ap.av.getAlignment().getWidth()));
1222       int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup()
1223               .getName());
1224
1225       sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus());
1226
1227       SliderPanel.showPIDSlider();
1228
1229     }
1230     else
1231     // remove PIDColouring
1232     {
1233       SliderPanel.hidePIDSlider();
1234       sg.cs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
1235     }
1236     modifyPID.setEnabled(abovePIDColour.getState());
1237     refresh();
1238   }
1239
1240   protected void userDefinedColour_actionPerformed()
1241   {
1242     new UserDefinedColours(ap, getGroup());
1243   }
1244
1245   protected void PIDColour_actionPerformed()
1246   {
1247     SequenceGroup sg = getGroup();
1248     sg.cs = new CollectionColourScheme(new PIDColourScheme());
1249     sg.cs.setConsensus(AAFrequency.calculate(sg.getSequences(ap.av
1250             .getHiddenRepSequences()), 0, ap.av.getAlignment().getWidth()));
1251     refresh();
1252   }
1253
1254   protected void BLOSUM62Colour_actionPerformed()
1255   {
1256     SequenceGroup sg = getGroup();
1257
1258     sg.cs = new CollectionColourScheme(new Blosum62ColourScheme());
1259
1260     sg.cs.setConsensus(AAFrequency.calculate(sg.getSequences(ap.av
1261             .getHiddenRepSequences()), 0, ap.av.getAlignment().getWidth()));
1262
1263     refresh();
1264   }
1265
1266   protected void noColourmenuItem_actionPerformed()
1267   {
1268     getGroup().cs = null;
1269     refresh();
1270   }
1271
1272   protected void conservationMenuItem_itemStateChanged()
1273   {
1274     SequenceGroup sg = getGroup();
1275     if (sg.cs == null)
1276     {
1277       return;
1278     }
1279
1280     if (conservationColour.getState())
1281     {
1282       Conservation conservation = Conservation.calculateConservation(
1283               "Group", sg
1284               .getSequences(ap.av.getHiddenRepSequences()), 0, ap.av
1285               .getAlignment().getWidth(), false, ap.av.getConsPercGaps(),
1286               false);
1287       sg.getGroupColourScheme().setConservation(conservation);
1288       SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
1289       SliderPanel.showConservationSlider();
1290     }
1291     else
1292     // remove ConservationColouring
1293     {
1294       SliderPanel.hideConservationSlider();
1295       sg.cs.setConservation(null);
1296     }
1297     modifyConservation.setEnabled(conservationColour.getState());
1298     refresh();
1299   }
1300
1301   SequenceGroup getGroup()
1302   {
1303     SequenceGroup sg = ap.av.getSelectionGroup();
1304
1305     // this method won't add a new group if it already exists
1306     if (sg != null)
1307     {
1308       ap.av.getAlignment().addGroup(sg);
1309     }
1310
1311     return sg;
1312   }
1313
1314   void unGroupMenuItem_actionPerformed()
1315   {
1316     SequenceGroup sg = ap.av.getSelectionGroup();
1317     ap.av.getAlignment().deleteGroup(sg);
1318     ap.av.setSelectionGroup(null);
1319     ap.paintAlignment(true);
1320   }
1321
1322   void createGroupMenuItem_actionPerformed()
1323   {
1324     getGroup(); // implicitly create group
1325     refresh();
1326   }
1327
1328   public void showColourText_itemStateChanged()
1329   {
1330     getGroup().setColourText(showColourText.getState());
1331     refresh();
1332   }
1333
1334   public void showText_itemStateChanged()
1335   {
1336     getGroup().setDisplayText(showText.getState());
1337     refresh();
1338   }
1339
1340   public void makeReferenceSeq_actionPerformed()
1341   {
1342     if (!ap.av.getAlignment().hasSeqrep())
1343     {
1344       // initialise the display flags so the user sees something happen
1345       ap.av.setDisplayReferenceSeq(true);
1346       ap.av.setColourByReferenceSeq(true);
1347       ap.av.getAlignment().setSeqrep(seq);
1348     }
1349     else
1350     {
1351       if (ap.av.getAlignment().getSeqrep() == seq)
1352       {
1353         ap.av.getAlignment().setSeqrep(null);
1354       }
1355       else
1356       {
1357         ap.av.getAlignment().setSeqrep(seq);
1358       }
1359     }
1360     refresh();
1361   }
1362
1363   public void showNonconserved_itemStateChanged()
1364   {
1365     getGroup().setShowNonconserved(this.displayNonconserved.getState());
1366     refresh();
1367   }
1368
1369   public void showBoxes_itemStateChanged()
1370   {
1371     getGroup().setDisplayBoxes(showBoxes.getState());
1372     refresh();
1373   }
1374
1375   void hideSequences(boolean representGroup)
1376   {
1377     ap.av.hideSequences(seq, representGroup);
1378   }
1379
1380   /**
1381    * Add annotation types to 'Show annotations' and/or 'Hide annotations' menus.
1382    * "All" is added first, followed by a separator. Then add any annotation
1383    * types associated with the current selection. Separate menus are built for
1384    * the selected sequence group (if any), and the selected sequence.
1385    * <p>
1386    * Some annotation rows are always rendered together - these can be identified
1387    * by a common graphGroup property > -1. Only one of each group will be marked
1388    * as visible (to avoid duplication of the display). For such groups we add a
1389    * composite type name, e.g.
1390    * <p>
1391    * IUPredWS (Long), IUPredWS (Short)
1392    * 
1393    * @param seq
1394    */
1395   protected void buildAnnotationTypesMenus(Menu showMenu, Menu hideMenu,
1396           List<SequenceI> forSequences)
1397   {
1398     showMenu.removeAll();
1399     hideMenu.removeAll();
1400
1401     final List<String> all = Arrays.asList(new String[] { MessageManager
1402             .getString("label.all") });
1403     addAnnotationTypeToShowHide(showMenu, forSequences, "", all, true, true);
1404     addAnnotationTypeToShowHide(hideMenu, forSequences, "", all, true,
1405             false);
1406     showMenu.addSeparator();
1407     hideMenu.addSeparator();
1408
1409     final AlignmentAnnotation[] annotations = ap.getAlignment()
1410             .getAlignmentAnnotation();
1411
1412     /*
1413      * Find shown/hidden annotations types, distinguished by source (calcId),
1414      * and grouped by graphGroup. Using LinkedHashMap means we will retrieve in
1415      * the insertion order, which is the order of the annotations on the
1416      * alignment.
1417      */
1418     Map<String, List<List<String>>> shownTypes = new LinkedHashMap<String, List<List<String>>>();
1419     Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<String, List<List<String>>>();
1420     AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
1421             AlignmentAnnotationUtils.asList(annotations), forSequences);
1422
1423     for (String calcId : hiddenTypes.keySet())
1424     {
1425       for (List<String> type : hiddenTypes.get(calcId))
1426       {
1427         addAnnotationTypeToShowHide(showMenu, forSequences, calcId, type,
1428                 false, true);
1429       }
1430     }
1431     // grey out 'show annotations' if none are hidden
1432     showMenu.setEnabled(!hiddenTypes.isEmpty());
1433
1434     for (String calcId : shownTypes.keySet())
1435     {
1436       for (List<String> type : shownTypes.get(calcId))
1437       {
1438         addAnnotationTypeToShowHide(hideMenu, forSequences, calcId, type,
1439                 false, false);
1440       }
1441     }
1442     // grey out 'hide annotations' if none are shown
1443     hideMenu.setEnabled(!shownTypes.isEmpty());
1444   }
1445
1446   /**
1447    * Add one annotation type to the 'Show Annotations' or 'Hide Annotations'
1448    * menus.
1449    * 
1450    * @param showOrHideMenu
1451    *          the menu to add to
1452    * @param forSequences
1453    *          the sequences whose annotations may be shown or hidden
1454    * @param calcId
1455    * @param types
1456    *          the label to add
1457    * @param allTypes
1458    *          if true this is a special label meaning 'All'
1459    * @param actionIsShow
1460    *          if true, the select menu item action is to show the annotation
1461    *          type, else hide
1462    */
1463   protected void addAnnotationTypeToShowHide(Menu showOrHideMenu,
1464           final List<SequenceI> forSequences, String calcId,
1465           final List<String> types, final boolean allTypes,
1466           final boolean actionIsShow)
1467   {
1468     String label = types.toString(); // [a, b, c]
1469     label = label.substring(1, label.length() - 1);
1470     final MenuItem item = new MenuItem(label);
1471     item.addActionListener(new java.awt.event.ActionListener()
1472     {
1473       @Override
1474       public void actionPerformed(ActionEvent e)
1475       {
1476         AlignmentUtils.showOrHideSequenceAnnotations(ap.getAlignment(),
1477                 types, forSequences, allTypes, actionIsShow);
1478         refresh();
1479       }
1480     });
1481     showOrHideMenu.add(item);
1482   }
1483
1484 }