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