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