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