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