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