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