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