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