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