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