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