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