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