fileFormat enum wip changes
[jalview.git] / src / jalview / gui / PopupMenu.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import jalview.analysis.AAFrequency;
24 import jalview.analysis.AlignmentAnnotationUtils;
25 import jalview.analysis.AlignmentUtils;
26 import jalview.analysis.Conservation;
27 import jalview.bin.Cache;
28 import jalview.commands.ChangeCaseCommand;
29 import jalview.commands.EditCommand;
30 import jalview.commands.EditCommand.Action;
31 import jalview.datamodel.AlignmentAnnotation;
32 import jalview.datamodel.AlignmentI;
33 import jalview.datamodel.Annotation;
34 import jalview.datamodel.ColumnSelection;
35 import jalview.datamodel.DBRefEntry;
36 import jalview.datamodel.PDBEntry;
37 import jalview.datamodel.Sequence;
38 import jalview.datamodel.SequenceFeature;
39 import jalview.datamodel.SequenceGroup;
40 import jalview.datamodel.SequenceI;
41 import jalview.io.FileFormat;
42 import jalview.io.FormatAdapter;
43 import jalview.io.SequenceAnnotationReport;
44 import jalview.schemes.AnnotationColourGradient;
45 import jalview.schemes.Blosum62ColourScheme;
46 import jalview.schemes.BuriedColourScheme;
47 import jalview.schemes.ClustalxColourScheme;
48 import jalview.schemes.HelixColourScheme;
49 import jalview.schemes.HydrophobicColourScheme;
50 import jalview.schemes.NucleotideColourScheme;
51 import jalview.schemes.PIDColourScheme;
52 import jalview.schemes.PurinePyrimidineColourScheme;
53 import jalview.schemes.ResidueProperties;
54 import jalview.schemes.StrandColourScheme;
55 import jalview.schemes.TaylorColourScheme;
56 import jalview.schemes.TurnColourScheme;
57 import jalview.schemes.UserColourScheme;
58 import jalview.schemes.ZappoColourScheme;
59 import jalview.util.DBRefUtils;
60 import jalview.util.GroupUrlLink;
61 import jalview.util.GroupUrlLink.UrlStringTooLongException;
62 import jalview.util.MessageManager;
63 import jalview.util.UrlLink;
64
65 import java.awt.Color;
66 import java.awt.event.ActionEvent;
67 import java.awt.event.ActionListener;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.Collections;
71 import java.util.Hashtable;
72 import java.util.LinkedHashMap;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.TreeMap;
76 import java.util.Vector;
77
78 import javax.swing.ButtonGroup;
79 import javax.swing.JCheckBoxMenuItem;
80 import javax.swing.JColorChooser;
81 import javax.swing.JMenu;
82 import javax.swing.JMenuItem;
83 import javax.swing.JOptionPane;
84 import javax.swing.JPopupMenu;
85 import javax.swing.JRadioButtonMenuItem;
86
87 /**
88  * DOCUMENT ME!
89  * 
90  * @author $author$
91  * @version $Revision: 1.118 $
92  */
93 public class PopupMenu extends JPopupMenu
94 {
95   private static final String ALL_ANNOTATIONS = "All";
96
97   JMenu groupMenu = new JMenu();
98
99   JMenuItem groupName = new JMenuItem();
100
101   protected JRadioButtonMenuItem clustalColour = new JRadioButtonMenuItem();
102
103   protected JRadioButtonMenuItem zappoColour = new JRadioButtonMenuItem();
104
105   protected JRadioButtonMenuItem taylorColour = new JRadioButtonMenuItem();
106
107   protected JRadioButtonMenuItem hydrophobicityColour = new JRadioButtonMenuItem();
108
109   protected JRadioButtonMenuItem helixColour = new JRadioButtonMenuItem();
110
111   protected JRadioButtonMenuItem strandColour = new JRadioButtonMenuItem();
112
113   protected JRadioButtonMenuItem turnColour = new JRadioButtonMenuItem();
114
115   protected JRadioButtonMenuItem buriedColour = new JRadioButtonMenuItem();
116
117   protected JCheckBoxMenuItem abovePIDColour = new JCheckBoxMenuItem();
118
119   protected JRadioButtonMenuItem userDefinedColour = new JRadioButtonMenuItem();
120
121   protected JRadioButtonMenuItem PIDColour = new JRadioButtonMenuItem();
122
123   protected JRadioButtonMenuItem BLOSUM62Colour = new JRadioButtonMenuItem();
124
125   protected JRadioButtonMenuItem purinePyrimidineColour = new JRadioButtonMenuItem();
126
127   protected JRadioButtonMenuItem RNAInteractionColour = new JRadioButtonMenuItem();
128
129   JRadioButtonMenuItem noColourmenuItem = new JRadioButtonMenuItem();
130
131   protected JCheckBoxMenuItem conservationMenuItem = new JCheckBoxMenuItem();
132
133   AlignmentPanel ap;
134
135   JMenu sequenceMenu = new JMenu();
136
137   JMenuItem sequenceName = new JMenuItem();
138
139   JMenuItem sequenceDetails = new JMenuItem();
140
141   JMenuItem sequenceSelDetails = new JMenuItem();
142
143   JMenuItem makeReferenceSeq = new JMenuItem();
144
145   JMenuItem chooseAnnotations = new JMenuItem();
146
147   SequenceI sequence;
148
149   JMenuItem createGroupMenuItem = new JMenuItem();
150
151   JMenuItem unGroupMenuItem = new JMenuItem();
152
153   JMenuItem outline = new JMenuItem();
154
155   JRadioButtonMenuItem nucleotideMenuItem = new JRadioButtonMenuItem();
156
157   JMenu colourMenu = new JMenu();
158
159   JCheckBoxMenuItem showBoxes = new JCheckBoxMenuItem();
160
161   JCheckBoxMenuItem showText = new JCheckBoxMenuItem();
162
163   JCheckBoxMenuItem showColourText = new JCheckBoxMenuItem();
164
165   JCheckBoxMenuItem displayNonconserved = new JCheckBoxMenuItem();
166
167   JMenu editMenu = new JMenu();
168
169   JMenuItem cut = new JMenuItem();
170
171   JMenuItem copy = new JMenuItem();
172
173   JMenuItem upperCase = new JMenuItem();
174
175   JMenuItem lowerCase = new JMenuItem();
176
177   JMenuItem toggle = new JMenuItem();
178
179   JMenu pdbMenu = new JMenu();
180
181   JMenu outputMenu = new JMenu();
182
183   JMenu seqShowAnnotationsMenu = new JMenu();
184
185   JMenu seqHideAnnotationsMenu = new JMenu();
186
187   JMenuItem seqAddReferenceAnnotations = new JMenuItem(
188           MessageManager.getString("label.add_reference_annotations"));
189
190   JMenu groupShowAnnotationsMenu = new JMenu();
191
192   JMenu groupHideAnnotationsMenu = new JMenu();
193
194   JMenuItem groupAddReferenceAnnotations = new JMenuItem(
195           MessageManager.getString("label.add_reference_annotations"));
196
197   JMenuItem sequenceFeature = new JMenuItem();
198
199   JMenuItem textColour = new JMenuItem();
200
201   JMenu jMenu1 = new JMenu();
202
203   JMenuItem pdbStructureDialog = new JMenuItem();
204
205   JMenu rnaStructureMenu = new JMenu();
206
207   JMenuItem editSequence = new JMenuItem();
208
209   JMenu groupLinksMenu;
210
211   JMenuItem hideInsertions = new JMenuItem();
212
213   /**
214    * Creates a new PopupMenu object.
215    * 
216    * @param ap
217    *          DOCUMENT ME!
218    * @param seq
219    *          DOCUMENT ME!
220    */
221   public PopupMenu(final AlignmentPanel ap, Sequence seq, List<String> links)
222   {
223     this(ap, seq, links, null);
224   }
225
226   /**
227    * 
228    * @param ap
229    * @param seq
230    * @param links
231    * @param groupLinks
232    */
233   public PopupMenu(final AlignmentPanel ap, final SequenceI seq,
234           List<String> links, List<String> groupLinks)
235   {
236     // /////////////////////////////////////////////////////////
237     // If this is activated from the sequence panel, the user may want to
238     // edit or annotate a particular residue. Therefore display the residue menu
239     //
240     // If from the IDPanel, we must display the sequence menu
241     // ////////////////////////////////////////////////////////
242     this.ap = ap;
243     sequence = seq;
244
245     ButtonGroup colours = new ButtonGroup();
246     colours.add(noColourmenuItem);
247     colours.add(clustalColour);
248     colours.add(zappoColour);
249     colours.add(taylorColour);
250     colours.add(hydrophobicityColour);
251     colours.add(helixColour);
252     colours.add(strandColour);
253     colours.add(turnColour);
254     colours.add(buriedColour);
255     colours.add(abovePIDColour);
256     colours.add(userDefinedColour);
257     colours.add(PIDColour);
258     colours.add(BLOSUM62Colour);
259     colours.add(purinePyrimidineColour);
260     colours.add(RNAInteractionColour);
261
262     for (int i = 0; i < jalview.io.FormatAdapter.WRITEABLE_FORMATS.length; i++)
263     {
264       JMenuItem item = new JMenuItem(
265               jalview.io.FormatAdapter.WRITEABLE_FORMATS[i]);
266
267       item.addActionListener(new java.awt.event.ActionListener()
268       {
269         @Override
270         public void actionPerformed(ActionEvent e)
271         {
272           outputText_actionPerformed(e);
273         }
274       });
275
276       outputMenu.add(item);
277     }
278
279     /*
280      * Build menus for annotation types that may be shown or hidden, and for
281      * 'reference annotations' that may be added to the alignment. First for the
282      * currently selected sequence (if there is one):
283      */
284     final List<SequenceI> selectedSequence = (seq == null ? Collections
285             .<SequenceI> emptyList() : Arrays.asList(seq));
286     buildAnnotationTypesMenus(seqShowAnnotationsMenu,
287             seqHideAnnotationsMenu, selectedSequence);
288     configureReferenceAnnotationsMenu(seqAddReferenceAnnotations,
289             selectedSequence);
290
291     /*
292      * And repeat for the current selection group (if there is one):
293      */
294     final List<SequenceI> selectedGroup = (ap.av.getSelectionGroup() == null ? Collections
295             .<SequenceI> emptyList() : ap.av.getSelectionGroup()
296             .getSequences());
297     buildAnnotationTypesMenus(groupShowAnnotationsMenu,
298             groupHideAnnotationsMenu, selectedGroup);
299     configureReferenceAnnotationsMenu(groupAddReferenceAnnotations,
300             selectedGroup);
301
302     try
303     {
304       jbInit();
305     } catch (Exception e)
306     {
307       e.printStackTrace();
308     }
309
310     JMenuItem menuItem;
311     if (seq != null)
312     {
313       sequenceMenu.setText(sequence.getName());
314       if (seq == ap.av.getAlignment().getSeqrep())
315       {
316         makeReferenceSeq.setText(MessageManager
317                 .getString("action.unmark_as_reference"));
318       }
319       else
320       {
321         makeReferenceSeq.setText(MessageManager
322                 .getString("action.set_as_reference"));
323       }
324
325       if (!ap.av.getAlignment().isNucleotide())
326       {
327         remove(rnaStructureMenu);
328       }
329       else
330       {
331         int origCount = rnaStructureMenu.getItemCount();
332         /*
333          * add menu items to 2D-render any alignment or sequence secondary
334          * structure annotation
335          */
336         AlignmentAnnotation[] aas = ap.av.getAlignment()
337                 .getAlignmentAnnotation();
338         if (aas != null)
339         {
340           for (final AlignmentAnnotation aa : aas)
341           {
342             if (aa.isValidStruc() && aa.sequenceRef == null)
343             {
344               /*
345                * valid alignment RNA secondary structure annotation
346                */
347               menuItem = new JMenuItem();
348               menuItem.setText(MessageManager.formatMessage(
349                       "label.2d_rna_structure_line",
350                       new Object[] { aa.label }));
351               menuItem.addActionListener(new java.awt.event.ActionListener()
352               {
353                 @Override
354                 public void actionPerformed(ActionEvent e)
355                 {
356                   new AppVarna(seq, aa, ap);
357                 }
358               });
359               rnaStructureMenu.add(menuItem);
360             }
361           }
362         }
363
364         if (seq.getAnnotation() != null)
365         {
366           AlignmentAnnotation seqAnns[] = seq.getAnnotation();
367           for (final AlignmentAnnotation aa : seqAnns)
368           {
369             if (aa.isValidStruc())
370             {
371               /*
372                * valid sequence RNA secondary structure annotation
373                */
374               // TODO: make rnastrucF a bit more nice
375               menuItem = new JMenuItem();
376               menuItem.setText(MessageManager.formatMessage(
377                       "label.2d_rna_sequence_name",
378                       new Object[] { seq.getName() }));
379               menuItem.addActionListener(new java.awt.event.ActionListener()
380               {
381                 @Override
382                 public void actionPerformed(ActionEvent e)
383                 {
384                   // TODO: VARNA does'nt print gaps in the sequence
385                   new AppVarna(seq, aa, ap);
386                 }
387               });
388               rnaStructureMenu.add(menuItem);
389             }
390           }
391         }
392         if (rnaStructureMenu.getItemCount() == origCount)
393         {
394           remove(rnaStructureMenu);
395         }
396       }
397
398       menuItem = new JMenuItem(
399               MessageManager.getString("action.hide_sequences"));
400       menuItem.addActionListener(new java.awt.event.ActionListener()
401       {
402         @Override
403         public void actionPerformed(ActionEvent e)
404         {
405           hideSequences(false);
406         }
407       });
408       add(menuItem);
409
410       if (ap.av.getSelectionGroup() != null
411               && ap.av.getSelectionGroup().getSize() > 1)
412       {
413         menuItem = new JMenuItem(MessageManager.formatMessage(
414                 "label.represent_group_with",
415                 new Object[] { seq.getName() }));
416         menuItem.addActionListener(new java.awt.event.ActionListener()
417         {
418           @Override
419           public void actionPerformed(ActionEvent e)
420           {
421             hideSequences(true);
422           }
423         });
424         sequenceMenu.add(menuItem);
425       }
426
427       if (ap.av.hasHiddenRows())
428       {
429         final int index = ap.av.getAlignment().findIndex(seq);
430
431         if (ap.av.adjustForHiddenSeqs(index)
432                 - ap.av.adjustForHiddenSeqs(index - 1) > 1)
433         {
434           menuItem = new JMenuItem(
435                   MessageManager.getString("action.reveal_sequences"));
436           menuItem.addActionListener(new ActionListener()
437           {
438             @Override
439             public void actionPerformed(ActionEvent e)
440             {
441               ap.av.showSequence(index);
442               if (ap.overviewPanel != null)
443               {
444                 ap.overviewPanel.updateOverviewImage();
445               }
446             }
447           });
448           add(menuItem);
449         }
450       }
451     }
452     // for the case when no sequences are even visible
453     if (ap.av.hasHiddenRows())
454     {
455       {
456         menuItem = new JMenuItem(
457                 MessageManager.getString("action.reveal_all"));
458         menuItem.addActionListener(new ActionListener()
459         {
460           @Override
461           public void actionPerformed(ActionEvent e)
462           {
463             ap.av.showAllHiddenSeqs();
464             if (ap.overviewPanel != null)
465             {
466               ap.overviewPanel.updateOverviewImage();
467             }
468           }
469         });
470
471         add(menuItem);
472       }
473
474     }
475
476     SequenceGroup sg = ap.av.getSelectionGroup();
477     boolean isDefinedGroup = (sg != null) ? ap.av.getAlignment()
478             .getGroups().contains(sg) : false;
479
480     if (sg != null && sg.getSize() > 0)
481     {
482       groupName.setText(MessageManager.formatMessage("label.name_param",
483               new Object[] { sg.getName() }));
484       groupName.setText(MessageManager
485               .getString("label.edit_name_and_description_current_group"));
486
487       if (sg.cs instanceof ZappoColourScheme)
488       {
489         zappoColour.setSelected(true);
490       }
491       else if (sg.cs instanceof TaylorColourScheme)
492       {
493         taylorColour.setSelected(true);
494       }
495       else if (sg.cs instanceof PIDColourScheme)
496       {
497         PIDColour.setSelected(true);
498       }
499       else if (sg.cs instanceof Blosum62ColourScheme)
500       {
501         BLOSUM62Colour.setSelected(true);
502       }
503       else if (sg.cs instanceof UserColourScheme)
504       {
505         userDefinedColour.setSelected(true);
506       }
507       else if (sg.cs instanceof HydrophobicColourScheme)
508       {
509         hydrophobicityColour.setSelected(true);
510       }
511       else if (sg.cs instanceof HelixColourScheme)
512       {
513         helixColour.setSelected(true);
514       }
515       else if (sg.cs instanceof StrandColourScheme)
516       {
517         strandColour.setSelected(true);
518       }
519       else if (sg.cs instanceof TurnColourScheme)
520       {
521         turnColour.setSelected(true);
522       }
523       else if (sg.cs instanceof BuriedColourScheme)
524       {
525         buriedColour.setSelected(true);
526       }
527       else if (sg.cs instanceof ClustalxColourScheme)
528       {
529         clustalColour.setSelected(true);
530       }
531       else if (sg.cs instanceof PurinePyrimidineColourScheme)
532       {
533         purinePyrimidineColour.setSelected(true);
534       }
535
536       /*
537        * else if (sg.cs instanceof CovariationColourScheme) {
538        * covariationColour.setSelected(true); }
539        */
540       else
541       {
542         noColourmenuItem.setSelected(true);
543       }
544
545       if (sg.cs != null && sg.cs.conservationApplied())
546       {
547         conservationMenuItem.setSelected(true);
548       }
549       displayNonconserved.setSelected(sg.getShowNonconserved());
550       showText.setSelected(sg.getDisplayText());
551       showColourText.setSelected(sg.getColourText());
552       showBoxes.setSelected(sg.getDisplayBoxes());
553       // add any groupURLs to the groupURL submenu and make it visible
554       if (groupLinks != null && groupLinks.size() > 0)
555       {
556         buildGroupURLMenu(sg, groupLinks);
557       }
558       // Add a 'show all structures' for the current selection
559       Hashtable<String, PDBEntry> pdbe = new Hashtable<String, PDBEntry>(), reppdb = new Hashtable<String, PDBEntry>();
560       SequenceI sqass = null;
561       for (SequenceI sq : ap.av.getSequenceSelection())
562       {
563         Vector<PDBEntry> pes = sq.getDatasetSequence().getAllPDBEntries();
564         if (pes != null && pes.size() > 0)
565         {
566           reppdb.put(pes.get(0).getId(), pes.get(0));
567           for (PDBEntry pe : pes)
568           {
569             pdbe.put(pe.getId(), pe);
570             if (sqass == null)
571             {
572               sqass = sq;
573             }
574           }
575         }
576       }
577       if (pdbe.size() > 0)
578       {
579         final PDBEntry[] pe = pdbe.values().toArray(
580                 new PDBEntry[pdbe.size()]), pr = reppdb.values().toArray(
581                 new PDBEntry[reppdb.size()]);
582         final JMenuItem gpdbview, rpdbview;
583       }
584     }
585     else
586     {
587       groupMenu.setVisible(false);
588       editMenu.setVisible(false);
589     }
590
591     if (!isDefinedGroup)
592     {
593       createGroupMenuItem.setVisible(true);
594       unGroupMenuItem.setVisible(false);
595       jMenu1.setText(MessageManager.getString("action.edit_new_group"));
596     }
597     else
598     {
599       createGroupMenuItem.setVisible(false);
600       unGroupMenuItem.setVisible(true);
601       jMenu1.setText(MessageManager.getString("action.edit_group"));
602     }
603
604     if (seq == null)
605     {
606       sequenceMenu.setVisible(false);
607       pdbStructureDialog.setVisible(false);
608       rnaStructureMenu.setVisible(false);
609     }
610
611     if (links != null && links.size() > 0)
612     {
613       addFeatureLinks(seq, links);
614     }
615   }
616
617   /**
618    * Adds a 'Link' menu item with a sub-menu item for each hyperlink provided.
619    * 
620    * @param seq
621    * @param links
622    */
623   void addFeatureLinks(final SequenceI seq, List<String> links)
624   {
625     JMenu linkMenu = new JMenu(MessageManager.getString("action.link"));
626     List<String> linkset = new ArrayList<String>();
627     for (String link : links)
628     {
629       UrlLink urlLink = null;
630       try
631       {
632         urlLink = new UrlLink(link);
633       } catch (Exception foo)
634       {
635         Cache.log.error("Exception for URLLink '" + link + "'", foo);
636         continue;
637       }
638       ;
639       if (!urlLink.isValid())
640       {
641         Cache.log.error(urlLink.getInvalidMessage());
642         continue;
643       }
644       final String label = urlLink.getLabel();
645       if (seq != null && urlLink.isDynamic())
646       {
647
648         // collect matching db-refs
649         DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(),
650                 new String[] { urlLink.getTarget() });
651         // collect id string too
652         String id = seq.getName();
653         String descr = seq.getDescription();
654         if (descr != null && descr.length() < 1)
655         {
656           descr = null;
657         }
658
659         if (dbr != null)
660         {
661           for (int r = 0; r < dbr.length; r++)
662           {
663             if (id != null && dbr[r].getAccessionId().equals(id))
664             {
665               // suppress duplicate link creation for the bare sequence ID
666               // string with this link
667               id = null;
668             }
669             // create Bare ID link for this URL
670             String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true);
671             if (urls != null)
672             {
673               for (int u = 0; u < urls.length; u += 2)
674               {
675                 if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
676                 {
677                   linkset.add(urls[u] + "|" + urls[u + 1]);
678                   addshowLink(linkMenu, label + "|" + urls[u], urls[u + 1]);
679                 }
680               }
681             }
682           }
683         }
684         if (id != null)
685         {
686           // create Bare ID link for this URL
687           String[] urls = urlLink.makeUrls(id, true);
688           if (urls != null)
689           {
690             for (int u = 0; u < urls.length; u += 2)
691             {
692               if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
693               {
694                 linkset.add(urls[u] + "|" + urls[u + 1]);
695                 addshowLink(linkMenu, label, urls[u + 1]);
696               }
697             }
698           }
699         }
700         // Create urls from description but only for URL links which are regex
701         // links
702         if (descr != null && urlLink.getRegexReplace() != null)
703         {
704           // create link for this URL from description where regex matches
705           String[] urls = urlLink.makeUrls(descr, true);
706           if (urls != null)
707           {
708             for (int u = 0; u < urls.length; u += 2)
709             {
710               if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
711               {
712                 linkset.add(urls[u] + "|" + urls[u + 1]);
713                 addshowLink(linkMenu, label, urls[u + 1]);
714               }
715             }
716           }
717         }
718       }
719       else
720       {
721         if (!linkset.contains(label + "|" + urlLink.getUrl_prefix()))
722         {
723           linkset.add(label + "|" + urlLink.getUrl_prefix());
724           // Add a non-dynamic link
725           addshowLink(linkMenu, label, urlLink.getUrl_prefix());
726         }
727       }
728     }
729     if (sequence != null)
730     {
731       sequenceMenu.add(linkMenu);
732     }
733     else
734     {
735       add(linkMenu);
736     }
737   }
738
739   /**
740    * Add annotation types to 'Show annotations' and/or 'Hide annotations' menus.
741    * "All" is added first, followed by a separator. Then add any annotation
742    * types associated with the current selection. Separate menus are built for
743    * the selected sequence group (if any), and the selected sequence.
744    * <p>
745    * Some annotation rows are always rendered together - these can be identified
746    * by a common graphGroup property > -1. Only one of each group will be marked
747    * as visible (to avoid duplication of the display). For such groups we add a
748    * composite type name, e.g.
749    * <p>
750    * IUPredWS (Long), IUPredWS (Short)
751    * 
752    * @param seq
753    */
754   protected void buildAnnotationTypesMenus(JMenu showMenu, JMenu hideMenu,
755           List<SequenceI> forSequences)
756   {
757     showMenu.removeAll();
758     hideMenu.removeAll();
759
760     final List<String> all = Arrays.asList(ALL_ANNOTATIONS);
761     addAnnotationTypeToShowHide(showMenu, forSequences, "", all, true, true);
762     addAnnotationTypeToShowHide(hideMenu, forSequences, "", all, true,
763             false);
764     showMenu.addSeparator();
765     hideMenu.addSeparator();
766
767     final AlignmentAnnotation[] annotations = ap.getAlignment()
768             .getAlignmentAnnotation();
769
770     /*
771      * Find shown/hidden annotations types, distinguished by source (calcId),
772      * and grouped by graphGroup. Using LinkedHashMap means we will retrieve in
773      * the insertion order, which is the order of the annotations on the
774      * alignment.
775      */
776     Map<String, List<List<String>>> shownTypes = new LinkedHashMap<String, List<List<String>>>();
777     Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<String, List<List<String>>>();
778     AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
779             AlignmentAnnotationUtils.asList(annotations), forSequences);
780
781     for (String calcId : hiddenTypes.keySet())
782     {
783       for (List<String> type : hiddenTypes.get(calcId))
784       {
785         addAnnotationTypeToShowHide(showMenu, forSequences, calcId, type,
786                 false, true);
787       }
788     }
789     // grey out 'show annotations' if none are hidden
790     showMenu.setEnabled(!hiddenTypes.isEmpty());
791
792     for (String calcId : shownTypes.keySet())
793     {
794       for (List<String> type : shownTypes.get(calcId))
795       {
796         addAnnotationTypeToShowHide(hideMenu, forSequences, calcId, type,
797                 false, false);
798       }
799     }
800     // grey out 'hide annotations' if none are shown
801     hideMenu.setEnabled(!shownTypes.isEmpty());
802   }
803
804   /**
805    * Returns a list of sequences - either the current selection group (if there
806    * is one), else the specified single sequence.
807    * 
808    * @param seq
809    * @return
810    */
811   protected List<SequenceI> getSequenceScope(SequenceI seq)
812   {
813     List<SequenceI> forSequences = null;
814     final SequenceGroup selectionGroup = ap.av.getSelectionGroup();
815     if (selectionGroup != null && selectionGroup.getSize() > 0)
816     {
817       forSequences = selectionGroup.getSequences();
818     }
819     else
820     {
821       forSequences = seq == null ? Collections.<SequenceI> emptyList()
822               : Arrays.asList(seq);
823     }
824     return forSequences;
825   }
826
827   /**
828    * Add one annotation type to the 'Show Annotations' or 'Hide Annotations'
829    * menus.
830    * 
831    * @param showOrHideMenu
832    *          the menu to add to
833    * @param forSequences
834    *          the sequences whose annotations may be shown or hidden
835    * @param calcId
836    * @param types
837    *          the label to add
838    * @param allTypes
839    *          if true this is a special label meaning 'All'
840    * @param actionIsShow
841    *          if true, the select menu item action is to show the annotation
842    *          type, else hide
843    */
844   protected void addAnnotationTypeToShowHide(JMenu showOrHideMenu,
845           final List<SequenceI> forSequences, String calcId,
846           final List<String> types, final boolean allTypes,
847           final boolean actionIsShow)
848   {
849     String label = types.toString(); // [a, b, c]
850     label = label.substring(1, label.length() - 1); // a, b, c
851     final JMenuItem item = new JMenuItem(label);
852     item.setToolTipText(calcId);
853     item.addActionListener(new java.awt.event.ActionListener()
854     {
855       @Override
856       public void actionPerformed(ActionEvent e)
857       {
858         AlignmentUtils.showOrHideSequenceAnnotations(ap.getAlignment(),
859                 types, forSequences, allTypes, actionIsShow);
860         refresh();
861       }
862     });
863     showOrHideMenu.add(item);
864   }
865
866   private void buildGroupURLMenu(SequenceGroup sg, List<String> groupLinks)
867   {
868
869     // TODO: usability: thread off the generation of group url content so root
870     // menu appears asap
871     // sequence only URLs
872     // ID/regex match URLs
873     groupLinksMenu = new JMenu(
874             MessageManager.getString("action.group_link"));
875     // three types of url that might be created.
876     JMenu[] linkMenus = new JMenu[] { null,
877         new JMenu(MessageManager.getString("action.ids")),
878         new JMenu(MessageManager.getString("action.sequences")),
879         new JMenu(MessageManager.getString("action.ids_sequences")) };
880
881     SequenceI[] seqs = ap.av.getSelectionAsNewSequence();
882     String[][] idandseqs = GroupUrlLink.formStrings(seqs);
883     Hashtable<String, Object[]> commonDbrefs = new Hashtable<String, Object[]>();
884     for (int sq = 0; sq < seqs.length; sq++)
885     {
886
887       int start = seqs[sq].findPosition(sg.getStartRes()), end = seqs[sq]
888               .findPosition(sg.getEndRes());
889       // just collect ids from dataset sequence
890       // TODO: check if IDs collected from selecton group intersects with the
891       // current selection, too
892       SequenceI sqi = seqs[sq];
893       while (sqi.getDatasetSequence() != null)
894       {
895         sqi = sqi.getDatasetSequence();
896       }
897       DBRefEntry[] dbr = sqi.getDBRefs();
898       if (dbr != null && dbr.length > 0)
899       {
900         for (int d = 0; d < dbr.length; d++)
901         {
902           String src = dbr[d].getSource(); // jalview.util.DBRefUtils.getCanonicalName(dbr[d].getSource()).toUpperCase();
903           Object[] sarray = commonDbrefs.get(src);
904           if (sarray == null)
905           {
906             sarray = new Object[2];
907             sarray[0] = new int[] { 0 };
908             sarray[1] = new String[seqs.length];
909
910             commonDbrefs.put(src, sarray);
911           }
912
913           if (((String[]) sarray[1])[sq] == null)
914           {
915             if (!dbr[d].hasMap()
916                     || (dbr[d].getMap().locateMappedRange(start, end) != null))
917             {
918               ((String[]) sarray[1])[sq] = dbr[d].getAccessionId();
919               ((int[]) sarray[0])[0]++;
920             }
921           }
922         }
923       }
924     }
925     // now create group links for all distinct ID/sequence sets.
926     boolean addMenu = false; // indicates if there are any group links to give
927                              // to user
928     for (String link : groupLinks)
929     {
930       GroupUrlLink urlLink = null;
931       try
932       {
933         urlLink = new GroupUrlLink(link);
934       } catch (Exception foo)
935       {
936         Cache.log.error("Exception for GroupURLLink '" + link
937                 + "'", foo);
938         continue;
939       }
940       ;
941       if (!urlLink.isValid())
942       {
943         Cache.log.error(urlLink.getInvalidMessage());
944         continue;
945       }
946       final String label = urlLink.getLabel();
947       boolean usingNames = false;
948       // Now see which parts of the group apply for this URL
949       String ltarget = urlLink.getTarget(); // jalview.util.DBRefUtils.getCanonicalName(urlLink.getTarget());
950       Object[] idset = commonDbrefs.get(ltarget.toUpperCase());
951       String[] seqstr, ids; // input to makeUrl
952       if (idset != null)
953       {
954         int numinput = ((int[]) idset[0])[0];
955         String[] allids = ((String[]) idset[1]);
956         seqstr = new String[numinput];
957         ids = new String[numinput];
958         for (int sq = 0, idcount = 0; sq < seqs.length; sq++)
959         {
960           if (allids[sq] != null)
961           {
962             ids[idcount] = allids[sq];
963             seqstr[idcount++] = idandseqs[1][sq];
964           }
965         }
966       }
967       else
968       {
969         // just use the id/seq set
970         seqstr = idandseqs[1];
971         ids = idandseqs[0];
972         usingNames = true;
973       }
974       // and try and make the groupURL!
975
976       Object[] urlset = null;
977       try
978       {
979         urlset = urlLink.makeUrlStubs(ids, seqstr,
980                 "FromJalview" + System.currentTimeMillis(), false);
981       } catch (UrlStringTooLongException e)
982       {
983       }
984       if (urlset != null)
985       {
986         int type = urlLink.getGroupURLType() & 3;
987         // first two bits ofurlLink type bitfield are sequenceids and sequences
988         // TODO: FUTURE: ensure the groupURL menu structure can be generalised
989         addshowLink(linkMenus[type], label
990                 + (((type & 1) == 1) ? ("("
991                         + (usingNames ? "Names" : ltarget) + ")") : ""),
992                 urlLink, urlset);
993         addMenu = true;
994       }
995     }
996     if (addMenu)
997     {
998       groupLinksMenu = new JMenu(
999               MessageManager.getString("action.group_link"));
1000       for (int m = 0; m < linkMenus.length; m++)
1001       {
1002         if (linkMenus[m] != null
1003                 && linkMenus[m].getMenuComponentCount() > 0)
1004         {
1005           groupLinksMenu.add(linkMenus[m]);
1006         }
1007       }
1008
1009       groupMenu.add(groupLinksMenu);
1010     }
1011   }
1012
1013   /**
1014    * add a show URL menu item to the given linkMenu
1015    * 
1016    * @param linkMenu
1017    * @param label
1018    *          - menu label string
1019    * @param url
1020    *          - url to open
1021    */
1022   private void addshowLink(JMenu linkMenu, String label, final String url)
1023   {
1024     JMenuItem item = new JMenuItem(label);
1025     item.setToolTipText(MessageManager.formatMessage(
1026             "label.open_url_param", new Object[] { url }));
1027     item.addActionListener(new java.awt.event.ActionListener()
1028     {
1029       @Override
1030       public void actionPerformed(ActionEvent e)
1031       {
1032         new Thread(new Runnable()
1033         {
1034
1035           @Override
1036           public void run()
1037           {
1038             showLink(url);
1039           }
1040
1041         }).start();
1042       }
1043     });
1044
1045     linkMenu.add(item);
1046   }
1047
1048   /**
1049    * add a late bound groupURL item to the given linkMenu
1050    * 
1051    * @param linkMenu
1052    * @param label
1053    *          - menu label string
1054    * @param urlgenerator
1055    *          GroupURLLink used to generate URL
1056    * @param urlstub
1057    *          Object array returned from the makeUrlStubs function.
1058    */
1059   private void addshowLink(JMenu linkMenu, String label,
1060           final GroupUrlLink urlgenerator, final Object[] urlstub)
1061   {
1062     JMenuItem item = new JMenuItem(label);
1063     item.setToolTipText(MessageManager.formatMessage(
1064             "label.open_url_seqs_param",
1065             new Object[] { urlgenerator.getUrl_prefix(),
1066                 urlgenerator.getNumberInvolved(urlstub) }));
1067     // TODO: put in info about what is being sent.
1068     item.addActionListener(new ActionListener()
1069     {
1070       @Override
1071       public void actionPerformed(ActionEvent e)
1072       {
1073         new Thread(new Runnable()
1074         {
1075
1076           @Override
1077           public void run()
1078           {
1079             try
1080             {
1081               showLink(urlgenerator.constructFrom(urlstub));
1082             } catch (UrlStringTooLongException e2)
1083             {
1084             }
1085           }
1086
1087         }).start();
1088       }
1089     });
1090
1091     linkMenu.add(item);
1092   }
1093
1094   /**
1095    * DOCUMENT ME!
1096    * 
1097    * @throws Exception
1098    *           DOCUMENT ME!
1099    */
1100   private void jbInit() throws Exception
1101   {
1102     groupMenu.setText(MessageManager.getString("label.group"));
1103     groupMenu.setText(MessageManager.getString("label.selection"));
1104     groupName.setText(MessageManager.getString("label.name"));
1105     groupName.addActionListener(new java.awt.event.ActionListener()
1106     {
1107       @Override
1108       public void actionPerformed(ActionEvent e)
1109       {
1110         groupName_actionPerformed();
1111       }
1112     });
1113     sequenceMenu.setText(MessageManager.getString("label.sequence"));
1114     sequenceName.setText(MessageManager
1115             .getString("label.edit_name_description"));
1116     sequenceName.addActionListener(new java.awt.event.ActionListener()
1117     {
1118       @Override
1119       public void actionPerformed(ActionEvent e)
1120       {
1121         sequenceName_actionPerformed();
1122       }
1123     });
1124     chooseAnnotations.setText(MessageManager
1125             .getString("action.choose_annotations"));
1126     chooseAnnotations.addActionListener(new java.awt.event.ActionListener()
1127     {
1128       @Override
1129       public void actionPerformed(ActionEvent e)
1130       {
1131         chooseAnnotations_actionPerformed(e);
1132       }
1133     });
1134     sequenceDetails.setText(MessageManager
1135             .getString("label.sequence_details"));
1136     sequenceDetails.addActionListener(new java.awt.event.ActionListener()
1137     {
1138       @Override
1139       public void actionPerformed(ActionEvent e)
1140       {
1141         sequenceDetails_actionPerformed();
1142       }
1143     });
1144     sequenceSelDetails.setText(MessageManager
1145             .getString("label.sequence_details"));
1146     sequenceSelDetails
1147             .addActionListener(new java.awt.event.ActionListener()
1148             {
1149               @Override
1150               public void actionPerformed(ActionEvent e)
1151               {
1152                 sequenceSelectionDetails_actionPerformed();
1153               }
1154             });
1155     PIDColour.setFocusPainted(false);
1156     unGroupMenuItem
1157             .setText(MessageManager.getString("action.remove_group"));
1158     unGroupMenuItem.addActionListener(new java.awt.event.ActionListener()
1159     {
1160       @Override
1161       public void actionPerformed(ActionEvent e)
1162       {
1163         unGroupMenuItem_actionPerformed();
1164       }
1165     });
1166     createGroupMenuItem.setText(MessageManager
1167             .getString("action.create_group"));
1168     createGroupMenuItem
1169             .addActionListener(new java.awt.event.ActionListener()
1170             {
1171               @Override
1172               public void actionPerformed(ActionEvent e)
1173               {
1174                 createGroupMenuItem_actionPerformed();
1175               }
1176             });
1177
1178     outline.setText(MessageManager.getString("action.border_colour"));
1179     outline.addActionListener(new java.awt.event.ActionListener()
1180     {
1181       @Override
1182       public void actionPerformed(ActionEvent e)
1183       {
1184         outline_actionPerformed();
1185       }
1186     });
1187     nucleotideMenuItem
1188             .setText(MessageManager.getString("label.nucleotide"));
1189     nucleotideMenuItem.addActionListener(new ActionListener()
1190     {
1191       @Override
1192       public void actionPerformed(ActionEvent e)
1193       {
1194         nucleotideMenuItem_actionPerformed();
1195       }
1196     });
1197     colourMenu.setText(MessageManager.getString("label.group_colour"));
1198     showBoxes.setText(MessageManager.getString("action.boxes"));
1199     showBoxes.setState(true);
1200     showBoxes.addActionListener(new ActionListener()
1201     {
1202       @Override
1203       public void actionPerformed(ActionEvent e)
1204       {
1205         showBoxes_actionPerformed();
1206       }
1207     });
1208     showText.setText(MessageManager.getString("action.text"));
1209     showText.setState(true);
1210     showText.addActionListener(new ActionListener()
1211     {
1212       @Override
1213       public void actionPerformed(ActionEvent e)
1214       {
1215         showText_actionPerformed();
1216       }
1217     });
1218     showColourText.setText(MessageManager.getString("label.colour_text"));
1219     showColourText.addActionListener(new ActionListener()
1220     {
1221       @Override
1222       public void actionPerformed(ActionEvent e)
1223       {
1224         showColourText_actionPerformed();
1225       }
1226     });
1227     displayNonconserved.setText(MessageManager
1228             .getString("label.show_non_conversed"));
1229     displayNonconserved.setState(true);
1230     displayNonconserved.addActionListener(new ActionListener()
1231     {
1232       @Override
1233       public void actionPerformed(ActionEvent e)
1234       {
1235         showNonconserved_actionPerformed();
1236       }
1237     });
1238     editMenu.setText(MessageManager.getString("action.edit"));
1239     cut.setText(MessageManager.getString("action.cut"));
1240     cut.addActionListener(new ActionListener()
1241     {
1242       @Override
1243       public void actionPerformed(ActionEvent e)
1244       {
1245         cut_actionPerformed();
1246       }
1247     });
1248     upperCase.setText(MessageManager.getString("label.to_upper_case"));
1249     upperCase.addActionListener(new ActionListener()
1250     {
1251       @Override
1252       public void actionPerformed(ActionEvent e)
1253       {
1254         changeCase(e);
1255       }
1256     });
1257     copy.setText(MessageManager.getString("action.copy"));
1258     copy.addActionListener(new ActionListener()
1259     {
1260       @Override
1261       public void actionPerformed(ActionEvent e)
1262       {
1263         copy_actionPerformed();
1264       }
1265     });
1266     lowerCase.setText(MessageManager.getString("label.to_lower_case"));
1267     lowerCase.addActionListener(new ActionListener()
1268     {
1269       @Override
1270       public void actionPerformed(ActionEvent e)
1271       {
1272         changeCase(e);
1273       }
1274     });
1275     toggle.setText(MessageManager.getString("label.toggle_case"));
1276     toggle.addActionListener(new ActionListener()
1277     {
1278       @Override
1279       public void actionPerformed(ActionEvent e)
1280       {
1281         changeCase(e);
1282       }
1283     });
1284     outputMenu.setText(MessageManager.getString("label.out_to_textbox")
1285             + "...");
1286     seqShowAnnotationsMenu.setText(MessageManager
1287             .getString("label.show_annotations"));
1288     seqHideAnnotationsMenu.setText(MessageManager
1289             .getString("label.hide_annotations"));
1290     groupShowAnnotationsMenu.setText(MessageManager
1291             .getString("label.show_annotations"));
1292     groupHideAnnotationsMenu.setText(MessageManager
1293             .getString("label.hide_annotations"));
1294     sequenceFeature.setText(MessageManager
1295             .getString("label.create_sequence_feature"));
1296     sequenceFeature.addActionListener(new ActionListener()
1297     {
1298       @Override
1299       public void actionPerformed(ActionEvent e)
1300       {
1301         sequenceFeature_actionPerformed();
1302       }
1303     });
1304     textColour.setText(MessageManager.getString("label.text_colour"));
1305     textColour.addActionListener(new ActionListener()
1306     {
1307       @Override
1308       public void actionPerformed(ActionEvent e)
1309       {
1310         textColour_actionPerformed();
1311       }
1312     });
1313     jMenu1.setText(MessageManager.getString("label.group"));
1314     pdbStructureDialog.setText(MessageManager
1315             .getString("label.show_pdbstruct_dialog"));
1316     pdbStructureDialog.addActionListener(new ActionListener()
1317     {
1318       @Override
1319       public void actionPerformed(ActionEvent actionEvent)
1320       {
1321         SequenceI[] selectedSeqs = new SequenceI[] { sequence };
1322         if (ap.av.getSelectionGroup() != null)
1323         {
1324           selectedSeqs = ap.av.getSequenceSelection();
1325         }
1326         new StructureChooser(selectedSeqs, sequence, ap);
1327       }
1328     });
1329
1330     rnaStructureMenu.setText(MessageManager
1331             .getString("label.view_rna_structure"));
1332
1333     // colStructureMenu.setText("Colour By Structure");
1334     editSequence.setText(MessageManager.getString("label.edit_sequence")
1335             + "...");
1336     editSequence.addActionListener(new ActionListener()
1337     {
1338       @Override
1339       public void actionPerformed(ActionEvent actionEvent)
1340       {
1341         editSequence_actionPerformed(actionEvent);
1342       }
1343     });
1344     makeReferenceSeq.setText(MessageManager
1345             .getString("label.mark_as_representative"));
1346     makeReferenceSeq.addActionListener(new ActionListener()
1347     {
1348
1349       @Override
1350       public void actionPerformed(ActionEvent actionEvent)
1351       {
1352         makeReferenceSeq_actionPerformed(actionEvent);
1353
1354       }
1355     });
1356     hideInsertions.setText(MessageManager
1357             .getString("label.hide_insertions"));
1358     hideInsertions.addActionListener(new ActionListener()
1359     {
1360
1361       @Override
1362       public void actionPerformed(ActionEvent e)
1363       {
1364         hideInsertions_actionPerformed(e);
1365       }
1366     });
1367     /*
1368      * annotationMenuItem.setText("By Annotation");
1369      * annotationMenuItem.addActionListener(new ActionListener() { public void
1370      * actionPerformed(ActionEvent actionEvent) {
1371      * annotationMenuItem_actionPerformed(actionEvent); } });
1372      */
1373     groupMenu.add(sequenceSelDetails);
1374     add(groupMenu);
1375     add(sequenceMenu);
1376     add(rnaStructureMenu);
1377     add(pdbStructureDialog);
1378     if (sequence != null)
1379     {
1380       add(hideInsertions);
1381     }
1382     // annotations configuration panel suppressed for now
1383     // groupMenu.add(chooseAnnotations);
1384
1385     /*
1386      * Add show/hide annotations to the Sequence menu, and to the Selection menu
1387      * (if a selection group is in force).
1388      */
1389     sequenceMenu.add(seqShowAnnotationsMenu);
1390     sequenceMenu.add(seqHideAnnotationsMenu);
1391     sequenceMenu.add(seqAddReferenceAnnotations);
1392     groupMenu.add(groupShowAnnotationsMenu);
1393     groupMenu.add(groupHideAnnotationsMenu);
1394     groupMenu.add(groupAddReferenceAnnotations);
1395     groupMenu.add(editMenu);
1396     groupMenu.add(outputMenu);
1397     groupMenu.add(sequenceFeature);
1398     groupMenu.add(createGroupMenuItem);
1399     groupMenu.add(unGroupMenuItem);
1400     groupMenu.add(jMenu1);
1401     sequenceMenu.add(sequenceName);
1402     sequenceMenu.add(sequenceDetails);
1403     sequenceMenu.add(makeReferenceSeq);
1404     colourMenu.add(textColour);
1405     colourMenu.add(noColourmenuItem);
1406     colourMenu.add(clustalColour);
1407     colourMenu.add(BLOSUM62Colour);
1408     colourMenu.add(PIDColour);
1409     colourMenu.add(zappoColour);
1410     colourMenu.add(taylorColour);
1411     colourMenu.add(hydrophobicityColour);
1412     colourMenu.add(helixColour);
1413     colourMenu.add(strandColour);
1414     colourMenu.add(turnColour);
1415     colourMenu.add(buriedColour);
1416     colourMenu.add(nucleotideMenuItem);
1417     if (ap.getAlignment().isNucleotide())
1418     {
1419       // JBPNote - commented since the colourscheme isn't functional
1420       colourMenu.add(purinePyrimidineColour);
1421     }
1422     colourMenu.add(userDefinedColour);
1423
1424     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
1425     {
1426       java.util.Enumeration userColours = jalview.gui.UserDefinedColours
1427               .getUserColourSchemes().keys();
1428
1429       while (userColours.hasMoreElements())
1430       {
1431         JMenuItem item = new JMenuItem(userColours.nextElement().toString());
1432         item.addActionListener(new ActionListener()
1433         {
1434           @Override
1435           public void actionPerformed(ActionEvent evt)
1436           {
1437             userDefinedColour_actionPerformed(evt);
1438           }
1439         });
1440         colourMenu.add(item);
1441       }
1442     }
1443
1444     colourMenu.addSeparator();
1445     colourMenu.add(abovePIDColour);
1446     colourMenu.add(conservationMenuItem);
1447     editMenu.add(copy);
1448     editMenu.add(cut);
1449     editMenu.add(editSequence);
1450     editMenu.add(upperCase);
1451     editMenu.add(lowerCase);
1452     editMenu.add(toggle);
1453     // JBPNote: These shouldn't be added here - should appear in a generic
1454     // 'apply web service to this sequence menu'
1455     // pdbMenu.add(RNAFold);
1456     // pdbMenu.add(ContraFold);
1457     jMenu1.add(groupName);
1458     jMenu1.add(colourMenu);
1459     jMenu1.add(showBoxes);
1460     jMenu1.add(showText);
1461     jMenu1.add(showColourText);
1462     jMenu1.add(outline);
1463     jMenu1.add(displayNonconserved);
1464     noColourmenuItem.setText(MessageManager.getString("label.none"));
1465     noColourmenuItem.addActionListener(new java.awt.event.ActionListener()
1466     {
1467       @Override
1468       public void actionPerformed(ActionEvent e)
1469       {
1470         noColourmenuItem_actionPerformed();
1471       }
1472     });
1473
1474     clustalColour.setText(MessageManager
1475             .getString("label.clustalx_colours"));
1476     clustalColour.addActionListener(new java.awt.event.ActionListener()
1477     {
1478       @Override
1479       public void actionPerformed(ActionEvent e)
1480       {
1481         clustalColour_actionPerformed();
1482       }
1483     });
1484     zappoColour.setText(MessageManager.getString("label.zappo"));
1485     zappoColour.addActionListener(new java.awt.event.ActionListener()
1486     {
1487       @Override
1488       public void actionPerformed(ActionEvent e)
1489       {
1490         zappoColour_actionPerformed();
1491       }
1492     });
1493     taylorColour.setText(MessageManager.getString("label.taylor"));
1494     taylorColour.addActionListener(new java.awt.event.ActionListener()
1495     {
1496       @Override
1497       public void actionPerformed(ActionEvent e)
1498       {
1499         taylorColour_actionPerformed();
1500       }
1501     });
1502     hydrophobicityColour.setText(MessageManager
1503             .getString("label.hydrophobicity"));
1504     hydrophobicityColour
1505             .addActionListener(new java.awt.event.ActionListener()
1506             {
1507               @Override
1508               public void actionPerformed(ActionEvent e)
1509               {
1510                 hydrophobicityColour_actionPerformed();
1511               }
1512             });
1513     helixColour.setText(MessageManager.getString("label.helix_propensity"));
1514     helixColour.addActionListener(new java.awt.event.ActionListener()
1515     {
1516       @Override
1517       public void actionPerformed(ActionEvent e)
1518       {
1519         helixColour_actionPerformed();
1520       }
1521     });
1522     strandColour.setText(MessageManager
1523             .getString("label.strand_propensity"));
1524     strandColour.addActionListener(new java.awt.event.ActionListener()
1525     {
1526       @Override
1527       public void actionPerformed(ActionEvent e)
1528       {
1529         strandColour_actionPerformed();
1530       }
1531     });
1532     turnColour.setText(MessageManager.getString("label.turn_propensity"));
1533     turnColour.addActionListener(new java.awt.event.ActionListener()
1534     {
1535       @Override
1536       public void actionPerformed(ActionEvent e)
1537       {
1538         turnColour_actionPerformed();
1539       }
1540     });
1541     buriedColour.setText(MessageManager.getString("label.buried_index"));
1542     buriedColour.addActionListener(new java.awt.event.ActionListener()
1543     {
1544       @Override
1545       public void actionPerformed(ActionEvent e)
1546       {
1547         buriedColour_actionPerformed();
1548       }
1549     });
1550     abovePIDColour.setText(MessageManager
1551             .getString("label.above_identity_percentage"));
1552     abovePIDColour.addActionListener(new java.awt.event.ActionListener()
1553     {
1554       @Override
1555       public void actionPerformed(ActionEvent e)
1556       {
1557         abovePIDColour_actionPerformed();
1558       }
1559     });
1560     userDefinedColour.setText(MessageManager
1561             .getString("action.user_defined"));
1562     userDefinedColour.addActionListener(new java.awt.event.ActionListener()
1563     {
1564       @Override
1565       public void actionPerformed(ActionEvent e)
1566       {
1567         userDefinedColour_actionPerformed(e);
1568       }
1569     });
1570     PIDColour
1571             .setText(MessageManager.getString("label.percentage_identity"));
1572     PIDColour.addActionListener(new java.awt.event.ActionListener()
1573     {
1574       @Override
1575       public void actionPerformed(ActionEvent e)
1576       {
1577         PIDColour_actionPerformed();
1578       }
1579     });
1580     BLOSUM62Colour.setText(MessageManager.getString("label.blosum62"));
1581     BLOSUM62Colour.addActionListener(new java.awt.event.ActionListener()
1582     {
1583       @Override
1584       public void actionPerformed(ActionEvent e)
1585       {
1586         BLOSUM62Colour_actionPerformed();
1587       }
1588     });
1589     purinePyrimidineColour.setText(MessageManager
1590             .getString("label.purine_pyrimidine"));
1591     purinePyrimidineColour
1592             .addActionListener(new java.awt.event.ActionListener()
1593             {
1594               @Override
1595               public void actionPerformed(ActionEvent e)
1596               {
1597                 purinePyrimidineColour_actionPerformed();
1598               }
1599             });
1600
1601     /*
1602      * covariationColour.addActionListener(new java.awt.event.ActionListener() {
1603      * public void actionPerformed(ActionEvent e) {
1604      * covariationColour_actionPerformed(); } });
1605      */
1606
1607     conservationMenuItem.setText(MessageManager
1608             .getString("label.conservation"));
1609     conservationMenuItem
1610             .addActionListener(new java.awt.event.ActionListener()
1611             {
1612               @Override
1613               public void actionPerformed(ActionEvent e)
1614               {
1615                 conservationMenuItem_actionPerformed();
1616               }
1617             });
1618   }
1619
1620   /**
1621    * Check for any annotations on the underlying dataset sequences (for the
1622    * current selection group) which are not 'on the alignment'.If any are found,
1623    * enable the option to add them to the alignment. The criteria for 'on the
1624    * alignment' is finding an alignment annotation on the alignment, matched on
1625    * calcId, label and sequenceRef.
1626    * 
1627    * A tooltip is also constructed that displays the source (calcId) and type
1628    * (label) of the annotations that can be added.
1629    * 
1630    * @param menuItem
1631    * @param forSequences
1632    */
1633   protected void configureReferenceAnnotationsMenu(JMenuItem menuItem,
1634           List<SequenceI> forSequences)
1635   {
1636     menuItem.setEnabled(false);
1637
1638     /*
1639      * Temporary store to hold distinct calcId / type pairs for the tooltip.
1640      * Using TreeMap means calcIds are shown in alphabetical order.
1641      */
1642     Map<String, String> tipEntries = new TreeMap<String, String>();
1643     final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
1644     AlignmentI al = this.ap.av.getAlignment();
1645     AlignmentUtils.findAddableReferenceAnnotations(forSequences,
1646             tipEntries, candidates, al);
1647     if (!candidates.isEmpty())
1648     {
1649       StringBuilder tooltip = new StringBuilder(64);
1650       tooltip.append(MessageManager.getString("label.add_annotations_for"));
1651
1652       /*
1653        * Found annotations that could be added. Enable the menu item, and
1654        * configure its tooltip and action.
1655        */
1656       menuItem.setEnabled(true);
1657       for (String calcId : tipEntries.keySet())
1658       {
1659         tooltip.append("<br/>" + calcId + "/" + tipEntries.get(calcId));
1660       }
1661       String tooltipText = JvSwingUtils.wrapTooltip(true,
1662               tooltip.toString());
1663       menuItem.setToolTipText(tooltipText);
1664
1665       menuItem.addActionListener(new ActionListener()
1666       {
1667         @Override
1668         public void actionPerformed(ActionEvent e)
1669         {
1670           addReferenceAnnotations_actionPerformed(candidates);
1671         }
1672       });
1673     }
1674   }
1675
1676   /**
1677    * Add annotations to the sequences and to the alignment.
1678    * 
1679    * @param candidates
1680    *          a map whose keys are sequences on the alignment, and values a list
1681    *          of annotations to add to each sequence
1682    */
1683   protected void addReferenceAnnotations_actionPerformed(
1684           Map<SequenceI, List<AlignmentAnnotation>> candidates)
1685   {
1686     final SequenceGroup selectionGroup = this.ap.av.getSelectionGroup();
1687     final AlignmentI alignment = this.ap.getAlignment();
1688     AlignmentUtils.addReferenceAnnotations(candidates, alignment,
1689             selectionGroup);
1690     refresh();
1691   }
1692
1693   protected void makeReferenceSeq_actionPerformed(ActionEvent actionEvent)
1694   {
1695     if (!ap.av.getAlignment().hasSeqrep())
1696     {
1697       // initialise the display flags so the user sees something happen
1698       ap.av.setDisplayReferenceSeq(true);
1699       ap.av.setColourByReferenceSeq(true);
1700       ap.av.getAlignment().setSeqrep(sequence);
1701     }
1702     else
1703     {
1704       if (ap.av.getAlignment().getSeqrep() == sequence)
1705       {
1706         ap.av.getAlignment().setSeqrep(null);
1707       }
1708       else
1709       {
1710         ap.av.getAlignment().setSeqrep(sequence);
1711       }
1712     }
1713     refresh();
1714   }
1715
1716   protected void hideInsertions_actionPerformed(ActionEvent actionEvent)
1717   {
1718     if (sequence != null)
1719     {
1720       ColumnSelection cs = ap.av.getColumnSelection();
1721       if (cs == null)
1722       {
1723         cs = new ColumnSelection();
1724       }
1725       cs.hideInsertionsFor(sequence);
1726       ap.av.setColumnSelection(cs);
1727     }
1728     refresh();
1729   }
1730
1731   protected void sequenceSelectionDetails_actionPerformed()
1732   {
1733     createSequenceDetailsReport(ap.av.getSequenceSelection());
1734   }
1735
1736   protected void sequenceDetails_actionPerformed()
1737   {
1738     createSequenceDetailsReport(new SequenceI[] { sequence });
1739   }
1740
1741   public void createSequenceDetailsReport(SequenceI[] sequences)
1742   {
1743     CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer();
1744     StringBuffer contents = new StringBuffer();
1745     for (SequenceI seq : sequences)
1746     {
1747       contents.append("<p><h2>"
1748               + MessageManager
1749                       .formatMessage(
1750                               "label.create_sequence_details_report_annotation_for",
1751                               new Object[] { seq.getDisplayId(true) })
1752               + "</h2></p><p>");
1753       new SequenceAnnotationReport(null)
1754               .createSequenceAnnotationReport(
1755                       contents,
1756                       seq,
1757                       true,
1758                       true,
1759                       false,
1760                       (ap.getSeqPanel().seqCanvas.fr != null) ? ap
1761                               .getSeqPanel().seqCanvas.fr.getMinMax()
1762                               : null);
1763       contents.append("</p>");
1764     }
1765     cap.setText("<html>" + contents.toString() + "</html>");
1766
1767     Desktop.addInternalFrame(cap, MessageManager.formatMessage(
1768             "label.sequence_details_for",
1769             (sequences.length == 1 ? new Object[] { sequences[0]
1770                     .getDisplayId(true) } : new Object[] { MessageManager
1771                     .getString("label.selection") })), 500, 400);
1772
1773   }
1774
1775   protected void showNonconserved_actionPerformed()
1776   {
1777     getGroup().setShowNonconserved(displayNonconserved.isSelected());
1778     refresh();
1779   }
1780
1781   /**
1782    * call to refresh view after settings change
1783    */
1784   void refresh()
1785   {
1786     ap.updateAnnotation();
1787     ap.paintAlignment(true);
1788
1789     PaintRefresher.Refresh(this, ap.av.getSequenceSetId());
1790   }
1791
1792   /**
1793    * DOCUMENT ME!
1794    * 
1795    * @param e
1796    *          DOCUMENT ME!
1797    */
1798   protected void clustalColour_actionPerformed()
1799   {
1800     SequenceGroup sg = getGroup();
1801     sg.cs = new ClustalxColourScheme(sg, ap.av.getHiddenRepSequences());
1802     refresh();
1803   }
1804
1805   /**
1806    * DOCUMENT ME!
1807    * 
1808    * @param e
1809    *          DOCUMENT ME!
1810    */
1811   protected void zappoColour_actionPerformed()
1812   {
1813     getGroup().cs = new ZappoColourScheme();
1814     refresh();
1815   }
1816
1817   /**
1818    * DOCUMENT ME!
1819    * 
1820    * @param e
1821    *          DOCUMENT ME!
1822    */
1823   protected void taylorColour_actionPerformed()
1824   {
1825     getGroup().cs = new TaylorColourScheme();
1826     refresh();
1827   }
1828
1829   /**
1830    * DOCUMENT ME!
1831    * 
1832    * @param e
1833    *          DOCUMENT ME!
1834    */
1835   protected void hydrophobicityColour_actionPerformed()
1836   {
1837     getGroup().cs = new HydrophobicColourScheme();
1838     refresh();
1839   }
1840
1841   /**
1842    * DOCUMENT ME!
1843    * 
1844    * @param e
1845    *          DOCUMENT ME!
1846    */
1847   protected void helixColour_actionPerformed()
1848   {
1849     getGroup().cs = new HelixColourScheme();
1850     refresh();
1851   }
1852
1853   /**
1854    * DOCUMENT ME!
1855    * 
1856    * @param e
1857    *          DOCUMENT ME!
1858    */
1859   protected void strandColour_actionPerformed()
1860   {
1861     getGroup().cs = new StrandColourScheme();
1862     refresh();
1863   }
1864
1865   /**
1866    * DOCUMENT ME!
1867    * 
1868    * @param e
1869    *          DOCUMENT ME!
1870    */
1871   protected void turnColour_actionPerformed()
1872   {
1873     getGroup().cs = new TurnColourScheme();
1874     refresh();
1875   }
1876
1877   /**
1878    * DOCUMENT ME!
1879    * 
1880    * @param e
1881    *          DOCUMENT ME!
1882    */
1883   protected void buriedColour_actionPerformed()
1884   {
1885     getGroup().cs = new BuriedColourScheme();
1886     refresh();
1887   }
1888
1889   /**
1890    * DOCUMENT ME!
1891    * 
1892    * @param e
1893    *          DOCUMENT ME!
1894    */
1895   public void nucleotideMenuItem_actionPerformed()
1896   {
1897     getGroup().cs = new NucleotideColourScheme();
1898     refresh();
1899   }
1900
1901   protected void purinePyrimidineColour_actionPerformed()
1902   {
1903     getGroup().cs = new PurinePyrimidineColourScheme();
1904     refresh();
1905   }
1906
1907   /*
1908    * protected void covariationColour_actionPerformed() { getGroup().cs = new
1909    * CovariationColourScheme(sequence.getAnnotation()[0]); refresh(); }
1910    */
1911   /**
1912    * DOCUMENT ME!
1913    * 
1914    * @param e
1915    *          DOCUMENT ME!
1916    */
1917   protected void abovePIDColour_actionPerformed()
1918   {
1919     SequenceGroup sg = getGroup();
1920     if (sg.cs == null)
1921     {
1922       return;
1923     }
1924
1925     if (abovePIDColour.isSelected())
1926     {
1927       sg.cs.setConsensus(AAFrequency.calculate(
1928               sg.getSequences(ap.av.getHiddenRepSequences()),
1929               sg.getStartRes(), sg.getEndRes() + 1));
1930
1931       int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup()
1932               .getName());
1933
1934       sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus());
1935
1936       SliderPanel.showPIDSlider();
1937     }
1938     else
1939     // remove PIDColouring
1940     {
1941       sg.cs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
1942     }
1943
1944     refresh();
1945   }
1946
1947   /**
1948    * DOCUMENT ME!
1949    * 
1950    * @param e
1951    *          DOCUMENT ME!
1952    */
1953   protected void userDefinedColour_actionPerformed(ActionEvent e)
1954   {
1955     SequenceGroup sg = getGroup();
1956
1957     if (e.getSource().equals(userDefinedColour))
1958     {
1959       new UserDefinedColours(ap, sg);
1960     }
1961     else
1962     {
1963       UserColourScheme udc = (UserColourScheme) UserDefinedColours
1964               .getUserColourSchemes().get(e.getActionCommand());
1965
1966       sg.cs = udc;
1967     }
1968     refresh();
1969   }
1970
1971   /**
1972    * Open a panel where the user can choose which types of sequence annotation
1973    * to show or hide.
1974    * 
1975    * @param e
1976    */
1977   protected void chooseAnnotations_actionPerformed(ActionEvent e)
1978   {
1979     // todo correct way to guard against opening a duplicate panel?
1980     new AnnotationChooser(ap);
1981   }
1982
1983   /**
1984    * DOCUMENT ME!
1985    * 
1986    * @param e
1987    *          DOCUMENT ME!
1988    */
1989   protected void PIDColour_actionPerformed()
1990   {
1991     SequenceGroup sg = getGroup();
1992     sg.cs = new PIDColourScheme();
1993     sg.cs.setConsensus(AAFrequency.calculate(
1994             sg.getSequences(ap.av.getHiddenRepSequences()),
1995             sg.getStartRes(), sg.getEndRes() + 1));
1996     refresh();
1997   }
1998
1999   /**
2000    * DOCUMENT ME!
2001    * 
2002    * @param e
2003    *          DOCUMENT ME!
2004    */
2005   protected void BLOSUM62Colour_actionPerformed()
2006   {
2007     SequenceGroup sg = getGroup();
2008
2009     sg.cs = new Blosum62ColourScheme();
2010
2011     sg.cs.setConsensus(AAFrequency.calculate(
2012             sg.getSequences(ap.av.getHiddenRepSequences()),
2013             sg.getStartRes(), sg.getEndRes() + 1));
2014
2015     refresh();
2016   }
2017
2018   /**
2019    * DOCUMENT ME!
2020    * 
2021    * @param e
2022    *          DOCUMENT ME!
2023    */
2024   protected void noColourmenuItem_actionPerformed()
2025   {
2026     getGroup().cs = null;
2027     refresh();
2028   }
2029
2030   /**
2031    * DOCUMENT ME!
2032    * 
2033    * @param e
2034    *          DOCUMENT ME!
2035    */
2036   protected void conservationMenuItem_actionPerformed()
2037   {
2038     SequenceGroup sg = getGroup();
2039     if (sg.cs == null)
2040     {
2041       return;
2042     }
2043
2044     if (conservationMenuItem.isSelected())
2045     {
2046       // JBPNote: Conservation name shouldn't be i18n translated
2047       Conservation c = new Conservation("Group",
2048               ResidueProperties.propHash, 3, sg.getSequences(ap.av
2049                       .getHiddenRepSequences()), sg.getStartRes(),
2050               sg.getEndRes() + 1);
2051
2052       c.calculate();
2053       c.verdict(false, ap.av.getConsPercGaps());
2054
2055       sg.cs.setConservation(c);
2056
2057       SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
2058       SliderPanel.showConservationSlider();
2059     }
2060     else
2061     // remove ConservationColouring
2062     {
2063       sg.cs.setConservation(null);
2064     }
2065
2066     refresh();
2067   }
2068
2069   public void annotationMenuItem_actionPerformed(ActionEvent actionEvent)
2070   {
2071     SequenceGroup sg = getGroup();
2072     if (sg == null)
2073     {
2074       return;
2075     }
2076
2077     AnnotationColourGradient acg = new AnnotationColourGradient(
2078             sequence.getAnnotation()[0], null,
2079             AnnotationColourGradient.NO_THRESHOLD);
2080
2081     acg.setPredefinedColours(true);
2082     sg.cs = acg;
2083
2084     refresh();
2085   }
2086
2087   /**
2088    * DOCUMENT ME!
2089    * 
2090    * @param e
2091    *          DOCUMENT ME!
2092    */
2093   protected void groupName_actionPerformed()
2094   {
2095
2096     SequenceGroup sg = getGroup();
2097     EditNameDialog dialog = new EditNameDialog(sg.getName(),
2098             sg.getDescription(), "       "
2099                     + MessageManager.getString("label.group_name") + " ",
2100             MessageManager.getString("label.group_description") + " ",
2101             MessageManager.getString("label.edit_group_name_description"),
2102             ap.alignFrame);
2103
2104     if (!dialog.accept)
2105     {
2106       return;
2107     }
2108
2109     sg.setName(dialog.getName());
2110     sg.setDescription(dialog.getDescription());
2111     refresh();
2112   }
2113
2114   /**
2115    * Get selection group - adding it to the alignment if necessary.
2116    * 
2117    * @return sequence group to operate on
2118    */
2119   SequenceGroup getGroup()
2120   {
2121     SequenceGroup sg = ap.av.getSelectionGroup();
2122     // this method won't add a new group if it already exists
2123     if (sg != null)
2124     {
2125       ap.av.getAlignment().addGroup(sg);
2126     }
2127
2128     return sg;
2129   }
2130
2131   /**
2132    * DOCUMENT ME!
2133    * 
2134    * @param e
2135    *          DOCUMENT ME!
2136    */
2137   void sequenceName_actionPerformed()
2138   {
2139     EditNameDialog dialog = new EditNameDialog(sequence.getName(),
2140             sequence.getDescription(),
2141             "       " + MessageManager.getString("label.sequence_name")
2142                     + " ",
2143             MessageManager.getString("label.sequence_description") + " ",
2144             MessageManager
2145                     .getString("label.edit_sequence_name_description"),
2146             ap.alignFrame);
2147
2148     if (!dialog.accept)
2149     {
2150       return;
2151     }
2152
2153     if (dialog.getName() != null)
2154     {
2155       if (dialog.getName().indexOf(" ") > -1)
2156       {
2157         JOptionPane
2158                 .showMessageDialog(
2159                         ap,
2160                         MessageManager
2161                                 .getString("label.spaces_converted_to_backslashes"),
2162                         MessageManager
2163                                 .getString("label.no_spaces_allowed_sequence_name"),
2164                         JOptionPane.WARNING_MESSAGE);
2165       }
2166
2167       sequence.setName(dialog.getName().replace(' ', '_'));
2168       ap.paintAlignment(false);
2169     }
2170
2171     sequence.setDescription(dialog.getDescription());
2172
2173     ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
2174             .getSequences());
2175
2176   }
2177
2178   /**
2179    * DOCUMENT ME!
2180    * 
2181    * @param e
2182    *          DOCUMENT ME!
2183    */
2184   void unGroupMenuItem_actionPerformed()
2185   {
2186     SequenceGroup sg = ap.av.getSelectionGroup();
2187     ap.av.getAlignment().deleteGroup(sg);
2188     ap.av.setSelectionGroup(null);
2189     refresh();
2190   }
2191
2192   void createGroupMenuItem_actionPerformed()
2193   {
2194     getGroup(); // implicitly creates group - note - should apply defaults / use
2195                 // standard alignment window logic for this
2196     refresh();
2197   }
2198
2199   /**
2200    * DOCUMENT ME!
2201    * 
2202    * @param e
2203    *          DOCUMENT ME!
2204    */
2205   protected void outline_actionPerformed()
2206   {
2207     SequenceGroup sg = getGroup();
2208     Color col = JColorChooser.showDialog(this,
2209             MessageManager.getString("label.select_outline_colour"),
2210             Color.BLUE);
2211
2212     if (col != null)
2213     {
2214       sg.setOutlineColour(col);
2215     }
2216
2217     refresh();
2218   }
2219
2220   /**
2221    * DOCUMENT ME!
2222    * 
2223    * @param e
2224    *          DOCUMENT ME!
2225    */
2226   public void showBoxes_actionPerformed()
2227   {
2228     getGroup().setDisplayBoxes(showBoxes.isSelected());
2229     refresh();
2230   }
2231
2232   /**
2233    * DOCUMENT ME!
2234    * 
2235    * @param e
2236    *          DOCUMENT ME!
2237    */
2238   public void showText_actionPerformed()
2239   {
2240     getGroup().setDisplayText(showText.isSelected());
2241     refresh();
2242   }
2243
2244   /**
2245    * DOCUMENT ME!
2246    * 
2247    * @param e
2248    *          DOCUMENT ME!
2249    */
2250   public void showColourText_actionPerformed()
2251   {
2252     getGroup().setColourText(showColourText.isSelected());
2253     refresh();
2254   }
2255
2256   public void showLink(String url)
2257   {
2258     try
2259     {
2260       jalview.util.BrowserLauncher.openURL(url);
2261     } catch (Exception ex)
2262     {
2263       JOptionPane.showInternalMessageDialog(Desktop.desktop,
2264               MessageManager.getString("label.web_browser_not_found_unix"),
2265               MessageManager.getString("label.web_browser_not_found"),
2266               JOptionPane.WARNING_MESSAGE);
2267
2268       ex.printStackTrace();
2269     }
2270   }
2271
2272   void hideSequences(boolean representGroup)
2273   {
2274     ap.av.hideSequences(sequence, representGroup);
2275   }
2276
2277   public void copy_actionPerformed()
2278   {
2279     ap.alignFrame.copy_actionPerformed(null);
2280   }
2281
2282   public void cut_actionPerformed()
2283   {
2284     ap.alignFrame.cut_actionPerformed(null);
2285   }
2286
2287   void changeCase(ActionEvent e)
2288   {
2289     Object source = e.getSource();
2290     SequenceGroup sg = ap.av.getSelectionGroup();
2291
2292     if (sg != null)
2293     {
2294       List<int[]> startEnd = ap.av.getVisibleRegionBoundaries(
2295               sg.getStartRes(), sg.getEndRes() + 1);
2296
2297       String description;
2298       int caseChange;
2299
2300       if (source == toggle)
2301       {
2302         description = MessageManager.getString("label.toggle_case");
2303         caseChange = ChangeCaseCommand.TOGGLE_CASE;
2304       }
2305       else if (source == upperCase)
2306       {
2307         description = MessageManager.getString("label.to_upper_case");
2308         caseChange = ChangeCaseCommand.TO_UPPER;
2309       }
2310       else
2311       {
2312         description = MessageManager.getString("label.to_lower_case");
2313         caseChange = ChangeCaseCommand.TO_LOWER;
2314       }
2315
2316       ChangeCaseCommand caseCommand = new ChangeCaseCommand(description,
2317               sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
2318               startEnd, caseChange);
2319
2320       ap.alignFrame.addHistoryItem(caseCommand);
2321
2322       ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
2323               .getSequences());
2324
2325     }
2326   }
2327
2328   public void outputText_actionPerformed(ActionEvent e)
2329   {
2330     CutAndPasteTransfer cap = new CutAndPasteTransfer();
2331     cap.setForInput(null);
2332     Desktop.addInternalFrame(cap, MessageManager.formatMessage(
2333             "label.alignment_output_command",
2334             new Object[] { e.getActionCommand() }), 600, 500);
2335
2336     String[] omitHidden = null;
2337
2338     System.out.println("PROMPT USER HERE"); // TODO: decide if a prompt happens
2339     // or we simply trust the user wants
2340     // wysiwig behaviour
2341
2342     FileFormat fileFormat = FileFormat.forName(e.getActionCommand());
2343     cap.setText(new FormatAdapter(ap).formatSequences(fileFormat, ap, true));
2344   }
2345
2346   public void sequenceFeature_actionPerformed()
2347   {
2348     SequenceGroup sg = ap.av.getSelectionGroup();
2349     if (sg == null)
2350     {
2351       return;
2352     }
2353
2354     int rsize = 0, gSize = sg.getSize();
2355     SequenceI[] rseqs, seqs = new SequenceI[gSize];
2356     SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
2357
2358     for (int i = 0; i < gSize; i++)
2359     {
2360       int start = sg.getSequenceAt(i).findPosition(sg.getStartRes());
2361       int end = sg.findEndRes(sg.getSequenceAt(i));
2362       if (start <= end)
2363       {
2364         seqs[rsize] = sg.getSequenceAt(i).getDatasetSequence();
2365         features[rsize] = new SequenceFeature(null, null, null, start, end,
2366                 "Jalview");
2367         rsize++;
2368       }
2369     }
2370     rseqs = new SequenceI[rsize];
2371     tfeatures = new SequenceFeature[rsize];
2372     System.arraycopy(seqs, 0, rseqs, 0, rsize);
2373     System.arraycopy(features, 0, tfeatures, 0, rsize);
2374     features = tfeatures;
2375     seqs = rseqs;
2376     if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
2377             features, true, ap))
2378     {
2379       ap.alignFrame.setShowSeqFeatures(true);
2380       ap.highlightSearchResults(null);
2381     }
2382   }
2383
2384   public void textColour_actionPerformed()
2385   {
2386     SequenceGroup sg = getGroup();
2387     if (sg != null)
2388     {
2389       new TextColourChooser().chooseColour(ap, sg);
2390     }
2391   }
2392
2393   public void colourByStructure(String pdbid)
2394   {
2395     Annotation[] anots = ap.av.getStructureSelectionManager()
2396             .colourSequenceFromStructure(sequence, pdbid);
2397
2398     AlignmentAnnotation an = new AlignmentAnnotation("Structure",
2399             "Coloured by " + pdbid, anots);
2400
2401     ap.av.getAlignment().addAnnotation(an);
2402     an.createSequenceMapping(sequence, 0, true);
2403     // an.adjustForAlignment();
2404     ap.av.getAlignment().setAnnotationIndex(an, 0);
2405
2406     ap.adjustAnnotationHeight();
2407
2408     sequence.addAlignmentAnnotation(an);
2409
2410   }
2411
2412   public void editSequence_actionPerformed(ActionEvent actionEvent)
2413   {
2414     SequenceGroup sg = ap.av.getSelectionGroup();
2415
2416     if (sg != null)
2417     {
2418       if (sequence == null)
2419       {
2420         sequence = sg.getSequenceAt(0);
2421       }
2422
2423       EditNameDialog dialog = new EditNameDialog(
2424               sequence.getSequenceAsString(sg.getStartRes(),
2425                       sg.getEndRes() + 1), null,
2426               MessageManager.getString("label.edit_sequence"), null,
2427               MessageManager.getString("label.edit_sequence"),
2428               ap.alignFrame);
2429
2430       if (dialog.accept)
2431       {
2432         EditCommand editCommand = new EditCommand(
2433                 MessageManager.getString("label.edit_sequences"),
2434                 Action.REPLACE, dialog.getName().replace(' ',
2435                         ap.av.getGapCharacter()),
2436                 sg.getSequencesAsArray(ap.av.getHiddenRepSequences()),
2437                 sg.getStartRes(), sg.getEndRes() + 1, ap.av.getAlignment());
2438
2439         ap.alignFrame.addHistoryItem(editCommand);
2440
2441         ap.av.firePropertyChange("alignment", null, ap.av.getAlignment()
2442                 .getSequences());
2443       }
2444     }
2445   }
2446
2447 }