Merge branch 'develop' into features/filetypeEnum
[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.FileFormat;
42 import jalview.io.FileFormatI;
43 import jalview.io.FormatAdapter;
44 import jalview.io.SequenceAnnotationReport;
45 import jalview.schemes.AnnotationColourGradient;
46 import jalview.schemes.Blosum62ColourScheme;
47 import jalview.schemes.BuriedColourScheme;
48 import jalview.schemes.ClustalxColourScheme;
49 import jalview.schemes.HelixColourScheme;
50 import jalview.schemes.HydrophobicColourScheme;
51 import jalview.schemes.NucleotideColourScheme;
52 import jalview.schemes.PIDColourScheme;
53 import jalview.schemes.PurinePyrimidineColourScheme;
54 import jalview.schemes.ResidueProperties;
55 import jalview.schemes.StrandColourScheme;
56 import jalview.schemes.TaylorColourScheme;
57 import jalview.schemes.TurnColourScheme;
58 import jalview.schemes.UserColourScheme;
59 import jalview.schemes.ZappoColourScheme;
60 import jalview.util.DBRefUtils;
61 import jalview.util.GroupUrlLink;
62 import jalview.util.GroupUrlLink.UrlStringTooLongException;
63 import jalview.util.MessageManager;
64 import jalview.util.UrlLink;
65
66 import java.awt.Color;
67 import java.awt.event.ActionEvent;
68 import java.awt.event.ActionListener;
69 import java.util.ArrayList;
70 import java.util.Arrays;
71 import java.util.Collections;
72 import java.util.Hashtable;
73 import java.util.LinkedHashMap;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.TreeMap;
77 import java.util.Vector;
78
79 import javax.swing.ButtonGroup;
80 import javax.swing.JCheckBoxMenuItem;
81 import javax.swing.JColorChooser;
82 import javax.swing.JMenu;
83 import javax.swing.JMenuItem;
84 import javax.swing.JOptionPane;
85 import javax.swing.JPopupMenu;
86 import javax.swing.JRadioButtonMenuItem;
87
88 /**
89  * DOCUMENT ME!
90  * 
91  * @author $author$
92  * @version $Revision: 1.118 $
93  */
94 public class PopupMenu extends JPopupMenu
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
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.selection"));
1101     groupName.setText(MessageManager.getString("label.name"));
1102     groupName.addActionListener(new java.awt.event.ActionListener()
1103     {
1104       @Override
1105       public void actionPerformed(ActionEvent e)
1106       {
1107         groupName_actionPerformed();
1108       }
1109     });
1110     sequenceMenu.setText(MessageManager.getString("label.sequence"));
1111     sequenceName.setText(MessageManager
1112             .getString("label.edit_name_description"));
1113     sequenceName.addActionListener(new java.awt.event.ActionListener()
1114     {
1115       @Override
1116       public void actionPerformed(ActionEvent e)
1117       {
1118         sequenceName_actionPerformed();
1119       }
1120     });
1121     chooseAnnotations.setText(MessageManager
1122             .getString("action.choose_annotations"));
1123     chooseAnnotations.addActionListener(new java.awt.event.ActionListener()
1124     {
1125       @Override
1126       public void actionPerformed(ActionEvent e)
1127       {
1128         chooseAnnotations_actionPerformed(e);
1129       }
1130     });
1131     sequenceDetails.setText(MessageManager
1132             .getString("label.sequence_details"));
1133     sequenceDetails.addActionListener(new java.awt.event.ActionListener()
1134     {
1135       @Override
1136       public void actionPerformed(ActionEvent e)
1137       {
1138         sequenceDetails_actionPerformed();
1139       }
1140     });
1141     sequenceSelDetails.setText(MessageManager
1142             .getString("label.sequence_details"));
1143     sequenceSelDetails
1144             .addActionListener(new java.awt.event.ActionListener()
1145             {
1146               @Override
1147               public void actionPerformed(ActionEvent e)
1148               {
1149                 sequenceSelectionDetails_actionPerformed();
1150               }
1151             });
1152     PIDColour.setFocusPainted(false);
1153     unGroupMenuItem
1154             .setText(MessageManager.getString("action.remove_group"));
1155     unGroupMenuItem.addActionListener(new java.awt.event.ActionListener()
1156     {
1157       @Override
1158       public void actionPerformed(ActionEvent e)
1159       {
1160         unGroupMenuItem_actionPerformed();
1161       }
1162     });
1163     createGroupMenuItem.setText(MessageManager
1164             .getString("action.create_group"));
1165     createGroupMenuItem
1166             .addActionListener(new java.awt.event.ActionListener()
1167             {
1168               @Override
1169               public void actionPerformed(ActionEvent e)
1170               {
1171                 createGroupMenuItem_actionPerformed();
1172               }
1173             });
1174
1175     outline.setText(MessageManager.getString("action.border_colour"));
1176     outline.addActionListener(new java.awt.event.ActionListener()
1177     {
1178       @Override
1179       public void actionPerformed(ActionEvent e)
1180       {
1181         outline_actionPerformed();
1182       }
1183     });
1184     nucleotideMenuItem
1185             .setText(MessageManager.getString("label.nucleotide"));
1186     nucleotideMenuItem.addActionListener(new ActionListener()
1187     {
1188       @Override
1189       public void actionPerformed(ActionEvent e)
1190       {
1191         nucleotideMenuItem_actionPerformed();
1192       }
1193     });
1194     colourMenu.setText(MessageManager.getString("label.group_colour"));
1195     showBoxes.setText(MessageManager.getString("action.boxes"));
1196     showBoxes.setState(true);
1197     showBoxes.addActionListener(new ActionListener()
1198     {
1199       @Override
1200       public void actionPerformed(ActionEvent e)
1201       {
1202         showBoxes_actionPerformed();
1203       }
1204     });
1205     showText.setText(MessageManager.getString("action.text"));
1206     showText.setState(true);
1207     showText.addActionListener(new ActionListener()
1208     {
1209       @Override
1210       public void actionPerformed(ActionEvent e)
1211       {
1212         showText_actionPerformed();
1213       }
1214     });
1215     showColourText.setText(MessageManager.getString("label.colour_text"));
1216     showColourText.addActionListener(new ActionListener()
1217     {
1218       @Override
1219       public void actionPerformed(ActionEvent e)
1220       {
1221         showColourText_actionPerformed();
1222       }
1223     });
1224     displayNonconserved.setText(MessageManager
1225             .getString("label.show_non_conversed"));
1226     displayNonconserved.setState(true);
1227     displayNonconserved.addActionListener(new ActionListener()
1228     {
1229       @Override
1230       public void actionPerformed(ActionEvent e)
1231       {
1232         showNonconserved_actionPerformed();
1233       }
1234     });
1235     editMenu.setText(MessageManager.getString("action.edit"));
1236     cut.setText(MessageManager.getString("action.cut"));
1237     cut.addActionListener(new ActionListener()
1238     {
1239       @Override
1240       public void actionPerformed(ActionEvent e)
1241       {
1242         cut_actionPerformed();
1243       }
1244     });
1245     upperCase.setText(MessageManager.getString("label.to_upper_case"));
1246     upperCase.addActionListener(new ActionListener()
1247     {
1248       @Override
1249       public void actionPerformed(ActionEvent e)
1250       {
1251         changeCase(e);
1252       }
1253     });
1254     copy.setText(MessageManager.getString("action.copy"));
1255     copy.addActionListener(new ActionListener()
1256     {
1257       @Override
1258       public void actionPerformed(ActionEvent e)
1259       {
1260         copy_actionPerformed();
1261       }
1262     });
1263     lowerCase.setText(MessageManager.getString("label.to_lower_case"));
1264     lowerCase.addActionListener(new ActionListener()
1265     {
1266       @Override
1267       public void actionPerformed(ActionEvent e)
1268       {
1269         changeCase(e);
1270       }
1271     });
1272     toggle.setText(MessageManager.getString("label.toggle_case"));
1273     toggle.addActionListener(new ActionListener()
1274     {
1275       @Override
1276       public void actionPerformed(ActionEvent e)
1277       {
1278         changeCase(e);
1279       }
1280     });
1281     outputMenu.setText(MessageManager.getString("label.out_to_textbox")
1282             + "...");
1283     seqShowAnnotationsMenu.setText(MessageManager
1284             .getString("label.show_annotations"));
1285     seqHideAnnotationsMenu.setText(MessageManager
1286             .getString("label.hide_annotations"));
1287     groupShowAnnotationsMenu.setText(MessageManager
1288             .getString("label.show_annotations"));
1289     groupHideAnnotationsMenu.setText(MessageManager
1290             .getString("label.hide_annotations"));
1291     sequenceFeature.setText(MessageManager
1292             .getString("label.create_sequence_feature"));
1293     sequenceFeature.addActionListener(new ActionListener()
1294     {
1295       @Override
1296       public void actionPerformed(ActionEvent e)
1297       {
1298         sequenceFeature_actionPerformed();
1299       }
1300     });
1301     textColour.setText(MessageManager.getString("label.text_colour"));
1302     textColour.addActionListener(new ActionListener()
1303     {
1304       @Override
1305       public void actionPerformed(ActionEvent e)
1306       {
1307         textColour_actionPerformed();
1308       }
1309     });
1310     jMenu1.setText(MessageManager.getString("label.group"));
1311     pdbStructureDialog.setText(MessageManager
1312             .getString("label.show_pdbstruct_dialog"));
1313     pdbStructureDialog.addActionListener(new ActionListener()
1314     {
1315       @Override
1316       public void actionPerformed(ActionEvent actionEvent)
1317       {
1318         SequenceI[] selectedSeqs = new SequenceI[] { sequence };
1319         if (ap.av.getSelectionGroup() != null)
1320         {
1321           selectedSeqs = ap.av.getSequenceSelection();
1322         }
1323         new StructureChooser(selectedSeqs, sequence, ap);
1324       }
1325     });
1326
1327     rnaStructureMenu.setText(MessageManager
1328             .getString("label.view_rna_structure"));
1329
1330     // colStructureMenu.setText("Colour By Structure");
1331     editSequence.setText(MessageManager.getString("label.edit_sequence")
1332             + "...");
1333     editSequence.addActionListener(new ActionListener()
1334     {
1335       @Override
1336       public void actionPerformed(ActionEvent actionEvent)
1337       {
1338         editSequence_actionPerformed(actionEvent);
1339       }
1340     });
1341     makeReferenceSeq.setText(MessageManager
1342             .getString("label.mark_as_representative"));
1343     makeReferenceSeq.addActionListener(new ActionListener()
1344     {
1345
1346       @Override
1347       public void actionPerformed(ActionEvent actionEvent)
1348       {
1349         makeReferenceSeq_actionPerformed(actionEvent);
1350
1351       }
1352     });
1353     hideInsertions.setText(MessageManager
1354             .getString("label.hide_insertions"));
1355     hideInsertions.addActionListener(new ActionListener()
1356     {
1357
1358       @Override
1359       public void actionPerformed(ActionEvent e)
1360       {
1361         hideInsertions_actionPerformed(e);
1362       }
1363     });
1364     /*
1365      * annotationMenuItem.setText("By Annotation");
1366      * annotationMenuItem.addActionListener(new ActionListener() { public void
1367      * actionPerformed(ActionEvent actionEvent) {
1368      * annotationMenuItem_actionPerformed(actionEvent); } });
1369      */
1370     groupMenu.add(sequenceSelDetails);
1371     add(groupMenu);
1372     add(sequenceMenu);
1373     add(rnaStructureMenu);
1374     add(pdbStructureDialog);
1375     if (sequence != null)
1376     {
1377       add(hideInsertions);
1378     }
1379     // annotations configuration panel suppressed for now
1380     // groupMenu.add(chooseAnnotations);
1381
1382     /*
1383      * Add show/hide annotations to the Sequence menu, and to the Selection menu
1384      * (if a selection group is in force).
1385      */
1386     sequenceMenu.add(seqShowAnnotationsMenu);
1387     sequenceMenu.add(seqHideAnnotationsMenu);
1388     sequenceMenu.add(seqAddReferenceAnnotations);
1389     groupMenu.add(groupShowAnnotationsMenu);
1390     groupMenu.add(groupHideAnnotationsMenu);
1391     groupMenu.add(groupAddReferenceAnnotations);
1392     groupMenu.add(editMenu);
1393     groupMenu.add(outputMenu);
1394     groupMenu.add(sequenceFeature);
1395     groupMenu.add(createGroupMenuItem);
1396     groupMenu.add(unGroupMenuItem);
1397     groupMenu.add(jMenu1);
1398     sequenceMenu.add(sequenceName);
1399     sequenceMenu.add(sequenceDetails);
1400     sequenceMenu.add(makeReferenceSeq);
1401     colourMenu.add(textColour);
1402     colourMenu.add(noColourmenuItem);
1403     colourMenu.add(clustalColour);
1404     colourMenu.add(BLOSUM62Colour);
1405     colourMenu.add(PIDColour);
1406     colourMenu.add(zappoColour);
1407     colourMenu.add(taylorColour);
1408     colourMenu.add(hydrophobicityColour);
1409     colourMenu.add(helixColour);
1410     colourMenu.add(strandColour);
1411     colourMenu.add(turnColour);
1412     colourMenu.add(buriedColour);
1413     colourMenu.add(nucleotideMenuItem);
1414     if (ap.getAlignment().isNucleotide())
1415     {
1416       // JBPNote - commented since the colourscheme isn't functional
1417       colourMenu.add(purinePyrimidineColour);
1418     }
1419     colourMenu.add(userDefinedColour);
1420
1421     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
1422     {
1423       java.util.Enumeration userColours = jalview.gui.UserDefinedColours
1424               .getUserColourSchemes().keys();
1425
1426       while (userColours.hasMoreElements())
1427       {
1428         JMenuItem item = new JMenuItem(userColours.nextElement().toString());
1429         item.addActionListener(new ActionListener()
1430         {
1431           @Override
1432           public void actionPerformed(ActionEvent evt)
1433           {
1434             userDefinedColour_actionPerformed(evt);
1435           }
1436         });
1437         colourMenu.add(item);
1438       }
1439     }
1440
1441     colourMenu.addSeparator();
1442     colourMenu.add(abovePIDColour);
1443     colourMenu.add(conservationMenuItem);
1444     editMenu.add(copy);
1445     editMenu.add(cut);
1446     editMenu.add(editSequence);
1447     editMenu.add(upperCase);
1448     editMenu.add(lowerCase);
1449     editMenu.add(toggle);
1450     // JBPNote: These shouldn't be added here - should appear in a generic
1451     // 'apply web service to this sequence menu'
1452     // pdbMenu.add(RNAFold);
1453     // pdbMenu.add(ContraFold);
1454     jMenu1.add(groupName);
1455     jMenu1.add(colourMenu);
1456     jMenu1.add(showBoxes);
1457     jMenu1.add(showText);
1458     jMenu1.add(showColourText);
1459     jMenu1.add(outline);
1460     jMenu1.add(displayNonconserved);
1461     noColourmenuItem.setText(MessageManager.getString("label.none"));
1462     noColourmenuItem.addActionListener(new java.awt.event.ActionListener()
1463     {
1464       @Override
1465       public void actionPerformed(ActionEvent e)
1466       {
1467         noColourmenuItem_actionPerformed();
1468       }
1469     });
1470
1471     clustalColour.setText(MessageManager
1472             .getString("label.clustalx_colours"));
1473     clustalColour.addActionListener(new java.awt.event.ActionListener()
1474     {
1475       @Override
1476       public void actionPerformed(ActionEvent e)
1477       {
1478         clustalColour_actionPerformed();
1479       }
1480     });
1481     zappoColour.setText(MessageManager.getString("label.zappo"));
1482     zappoColour.addActionListener(new java.awt.event.ActionListener()
1483     {
1484       @Override
1485       public void actionPerformed(ActionEvent e)
1486       {
1487         zappoColour_actionPerformed();
1488       }
1489     });
1490     taylorColour.setText(MessageManager.getString("label.taylor"));
1491     taylorColour.addActionListener(new java.awt.event.ActionListener()
1492     {
1493       @Override
1494       public void actionPerformed(ActionEvent e)
1495       {
1496         taylorColour_actionPerformed();
1497       }
1498     });
1499     hydrophobicityColour.setText(MessageManager
1500             .getString("label.hydrophobicity"));
1501     hydrophobicityColour
1502             .addActionListener(new java.awt.event.ActionListener()
1503             {
1504               @Override
1505               public void actionPerformed(ActionEvent e)
1506               {
1507                 hydrophobicityColour_actionPerformed();
1508               }
1509             });
1510     helixColour.setText(MessageManager.getString("label.helix_propensity"));
1511     helixColour.addActionListener(new java.awt.event.ActionListener()
1512     {
1513       @Override
1514       public void actionPerformed(ActionEvent e)
1515       {
1516         helixColour_actionPerformed();
1517       }
1518     });
1519     strandColour.setText(MessageManager
1520             .getString("label.strand_propensity"));
1521     strandColour.addActionListener(new java.awt.event.ActionListener()
1522     {
1523       @Override
1524       public void actionPerformed(ActionEvent e)
1525       {
1526         strandColour_actionPerformed();
1527       }
1528     });
1529     turnColour.setText(MessageManager.getString("label.turn_propensity"));
1530     turnColour.addActionListener(new java.awt.event.ActionListener()
1531     {
1532       @Override
1533       public void actionPerformed(ActionEvent e)
1534       {
1535         turnColour_actionPerformed();
1536       }
1537     });
1538     buriedColour.setText(MessageManager.getString("label.buried_index"));
1539     buriedColour.addActionListener(new java.awt.event.ActionListener()
1540     {
1541       @Override
1542       public void actionPerformed(ActionEvent e)
1543       {
1544         buriedColour_actionPerformed();
1545       }
1546     });
1547     abovePIDColour.setText(MessageManager
1548             .getString("label.above_identity_percentage"));
1549     abovePIDColour.addActionListener(new java.awt.event.ActionListener()
1550     {
1551       @Override
1552       public void actionPerformed(ActionEvent e)
1553       {
1554         abovePIDColour_actionPerformed();
1555       }
1556     });
1557     userDefinedColour.setText(MessageManager
1558             .getString("action.user_defined"));
1559     userDefinedColour.addActionListener(new java.awt.event.ActionListener()
1560     {
1561       @Override
1562       public void actionPerformed(ActionEvent e)
1563       {
1564         userDefinedColour_actionPerformed(e);
1565       }
1566     });
1567     PIDColour
1568             .setText(MessageManager.getString("label.percentage_identity"));
1569     PIDColour.addActionListener(new java.awt.event.ActionListener()
1570     {
1571       @Override
1572       public void actionPerformed(ActionEvent e)
1573       {
1574         PIDColour_actionPerformed();
1575       }
1576     });
1577     BLOSUM62Colour.setText(MessageManager.getString("label.blosum62"));
1578     BLOSUM62Colour.addActionListener(new java.awt.event.ActionListener()
1579     {
1580       @Override
1581       public void actionPerformed(ActionEvent e)
1582       {
1583         BLOSUM62Colour_actionPerformed();
1584       }
1585     });
1586     purinePyrimidineColour.setText(MessageManager
1587             .getString("label.purine_pyrimidine"));
1588     purinePyrimidineColour
1589             .addActionListener(new java.awt.event.ActionListener()
1590             {
1591               @Override
1592               public void actionPerformed(ActionEvent e)
1593               {
1594                 purinePyrimidineColour_actionPerformed();
1595               }
1596             });
1597
1598     /*
1599      * covariationColour.addActionListener(new java.awt.event.ActionListener() {
1600      * public void actionPerformed(ActionEvent e) {
1601      * covariationColour_actionPerformed(); } });
1602      */
1603
1604     conservationMenuItem.setText(MessageManager
1605             .getString("label.conservation"));
1606     conservationMenuItem
1607             .addActionListener(new java.awt.event.ActionListener()
1608             {
1609               @Override
1610               public void actionPerformed(ActionEvent e)
1611               {
1612                 conservationMenuItem_actionPerformed();
1613               }
1614             });
1615   }
1616
1617   /**
1618    * Check for any annotations on the underlying dataset sequences (for the
1619    * current selection group) which are not 'on the alignment'.If any are found,
1620    * enable the option to add them to the alignment. The criteria for 'on the
1621    * alignment' is finding an alignment annotation on the alignment, matched on
1622    * calcId, label and sequenceRef.
1623    * 
1624    * A tooltip is also constructed that displays the source (calcId) and type
1625    * (label) of the annotations that can be added.
1626    * 
1627    * @param menuItem
1628    * @param forSequences
1629    */
1630   protected void configureReferenceAnnotationsMenu(JMenuItem menuItem,
1631           List<SequenceI> forSequences)
1632   {
1633     menuItem.setEnabled(false);
1634
1635     /*
1636      * Temporary store to hold distinct calcId / type pairs for the tooltip.
1637      * Using TreeMap means calcIds are shown in alphabetical order.
1638      */
1639     Map<String, String> tipEntries = new TreeMap<String, String>();
1640     final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
1641     AlignmentI al = this.ap.av.getAlignment();
1642     AlignmentUtils.findAddableReferenceAnnotations(forSequences,
1643             tipEntries, candidates, al);
1644     if (!candidates.isEmpty())
1645     {
1646       StringBuilder tooltip = new StringBuilder(64);
1647       tooltip.append(MessageManager.getString("label.add_annotations_for"));
1648
1649       /*
1650        * Found annotations that could be added. Enable the menu item, and
1651        * configure its tooltip and action.
1652        */
1653       menuItem.setEnabled(true);
1654       for (String calcId : tipEntries.keySet())
1655       {
1656         tooltip.append("<br/>" + calcId + "/" + tipEntries.get(calcId));
1657       }
1658       String tooltipText = JvSwingUtils.wrapTooltip(true,
1659               tooltip.toString());
1660       menuItem.setToolTipText(tooltipText);
1661
1662       menuItem.addActionListener(new ActionListener()
1663       {
1664         @Override
1665         public void actionPerformed(ActionEvent e)
1666         {
1667           addReferenceAnnotations_actionPerformed(candidates);
1668         }
1669       });
1670     }
1671   }
1672
1673   /**
1674    * Add annotations to the sequences and to the alignment.
1675    * 
1676    * @param candidates
1677    *          a map whose keys are sequences on the alignment, and values a list
1678    *          of annotations to add to each sequence
1679    */
1680   protected void addReferenceAnnotations_actionPerformed(
1681           Map<SequenceI, List<AlignmentAnnotation>> candidates)
1682   {
1683     final SequenceGroup selectionGroup = this.ap.av.getSelectionGroup();
1684     final AlignmentI alignment = this.ap.getAlignment();
1685     AlignmentUtils.addReferenceAnnotations(candidates, alignment,
1686             selectionGroup);
1687     refresh();
1688   }
1689
1690   protected void makeReferenceSeq_actionPerformed(ActionEvent actionEvent)
1691   {
1692     if (!ap.av.getAlignment().hasSeqrep())
1693     {
1694       // initialise the display flags so the user sees something happen
1695       ap.av.setDisplayReferenceSeq(true);
1696       ap.av.setColourByReferenceSeq(true);
1697       ap.av.getAlignment().setSeqrep(sequence);
1698     }
1699     else
1700     {
1701       if (ap.av.getAlignment().getSeqrep() == sequence)
1702       {
1703         ap.av.getAlignment().setSeqrep(null);
1704       }
1705       else
1706       {
1707         ap.av.getAlignment().setSeqrep(sequence);
1708       }
1709     }
1710     refresh();
1711   }
1712
1713   protected void hideInsertions_actionPerformed(ActionEvent actionEvent)
1714   {
1715     if (sequence != null)
1716     {
1717       ColumnSelection cs = ap.av.getColumnSelection();
1718       if (cs == null)
1719       {
1720         cs = new ColumnSelection();
1721       }
1722       cs.hideInsertionsFor(sequence);
1723       ap.av.setColumnSelection(cs);
1724     }
1725     refresh();
1726   }
1727
1728   protected void sequenceSelectionDetails_actionPerformed()
1729   {
1730     createSequenceDetailsReport(ap.av.getSequenceSelection());
1731   }
1732
1733   protected void sequenceDetails_actionPerformed()
1734   {
1735     createSequenceDetailsReport(new SequenceI[] { sequence });
1736   }
1737
1738   public void createSequenceDetailsReport(SequenceI[] sequences)
1739   {
1740     CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer();
1741     StringBuffer contents = new StringBuffer();
1742     for (SequenceI seq : sequences)
1743     {
1744       contents.append("<p><h2>"
1745               + MessageManager
1746                       .formatMessage(
1747                               "label.create_sequence_details_report_annotation_for",
1748                               new Object[] { seq.getDisplayId(true) })
1749               + "</h2></p><p>");
1750       new SequenceAnnotationReport(null)
1751               .createSequenceAnnotationReport(
1752                       contents,
1753                       seq,
1754                       true,
1755                       true,
1756                       false,
1757                       (ap.getSeqPanel().seqCanvas.fr != null) ? ap
1758                               .getSeqPanel().seqCanvas.fr.getMinMax()
1759                               : null);
1760       contents.append("</p>");
1761     }
1762     cap.setText("<html>" + contents.toString() + "</html>");
1763
1764     Desktop.addInternalFrame(cap, MessageManager.formatMessage(
1765             "label.sequence_details_for",
1766             (sequences.length == 1 ? new Object[] { sequences[0]
1767                     .getDisplayId(true) } : new Object[] { MessageManager
1768                     .getString("label.selection") })), 500, 400);
1769
1770   }
1771
1772   protected void showNonconserved_actionPerformed()
1773   {
1774     getGroup().setShowNonconserved(displayNonconserved.isSelected());
1775     refresh();
1776   }
1777
1778   /**
1779    * call to refresh view after settings change
1780    */
1781   void refresh()
1782   {
1783     ap.updateAnnotation();
1784     ap.paintAlignment(true);
1785
1786     PaintRefresher.Refresh(this, ap.av.getSequenceSetId());
1787   }
1788
1789   /**
1790    * DOCUMENT ME!
1791    * 
1792    * @param e
1793    *          DOCUMENT ME!
1794    */
1795   protected void clustalColour_actionPerformed()
1796   {
1797     SequenceGroup sg = getGroup();
1798     sg.cs = new ClustalxColourScheme(sg, ap.av.getHiddenRepSequences());
1799     refresh();
1800   }
1801
1802   /**
1803    * DOCUMENT ME!
1804    * 
1805    * @param e
1806    *          DOCUMENT ME!
1807    */
1808   protected void zappoColour_actionPerformed()
1809   {
1810     getGroup().cs = new ZappoColourScheme();
1811     refresh();
1812   }
1813
1814   /**
1815    * DOCUMENT ME!
1816    * 
1817    * @param e
1818    *          DOCUMENT ME!
1819    */
1820   protected void taylorColour_actionPerformed()
1821   {
1822     getGroup().cs = new TaylorColourScheme();
1823     refresh();
1824   }
1825
1826   /**
1827    * DOCUMENT ME!
1828    * 
1829    * @param e
1830    *          DOCUMENT ME!
1831    */
1832   protected void hydrophobicityColour_actionPerformed()
1833   {
1834     getGroup().cs = new HydrophobicColourScheme();
1835     refresh();
1836   }
1837
1838   /**
1839    * DOCUMENT ME!
1840    * 
1841    * @param e
1842    *          DOCUMENT ME!
1843    */
1844   protected void helixColour_actionPerformed()
1845   {
1846     getGroup().cs = new HelixColourScheme();
1847     refresh();
1848   }
1849
1850   /**
1851    * DOCUMENT ME!
1852    * 
1853    * @param e
1854    *          DOCUMENT ME!
1855    */
1856   protected void strandColour_actionPerformed()
1857   {
1858     getGroup().cs = new StrandColourScheme();
1859     refresh();
1860   }
1861
1862   /**
1863    * DOCUMENT ME!
1864    * 
1865    * @param e
1866    *          DOCUMENT ME!
1867    */
1868   protected void turnColour_actionPerformed()
1869   {
1870     getGroup().cs = new TurnColourScheme();
1871     refresh();
1872   }
1873
1874   /**
1875    * DOCUMENT ME!
1876    * 
1877    * @param e
1878    *          DOCUMENT ME!
1879    */
1880   protected void buriedColour_actionPerformed()
1881   {
1882     getGroup().cs = new BuriedColourScheme();
1883     refresh();
1884   }
1885
1886   /**
1887    * DOCUMENT ME!
1888    * 
1889    * @param e
1890    *          DOCUMENT ME!
1891    */
1892   public void nucleotideMenuItem_actionPerformed()
1893   {
1894     getGroup().cs = new NucleotideColourScheme();
1895     refresh();
1896   }
1897
1898   protected void purinePyrimidineColour_actionPerformed()
1899   {
1900     getGroup().cs = new PurinePyrimidineColourScheme();
1901     refresh();
1902   }
1903
1904   /*
1905    * protected void covariationColour_actionPerformed() { getGroup().cs = new
1906    * CovariationColourScheme(sequence.getAnnotation()[0]); refresh(); }
1907    */
1908   /**
1909    * DOCUMENT ME!
1910    * 
1911    * @param e
1912    *          DOCUMENT ME!
1913    */
1914   protected void abovePIDColour_actionPerformed()
1915   {
1916     SequenceGroup sg = getGroup();
1917     if (sg.cs == null)
1918     {
1919       return;
1920     }
1921
1922     if (abovePIDColour.isSelected())
1923     {
1924       sg.cs.setConsensus(AAFrequency.calculate(
1925               sg.getSequences(ap.av.getHiddenRepSequences()),
1926               sg.getStartRes(), sg.getEndRes() + 1));
1927
1928       int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup()
1929               .getName());
1930
1931       sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus());
1932
1933       SliderPanel.showPIDSlider();
1934     }
1935     else
1936     // remove PIDColouring
1937     {
1938       sg.cs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
1939     }
1940
1941     refresh();
1942   }
1943
1944   /**
1945    * DOCUMENT ME!
1946    * 
1947    * @param e
1948    *          DOCUMENT ME!
1949    */
1950   protected void userDefinedColour_actionPerformed(ActionEvent e)
1951   {
1952     SequenceGroup sg = getGroup();
1953
1954     if (e.getSource().equals(userDefinedColour))
1955     {
1956       new UserDefinedColours(ap, sg);
1957     }
1958     else
1959     {
1960       UserColourScheme udc = (UserColourScheme) UserDefinedColours
1961               .getUserColourSchemes().get(e.getActionCommand());
1962
1963       sg.cs = udc;
1964     }
1965     refresh();
1966   }
1967
1968   /**
1969    * Open a panel where the user can choose which types of sequence annotation
1970    * to show or hide.
1971    * 
1972    * @param e
1973    */
1974   protected void chooseAnnotations_actionPerformed(ActionEvent e)
1975   {
1976     // todo correct way to guard against opening a duplicate panel?
1977     new AnnotationChooser(ap);
1978   }
1979
1980   /**
1981    * DOCUMENT ME!
1982    * 
1983    * @param e
1984    *          DOCUMENT ME!
1985    */
1986   protected void PIDColour_actionPerformed()
1987   {
1988     SequenceGroup sg = getGroup();
1989     sg.cs = new PIDColourScheme();
1990     sg.cs.setConsensus(AAFrequency.calculate(
1991             sg.getSequences(ap.av.getHiddenRepSequences()),
1992             sg.getStartRes(), sg.getEndRes() + 1));
1993     refresh();
1994   }
1995
1996   /**
1997    * DOCUMENT ME!
1998    * 
1999    * @param e
2000    *          DOCUMENT ME!
2001    */
2002   protected void BLOSUM62Colour_actionPerformed()
2003   {
2004     SequenceGroup sg = getGroup();
2005
2006     sg.cs = new Blosum62ColourScheme();
2007
2008     sg.cs.setConsensus(AAFrequency.calculate(
2009             sg.getSequences(ap.av.getHiddenRepSequences()),
2010             sg.getStartRes(), sg.getEndRes() + 1));
2011
2012     refresh();
2013   }
2014
2015   /**
2016    * DOCUMENT ME!
2017    * 
2018    * @param e
2019    *          DOCUMENT ME!
2020    */
2021   protected void noColourmenuItem_actionPerformed()
2022   {
2023     getGroup().cs = null;
2024     refresh();
2025   }
2026
2027   /**
2028    * DOCUMENT ME!
2029    * 
2030    * @param e
2031    *          DOCUMENT ME!
2032    */
2033   protected void conservationMenuItem_actionPerformed()
2034   {
2035     SequenceGroup sg = getGroup();
2036     if (sg.cs == null)
2037     {
2038       return;
2039     }
2040
2041     if (conservationMenuItem.isSelected())
2042     {
2043       // JBPNote: Conservation name shouldn't be i18n translated
2044       Conservation c = new Conservation("Group",
2045               ResidueProperties.propHash, 3, sg.getSequences(ap.av
2046                       .getHiddenRepSequences()), sg.getStartRes(),
2047               sg.getEndRes() + 1);
2048
2049       c.calculate();
2050       c.verdict(false, ap.av.getConsPercGaps());
2051
2052       sg.cs.setConservation(c);
2053
2054       SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
2055       SliderPanel.showConservationSlider();
2056     }
2057     else
2058     // remove ConservationColouring
2059     {
2060       sg.cs.setConservation(null);
2061     }
2062
2063     refresh();
2064   }
2065
2066   public void annotationMenuItem_actionPerformed(ActionEvent actionEvent)
2067   {
2068     SequenceGroup sg = getGroup();
2069     if (sg == null)
2070     {
2071       return;
2072     }
2073
2074     AnnotationColourGradient acg = new AnnotationColourGradient(
2075             sequence.getAnnotation()[0], null,
2076             AnnotationColourGradient.NO_THRESHOLD);
2077
2078     acg.setPredefinedColours(true);
2079     sg.cs = acg;
2080
2081     refresh();
2082   }
2083
2084   /**
2085    * DOCUMENT ME!
2086    * 
2087    * @param e
2088    *          DOCUMENT ME!
2089    */
2090   protected void groupName_actionPerformed()
2091   {
2092
2093     SequenceGroup sg = getGroup();
2094     EditNameDialog dialog = new EditNameDialog(sg.getName(),
2095             sg.getDescription(), "       "
2096                     + MessageManager.getString("label.group_name") + " ",
2097             MessageManager.getString("label.group_description") + " ",
2098             MessageManager.getString("label.edit_group_name_description"),
2099             ap.alignFrame);
2100
2101     if (!dialog.accept)
2102     {
2103       return;
2104     }
2105
2106     sg.setName(dialog.getName());
2107     sg.setDescription(dialog.getDescription());
2108     refresh();
2109   }
2110
2111   /**
2112    * Get selection group - adding it to the alignment if necessary.
2113    * 
2114    * @return sequence group to operate on
2115    */
2116   SequenceGroup getGroup()
2117   {
2118     SequenceGroup sg = ap.av.getSelectionGroup();
2119     // this method won't add a new group if it already exists
2120     if (sg != null)
2121     {
2122       ap.av.getAlignment().addGroup(sg);
2123     }
2124
2125     return sg;
2126   }
2127
2128   /**
2129    * DOCUMENT ME!
2130    * 
2131    * @param e
2132    *          DOCUMENT ME!
2133    */
2134   void sequenceName_actionPerformed()
2135   {
2136     EditNameDialog dialog = new EditNameDialog(sequence.getName(),
2137             sequence.getDescription(),
2138             "       " + MessageManager.getString("label.sequence_name")
2139                     + " ",
2140             MessageManager.getString("label.sequence_description") + " ",
2141             MessageManager
2142                     .getString("label.edit_sequence_name_description"),
2143             ap.alignFrame);
2144
2145     if (!dialog.accept)
2146     {
2147       return;
2148     }
2149
2150     if (dialog.getName() != null)
2151     {
2152       if (dialog.getName().indexOf(" ") > -1)
2153       {
2154         JOptionPane
2155                 .showMessageDialog(
2156                         ap,
2157                         MessageManager
2158                                 .getString("label.spaces_converted_to_backslashes"),
2159                         MessageManager
2160                                 .getString("label.no_spaces_allowed_sequence_name"),
2161                         JOptionPane.WARNING_MESSAGE);
2162       }
2163
2164       sequence.setName(dialog.getName().replace(' ', '_'));
2165       ap.paintAlignment(false);
2166     }
2167
2168     sequence.setDescription(dialog.getDescription());
2169
2170     ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
2171             .getSequences());
2172
2173   }
2174
2175   /**
2176    * DOCUMENT ME!
2177    * 
2178    * @param e
2179    *          DOCUMENT ME!
2180    */
2181   void unGroupMenuItem_actionPerformed()
2182   {
2183     SequenceGroup sg = ap.av.getSelectionGroup();
2184     ap.av.getAlignment().deleteGroup(sg);
2185     ap.av.setSelectionGroup(null);
2186     refresh();
2187   }
2188
2189   void createGroupMenuItem_actionPerformed()
2190   {
2191     getGroup(); // implicitly creates group - note - should apply defaults / use
2192                 // standard alignment window logic for this
2193     refresh();
2194   }
2195
2196   /**
2197    * DOCUMENT ME!
2198    * 
2199    * @param e
2200    *          DOCUMENT ME!
2201    */
2202   protected void outline_actionPerformed()
2203   {
2204     SequenceGroup sg = getGroup();
2205     Color col = JColorChooser.showDialog(this,
2206             MessageManager.getString("label.select_outline_colour"),
2207             Color.BLUE);
2208
2209     if (col != null)
2210     {
2211       sg.setOutlineColour(col);
2212     }
2213
2214     refresh();
2215   }
2216
2217   /**
2218    * DOCUMENT ME!
2219    * 
2220    * @param e
2221    *          DOCUMENT ME!
2222    */
2223   public void showBoxes_actionPerformed()
2224   {
2225     getGroup().setDisplayBoxes(showBoxes.isSelected());
2226     refresh();
2227   }
2228
2229   /**
2230    * DOCUMENT ME!
2231    * 
2232    * @param e
2233    *          DOCUMENT ME!
2234    */
2235   public void showText_actionPerformed()
2236   {
2237     getGroup().setDisplayText(showText.isSelected());
2238     refresh();
2239   }
2240
2241   /**
2242    * DOCUMENT ME!
2243    * 
2244    * @param e
2245    *          DOCUMENT ME!
2246    */
2247   public void showColourText_actionPerformed()
2248   {
2249     getGroup().setColourText(showColourText.isSelected());
2250     refresh();
2251   }
2252
2253   public void showLink(String url)
2254   {
2255     try
2256     {
2257       jalview.util.BrowserLauncher.openURL(url);
2258     } catch (Exception ex)
2259     {
2260       JOptionPane.showInternalMessageDialog(Desktop.desktop,
2261               MessageManager.getString("label.web_browser_not_found_unix"),
2262               MessageManager.getString("label.web_browser_not_found"),
2263               JOptionPane.WARNING_MESSAGE);
2264
2265       ex.printStackTrace();
2266     }
2267   }
2268
2269   void hideSequences(boolean representGroup)
2270   {
2271     ap.av.hideSequences(sequence, representGroup);
2272   }
2273
2274   public void copy_actionPerformed()
2275   {
2276     ap.alignFrame.copy_actionPerformed(null);
2277   }
2278
2279   public void cut_actionPerformed()
2280   {
2281     ap.alignFrame.cut_actionPerformed(null);
2282   }
2283
2284   void changeCase(ActionEvent e)
2285   {
2286     Object source = e.getSource();
2287     SequenceGroup sg = ap.av.getSelectionGroup();
2288
2289     if (sg != null)
2290     {
2291       List<int[]> startEnd = ap.av.getVisibleRegionBoundaries(
2292               sg.getStartRes(), sg.getEndRes() + 1);
2293
2294       String description;
2295       int caseChange;
2296
2297       if (source == toggle)
2298       {
2299         description = MessageManager.getString("label.toggle_case");
2300         caseChange = ChangeCaseCommand.TOGGLE_CASE;
2301       }
2302       else if (source == upperCase)
2303       {
2304         description = MessageManager.getString("label.to_upper_case");
2305         caseChange = ChangeCaseCommand.TO_UPPER;
2306       }
2307       else
2308       {
2309         description = MessageManager.getString("label.to_lower_case");
2310         caseChange = ChangeCaseCommand.TO_LOWER;
2311       }
2312
2313       ChangeCaseCommand caseCommand = new ChangeCaseCommand(description,
2314               sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
2315               startEnd, caseChange);
2316
2317       ap.alignFrame.addHistoryItem(caseCommand);
2318
2319       ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
2320               .getSequences());
2321
2322     }
2323   }
2324
2325   public void outputText_actionPerformed(ActionEvent e)
2326   {
2327     CutAndPasteTransfer cap = new CutAndPasteTransfer();
2328     cap.setForInput(null);
2329     Desktop.addInternalFrame(cap, MessageManager.formatMessage(
2330             "label.alignment_output_command",
2331             new Object[] { e.getActionCommand() }), 600, 500);
2332
2333     String[] omitHidden = null;
2334
2335     System.out.println("PROMPT USER HERE"); // TODO: decide if a prompt happens
2336     // or we simply trust the user wants
2337     // wysiwig behaviour
2338
2339     FileFormatI fileFormat = FileFormat.forName(e.getActionCommand());
2340     cap.setText(new FormatAdapter(ap).formatSequences(fileFormat, ap, true));
2341   }
2342
2343   public void sequenceFeature_actionPerformed()
2344   {
2345     SequenceGroup sg = ap.av.getSelectionGroup();
2346     if (sg == null)
2347     {
2348       return;
2349     }
2350
2351     int rsize = 0, gSize = sg.getSize();
2352     SequenceI[] rseqs, seqs = new SequenceI[gSize];
2353     SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
2354
2355     for (int i = 0; i < gSize; i++)
2356     {
2357       int start = sg.getSequenceAt(i).findPosition(sg.getStartRes());
2358       int end = sg.findEndRes(sg.getSequenceAt(i));
2359       if (start <= end)
2360       {
2361         seqs[rsize] = sg.getSequenceAt(i).getDatasetSequence();
2362         features[rsize] = new SequenceFeature(null, null, null, start, end,
2363                 "Jalview");
2364         rsize++;
2365       }
2366     }
2367     rseqs = new SequenceI[rsize];
2368     tfeatures = new SequenceFeature[rsize];
2369     System.arraycopy(seqs, 0, rseqs, 0, rsize);
2370     System.arraycopy(features, 0, tfeatures, 0, rsize);
2371     features = tfeatures;
2372     seqs = rseqs;
2373     if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
2374             features, true, ap))
2375     {
2376       ap.alignFrame.setShowSeqFeatures(true);
2377       ap.highlightSearchResults(null);
2378     }
2379   }
2380
2381   public void textColour_actionPerformed()
2382   {
2383     SequenceGroup sg = getGroup();
2384     if (sg != null)
2385     {
2386       new TextColourChooser().chooseColour(ap, sg);
2387     }
2388   }
2389
2390   public void colourByStructure(String pdbid)
2391   {
2392     Annotation[] anots = ap.av.getStructureSelectionManager()
2393             .colourSequenceFromStructure(sequence, pdbid);
2394
2395     AlignmentAnnotation an = new AlignmentAnnotation("Structure",
2396             "Coloured by " + pdbid, anots);
2397
2398     ap.av.getAlignment().addAnnotation(an);
2399     an.createSequenceMapping(sequence, 0, true);
2400     // an.adjustForAlignment();
2401     ap.av.getAlignment().setAnnotationIndex(an, 0);
2402
2403     ap.adjustAnnotationHeight();
2404
2405     sequence.addAlignmentAnnotation(an);
2406
2407   }
2408
2409   public void editSequence_actionPerformed(ActionEvent actionEvent)
2410   {
2411     SequenceGroup sg = ap.av.getSelectionGroup();
2412
2413     if (sg != null)
2414     {
2415       if (sequence == null)
2416       {
2417         sequence = sg.getSequenceAt(0);
2418       }
2419
2420       EditNameDialog dialog = new EditNameDialog(
2421               sequence.getSequenceAsString(sg.getStartRes(),
2422                       sg.getEndRes() + 1), null,
2423               MessageManager.getString("label.edit_sequence"), null,
2424               MessageManager.getString("label.edit_sequence"),
2425               ap.alignFrame);
2426
2427       if (dialog.accept)
2428       {
2429         EditCommand editCommand = new EditCommand(
2430                 MessageManager.getString("label.edit_sequences"),
2431                 Action.REPLACE, dialog.getName().replace(' ',
2432                         ap.av.getGapCharacter()),
2433                 sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
2434                 sg.getStartRes(), sg.getEndRes() + 1, ap.av.getAlignment());
2435
2436         ap.alignFrame.addHistoryItem(editCommand);
2437
2438         ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
2439                 .getSequences());
2440       }
2441     }
2442   }
2443
2444 }