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