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