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