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