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