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