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