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