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