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