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