Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.gui

File PopupMenu.java

 

Coverage histogram

../../img/srcFileCovDistChart5.png
39% of files have more coverage

Code metrics

198
695
95
1
2,319
1,684
215
0.31
7.32
95
2.26

Classes

Class Line # Actions
PopupMenu 94 695 215
0.438259143.8%
 

Contributing tests

This file is covered by 15 tests. .

Source view

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