JAL-2124 i18n of "All" menu item
[jalview.git] / src / jalview / gui / PopupMenu.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.gui;
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.Cache;
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.Annotation;
34 import jalview.datamodel.ColumnSelection;
35 import jalview.datamodel.DBRefEntry;
36 import jalview.datamodel.PDBEntry;
37 import jalview.datamodel.Sequence;
38 import jalview.datamodel.SequenceFeature;
39 import jalview.datamodel.SequenceGroup;
40 import jalview.datamodel.SequenceI;
41 import jalview.io.FormatAdapter;
42 import jalview.io.SequenceAnnotationReport;
43 import jalview.schemes.AnnotationColourGradient;
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.NucleotideColourScheme;
50 import jalview.schemes.PIDColourScheme;
51 import jalview.schemes.PurinePyrimidineColourScheme;
52 import jalview.schemes.ResidueProperties;
53 import jalview.schemes.StrandColourScheme;
54 import jalview.schemes.TaylorColourScheme;
55 import jalview.schemes.TurnColourScheme;
56 import jalview.schemes.UserColourScheme;
57 import jalview.schemes.ZappoColourScheme;
58 import jalview.util.DBRefUtils;
59 import jalview.util.GroupUrlLink;
60 import jalview.util.GroupUrlLink.UrlStringTooLongException;
61 import jalview.util.MessageManager;
62 import jalview.util.UrlLink;
63
64 import java.awt.Color;
65 import java.awt.event.ActionEvent;
66 import java.awt.event.ActionListener;
67 import java.util.ArrayList;
68 import java.util.Arrays;
69 import java.util.Collections;
70 import java.util.Hashtable;
71 import java.util.LinkedHashMap;
72 import java.util.List;
73 import java.util.Map;
74 import java.util.TreeMap;
75 import java.util.Vector;
76
77 import javax.swing.ButtonGroup;
78 import javax.swing.JCheckBoxMenuItem;
79 import javax.swing.JColorChooser;
80 import javax.swing.JMenu;
81 import javax.swing.JMenuItem;
82 import javax.swing.JOptionPane;
83 import javax.swing.JPopupMenu;
84 import javax.swing.JRadioButtonMenuItem;
85
86 /**
87  * DOCUMENT ME!
88  * 
89  * @author $author$
90  * @version $Revision: 1.118 $
91  */
92 public class PopupMenu extends JPopupMenu
93 {
94   JMenu groupMenu = new JMenu();
95
96   JMenuItem groupName = new JMenuItem();
97
98   protected JRadioButtonMenuItem clustalColour = new JRadioButtonMenuItem();
99
100   protected JRadioButtonMenuItem zappoColour = new JRadioButtonMenuItem();
101
102   protected JRadioButtonMenuItem taylorColour = new JRadioButtonMenuItem();
103
104   protected JRadioButtonMenuItem hydrophobicityColour = new JRadioButtonMenuItem();
105
106   protected JRadioButtonMenuItem helixColour = new JRadioButtonMenuItem();
107
108   protected JRadioButtonMenuItem strandColour = new JRadioButtonMenuItem();
109
110   protected JRadioButtonMenuItem turnColour = new JRadioButtonMenuItem();
111
112   protected JRadioButtonMenuItem buriedColour = new JRadioButtonMenuItem();
113
114   protected JCheckBoxMenuItem abovePIDColour = new JCheckBoxMenuItem();
115
116   protected JRadioButtonMenuItem userDefinedColour = new JRadioButtonMenuItem();
117
118   protected JRadioButtonMenuItem PIDColour = new JRadioButtonMenuItem();
119
120   protected JRadioButtonMenuItem BLOSUM62Colour = new JRadioButtonMenuItem();
121
122   protected JRadioButtonMenuItem purinePyrimidineColour = new JRadioButtonMenuItem();
123
124   protected JRadioButtonMenuItem RNAInteractionColour = new JRadioButtonMenuItem();
125
126   JRadioButtonMenuItem noColourmenuItem = new JRadioButtonMenuItem();
127
128   protected JCheckBoxMenuItem conservationMenuItem = new JCheckBoxMenuItem();
129
130   AlignmentPanel ap;
131
132   JMenu sequenceMenu = new JMenu();
133
134   JMenuItem sequenceName = new JMenuItem();
135
136   JMenuItem sequenceDetails = new JMenuItem();
137
138   JMenuItem sequenceSelDetails = new JMenuItem();
139
140   JMenuItem makeReferenceSeq = new JMenuItem();
141
142   JMenuItem chooseAnnotations = new JMenuItem();
143
144   SequenceI sequence;
145
146   JMenuItem createGroupMenuItem = new JMenuItem();
147
148   JMenuItem unGroupMenuItem = new JMenuItem();
149
150   JMenuItem outline = new JMenuItem();
151
152   JRadioButtonMenuItem nucleotideMenuItem = new JRadioButtonMenuItem();
153
154   JMenu colourMenu = new JMenu();
155
156   JCheckBoxMenuItem showBoxes = new JCheckBoxMenuItem();
157
158   JCheckBoxMenuItem showText = new JCheckBoxMenuItem();
159
160   JCheckBoxMenuItem showColourText = new JCheckBoxMenuItem();
161
162   JCheckBoxMenuItem displayNonconserved = new JCheckBoxMenuItem();
163
164   JMenu editMenu = new JMenu();
165
166   JMenuItem cut = new JMenuItem();
167
168   JMenuItem copy = new JMenuItem();
169
170   JMenuItem upperCase = new JMenuItem();
171
172   JMenuItem lowerCase = new JMenuItem();
173
174   JMenuItem toggle = new JMenuItem();
175
176   JMenu pdbMenu = new JMenu();
177
178   JMenu outputMenu = new JMenu();
179
180   JMenu seqShowAnnotationsMenu = new JMenu();
181
182   JMenu seqHideAnnotationsMenu = new JMenu();
183
184   JMenuItem seqAddReferenceAnnotations = new JMenuItem(
185           MessageManager.getString("label.add_reference_annotations"));
186
187   JMenu groupShowAnnotationsMenu = new JMenu();
188
189   JMenu groupHideAnnotationsMenu = new JMenu();
190
191   JMenuItem groupAddReferenceAnnotations = new JMenuItem(
192           MessageManager.getString("label.add_reference_annotations"));
193
194   JMenuItem sequenceFeature = new JMenuItem();
195
196   JMenuItem textColour = new JMenuItem();
197
198   JMenu jMenu1 = new JMenu();
199
200   JMenuItem pdbStructureDialog = new JMenuItem();
201
202   JMenu rnaStructureMenu = new JMenu();
203
204   JMenuItem editSequence = new JMenuItem();
205
206   JMenu groupLinksMenu;
207
208   JMenuItem hideInsertions = new JMenuItem();
209
210   /**
211    * Creates a new PopupMenu object.
212    * 
213    * @param ap
214    *          DOCUMENT ME!
215    * @param seq
216    *          DOCUMENT ME!
217    */
218   public PopupMenu(final AlignmentPanel ap, Sequence seq, List<String> links)
219   {
220     this(ap, seq, links, null);
221   }
222
223   /**
224    * 
225    * @param ap
226    * @param seq
227    * @param links
228    * @param groupLinks
229    */
230   public PopupMenu(final AlignmentPanel ap, final SequenceI seq,
231           List<String> links, List<String> groupLinks)
232   {
233     // /////////////////////////////////////////////////////////
234     // If this is activated from the sequence panel, the user may want to
235     // edit or annotate a particular residue. Therefore display the residue menu
236     //
237     // If from the IDPanel, we must display the sequence menu
238     // ////////////////////////////////////////////////////////
239     this.ap = ap;
240     sequence = seq;
241
242     ButtonGroup colours = new ButtonGroup();
243     colours.add(noColourmenuItem);
244     colours.add(clustalColour);
245     colours.add(zappoColour);
246     colours.add(taylorColour);
247     colours.add(hydrophobicityColour);
248     colours.add(helixColour);
249     colours.add(strandColour);
250     colours.add(turnColour);
251     colours.add(buriedColour);
252     colours.add(abovePIDColour);
253     colours.add(userDefinedColour);
254     colours.add(PIDColour);
255     colours.add(BLOSUM62Colour);
256     colours.add(purinePyrimidineColour);
257     colours.add(RNAInteractionColour);
258
259     for (int i = 0; i < jalview.io.FormatAdapter.WRITEABLE_FORMATS.length; i++)
260     {
261       JMenuItem item = new JMenuItem(
262               jalview.io.FormatAdapter.WRITEABLE_FORMATS[i]);
263
264       item.addActionListener(new java.awt.event.ActionListener()
265       {
266         @Override
267         public void actionPerformed(ActionEvent e)
268         {
269           outputText_actionPerformed(e);
270         }
271       });
272
273       outputMenu.add(item);
274     }
275
276     /*
277      * Build menus for annotation types that may be shown or hidden, and for
278      * 'reference annotations' that may be added to the alignment. First for the
279      * currently selected sequence (if there is one):
280      */
281     final List<SequenceI> selectedSequence = (seq == null ? Collections
282             .<SequenceI> emptyList() : Arrays.asList(seq));
283     buildAnnotationTypesMenus(seqShowAnnotationsMenu,
284             seqHideAnnotationsMenu, selectedSequence);
285     configureReferenceAnnotationsMenu(seqAddReferenceAnnotations,
286             selectedSequence);
287
288     /*
289      * And repeat for the current selection group (if there is one):
290      */
291     final List<SequenceI> selectedGroup = (ap.av.getSelectionGroup() == null ? Collections
292             .<SequenceI> emptyList() : ap.av.getSelectionGroup()
293             .getSequences());
294     buildAnnotationTypesMenus(groupShowAnnotationsMenu,
295             groupHideAnnotationsMenu, selectedGroup);
296     configureReferenceAnnotationsMenu(groupAddReferenceAnnotations,
297             selectedGroup);
298
299     try
300     {
301       jbInit();
302     } catch (Exception e)
303     {
304       e.printStackTrace();
305     }
306
307     JMenuItem menuItem;
308     if (seq != null)
309     {
310       sequenceMenu.setText(sequence.getName());
311       if (seq == ap.av.getAlignment().getSeqrep())
312       {
313         makeReferenceSeq.setText(MessageManager
314                 .getString("action.unmark_as_reference"));
315       }
316       else
317       {
318         makeReferenceSeq.setText(MessageManager
319                 .getString("action.set_as_reference"));
320       }
321
322       if (!ap.av.getAlignment().isNucleotide())
323       {
324         remove(rnaStructureMenu);
325       }
326       else
327       {
328         int origCount = rnaStructureMenu.getItemCount();
329         /*
330          * add menu items to 2D-render any alignment or sequence secondary
331          * structure annotation
332          */
333         AlignmentAnnotation[] aas = ap.av.getAlignment()
334                 .getAlignmentAnnotation();
335         if (aas != null)
336         {
337           for (final AlignmentAnnotation aa : aas)
338           {
339             if (aa.isValidStruc() && aa.sequenceRef == null)
340             {
341               /*
342                * valid alignment RNA secondary structure annotation
343                */
344               menuItem = new JMenuItem();
345               menuItem.setText(MessageManager.formatMessage(
346                       "label.2d_rna_structure_line",
347                       new Object[] { aa.label }));
348               menuItem.addActionListener(new java.awt.event.ActionListener()
349               {
350                 @Override
351                 public void actionPerformed(ActionEvent e)
352                 {
353                   new AppVarna(seq, aa, ap);
354                 }
355               });
356               rnaStructureMenu.add(menuItem);
357             }
358           }
359         }
360
361         if (seq.getAnnotation() != null)
362         {
363           AlignmentAnnotation seqAnns[] = seq.getAnnotation();
364           for (final AlignmentAnnotation aa : seqAnns)
365           {
366             if (aa.isValidStruc())
367             {
368               /*
369                * valid sequence RNA secondary structure annotation
370                */
371               // TODO: make rnastrucF a bit more nice
372               menuItem = new JMenuItem();
373               menuItem.setText(MessageManager.formatMessage(
374                       "label.2d_rna_sequence_name",
375                       new Object[] { seq.getName() }));
376               menuItem.addActionListener(new java.awt.event.ActionListener()
377               {
378                 @Override
379                 public void actionPerformed(ActionEvent e)
380                 {
381                   // TODO: VARNA does'nt print gaps in the sequence
382                   new AppVarna(seq, aa, ap);
383                 }
384               });
385               rnaStructureMenu.add(menuItem);
386             }
387           }
388         }
389         if (rnaStructureMenu.getItemCount() == origCount)
390         {
391           remove(rnaStructureMenu);
392         }
393       }
394
395       menuItem = new JMenuItem(
396               MessageManager.getString("action.hide_sequences"));
397       menuItem.addActionListener(new java.awt.event.ActionListener()
398       {
399         @Override
400         public void actionPerformed(ActionEvent e)
401         {
402           hideSequences(false);
403         }
404       });
405       add(menuItem);
406
407       if (ap.av.getSelectionGroup() != null
408               && ap.av.getSelectionGroup().getSize() > 1)
409       {
410         menuItem = new JMenuItem(MessageManager.formatMessage(
411                 "label.represent_group_with",
412                 new Object[] { seq.getName() }));
413         menuItem.addActionListener(new java.awt.event.ActionListener()
414         {
415           @Override
416           public void actionPerformed(ActionEvent e)
417           {
418             hideSequences(true);
419           }
420         });
421         sequenceMenu.add(menuItem);
422       }
423
424       if (ap.av.hasHiddenRows())
425       {
426         final int index = ap.av.getAlignment().findIndex(seq);
427
428         if (ap.av.adjustForHiddenSeqs(index)
429                 - ap.av.adjustForHiddenSeqs(index - 1) > 1)
430         {
431           menuItem = new JMenuItem(
432                   MessageManager.getString("action.reveal_sequences"));
433           menuItem.addActionListener(new ActionListener()
434           {
435             @Override
436             public void actionPerformed(ActionEvent e)
437             {
438               ap.av.showSequence(index);
439               if (ap.overviewPanel != null)
440               {
441                 ap.overviewPanel.updateOverviewImage();
442               }
443             }
444           });
445           add(menuItem);
446         }
447       }
448     }
449     // for the case when no sequences are even visible
450     if (ap.av.hasHiddenRows())
451     {
452       {
453         menuItem = new JMenuItem(
454                 MessageManager.getString("action.reveal_all"));
455         menuItem.addActionListener(new ActionListener()
456         {
457           @Override
458           public void actionPerformed(ActionEvent e)
459           {
460             ap.av.showAllHiddenSeqs();
461             if (ap.overviewPanel != null)
462             {
463               ap.overviewPanel.updateOverviewImage();
464             }
465           }
466         });
467
468         add(menuItem);
469       }
470
471     }
472
473     SequenceGroup sg = ap.av.getSelectionGroup();
474     boolean isDefinedGroup = (sg != null) ? ap.av.getAlignment()
475             .getGroups().contains(sg) : false;
476
477     if (sg != null && sg.getSize() > 0)
478     {
479       groupName.setText(MessageManager.formatMessage("label.name_param",
480               new Object[] { sg.getName() }));
481       groupName.setText(MessageManager
482               .getString("label.edit_name_and_description_current_group"));
483
484       if (sg.cs instanceof ZappoColourScheme)
485       {
486         zappoColour.setSelected(true);
487       }
488       else if (sg.cs instanceof TaylorColourScheme)
489       {
490         taylorColour.setSelected(true);
491       }
492       else if (sg.cs instanceof PIDColourScheme)
493       {
494         PIDColour.setSelected(true);
495       }
496       else if (sg.cs instanceof Blosum62ColourScheme)
497       {
498         BLOSUM62Colour.setSelected(true);
499       }
500       else if (sg.cs instanceof UserColourScheme)
501       {
502         userDefinedColour.setSelected(true);
503       }
504       else if (sg.cs instanceof HydrophobicColourScheme)
505       {
506         hydrophobicityColour.setSelected(true);
507       }
508       else if (sg.cs instanceof HelixColourScheme)
509       {
510         helixColour.setSelected(true);
511       }
512       else if (sg.cs instanceof StrandColourScheme)
513       {
514         strandColour.setSelected(true);
515       }
516       else if (sg.cs instanceof TurnColourScheme)
517       {
518         turnColour.setSelected(true);
519       }
520       else if (sg.cs instanceof BuriedColourScheme)
521       {
522         buriedColour.setSelected(true);
523       }
524       else if (sg.cs instanceof ClustalxColourScheme)
525       {
526         clustalColour.setSelected(true);
527       }
528       else if (sg.cs instanceof PurinePyrimidineColourScheme)
529       {
530         purinePyrimidineColour.setSelected(true);
531       }
532
533       /*
534        * else if (sg.cs instanceof CovariationColourScheme) {
535        * covariationColour.setSelected(true); }
536        */
537       else
538       {
539         noColourmenuItem.setSelected(true);
540       }
541
542       if (sg.cs != null && sg.cs.conservationApplied())
543       {
544         conservationMenuItem.setSelected(true);
545       }
546       displayNonconserved.setSelected(sg.getShowNonconserved());
547       showText.setSelected(sg.getDisplayText());
548       showColourText.setSelected(sg.getColourText());
549       showBoxes.setSelected(sg.getDisplayBoxes());
550       // add any groupURLs to the groupURL submenu and make it visible
551       if (groupLinks != null && groupLinks.size() > 0)
552       {
553         buildGroupURLMenu(sg, groupLinks);
554       }
555       // Add a 'show all structures' for the current selection
556       Hashtable<String, PDBEntry> pdbe = new Hashtable<String, PDBEntry>(), reppdb = new Hashtable<String, PDBEntry>();
557       SequenceI sqass = null;
558       for (SequenceI sq : ap.av.getSequenceSelection())
559       {
560         Vector<PDBEntry> pes = sq.getDatasetSequence().getAllPDBEntries();
561         if (pes != null && pes.size() > 0)
562         {
563           reppdb.put(pes.get(0).getId(), pes.get(0));
564           for (PDBEntry pe : pes)
565           {
566             pdbe.put(pe.getId(), pe);
567             if (sqass == null)
568             {
569               sqass = sq;
570             }
571           }
572         }
573       }
574       if (pdbe.size() > 0)
575       {
576         final PDBEntry[] pe = pdbe.values().toArray(
577                 new PDBEntry[pdbe.size()]), pr = reppdb.values().toArray(
578                 new PDBEntry[reppdb.size()]);
579         final JMenuItem gpdbview, rpdbview;
580       }
581     }
582     else
583     {
584       groupMenu.setVisible(false);
585       editMenu.setVisible(false);
586     }
587
588     if (!isDefinedGroup)
589     {
590       createGroupMenuItem.setVisible(true);
591       unGroupMenuItem.setVisible(false);
592       jMenu1.setText(MessageManager.getString("action.edit_new_group"));
593     }
594     else
595     {
596       createGroupMenuItem.setVisible(false);
597       unGroupMenuItem.setVisible(true);
598       jMenu1.setText(MessageManager.getString("action.edit_group"));
599     }
600
601     if (seq == null)
602     {
603       sequenceMenu.setVisible(false);
604       pdbStructureDialog.setVisible(false);
605       rnaStructureMenu.setVisible(false);
606     }
607
608     if (links != null && links.size() > 0)
609     {
610       addFeatureLinks(seq, links);
611     }
612   }
613
614   /**
615    * Adds a 'Link' menu item with a sub-menu item for each hyperlink provided.
616    * 
617    * @param seq
618    * @param links
619    */
620   void addFeatureLinks(final SequenceI seq, List<String> links)
621   {
622     JMenu linkMenu = new JMenu(MessageManager.getString("action.link"));
623     List<String> linkset = new ArrayList<String>();
624     for (String link : links)
625     {
626       UrlLink urlLink = null;
627       try
628       {
629         urlLink = new UrlLink(link);
630       } catch (Exception foo)
631       {
632         Cache.log.error("Exception for URLLink '" + link + "'", foo);
633         continue;
634       }
635       ;
636       if (!urlLink.isValid())
637       {
638         Cache.log.error(urlLink.getInvalidMessage());
639         continue;
640       }
641       final String label = urlLink.getLabel();
642       if (seq != null && urlLink.isDynamic())
643       {
644
645         // collect matching db-refs
646         DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(),
647                 new String[] { urlLink.getTarget() });
648         // collect id string too
649         String id = seq.getName();
650         String descr = seq.getDescription();
651         if (descr != null && descr.length() < 1)
652         {
653           descr = null;
654         }
655
656         if (dbr != null)
657         {
658           for (int r = 0; r < dbr.length; r++)
659           {
660             if (id != null && dbr[r].getAccessionId().equals(id))
661             {
662               // suppress duplicate link creation for the bare sequence ID
663               // string with this link
664               id = null;
665             }
666             // create Bare ID link for this URL
667             String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true);
668             if (urls != null)
669             {
670               for (int u = 0; u < urls.length; u += 2)
671               {
672                 if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
673                 {
674                   linkset.add(urls[u] + "|" + urls[u + 1]);
675                   addshowLink(linkMenu, label + "|" + urls[u], urls[u + 1]);
676                 }
677               }
678             }
679           }
680         }
681         if (id != null)
682         {
683           // create Bare ID link for this URL
684           String[] urls = urlLink.makeUrls(id, true);
685           if (urls != null)
686           {
687             for (int u = 0; u < urls.length; u += 2)
688             {
689               if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
690               {
691                 linkset.add(urls[u] + "|" + urls[u + 1]);
692                 addshowLink(linkMenu, label, urls[u + 1]);
693               }
694             }
695           }
696         }
697         // Create urls from description but only for URL links which are regex
698         // links
699         if (descr != null && urlLink.getRegexReplace() != null)
700         {
701           // create link for this URL from description where regex matches
702           String[] urls = urlLink.makeUrls(descr, true);
703           if (urls != null)
704           {
705             for (int u = 0; u < urls.length; u += 2)
706             {
707               if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
708               {
709                 linkset.add(urls[u] + "|" + urls[u + 1]);
710                 addshowLink(linkMenu, label, urls[u + 1]);
711               }
712             }
713           }
714         }
715       }
716       else
717       {
718         if (!linkset.contains(label + "|" + urlLink.getUrl_prefix()))
719         {
720           linkset.add(label + "|" + urlLink.getUrl_prefix());
721           // Add a non-dynamic link
722           addshowLink(linkMenu, label, urlLink.getUrl_prefix());
723         }
724       }
725     }
726     if (sequence != null)
727     {
728       sequenceMenu.add(linkMenu);
729     }
730     else
731     {
732       add(linkMenu);
733     }
734   }
735
736   /**
737    * Add annotation types to 'Show annotations' and/or 'Hide annotations' menus.
738    * "All" is added first, followed by a separator. Then add any annotation
739    * types associated with the current selection. Separate menus are built for
740    * the selected sequence group (if any), and the selected sequence.
741    * <p>
742    * Some annotation rows are always rendered together - these can be identified
743    * by a common graphGroup property > -1. Only one of each group will be marked
744    * as visible (to avoid duplication of the display). For such groups we add a
745    * composite type name, e.g.
746    * <p>
747    * IUPredWS (Long), IUPredWS (Short)
748    * 
749    * @param seq
750    */
751   protected void buildAnnotationTypesMenus(JMenu showMenu, JMenu hideMenu,
752           List<SequenceI> forSequences)
753   {
754     showMenu.removeAll();
755     hideMenu.removeAll();
756
757     final List<String> all = Arrays.asList(new String[] { MessageManager
758             .getString("label.all") });
759     addAnnotationTypeToShowHide(showMenu, forSequences, "", all, true, true);
760     addAnnotationTypeToShowHide(hideMenu, forSequences, "", all, true,
761             false);
762     showMenu.addSeparator();
763     hideMenu.addSeparator();
764
765     final AlignmentAnnotation[] annotations = ap.getAlignment()
766             .getAlignmentAnnotation();
767
768     /*
769      * Find shown/hidden annotations types, distinguished by source (calcId),
770      * and grouped by graphGroup. Using LinkedHashMap means we will retrieve in
771      * the insertion order, which is the order of the annotations on the
772      * alignment.
773      */
774     Map<String, List<List<String>>> shownTypes = new LinkedHashMap<String, List<List<String>>>();
775     Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<String, List<List<String>>>();
776     AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
777             AlignmentAnnotationUtils.asList(annotations), forSequences);
778
779     for (String calcId : hiddenTypes.keySet())
780     {
781       for (List<String> type : hiddenTypes.get(calcId))
782       {
783         addAnnotationTypeToShowHide(showMenu, forSequences, calcId, type,
784                 false, true);
785       }
786     }
787     // grey out 'show annotations' if none are hidden
788     showMenu.setEnabled(!hiddenTypes.isEmpty());
789
790     for (String calcId : shownTypes.keySet())
791     {
792       for (List<String> type : shownTypes.get(calcId))
793       {
794         addAnnotationTypeToShowHide(hideMenu, forSequences, calcId, type,
795                 false, false);
796       }
797     }
798     // grey out 'hide annotations' if none are shown
799     hideMenu.setEnabled(!shownTypes.isEmpty());
800   }
801
802   /**
803    * Returns a list of sequences - either the current selection group (if there
804    * is one), else the specified single sequence.
805    * 
806    * @param seq
807    * @return
808    */
809   protected List<SequenceI> getSequenceScope(SequenceI seq)
810   {
811     List<SequenceI> forSequences = null;
812     final SequenceGroup selectionGroup = ap.av.getSelectionGroup();
813     if (selectionGroup != null && selectionGroup.getSize() > 0)
814     {
815       forSequences = selectionGroup.getSequences();
816     }
817     else
818     {
819       forSequences = seq == null ? Collections.<SequenceI> emptyList()
820               : Arrays.asList(seq);
821     }
822     return forSequences;
823   }
824
825   /**
826    * Add one annotation type to the 'Show Annotations' or 'Hide Annotations'
827    * menus.
828    * 
829    * @param showOrHideMenu
830    *          the menu to add to
831    * @param forSequences
832    *          the sequences whose annotations may be shown or hidden
833    * @param calcId
834    * @param types
835    *          the label to add
836    * @param allTypes
837    *          if true this is a special label meaning 'All'
838    * @param actionIsShow
839    *          if true, the select menu item action is to show the annotation
840    *          type, else hide
841    */
842   protected void addAnnotationTypeToShowHide(JMenu showOrHideMenu,
843           final List<SequenceI> forSequences, String calcId,
844           final List<String> types, final boolean allTypes,
845           final boolean actionIsShow)
846   {
847     String label = types.toString(); // [a, b, c]
848     label = label.substring(1, label.length() - 1); // a, b, c
849     final JMenuItem item = new JMenuItem(label);
850     item.setToolTipText(calcId);
851     item.addActionListener(new java.awt.event.ActionListener()
852     {
853       @Override
854       public void actionPerformed(ActionEvent e)
855       {
856         AlignmentUtils.showOrHideSequenceAnnotations(ap.getAlignment(),
857                 types, forSequences, allTypes, actionIsShow);
858         refresh();
859       }
860     });
861     showOrHideMenu.add(item);
862   }
863
864   private void buildGroupURLMenu(SequenceGroup sg, List<String> groupLinks)
865   {
866
867     // TODO: usability: thread off the generation of group url content so root
868     // menu appears asap
869     // sequence only URLs
870     // ID/regex match URLs
871     groupLinksMenu = new JMenu(
872             MessageManager.getString("action.group_link"));
873     // three types of url that might be created.
874     JMenu[] linkMenus = new JMenu[] { null,
875         new JMenu(MessageManager.getString("action.ids")),
876         new JMenu(MessageManager.getString("action.sequences")),
877         new JMenu(MessageManager.getString("action.ids_sequences")) };
878
879     SequenceI[] seqs = ap.av.getSelectionAsNewSequence();
880     String[][] idandseqs = GroupUrlLink.formStrings(seqs);
881     Hashtable<String, Object[]> commonDbrefs = new Hashtable<String, Object[]>();
882     for (int sq = 0; sq < seqs.length; sq++)
883     {
884
885       int start = seqs[sq].findPosition(sg.getStartRes()), end = seqs[sq]
886               .findPosition(sg.getEndRes());
887       // just collect ids from dataset sequence
888       // TODO: check if IDs collected from selecton group intersects with the
889       // current selection, too
890       SequenceI sqi = seqs[sq];
891       while (sqi.getDatasetSequence() != null)
892       {
893         sqi = sqi.getDatasetSequence();
894       }
895       DBRefEntry[] dbr = sqi.getDBRefs();
896       if (dbr != null && dbr.length > 0)
897       {
898         for (int d = 0; d < dbr.length; d++)
899         {
900           String src = dbr[d].getSource(); // jalview.util.DBRefUtils.getCanonicalName(dbr[d].getSource()).toUpperCase();
901           Object[] sarray = commonDbrefs.get(src);
902           if (sarray == null)
903           {
904             sarray = new Object[2];
905             sarray[0] = new int[] { 0 };
906             sarray[1] = new String[seqs.length];
907
908             commonDbrefs.put(src, sarray);
909           }
910
911           if (((String[]) sarray[1])[sq] == null)
912           {
913             if (!dbr[d].hasMap()
914                     || (dbr[d].getMap().locateMappedRange(start, end) != null))
915             {
916               ((String[]) sarray[1])[sq] = dbr[d].getAccessionId();
917               ((int[]) sarray[0])[0]++;
918             }
919           }
920         }
921       }
922     }
923     // now create group links for all distinct ID/sequence sets.
924     boolean addMenu = false; // indicates if there are any group links to give
925                              // to user
926     for (String link : groupLinks)
927     {
928       GroupUrlLink urlLink = null;
929       try
930       {
931         urlLink = new GroupUrlLink(link);
932       } catch (Exception foo)
933       {
934         Cache.log.error("Exception for GroupURLLink '" + link
935                 + "'", foo);
936         continue;
937       }
938       ;
939       if (!urlLink.isValid())
940       {
941         Cache.log.error(urlLink.getInvalidMessage());
942         continue;
943       }
944       final String label = urlLink.getLabel();
945       boolean usingNames = false;
946       // Now see which parts of the group apply for this URL
947       String ltarget = urlLink.getTarget(); // jalview.util.DBRefUtils.getCanonicalName(urlLink.getTarget());
948       Object[] idset = commonDbrefs.get(ltarget.toUpperCase());
949       String[] seqstr, ids; // input to makeUrl
950       if (idset != null)
951       {
952         int numinput = ((int[]) idset[0])[0];
953         String[] allids = ((String[]) idset[1]);
954         seqstr = new String[numinput];
955         ids = new String[numinput];
956         for (int sq = 0, idcount = 0; sq < seqs.length; sq++)
957         {
958           if (allids[sq] != null)
959           {
960             ids[idcount] = allids[sq];
961             seqstr[idcount++] = idandseqs[1][sq];
962           }
963         }
964       }
965       else
966       {
967         // just use the id/seq set
968         seqstr = idandseqs[1];
969         ids = idandseqs[0];
970         usingNames = true;
971       }
972       // and try and make the groupURL!
973
974       Object[] urlset = null;
975       try
976       {
977         urlset = urlLink.makeUrlStubs(ids, seqstr,
978                 "FromJalview" + System.currentTimeMillis(), false);
979       } catch (UrlStringTooLongException e)
980       {
981       }
982       if (urlset != null)
983       {
984         int type = urlLink.getGroupURLType() & 3;
985         // first two bits ofurlLink type bitfield are sequenceids and sequences
986         // TODO: FUTURE: ensure the groupURL menu structure can be generalised
987         addshowLink(linkMenus[type], label
988                 + (((type & 1) == 1) ? ("("
989                         + (usingNames ? "Names" : ltarget) + ")") : ""),
990                 urlLink, urlset);
991         addMenu = true;
992       }
993     }
994     if (addMenu)
995     {
996       groupLinksMenu = new JMenu(
997               MessageManager.getString("action.group_link"));
998       for (int m = 0; m < linkMenus.length; m++)
999       {
1000         if (linkMenus[m] != null
1001                 && linkMenus[m].getMenuComponentCount() > 0)
1002         {
1003           groupLinksMenu.add(linkMenus[m]);
1004         }
1005       }
1006
1007       groupMenu.add(groupLinksMenu);
1008     }
1009   }
1010
1011   /**
1012    * add a show URL menu item to the given linkMenu
1013    * 
1014    * @param linkMenu
1015    * @param label
1016    *          - menu label string
1017    * @param url
1018    *          - url to open
1019    */
1020   private void addshowLink(JMenu linkMenu, String label, final String url)
1021   {
1022     JMenuItem item = new JMenuItem(label);
1023     item.setToolTipText(MessageManager.formatMessage(
1024             "label.open_url_param", new Object[] { url }));
1025     item.addActionListener(new java.awt.event.ActionListener()
1026     {
1027       @Override
1028       public void actionPerformed(ActionEvent e)
1029       {
1030         new Thread(new Runnable()
1031         {
1032
1033           @Override
1034           public void run()
1035           {
1036             showLink(url);
1037           }
1038
1039         }).start();
1040       }
1041     });
1042
1043     linkMenu.add(item);
1044   }
1045
1046   /**
1047    * add a late bound groupURL item to the given linkMenu
1048    * 
1049    * @param linkMenu
1050    * @param label
1051    *          - menu label string
1052    * @param urlgenerator
1053    *          GroupURLLink used to generate URL
1054    * @param urlstub
1055    *          Object array returned from the makeUrlStubs function.
1056    */
1057   private void addshowLink(JMenu linkMenu, String label,
1058           final GroupUrlLink urlgenerator, final Object[] urlstub)
1059   {
1060     JMenuItem item = new JMenuItem(label);
1061     item.setToolTipText(MessageManager.formatMessage(
1062             "label.open_url_seqs_param",
1063             new Object[] { urlgenerator.getUrl_prefix(),
1064                 urlgenerator.getNumberInvolved(urlstub) }));
1065     // TODO: put in info about what is being sent.
1066     item.addActionListener(new ActionListener()
1067     {
1068       @Override
1069       public void actionPerformed(ActionEvent e)
1070       {
1071         new Thread(new Runnable()
1072         {
1073
1074           @Override
1075           public void run()
1076           {
1077             try
1078             {
1079               showLink(urlgenerator.constructFrom(urlstub));
1080             } catch (UrlStringTooLongException e2)
1081             {
1082             }
1083           }
1084
1085         }).start();
1086       }
1087     });
1088
1089     linkMenu.add(item);
1090   }
1091
1092   /**
1093    * DOCUMENT ME!
1094    * 
1095    * @throws Exception
1096    *           DOCUMENT ME!
1097    */
1098   private void jbInit() throws Exception
1099   {
1100     groupMenu.setText(MessageManager.getString("label.group"));
1101     groupMenu.setText(MessageManager.getString("label.selection"));
1102     groupName.setText(MessageManager.getString("label.name"));
1103     groupName.addActionListener(new java.awt.event.ActionListener()
1104     {
1105       @Override
1106       public void actionPerformed(ActionEvent e)
1107       {
1108         groupName_actionPerformed();
1109       }
1110     });
1111     sequenceMenu.setText(MessageManager.getString("label.sequence"));
1112     sequenceName.setText(MessageManager
1113             .getString("label.edit_name_description"));
1114     sequenceName.addActionListener(new java.awt.event.ActionListener()
1115     {
1116       @Override
1117       public void actionPerformed(ActionEvent e)
1118       {
1119         sequenceName_actionPerformed();
1120       }
1121     });
1122     chooseAnnotations.setText(MessageManager
1123             .getString("action.choose_annotations"));
1124     chooseAnnotations.addActionListener(new java.awt.event.ActionListener()
1125     {
1126       @Override
1127       public void actionPerformed(ActionEvent e)
1128       {
1129         chooseAnnotations_actionPerformed(e);
1130       }
1131     });
1132     sequenceDetails.setText(MessageManager
1133             .getString("label.sequence_details"));
1134     sequenceDetails.addActionListener(new java.awt.event.ActionListener()
1135     {
1136       @Override
1137       public void actionPerformed(ActionEvent e)
1138       {
1139         sequenceDetails_actionPerformed();
1140       }
1141     });
1142     sequenceSelDetails.setText(MessageManager
1143             .getString("label.sequence_details"));
1144     sequenceSelDetails
1145             .addActionListener(new java.awt.event.ActionListener()
1146             {
1147               @Override
1148               public void actionPerformed(ActionEvent e)
1149               {
1150                 sequenceSelectionDetails_actionPerformed();
1151               }
1152             });
1153     PIDColour.setFocusPainted(false);
1154     unGroupMenuItem
1155             .setText(MessageManager.getString("action.remove_group"));
1156     unGroupMenuItem.addActionListener(new java.awt.event.ActionListener()
1157     {
1158       @Override
1159       public void actionPerformed(ActionEvent e)
1160       {
1161         unGroupMenuItem_actionPerformed();
1162       }
1163     });
1164     createGroupMenuItem.setText(MessageManager
1165             .getString("action.create_group"));
1166     createGroupMenuItem
1167             .addActionListener(new java.awt.event.ActionListener()
1168             {
1169               @Override
1170               public void actionPerformed(ActionEvent e)
1171               {
1172                 createGroupMenuItem_actionPerformed();
1173               }
1174             });
1175
1176     outline.setText(MessageManager.getString("action.border_colour"));
1177     outline.addActionListener(new java.awt.event.ActionListener()
1178     {
1179       @Override
1180       public void actionPerformed(ActionEvent e)
1181       {
1182         outline_actionPerformed();
1183       }
1184     });
1185     nucleotideMenuItem
1186             .setText(MessageManager.getString("label.nucleotide"));
1187     nucleotideMenuItem.addActionListener(new ActionListener()
1188     {
1189       @Override
1190       public void actionPerformed(ActionEvent e)
1191       {
1192         nucleotideMenuItem_actionPerformed();
1193       }
1194     });
1195     colourMenu.setText(MessageManager.getString("label.group_colour"));
1196     showBoxes.setText(MessageManager.getString("action.boxes"));
1197     showBoxes.setState(true);
1198     showBoxes.addActionListener(new ActionListener()
1199     {
1200       @Override
1201       public void actionPerformed(ActionEvent e)
1202       {
1203         showBoxes_actionPerformed();
1204       }
1205     });
1206     showText.setText(MessageManager.getString("action.text"));
1207     showText.setState(true);
1208     showText.addActionListener(new ActionListener()
1209     {
1210       @Override
1211       public void actionPerformed(ActionEvent e)
1212       {
1213         showText_actionPerformed();
1214       }
1215     });
1216     showColourText.setText(MessageManager.getString("label.colour_text"));
1217     showColourText.addActionListener(new ActionListener()
1218     {
1219       @Override
1220       public void actionPerformed(ActionEvent e)
1221       {
1222         showColourText_actionPerformed();
1223       }
1224     });
1225     displayNonconserved.setText(MessageManager
1226             .getString("label.show_non_conversed"));
1227     displayNonconserved.setState(true);
1228     displayNonconserved.addActionListener(new ActionListener()
1229     {
1230       @Override
1231       public void actionPerformed(ActionEvent e)
1232       {
1233         showNonconserved_actionPerformed();
1234       }
1235     });
1236     editMenu.setText(MessageManager.getString("action.edit"));
1237     cut.setText(MessageManager.getString("action.cut"));
1238     cut.addActionListener(new ActionListener()
1239     {
1240       @Override
1241       public void actionPerformed(ActionEvent e)
1242       {
1243         cut_actionPerformed();
1244       }
1245     });
1246     upperCase.setText(MessageManager.getString("label.to_upper_case"));
1247     upperCase.addActionListener(new ActionListener()
1248     {
1249       @Override
1250       public void actionPerformed(ActionEvent e)
1251       {
1252         changeCase(e);
1253       }
1254     });
1255     copy.setText(MessageManager.getString("action.copy"));
1256     copy.addActionListener(new ActionListener()
1257     {
1258       @Override
1259       public void actionPerformed(ActionEvent e)
1260       {
1261         copy_actionPerformed();
1262       }
1263     });
1264     lowerCase.setText(MessageManager.getString("label.to_lower_case"));
1265     lowerCase.addActionListener(new ActionListener()
1266     {
1267       @Override
1268       public void actionPerformed(ActionEvent e)
1269       {
1270         changeCase(e);
1271       }
1272     });
1273     toggle.setText(MessageManager.getString("label.toggle_case"));
1274     toggle.addActionListener(new ActionListener()
1275     {
1276       @Override
1277       public void actionPerformed(ActionEvent e)
1278       {
1279         changeCase(e);
1280       }
1281     });
1282     outputMenu.setText(MessageManager.getString("label.out_to_textbox")
1283             + "...");
1284     seqShowAnnotationsMenu.setText(MessageManager
1285             .getString("label.show_annotations"));
1286     seqHideAnnotationsMenu.setText(MessageManager
1287             .getString("label.hide_annotations"));
1288     groupShowAnnotationsMenu.setText(MessageManager
1289             .getString("label.show_annotations"));
1290     groupHideAnnotationsMenu.setText(MessageManager
1291             .getString("label.hide_annotations"));
1292     sequenceFeature.setText(MessageManager
1293             .getString("label.create_sequence_feature"));
1294     sequenceFeature.addActionListener(new ActionListener()
1295     {
1296       @Override
1297       public void actionPerformed(ActionEvent e)
1298       {
1299         sequenceFeature_actionPerformed();
1300       }
1301     });
1302     textColour.setText(MessageManager.getString("label.text_colour"));
1303     textColour.addActionListener(new ActionListener()
1304     {
1305       @Override
1306       public void actionPerformed(ActionEvent e)
1307       {
1308         textColour_actionPerformed();
1309       }
1310     });
1311     jMenu1.setText(MessageManager.getString("label.group"));
1312     pdbStructureDialog.setText(MessageManager
1313             .getString("label.show_pdbstruct_dialog"));
1314     pdbStructureDialog.addActionListener(new ActionListener()
1315     {
1316       @Override
1317       public void actionPerformed(ActionEvent actionEvent)
1318       {
1319         SequenceI[] selectedSeqs = new SequenceI[] { sequence };
1320         if (ap.av.getSelectionGroup() != null)
1321         {
1322           selectedSeqs = ap.av.getSequenceSelection();
1323         }
1324         new StructureChooser(selectedSeqs, sequence, ap);
1325       }
1326     });
1327
1328     rnaStructureMenu.setText(MessageManager
1329             .getString("label.view_rna_structure"));
1330
1331     // colStructureMenu.setText("Colour By Structure");
1332     editSequence.setText(MessageManager.getString("label.edit_sequence")
1333             + "...");
1334     editSequence.addActionListener(new ActionListener()
1335     {
1336       @Override
1337       public void actionPerformed(ActionEvent actionEvent)
1338       {
1339         editSequence_actionPerformed(actionEvent);
1340       }
1341     });
1342     makeReferenceSeq.setText(MessageManager
1343             .getString("label.mark_as_representative"));
1344     makeReferenceSeq.addActionListener(new ActionListener()
1345     {
1346
1347       @Override
1348       public void actionPerformed(ActionEvent actionEvent)
1349       {
1350         makeReferenceSeq_actionPerformed(actionEvent);
1351
1352       }
1353     });
1354     hideInsertions.setText(MessageManager
1355             .getString("label.hide_insertions"));
1356     hideInsertions.addActionListener(new ActionListener()
1357     {
1358
1359       @Override
1360       public void actionPerformed(ActionEvent e)
1361       {
1362         hideInsertions_actionPerformed(e);
1363       }
1364     });
1365     /*
1366      * annotationMenuItem.setText("By Annotation");
1367      * annotationMenuItem.addActionListener(new ActionListener() { public void
1368      * actionPerformed(ActionEvent actionEvent) {
1369      * annotationMenuItem_actionPerformed(actionEvent); } });
1370      */
1371     groupMenu.add(sequenceSelDetails);
1372     add(groupMenu);
1373     add(sequenceMenu);
1374     add(rnaStructureMenu);
1375     add(pdbStructureDialog);
1376     if (sequence != null)
1377     {
1378       add(hideInsertions);
1379     }
1380     // annotations configuration panel suppressed for now
1381     // groupMenu.add(chooseAnnotations);
1382
1383     /*
1384      * Add show/hide annotations to the Sequence menu, and to the Selection menu
1385      * (if a selection group is in force).
1386      */
1387     sequenceMenu.add(seqShowAnnotationsMenu);
1388     sequenceMenu.add(seqHideAnnotationsMenu);
1389     sequenceMenu.add(seqAddReferenceAnnotations);
1390     groupMenu.add(groupShowAnnotationsMenu);
1391     groupMenu.add(groupHideAnnotationsMenu);
1392     groupMenu.add(groupAddReferenceAnnotations);
1393     groupMenu.add(editMenu);
1394     groupMenu.add(outputMenu);
1395     groupMenu.add(sequenceFeature);
1396     groupMenu.add(createGroupMenuItem);
1397     groupMenu.add(unGroupMenuItem);
1398     groupMenu.add(jMenu1);
1399     sequenceMenu.add(sequenceName);
1400     sequenceMenu.add(sequenceDetails);
1401     sequenceMenu.add(makeReferenceSeq);
1402     colourMenu.add(textColour);
1403     colourMenu.add(noColourmenuItem);
1404     colourMenu.add(clustalColour);
1405     colourMenu.add(BLOSUM62Colour);
1406     colourMenu.add(PIDColour);
1407     colourMenu.add(zappoColour);
1408     colourMenu.add(taylorColour);
1409     colourMenu.add(hydrophobicityColour);
1410     colourMenu.add(helixColour);
1411     colourMenu.add(strandColour);
1412     colourMenu.add(turnColour);
1413     colourMenu.add(buriedColour);
1414     colourMenu.add(nucleotideMenuItem);
1415     if (ap.getAlignment().isNucleotide())
1416     {
1417       // JBPNote - commented since the colourscheme isn't functional
1418       colourMenu.add(purinePyrimidineColour);
1419     }
1420     colourMenu.add(userDefinedColour);
1421
1422     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
1423     {
1424       java.util.Enumeration userColours = jalview.gui.UserDefinedColours
1425               .getUserColourSchemes().keys();
1426
1427       while (userColours.hasMoreElements())
1428       {
1429         JMenuItem item = new JMenuItem(userColours.nextElement().toString());
1430         item.addActionListener(new ActionListener()
1431         {
1432           @Override
1433           public void actionPerformed(ActionEvent evt)
1434           {
1435             userDefinedColour_actionPerformed(evt);
1436           }
1437         });
1438         colourMenu.add(item);
1439       }
1440     }
1441
1442     colourMenu.addSeparator();
1443     colourMenu.add(abovePIDColour);
1444     colourMenu.add(conservationMenuItem);
1445     editMenu.add(copy);
1446     editMenu.add(cut);
1447     editMenu.add(editSequence);
1448     editMenu.add(upperCase);
1449     editMenu.add(lowerCase);
1450     editMenu.add(toggle);
1451     // JBPNote: These shouldn't be added here - should appear in a generic
1452     // 'apply web service to this sequence menu'
1453     // pdbMenu.add(RNAFold);
1454     // pdbMenu.add(ContraFold);
1455     jMenu1.add(groupName);
1456     jMenu1.add(colourMenu);
1457     jMenu1.add(showBoxes);
1458     jMenu1.add(showText);
1459     jMenu1.add(showColourText);
1460     jMenu1.add(outline);
1461     jMenu1.add(displayNonconserved);
1462     noColourmenuItem.setText(MessageManager.getString("label.none"));
1463     noColourmenuItem.addActionListener(new java.awt.event.ActionListener()
1464     {
1465       @Override
1466       public void actionPerformed(ActionEvent e)
1467       {
1468         noColourmenuItem_actionPerformed();
1469       }
1470     });
1471
1472     clustalColour.setText(MessageManager
1473             .getString("label.clustalx_colours"));
1474     clustalColour.addActionListener(new java.awt.event.ActionListener()
1475     {
1476       @Override
1477       public void actionPerformed(ActionEvent e)
1478       {
1479         clustalColour_actionPerformed();
1480       }
1481     });
1482     zappoColour.setText(MessageManager.getString("label.zappo"));
1483     zappoColour.addActionListener(new java.awt.event.ActionListener()
1484     {
1485       @Override
1486       public void actionPerformed(ActionEvent e)
1487       {
1488         zappoColour_actionPerformed();
1489       }
1490     });
1491     taylorColour.setText(MessageManager.getString("label.taylor"));
1492     taylorColour.addActionListener(new java.awt.event.ActionListener()
1493     {
1494       @Override
1495       public void actionPerformed(ActionEvent e)
1496       {
1497         taylorColour_actionPerformed();
1498       }
1499     });
1500     hydrophobicityColour.setText(MessageManager
1501             .getString("label.hydrophobicity"));
1502     hydrophobicityColour
1503             .addActionListener(new java.awt.event.ActionListener()
1504             {
1505               @Override
1506               public void actionPerformed(ActionEvent e)
1507               {
1508                 hydrophobicityColour_actionPerformed();
1509               }
1510             });
1511     helixColour.setText(MessageManager.getString("label.helix_propensity"));
1512     helixColour.addActionListener(new java.awt.event.ActionListener()
1513     {
1514       @Override
1515       public void actionPerformed(ActionEvent e)
1516       {
1517         helixColour_actionPerformed();
1518       }
1519     });
1520     strandColour.setText(MessageManager
1521             .getString("label.strand_propensity"));
1522     strandColour.addActionListener(new java.awt.event.ActionListener()
1523     {
1524       @Override
1525       public void actionPerformed(ActionEvent e)
1526       {
1527         strandColour_actionPerformed();
1528       }
1529     });
1530     turnColour.setText(MessageManager.getString("label.turn_propensity"));
1531     turnColour.addActionListener(new java.awt.event.ActionListener()
1532     {
1533       @Override
1534       public void actionPerformed(ActionEvent e)
1535       {
1536         turnColour_actionPerformed();
1537       }
1538     });
1539     buriedColour.setText(MessageManager.getString("label.buried_index"));
1540     buriedColour.addActionListener(new java.awt.event.ActionListener()
1541     {
1542       @Override
1543       public void actionPerformed(ActionEvent e)
1544       {
1545         buriedColour_actionPerformed();
1546       }
1547     });
1548     abovePIDColour.setText(MessageManager
1549             .getString("label.above_identity_percentage"));
1550     abovePIDColour.addActionListener(new java.awt.event.ActionListener()
1551     {
1552       @Override
1553       public void actionPerformed(ActionEvent e)
1554       {
1555         abovePIDColour_actionPerformed();
1556       }
1557     });
1558     userDefinedColour.setText(MessageManager
1559             .getString("action.user_defined"));
1560     userDefinedColour.addActionListener(new java.awt.event.ActionListener()
1561     {
1562       @Override
1563       public void actionPerformed(ActionEvent e)
1564       {
1565         userDefinedColour_actionPerformed(e);
1566       }
1567     });
1568     PIDColour
1569             .setText(MessageManager.getString("label.percentage_identity"));
1570     PIDColour.addActionListener(new java.awt.event.ActionListener()
1571     {
1572       @Override
1573       public void actionPerformed(ActionEvent e)
1574       {
1575         PIDColour_actionPerformed();
1576       }
1577     });
1578     BLOSUM62Colour.setText(MessageManager.getString("label.blosum62"));
1579     BLOSUM62Colour.addActionListener(new java.awt.event.ActionListener()
1580     {
1581       @Override
1582       public void actionPerformed(ActionEvent e)
1583       {
1584         BLOSUM62Colour_actionPerformed();
1585       }
1586     });
1587     purinePyrimidineColour.setText(MessageManager
1588             .getString("label.purine_pyrimidine"));
1589     purinePyrimidineColour
1590             .addActionListener(new java.awt.event.ActionListener()
1591             {
1592               @Override
1593               public void actionPerformed(ActionEvent e)
1594               {
1595                 purinePyrimidineColour_actionPerformed();
1596               }
1597             });
1598
1599     /*
1600      * covariationColour.addActionListener(new java.awt.event.ActionListener() {
1601      * public void actionPerformed(ActionEvent e) {
1602      * covariationColour_actionPerformed(); } });
1603      */
1604
1605     conservationMenuItem.setText(MessageManager
1606             .getString("label.conservation"));
1607     conservationMenuItem
1608             .addActionListener(new java.awt.event.ActionListener()
1609             {
1610               @Override
1611               public void actionPerformed(ActionEvent e)
1612               {
1613                 conservationMenuItem_actionPerformed();
1614               }
1615             });
1616   }
1617
1618   /**
1619    * Check for any annotations on the underlying dataset sequences (for the
1620    * current selection group) which are not 'on the alignment'.If any are found,
1621    * enable the option to add them to the alignment. The criteria for 'on the
1622    * alignment' is finding an alignment annotation on the alignment, matched on
1623    * calcId, label and sequenceRef.
1624    * 
1625    * A tooltip is also constructed that displays the source (calcId) and type
1626    * (label) of the annotations that can be added.
1627    * 
1628    * @param menuItem
1629    * @param forSequences
1630    */
1631   protected void configureReferenceAnnotationsMenu(JMenuItem menuItem,
1632           List<SequenceI> forSequences)
1633   {
1634     menuItem.setEnabled(false);
1635
1636     /*
1637      * Temporary store to hold distinct calcId / type pairs for the tooltip.
1638      * Using TreeMap means calcIds are shown in alphabetical order.
1639      */
1640     Map<String, String> tipEntries = new TreeMap<String, String>();
1641     final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
1642     AlignmentI al = this.ap.av.getAlignment();
1643     AlignmentUtils.findAddableReferenceAnnotations(forSequences,
1644             tipEntries, candidates, al);
1645     if (!candidates.isEmpty())
1646     {
1647       StringBuilder tooltip = new StringBuilder(64);
1648       tooltip.append(MessageManager.getString("label.add_annotations_for"));
1649
1650       /*
1651        * Found annotations that could be added. Enable the menu item, and
1652        * configure its tooltip and action.
1653        */
1654       menuItem.setEnabled(true);
1655       for (String calcId : tipEntries.keySet())
1656       {
1657         tooltip.append("<br/>" + calcId + "/" + tipEntries.get(calcId));
1658       }
1659       String tooltipText = JvSwingUtils.wrapTooltip(true,
1660               tooltip.toString());
1661       menuItem.setToolTipText(tooltipText);
1662
1663       menuItem.addActionListener(new ActionListener()
1664       {
1665         @Override
1666         public void actionPerformed(ActionEvent e)
1667         {
1668           addReferenceAnnotations_actionPerformed(candidates);
1669         }
1670       });
1671     }
1672   }
1673
1674   /**
1675    * Add annotations to the sequences and to the alignment.
1676    * 
1677    * @param candidates
1678    *          a map whose keys are sequences on the alignment, and values a list
1679    *          of annotations to add to each sequence
1680    */
1681   protected void addReferenceAnnotations_actionPerformed(
1682           Map<SequenceI, List<AlignmentAnnotation>> candidates)
1683   {
1684     final SequenceGroup selectionGroup = this.ap.av.getSelectionGroup();
1685     final AlignmentI alignment = this.ap.getAlignment();
1686     AlignmentUtils.addReferenceAnnotations(candidates, alignment,
1687             selectionGroup);
1688     refresh();
1689   }
1690
1691   protected void makeReferenceSeq_actionPerformed(ActionEvent actionEvent)
1692   {
1693     if (!ap.av.getAlignment().hasSeqrep())
1694     {
1695       // initialise the display flags so the user sees something happen
1696       ap.av.setDisplayReferenceSeq(true);
1697       ap.av.setColourByReferenceSeq(true);
1698       ap.av.getAlignment().setSeqrep(sequence);
1699     }
1700     else
1701     {
1702       if (ap.av.getAlignment().getSeqrep() == sequence)
1703       {
1704         ap.av.getAlignment().setSeqrep(null);
1705       }
1706       else
1707       {
1708         ap.av.getAlignment().setSeqrep(sequence);
1709       }
1710     }
1711     refresh();
1712   }
1713
1714   protected void hideInsertions_actionPerformed(ActionEvent actionEvent)
1715   {
1716     if (sequence != null)
1717     {
1718       ColumnSelection cs = ap.av.getColumnSelection();
1719       if (cs == null)
1720       {
1721         cs = new ColumnSelection();
1722       }
1723       cs.hideInsertionsFor(sequence);
1724       ap.av.setColumnSelection(cs);
1725     }
1726     refresh();
1727   }
1728
1729   protected void sequenceSelectionDetails_actionPerformed()
1730   {
1731     createSequenceDetailsReport(ap.av.getSequenceSelection());
1732   }
1733
1734   protected void sequenceDetails_actionPerformed()
1735   {
1736     createSequenceDetailsReport(new SequenceI[] { sequence });
1737   }
1738
1739   public void createSequenceDetailsReport(SequenceI[] sequences)
1740   {
1741     CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer();
1742     StringBuffer contents = new StringBuffer();
1743     for (SequenceI seq : sequences)
1744     {
1745       contents.append("<p><h2>"
1746               + MessageManager
1747                       .formatMessage(
1748                               "label.create_sequence_details_report_annotation_for",
1749                               new Object[] { seq.getDisplayId(true) })
1750               + "</h2></p><p>");
1751       new SequenceAnnotationReport(null)
1752               .createSequenceAnnotationReport(
1753                       contents,
1754                       seq,
1755                       true,
1756                       true,
1757                       false,
1758                       (ap.getSeqPanel().seqCanvas.fr != null) ? ap
1759                               .getSeqPanel().seqCanvas.fr.getMinMax()
1760                               : null);
1761       contents.append("</p>");
1762     }
1763     cap.setText("<html>" + contents.toString() + "</html>");
1764
1765     Desktop.addInternalFrame(cap, MessageManager.formatMessage(
1766             "label.sequence_details_for",
1767             (sequences.length == 1 ? new Object[] { sequences[0]
1768                     .getDisplayId(true) } : new Object[] { MessageManager
1769                     .getString("label.selection") })), 500, 400);
1770
1771   }
1772
1773   protected void showNonconserved_actionPerformed()
1774   {
1775     getGroup().setShowNonconserved(displayNonconserved.isSelected());
1776     refresh();
1777   }
1778
1779   /**
1780    * call to refresh view after settings change
1781    */
1782   void refresh()
1783   {
1784     ap.updateAnnotation();
1785     ap.paintAlignment(true);
1786
1787     PaintRefresher.Refresh(this, ap.av.getSequenceSetId());
1788   }
1789
1790   /**
1791    * DOCUMENT ME!
1792    * 
1793    * @param e
1794    *          DOCUMENT ME!
1795    */
1796   protected void clustalColour_actionPerformed()
1797   {
1798     SequenceGroup sg = getGroup();
1799     sg.cs = new ClustalxColourScheme(sg, ap.av.getHiddenRepSequences());
1800     refresh();
1801   }
1802
1803   /**
1804    * DOCUMENT ME!
1805    * 
1806    * @param e
1807    *          DOCUMENT ME!
1808    */
1809   protected void zappoColour_actionPerformed()
1810   {
1811     getGroup().cs = new ZappoColourScheme();
1812     refresh();
1813   }
1814
1815   /**
1816    * DOCUMENT ME!
1817    * 
1818    * @param e
1819    *          DOCUMENT ME!
1820    */
1821   protected void taylorColour_actionPerformed()
1822   {
1823     getGroup().cs = new TaylorColourScheme();
1824     refresh();
1825   }
1826
1827   /**
1828    * DOCUMENT ME!
1829    * 
1830    * @param e
1831    *          DOCUMENT ME!
1832    */
1833   protected void hydrophobicityColour_actionPerformed()
1834   {
1835     getGroup().cs = new HydrophobicColourScheme();
1836     refresh();
1837   }
1838
1839   /**
1840    * DOCUMENT ME!
1841    * 
1842    * @param e
1843    *          DOCUMENT ME!
1844    */
1845   protected void helixColour_actionPerformed()
1846   {
1847     getGroup().cs = new HelixColourScheme();
1848     refresh();
1849   }
1850
1851   /**
1852    * DOCUMENT ME!
1853    * 
1854    * @param e
1855    *          DOCUMENT ME!
1856    */
1857   protected void strandColour_actionPerformed()
1858   {
1859     getGroup().cs = new StrandColourScheme();
1860     refresh();
1861   }
1862
1863   /**
1864    * DOCUMENT ME!
1865    * 
1866    * @param e
1867    *          DOCUMENT ME!
1868    */
1869   protected void turnColour_actionPerformed()
1870   {
1871     getGroup().cs = new TurnColourScheme();
1872     refresh();
1873   }
1874
1875   /**
1876    * DOCUMENT ME!
1877    * 
1878    * @param e
1879    *          DOCUMENT ME!
1880    */
1881   protected void buriedColour_actionPerformed()
1882   {
1883     getGroup().cs = new BuriedColourScheme();
1884     refresh();
1885   }
1886
1887   /**
1888    * DOCUMENT ME!
1889    * 
1890    * @param e
1891    *          DOCUMENT ME!
1892    */
1893   public void nucleotideMenuItem_actionPerformed()
1894   {
1895     getGroup().cs = new NucleotideColourScheme();
1896     refresh();
1897   }
1898
1899   protected void purinePyrimidineColour_actionPerformed()
1900   {
1901     getGroup().cs = new PurinePyrimidineColourScheme();
1902     refresh();
1903   }
1904
1905   /*
1906    * protected void covariationColour_actionPerformed() { getGroup().cs = new
1907    * CovariationColourScheme(sequence.getAnnotation()[0]); refresh(); }
1908    */
1909   /**
1910    * DOCUMENT ME!
1911    * 
1912    * @param e
1913    *          DOCUMENT ME!
1914    */
1915   protected void abovePIDColour_actionPerformed()
1916   {
1917     SequenceGroup sg = getGroup();
1918     if (sg.cs == null)
1919     {
1920       return;
1921     }
1922
1923     if (abovePIDColour.isSelected())
1924     {
1925       sg.cs.setConsensus(AAFrequency.calculate(
1926               sg.getSequences(ap.av.getHiddenRepSequences()),
1927               sg.getStartRes(), sg.getEndRes() + 1));
1928
1929       int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup()
1930               .getName());
1931
1932       sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus());
1933
1934       SliderPanel.showPIDSlider();
1935     }
1936     else
1937     // remove PIDColouring
1938     {
1939       sg.cs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
1940     }
1941
1942     refresh();
1943   }
1944
1945   /**
1946    * DOCUMENT ME!
1947    * 
1948    * @param e
1949    *          DOCUMENT ME!
1950    */
1951   protected void userDefinedColour_actionPerformed(ActionEvent e)
1952   {
1953     SequenceGroup sg = getGroup();
1954
1955     if (e.getSource().equals(userDefinedColour))
1956     {
1957       new UserDefinedColours(ap, sg);
1958     }
1959     else
1960     {
1961       UserColourScheme udc = (UserColourScheme) UserDefinedColours
1962               .getUserColourSchemes().get(e.getActionCommand());
1963
1964       sg.cs = udc;
1965     }
1966     refresh();
1967   }
1968
1969   /**
1970    * Open a panel where the user can choose which types of sequence annotation
1971    * to show or hide.
1972    * 
1973    * @param e
1974    */
1975   protected void chooseAnnotations_actionPerformed(ActionEvent e)
1976   {
1977     // todo correct way to guard against opening a duplicate panel?
1978     new AnnotationChooser(ap);
1979   }
1980
1981   /**
1982    * DOCUMENT ME!
1983    * 
1984    * @param e
1985    *          DOCUMENT ME!
1986    */
1987   protected void PIDColour_actionPerformed()
1988   {
1989     SequenceGroup sg = getGroup();
1990     sg.cs = new PIDColourScheme();
1991     sg.cs.setConsensus(AAFrequency.calculate(
1992             sg.getSequences(ap.av.getHiddenRepSequences()),
1993             sg.getStartRes(), sg.getEndRes() + 1));
1994     refresh();
1995   }
1996
1997   /**
1998    * DOCUMENT ME!
1999    * 
2000    * @param e
2001    *          DOCUMENT ME!
2002    */
2003   protected void BLOSUM62Colour_actionPerformed()
2004   {
2005     SequenceGroup sg = getGroup();
2006
2007     sg.cs = new Blosum62ColourScheme();
2008
2009     sg.cs.setConsensus(AAFrequency.calculate(
2010             sg.getSequences(ap.av.getHiddenRepSequences()),
2011             sg.getStartRes(), sg.getEndRes() + 1));
2012
2013     refresh();
2014   }
2015
2016   /**
2017    * DOCUMENT ME!
2018    * 
2019    * @param e
2020    *          DOCUMENT ME!
2021    */
2022   protected void noColourmenuItem_actionPerformed()
2023   {
2024     getGroup().cs = null;
2025     refresh();
2026   }
2027
2028   /**
2029    * DOCUMENT ME!
2030    * 
2031    * @param e
2032    *          DOCUMENT ME!
2033    */
2034   protected void conservationMenuItem_actionPerformed()
2035   {
2036     SequenceGroup sg = getGroup();
2037     if (sg.cs == null)
2038     {
2039       return;
2040     }
2041
2042     if (conservationMenuItem.isSelected())
2043     {
2044       // JBPNote: Conservation name shouldn't be i18n translated
2045       Conservation c = new Conservation("Group",
2046               ResidueProperties.propHash, 3, sg.getSequences(ap.av
2047                       .getHiddenRepSequences()), sg.getStartRes(),
2048               sg.getEndRes() + 1);
2049
2050       c.calculate();
2051       c.verdict(false, ap.av.getConsPercGaps());
2052
2053       sg.cs.setConservation(c);
2054
2055       SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
2056       SliderPanel.showConservationSlider();
2057     }
2058     else
2059     // remove ConservationColouring
2060     {
2061       sg.cs.setConservation(null);
2062     }
2063
2064     refresh();
2065   }
2066
2067   public void annotationMenuItem_actionPerformed(ActionEvent actionEvent)
2068   {
2069     SequenceGroup sg = getGroup();
2070     if (sg == null)
2071     {
2072       return;
2073     }
2074
2075     AnnotationColourGradient acg = new AnnotationColourGradient(
2076             sequence.getAnnotation()[0], null,
2077             AnnotationColourGradient.NO_THRESHOLD);
2078
2079     acg.setPredefinedColours(true);
2080     sg.cs = acg;
2081
2082     refresh();
2083   }
2084
2085   /**
2086    * DOCUMENT ME!
2087    * 
2088    * @param e
2089    *          DOCUMENT ME!
2090    */
2091   protected void groupName_actionPerformed()
2092   {
2093
2094     SequenceGroup sg = getGroup();
2095     EditNameDialog dialog = new EditNameDialog(sg.getName(),
2096             sg.getDescription(), "       "
2097                     + MessageManager.getString("label.group_name") + " ",
2098             MessageManager.getString("label.group_description") + " ",
2099             MessageManager.getString("label.edit_group_name_description"),
2100             ap.alignFrame);
2101
2102     if (!dialog.accept)
2103     {
2104       return;
2105     }
2106
2107     sg.setName(dialog.getName());
2108     sg.setDescription(dialog.getDescription());
2109     refresh();
2110   }
2111
2112   /**
2113    * Get selection group - adding it to the alignment if necessary.
2114    * 
2115    * @return sequence group to operate on
2116    */
2117   SequenceGroup getGroup()
2118   {
2119     SequenceGroup sg = ap.av.getSelectionGroup();
2120     // this method won't add a new group if it already exists
2121     if (sg != null)
2122     {
2123       ap.av.getAlignment().addGroup(sg);
2124     }
2125
2126     return sg;
2127   }
2128
2129   /**
2130    * DOCUMENT ME!
2131    * 
2132    * @param e
2133    *          DOCUMENT ME!
2134    */
2135   void sequenceName_actionPerformed()
2136   {
2137     EditNameDialog dialog = new EditNameDialog(sequence.getName(),
2138             sequence.getDescription(),
2139             "       " + MessageManager.getString("label.sequence_name")
2140                     + " ",
2141             MessageManager.getString("label.sequence_description") + " ",
2142             MessageManager
2143                     .getString("label.edit_sequence_name_description"),
2144             ap.alignFrame);
2145
2146     if (!dialog.accept)
2147     {
2148       return;
2149     }
2150
2151     if (dialog.getName() != null)
2152     {
2153       if (dialog.getName().indexOf(" ") > -1)
2154       {
2155         JOptionPane
2156                 .showMessageDialog(
2157                         ap,
2158                         MessageManager
2159                                 .getString("label.spaces_converted_to_backslashes"),
2160                         MessageManager
2161                                 .getString("label.no_spaces_allowed_sequence_name"),
2162                         JOptionPane.WARNING_MESSAGE);
2163       }
2164
2165       sequence.setName(dialog.getName().replace(' ', '_'));
2166       ap.paintAlignment(false);
2167     }
2168
2169     sequence.setDescription(dialog.getDescription());
2170
2171     ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
2172             .getSequences());
2173
2174   }
2175
2176   /**
2177    * DOCUMENT ME!
2178    * 
2179    * @param e
2180    *          DOCUMENT ME!
2181    */
2182   void unGroupMenuItem_actionPerformed()
2183   {
2184     SequenceGroup sg = ap.av.getSelectionGroup();
2185     ap.av.getAlignment().deleteGroup(sg);
2186     ap.av.setSelectionGroup(null);
2187     refresh();
2188   }
2189
2190   void createGroupMenuItem_actionPerformed()
2191   {
2192     getGroup(); // implicitly creates group - note - should apply defaults / use
2193                 // standard alignment window logic for this
2194     refresh();
2195   }
2196
2197   /**
2198    * DOCUMENT ME!
2199    * 
2200    * @param e
2201    *          DOCUMENT ME!
2202    */
2203   protected void outline_actionPerformed()
2204   {
2205     SequenceGroup sg = getGroup();
2206     Color col = JColorChooser.showDialog(this,
2207             MessageManager.getString("label.select_outline_colour"),
2208             Color.BLUE);
2209
2210     if (col != null)
2211     {
2212       sg.setOutlineColour(col);
2213     }
2214
2215     refresh();
2216   }
2217
2218   /**
2219    * DOCUMENT ME!
2220    * 
2221    * @param e
2222    *          DOCUMENT ME!
2223    */
2224   public void showBoxes_actionPerformed()
2225   {
2226     getGroup().setDisplayBoxes(showBoxes.isSelected());
2227     refresh();
2228   }
2229
2230   /**
2231    * DOCUMENT ME!
2232    * 
2233    * @param e
2234    *          DOCUMENT ME!
2235    */
2236   public void showText_actionPerformed()
2237   {
2238     getGroup().setDisplayText(showText.isSelected());
2239     refresh();
2240   }
2241
2242   /**
2243    * DOCUMENT ME!
2244    * 
2245    * @param e
2246    *          DOCUMENT ME!
2247    */
2248   public void showColourText_actionPerformed()
2249   {
2250     getGroup().setColourText(showColourText.isSelected());
2251     refresh();
2252   }
2253
2254   public void showLink(String url)
2255   {
2256     try
2257     {
2258       jalview.util.BrowserLauncher.openURL(url);
2259     } catch (Exception ex)
2260     {
2261       JOptionPane.showInternalMessageDialog(Desktop.desktop,
2262               MessageManager.getString("label.web_browser_not_found_unix"),
2263               MessageManager.getString("label.web_browser_not_found"),
2264               JOptionPane.WARNING_MESSAGE);
2265
2266       ex.printStackTrace();
2267     }
2268   }
2269
2270   void hideSequences(boolean representGroup)
2271   {
2272     ap.av.hideSequences(sequence, representGroup);
2273   }
2274
2275   public void copy_actionPerformed()
2276   {
2277     ap.alignFrame.copy_actionPerformed(null);
2278   }
2279
2280   public void cut_actionPerformed()
2281   {
2282     ap.alignFrame.cut_actionPerformed(null);
2283   }
2284
2285   void changeCase(ActionEvent e)
2286   {
2287     Object source = e.getSource();
2288     SequenceGroup sg = ap.av.getSelectionGroup();
2289
2290     if (sg != null)
2291     {
2292       List<int[]> startEnd = ap.av.getVisibleRegionBoundaries(
2293               sg.getStartRes(), sg.getEndRes() + 1);
2294
2295       String description;
2296       int caseChange;
2297
2298       if (source == toggle)
2299       {
2300         description = MessageManager.getString("label.toggle_case");
2301         caseChange = ChangeCaseCommand.TOGGLE_CASE;
2302       }
2303       else if (source == upperCase)
2304       {
2305         description = MessageManager.getString("label.to_upper_case");
2306         caseChange = ChangeCaseCommand.TO_UPPER;
2307       }
2308       else
2309       {
2310         description = MessageManager.getString("label.to_lower_case");
2311         caseChange = ChangeCaseCommand.TO_LOWER;
2312       }
2313
2314       ChangeCaseCommand caseCommand = new ChangeCaseCommand(description,
2315               sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
2316               startEnd, caseChange);
2317
2318       ap.alignFrame.addHistoryItem(caseCommand);
2319
2320       ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
2321               .getSequences());
2322
2323     }
2324   }
2325
2326   public void outputText_actionPerformed(ActionEvent e)
2327   {
2328     CutAndPasteTransfer cap = new CutAndPasteTransfer();
2329     cap.setForInput(null);
2330     Desktop.addInternalFrame(cap, MessageManager.formatMessage(
2331             "label.alignment_output_command",
2332             new Object[] { e.getActionCommand() }), 600, 500);
2333
2334     String[] omitHidden = null;
2335
2336     System.out.println("PROMPT USER HERE"); // TODO: decide if a prompt happens
2337     // or we simply trust the user wants
2338     // wysiwig behaviour
2339
2340     cap.setText(new FormatAdapter(ap).formatSequences(e.getActionCommand(),
2341             ap, true));
2342   }
2343
2344   public void sequenceFeature_actionPerformed()
2345   {
2346     SequenceGroup sg = ap.av.getSelectionGroup();
2347     if (sg == null)
2348     {
2349       return;
2350     }
2351
2352     int rsize = 0, gSize = sg.getSize();
2353     SequenceI[] rseqs, seqs = new SequenceI[gSize];
2354     SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
2355
2356     for (int i = 0; i < gSize; i++)
2357     {
2358       int start = sg.getSequenceAt(i).findPosition(sg.getStartRes());
2359       int end = sg.findEndRes(sg.getSequenceAt(i));
2360       if (start <= end)
2361       {
2362         seqs[rsize] = sg.getSequenceAt(i).getDatasetSequence();
2363         features[rsize] = new SequenceFeature(null, null, null, start, end,
2364                 "Jalview");
2365         rsize++;
2366       }
2367     }
2368     rseqs = new SequenceI[rsize];
2369     tfeatures = new SequenceFeature[rsize];
2370     System.arraycopy(seqs, 0, rseqs, 0, rsize);
2371     System.arraycopy(features, 0, tfeatures, 0, rsize);
2372     features = tfeatures;
2373     seqs = rseqs;
2374     if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
2375             features, true, ap))
2376     {
2377       ap.alignFrame.setShowSeqFeatures(true);
2378       ap.highlightSearchResults(null);
2379     }
2380   }
2381
2382   public void textColour_actionPerformed()
2383   {
2384     SequenceGroup sg = getGroup();
2385     if (sg != null)
2386     {
2387       new TextColourChooser().chooseColour(ap, sg);
2388     }
2389   }
2390
2391   public void colourByStructure(String pdbid)
2392   {
2393     Annotation[] anots = ap.av.getStructureSelectionManager()
2394             .colourSequenceFromStructure(sequence, pdbid);
2395
2396     AlignmentAnnotation an = new AlignmentAnnotation("Structure",
2397             "Coloured by " + pdbid, anots);
2398
2399     ap.av.getAlignment().addAnnotation(an);
2400     an.createSequenceMapping(sequence, 0, true);
2401     // an.adjustForAlignment();
2402     ap.av.getAlignment().setAnnotationIndex(an, 0);
2403
2404     ap.adjustAnnotationHeight();
2405
2406     sequence.addAlignmentAnnotation(an);
2407
2408   }
2409
2410   public void editSequence_actionPerformed(ActionEvent actionEvent)
2411   {
2412     SequenceGroup sg = ap.av.getSelectionGroup();
2413
2414     if (sg != null)
2415     {
2416       if (sequence == null)
2417       {
2418         sequence = sg.getSequenceAt(0);
2419       }
2420
2421       EditNameDialog dialog = new EditNameDialog(
2422               sequence.getSequenceAsString(sg.getStartRes(),
2423                       sg.getEndRes() + 1), null,
2424               MessageManager.getString("label.edit_sequence"), null,
2425               MessageManager.getString("label.edit_sequence"),
2426               ap.alignFrame);
2427
2428       if (dialog.accept)
2429       {
2430         EditCommand editCommand = new EditCommand(
2431                 MessageManager.getString("label.edit_sequences"),
2432                 Action.REPLACE, dialog.getName().replace(' ',
2433                         ap.av.getGapCharacter()),
2434                 sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
2435                 sg.getStartRes(), sg.getEndRes() + 1, ap.av.getAlignment());
2436
2437         ap.alignFrame.addHistoryItem(editCommand);
2438
2439         ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
2440                 .getSequences());
2441       }
2442     }
2443   }
2444
2445 }