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