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