JAL-2792 JAL-3187 linked features (if shown) in Feature details submenu
[jalview.git] / test / jalview / gui / PopupMenuTest.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 static jalview.util.UrlConstants.DB_ACCESSION;
24 import static jalview.util.UrlConstants.SEQUENCE_ID;
25 import static org.testng.AssertJUnit.assertEquals;
26 import static org.testng.AssertJUnit.assertFalse;
27 import static org.testng.AssertJUnit.assertTrue;
28
29 import jalview.bin.Cache;
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.DBRefSource;
36 import jalview.datamodel.HiddenColumns;
37 import jalview.datamodel.Sequence;
38 import jalview.datamodel.SequenceFeature;
39 import jalview.datamodel.SequenceGroup;
40 import jalview.datamodel.SequenceI;
41 import jalview.io.DataSourceType;
42 import jalview.io.FileFormat;
43 import jalview.io.FormatAdapter;
44 import jalview.urls.api.UrlProviderFactoryI;
45 import jalview.urls.desktop.DesktopUrlProviderFactory;
46 import jalview.util.MessageManager;
47 import jalview.util.UrlConstants;
48
49 import java.awt.Component;
50 import java.io.IOException;
51 import java.util.ArrayList;
52 import java.util.Collections;
53 import java.util.Iterator;
54 import java.util.List;
55
56 import javax.swing.JMenu;
57 import javax.swing.JMenuItem;
58 import javax.swing.JPopupMenu;
59 import javax.swing.JSeparator;
60
61 import org.testng.annotations.BeforeClass;
62 import org.testng.annotations.BeforeMethod;
63 import org.testng.annotations.Test;
64
65 public class PopupMenuTest
66 {
67
68   @BeforeClass(alwaysRun = true)
69   public void setUpJvOptionPane()
70   {
71     JvOptionPane.setInteractiveMode(false);
72     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
73   }
74
75   // 4 sequences x 13 positions
76   final static String TEST_DATA = ">FER_CAPAA Ferredoxin\n"
77           + "TIETHKEAELVG-\n"
78           + ">FER_CAPAN Ferredoxin, chloroplast precursor\n"
79           + "TIETHKEAELVG-\n"
80           + ">FER1_SOLLC Ferredoxin-1, chloroplast precursor\n"
81           + "TIETHKEEELTA-\n" + ">Q93XJ9_SOLTU Ferredoxin I precursor\n"
82           + "TIETHKEEELTA-\n";
83
84   AlignmentI alignment;
85
86   AlignmentPanel parentPanel;
87
88   PopupMenu testee = null;
89
90   @BeforeMethod(alwaysRun = true)
91   public void setUp() throws IOException
92   {
93     Cache.loadProperties("test/jalview/io/testProps.jvprops");
94     Cache.initLogger();
95
96     String inMenuString = ("EMBL-EBI Search | http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$"
97             + SEQUENCE_ID
98             + "$"
99             + "|"
100             + "UNIPROT | http://www.uniprot.org/uniprot/$" + DB_ACCESSION + "$")
101             + "|"
102             + ("INTERPRO | http://www.ebi.ac.uk/interpro/entry/$"
103                     + DB_ACCESSION + "$")
104             + "|"
105             +
106             // Gene3D entry tests for case (in)sensitivity
107             ("Gene3D | http://gene3d.biochem.ucl.ac.uk/Gene3D/search?sterm=$"
108                     + DB_ACCESSION + "$&mode=protein");
109
110     UrlProviderFactoryI factory = new DesktopUrlProviderFactory(
111             UrlConstants.DEFAULT_LABEL, inMenuString, "");
112     Preferences.sequenceUrlLinks = factory.createUrlProvider();
113
114     alignment = new FormatAdapter().readFile(TEST_DATA,
115             DataSourceType.PASTE, FileFormat.Fasta);
116     AlignFrame af = new AlignFrame(alignment, 700, 500);
117     parentPanel = new AlignmentPanel(af, af.getViewport());
118     testee = new PopupMenu(parentPanel, alignment.getSequenceAt(0), null);
119     int i = 0;
120     for (SequenceI seq : alignment.getSequences())
121     {
122       final AlignmentAnnotation annotation = new AlignmentAnnotation(
123               "label" + i, "desc" + i, i);
124       annotation.setCalcId("calcId" + i);
125       seq.addAlignmentAnnotation(annotation);
126       annotation.setSequenceRef(seq);
127     }
128   }
129
130   @Test(groups = { "Functional" })
131   public void testConfigureReferenceAnnotationsMenu_noSequenceSelected()
132   {
133     JMenuItem menu = new JMenuItem();
134     List<SequenceI> seqs = new ArrayList<>();
135     testee.configureReferenceAnnotationsMenu(menu, seqs);
136     assertFalse(menu.isEnabled());
137     // now try null list
138     menu.setEnabled(true);
139     testee.configureReferenceAnnotationsMenu(menu, null);
140     assertFalse(menu.isEnabled());
141   }
142
143   /**
144    * Test building the 'add reference annotations' menu for the case where there
145    * are no reference annotations to add to the alignment. The menu item should
146    * be disabled.
147    */
148   @Test(groups = { "Functional" })
149   public void testConfigureReferenceAnnotationsMenu_noReferenceAnnotations()
150   {
151     JMenuItem menu = new JMenuItem();
152
153     /*
154      * Initial state is that sequences have annotations, and have dataset
155      * sequences, but the dataset sequences have no annotations. Hence nothing
156      * to add.
157      */
158     List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
159
160     testee.configureReferenceAnnotationsMenu(menu, seqs);
161     assertFalse(menu.isEnabled());
162   }
163
164   /**
165    * Test building the 'add reference annotations' menu for the case where all
166    * reference annotations are already on the alignment. The menu item should be
167    * disabled.
168    */
169   @Test(groups = { "Functional" })
170   public void testConfigureReferenceAnnotationsMenu_alreadyAdded()
171   {
172     JMenuItem menu = new JMenuItem();
173     List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
174
175     // make up new annotations and add to dataset sequences, sequences and
176     // alignment
177     attachReferenceAnnotations(seqs, true, true);
178
179     testee.configureReferenceAnnotationsMenu(menu, seqs);
180     assertFalse(menu.isEnabled());
181   }
182
183   /**
184    * Test building the 'add reference annotations' menu for the case where
185    * several reference annotations are on the dataset but not on the sequences.
186    * The menu item should be enabled, and acquire a tooltip which lists the
187    * annotation sources (calcIds) and type (labels).
188    */
189   @Test(groups = { "Functional" })
190   public void testConfigureReferenceAnnotationsMenu()
191   {
192     JMenuItem menu = new JMenuItem();
193     List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
194
195     // make up new annotations and add to dataset sequences
196     attachReferenceAnnotations(seqs, false, false);
197
198     testee.configureReferenceAnnotationsMenu(menu, seqs);
199     assertTrue(menu.isEnabled());
200     String s = MessageManager.getString("label.add_annotations_for");
201     String expected = "<html><style> p.ttip {width: 350; text-align: justify; word-wrap: break-word;}</style><p class=\"ttip\">"
202             + s + "<br/>Jmol/secondary structure<br/>PDB/Temp</p></html>";
203     assertEquals(expected, menu.getToolTipText());
204   }
205
206   /**
207    * Test building the 'add reference annotations' menu for the case where
208    * several reference annotations are on the dataset and the sequences but not
209    * on the alignment. The menu item should be enabled, and acquire a tooltip
210    * which lists the annotation sources (calcIds) and type (labels).
211    */
212   @Test(groups = { "Functional" })
213   public void testConfigureReferenceAnnotationsMenu_notOnAlignment()
214   {
215     JMenuItem menu = new JMenuItem();
216     List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
217
218     // make up new annotations and add to dataset sequences and sequences
219     attachReferenceAnnotations(seqs, true, false);
220
221     testee.configureReferenceAnnotationsMenu(menu, seqs);
222     assertTrue(menu.isEnabled());
223     String s = MessageManager.getString("label.add_annotations_for");
224     String expected = "<html><style> p.ttip {width: 350; text-align: justify; word-wrap: break-word;}</style><p class=\"ttip\">"
225             + s + "<br/>Jmol/secondary structure<br/>PDB/Temp</p></html>";
226     assertEquals(expected, menu.getToolTipText());
227   }
228
229   /**
230    * Generate annotations and add to dataset sequences and (optionally)
231    * sequences and/or alignment
232    * 
233    * @param seqs
234    * @param addToSequence
235    * @param addToAlignment
236    */
237   private void attachReferenceAnnotations(List<SequenceI> seqs,
238           boolean addToSequence, boolean addToAlignment)
239   {
240     // PDB.secondary structure on Sequence0
241     AlignmentAnnotation annotation = new AlignmentAnnotation(
242             "secondary structure", "", 0);
243     annotation.setCalcId("PDB");
244     seqs.get(0).getDatasetSequence().addAlignmentAnnotation(annotation);
245     if (addToSequence)
246     {
247       seqs.get(0).addAlignmentAnnotation(annotation);
248     }
249     if (addToAlignment)
250     {
251       this.alignment.addAnnotation(annotation);
252     }
253
254     // PDB.Temp on Sequence1
255     annotation = new AlignmentAnnotation("Temp", "", 0);
256     annotation.setCalcId("PDB");
257     seqs.get(1).getDatasetSequence().addAlignmentAnnotation(annotation);
258     if (addToSequence)
259     {
260       seqs.get(1).addAlignmentAnnotation(annotation);
261     }
262     if (addToAlignment)
263     {
264       this.alignment.addAnnotation(annotation);
265     }
266
267     // JMOL.secondary structure on Sequence0
268     annotation = new AlignmentAnnotation("secondary structure", "", 0);
269     annotation.setCalcId("Jmol");
270     seqs.get(0).getDatasetSequence().addAlignmentAnnotation(annotation);
271     if (addToSequence)
272     {
273       seqs.get(0).addAlignmentAnnotation(annotation);
274     }
275     if (addToAlignment)
276     {
277       this.alignment.addAnnotation(annotation);
278     }
279   }
280
281   /**
282    * Test building the 'add reference annotations' menu for the case where there
283    * are two alignment views:
284    * <ul>
285    * <li>in one view, reference annotations have been added (are on the
286    * datasets, sequences and alignment)</li>
287    * <li>in the current view, reference annotations are on the dataset and
288    * sequence, but not the alignment</li>
289    * </ul>
290    * The menu item should be enabled, and acquire a tooltip which lists the
291    * annotation sources (calcIds) and type (labels).
292    */
293   @Test(groups = { "Functional" })
294   public void testConfigureReferenceAnnotationsMenu_twoViews()
295   {
296   }
297
298   /**
299    * Test for building menu options including 'show' and 'hide' annotation
300    * types.
301    */
302   @Test(groups = { "Functional" })
303   public void testBuildAnnotationTypesMenus()
304   {
305     JMenu showMenu = new JMenu();
306     JMenu hideMenu = new JMenu();
307     List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
308
309     // make up new annotations and add to sequences and to the alignment
310
311     // PDB.secondary structure on Sequence0
312     AlignmentAnnotation annotation = new AlignmentAnnotation(
313             "secondary structure", "", new Annotation[] {});
314     annotation.setCalcId("PDB");
315     annotation.visible = true;
316     seqs.get(0).addAlignmentAnnotation(annotation);
317     parentPanel.getAlignment().addAnnotation(annotation);
318
319     // JMOL.secondary structure on Sequence0 - hidden
320     annotation = new AlignmentAnnotation("secondary structure", "",
321             new Annotation[] {});
322     annotation.setCalcId("JMOL");
323     annotation.visible = false;
324     seqs.get(0).addAlignmentAnnotation(annotation);
325     parentPanel.getAlignment().addAnnotation(annotation);
326
327     // Jpred.SSP on Sequence0 - hidden
328     annotation = new AlignmentAnnotation("SSP", "", new Annotation[] {});
329     annotation.setCalcId("JPred");
330     annotation.visible = false;
331     seqs.get(0).addAlignmentAnnotation(annotation);
332     parentPanel.getAlignment().addAnnotation(annotation);
333
334     // PDB.Temp on Sequence1
335     annotation = new AlignmentAnnotation("Temp", "", new Annotation[] {});
336     annotation.setCalcId("PDB");
337     annotation.visible = true;
338     seqs.get(1).addAlignmentAnnotation(annotation);
339     parentPanel.getAlignment().addAnnotation(annotation);
340
341     /*
342      * Expect menu options to show "secondary structure" and "SSP", and to hide
343      * "secondary structure" and "Temp". Tooltip should be calcId.
344      */
345     testee.buildAnnotationTypesMenus(showMenu, hideMenu, seqs);
346
347     assertTrue(showMenu.isEnabled());
348     assertTrue(hideMenu.isEnabled());
349
350     Component[] showOptions = showMenu.getMenuComponents();
351     Component[] hideOptions = hideMenu.getMenuComponents();
352
353     assertEquals(4, showOptions.length); // includes 'All' and separator
354     assertEquals(4, hideOptions.length);
355     String all = MessageManager.getString("label.all");
356     assertEquals(all, ((JMenuItem) showOptions[0]).getText());
357     assertTrue(showOptions[1] instanceof JPopupMenu.Separator);
358     assertEquals(JSeparator.HORIZONTAL,
359             ((JSeparator) showOptions[1]).getOrientation());
360     assertEquals("secondary structure",
361             ((JMenuItem) showOptions[2]).getText());
362     assertEquals("JMOL", ((JMenuItem) showOptions[2]).getToolTipText());
363     assertEquals("SSP", ((JMenuItem) showOptions[3]).getText());
364     assertEquals("JPred", ((JMenuItem) showOptions[3]).getToolTipText());
365
366     assertEquals(all, ((JMenuItem) hideOptions[0]).getText());
367     assertTrue(hideOptions[1] instanceof JPopupMenu.Separator);
368     assertEquals(JSeparator.HORIZONTAL,
369             ((JSeparator) hideOptions[1]).getOrientation());
370     assertEquals("secondary structure",
371             ((JMenuItem) hideOptions[2]).getText());
372     assertEquals("PDB", ((JMenuItem) hideOptions[2]).getToolTipText());
373     assertEquals("Temp", ((JMenuItem) hideOptions[3]).getText());
374     assertEquals("PDB", ((JMenuItem) hideOptions[3]).getToolTipText());
375   }
376
377   /**
378    * Test for building menu options with only 'hide' annotation types enabled.
379    */
380   @Test(groups = { "Functional" })
381   public void testBuildAnnotationTypesMenus_showDisabled()
382   {
383     JMenu showMenu = new JMenu();
384     JMenu hideMenu = new JMenu();
385     List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
386
387     // make up new annotations and add to sequences and to the alignment
388
389     // PDB.secondary structure on Sequence0
390     AlignmentAnnotation annotation = new AlignmentAnnotation(
391             "secondary structure", "", new Annotation[] {});
392     annotation.setCalcId("PDB");
393     annotation.visible = true;
394     seqs.get(0).addAlignmentAnnotation(annotation);
395     parentPanel.getAlignment().addAnnotation(annotation);
396
397     // PDB.Temp on Sequence1
398     annotation = new AlignmentAnnotation("Temp", "", new Annotation[] {});
399     annotation.setCalcId("PDB");
400     annotation.visible = true;
401     seqs.get(1).addAlignmentAnnotation(annotation);
402     parentPanel.getAlignment().addAnnotation(annotation);
403
404     /*
405      * Expect menu options to hide "secondary structure" and "Temp". Tooltip
406      * should be calcId. 'Show' menu should be disabled.
407      */
408     testee.buildAnnotationTypesMenus(showMenu, hideMenu, seqs);
409
410     assertFalse(showMenu.isEnabled());
411     assertTrue(hideMenu.isEnabled());
412
413     Component[] showOptions = showMenu.getMenuComponents();
414     Component[] hideOptions = hideMenu.getMenuComponents();
415
416     assertEquals(2, showOptions.length); // includes 'All' and separator
417     assertEquals(4, hideOptions.length);
418     String all = MessageManager.getString("label.all");
419     assertEquals(all, ((JMenuItem) showOptions[0]).getText());
420     assertTrue(showOptions[1] instanceof JPopupMenu.Separator);
421     assertEquals(JSeparator.HORIZONTAL,
422             ((JSeparator) showOptions[1]).getOrientation());
423
424     assertEquals(all, ((JMenuItem) hideOptions[0]).getText());
425     assertTrue(hideOptions[1] instanceof JPopupMenu.Separator);
426     assertEquals(JSeparator.HORIZONTAL,
427             ((JSeparator) hideOptions[1]).getOrientation());
428     assertEquals("secondary structure",
429             ((JMenuItem) hideOptions[2]).getText());
430     assertEquals("PDB", ((JMenuItem) hideOptions[2]).getToolTipText());
431     assertEquals("Temp", ((JMenuItem) hideOptions[3]).getText());
432     assertEquals("PDB", ((JMenuItem) hideOptions[3]).getToolTipText());
433   }
434
435   /**
436    * Test for building menu options with only 'show' annotation types enabled.
437    */
438   @Test(groups = { "Functional" })
439   public void testBuildAnnotationTypesMenus_hideDisabled()
440   {
441     JMenu showMenu = new JMenu();
442     JMenu hideMenu = new JMenu();
443     List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
444
445     // make up new annotations and add to sequences and to the alignment
446
447     // PDB.secondary structure on Sequence0
448     AlignmentAnnotation annotation = new AlignmentAnnotation(
449             "secondary structure", "", new Annotation[] {});
450     annotation.setCalcId("PDB");
451     annotation.visible = false;
452     seqs.get(0).addAlignmentAnnotation(annotation);
453     parentPanel.getAlignment().addAnnotation(annotation);
454
455     // PDB.Temp on Sequence1
456     annotation = new AlignmentAnnotation("Temp", "", new Annotation[] {});
457     annotation.setCalcId("PDB2");
458     annotation.visible = false;
459     seqs.get(1).addAlignmentAnnotation(annotation);
460     parentPanel.getAlignment().addAnnotation(annotation);
461
462     /*
463      * Expect menu options to show "secondary structure" and "Temp". Tooltip
464      * should be calcId. 'hide' menu should be disabled.
465      */
466     testee.buildAnnotationTypesMenus(showMenu, hideMenu, seqs);
467
468     assertTrue(showMenu.isEnabled());
469     assertFalse(hideMenu.isEnabled());
470
471     Component[] showOptions = showMenu.getMenuComponents();
472     Component[] hideOptions = hideMenu.getMenuComponents();
473
474     assertEquals(4, showOptions.length); // includes 'All' and separator
475     assertEquals(2, hideOptions.length);
476     String all = MessageManager.getString("label.all");
477     assertEquals(all, ((JMenuItem) showOptions[0]).getText());
478     assertTrue(showOptions[1] instanceof JPopupMenu.Separator);
479     assertEquals(JSeparator.HORIZONTAL,
480             ((JSeparator) showOptions[1]).getOrientation());
481     assertEquals("secondary structure",
482             ((JMenuItem) showOptions[2]).getText());
483     assertEquals("PDB", ((JMenuItem) showOptions[2]).getToolTipText());
484     assertEquals("Temp", ((JMenuItem) showOptions[3]).getText());
485     assertEquals("PDB2", ((JMenuItem) showOptions[3]).getToolTipText());
486
487     assertEquals(all, ((JMenuItem) hideOptions[0]).getText());
488     assertTrue(hideOptions[1] instanceof JPopupMenu.Separator);
489     assertEquals(JSeparator.HORIZONTAL,
490             ((JSeparator) hideOptions[1]).getOrientation());
491   }
492
493   /**
494    * Test for adding sequence id, dbref and feature links
495    */
496   @Test(groups = { "Functional" })
497   public void testBuildLinkMenu()
498   {
499     List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
500     final SequenceI seq0 = seqs.get(0);
501     final SequenceI seq1 = seqs.get(1);
502     final List<SequenceFeature> noFeatures = Collections
503             .<SequenceFeature> emptyList();
504     final String linkText = MessageManager.getString("action.link");
505
506     seq0.addDBRef(new DBRefEntry(DBRefSource.UNIPROT, "1", "P83527"));
507     seq0.addDBRef(new DBRefEntry("INTERPRO", "1", "IPR001041"));
508     seq0.addDBRef(new DBRefEntry("INTERPRO", "1", "IPR012675"));
509     seq0.addDBRef(new DBRefEntry("INTERPRO", "1", "IPR006058"));
510     seq1.addDBRef(new DBRefEntry(DBRefSource.UNIPROT, "1", "Q9ZTS2"));
511     seq1.addDBRef(new DBRefEntry("GENE3D", "1", "3.10.20.30"));
512     
513     /*
514      * check the Link Menu for the first sequence
515      */
516     JMenu linkMenu = PopupMenu.buildLinkMenu(seq0, noFeatures);
517     assertEquals(linkText, linkMenu.getText());
518     Component[] linkItems = linkMenu.getMenuComponents();
519     
520     /*
521      * menu items are ordered: SEQUENCE_ID search first, then dbrefs in order
522      * of database name (and within that by order of dbref addition)
523      */
524     assertEquals(5, linkItems.length);
525     assertEquals("EMBL-EBI Search", ((JMenuItem) linkItems[0]).getText());
526     assertEquals("INTERPRO|IPR001041",
527             ((JMenuItem) linkItems[1]).getText());
528     assertEquals("INTERPRO|IPR012675",
529             ((JMenuItem) linkItems[2]).getText());
530     assertEquals("INTERPRO|IPR006058",
531             ((JMenuItem) linkItems[3]).getText());
532     assertEquals("UNIPROT|P83527", ((JMenuItem) linkItems[4]).getText());
533
534     /*
535      * check the Link Menu for the second sequence
536      * note dbref GENE3D is matched to link Gene3D, the latter is displayed
537      */
538     linkMenu = PopupMenu.buildLinkMenu(seq1, noFeatures);
539     linkItems = linkMenu.getMenuComponents();
540     assertEquals(3, linkItems.length);
541     assertEquals("EMBL-EBI Search", ((JMenuItem) linkItems[0]).getText());
542     assertEquals("Gene3D|3.10.20.30", ((JMenuItem) linkItems[1]).getText());
543     assertEquals("UNIPROT|Q9ZTS2", ((JMenuItem) linkItems[2]).getText());
544
545     /*
546      * if there are no valid links the Links submenu is still shown, but
547      * reduced to the EMBL-EBI lookup only (inserted by 
548      * CustomUrlProvider.choosePrimaryUrl())
549      */
550     String unmatched = "NOMATCH|http://www.uniprot.org/uniprot/$"
551             + DB_ACCESSION + "$";
552     UrlProviderFactoryI factory = new DesktopUrlProviderFactory(null,
553             unmatched, "");
554     Preferences.sequenceUrlLinks = factory.createUrlProvider();
555
556     linkMenu = PopupMenu.buildLinkMenu(seq1, noFeatures);
557     linkItems = linkMenu.getMenuComponents();
558     assertEquals(1, linkItems.length);
559     assertEquals("EMBL-EBI Search", ((JMenuItem) linkItems[0]).getText());
560
561     /*
562      * if sequence is null, only feature links are shown (alignment popup submenu)
563      */
564     linkMenu = PopupMenu.buildLinkMenu(null, noFeatures);
565     linkItems = linkMenu.getMenuComponents();
566     assertEquals(0, linkItems.length);
567
568     List<SequenceFeature> features = new ArrayList<>();
569     SequenceFeature sf = new SequenceFeature("type", "desc", 1, 20, null);
570     features.add(sf);
571     linkMenu = PopupMenu.buildLinkMenu(null, features);
572     linkItems = linkMenu.getMenuComponents();
573     assertEquals(0, linkItems.length); // feature has no links
574
575     sf.addLink("Pfam family|http://pfam.xfam.org/family/PF00111");
576     linkMenu = PopupMenu.buildLinkMenu(null, features);
577     linkItems = linkMenu.getMenuComponents();
578     assertEquals(1, linkItems.length);
579     JMenuItem item = (JMenuItem) linkItems[0];
580     assertEquals("Pfam family", item.getText());
581     // ? no way to verify URL, compiled into link's actionListener
582   }
583
584   @Test(groups = { "Functional" })
585   public void testHideInsertions()
586   {
587     // get sequences from the alignment
588     List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
589     
590     // add our own seqs to avoid problems with changes to existing sequences
591     // (gap at end of sequences varies depending on how tests are run!)
592     Sequence seqGap1 = new Sequence("GappySeq",
593             "AAAA----AA-AAAAAAA---AAA-----------AAAAAAAAAA--");
594     seqGap1.createDatasetSequence();
595     seqs.add(seqGap1);
596     Sequence seqGap2 = new Sequence("LessGappySeq",
597             "AAAAAA-AAAAA---AAA--AAAAA--AAAAAAA-AAAAAA");
598     seqGap2.createDatasetSequence();
599     seqs.add(seqGap2);
600     Sequence seqGap3 = new Sequence("AnotherGapSeq",
601             "AAAAAA-AAAAAA--AAAAAA-AAAAAAAAAAA---AAAAAAAA");
602     seqGap3.createDatasetSequence();
603     seqs.add(seqGap3);
604     Sequence seqGap4 = new Sequence("NoGaps",
605             "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
606     seqGap4.createDatasetSequence();
607     seqs.add(seqGap4);
608
609     ColumnSelection sel = new ColumnSelection();
610     parentPanel.av.getAlignment().getHiddenColumns()
611             .revealAllHiddenColumns(sel);
612
613     // get the Popup Menu for 7th sequence - no insertions
614     testee = new PopupMenu(parentPanel, seqs.get(7), null);
615     testee.hideInsertions_actionPerformed(null);
616     
617     HiddenColumns hidden = parentPanel.av.getAlignment().getHiddenColumns();
618     Iterator<int[]> it = hidden.iterator();
619     assertFalse(it.hasNext());
620
621     // get the Popup Menu for GappySeq - this time we have insertions
622     testee = new PopupMenu(parentPanel, seqs.get(4), null);
623     testee.hideInsertions_actionPerformed(null);
624     hidden = parentPanel.av.getAlignment().getHiddenColumns();
625     it = hidden.iterator();
626
627     assertTrue(it.hasNext());
628     int[] region = it.next();
629     assertEquals(region[0], 4);
630     assertEquals(region[1], 7);
631
632     assertTrue(it.hasNext());
633     region = it.next();
634     assertEquals(region[0], 10);
635     assertEquals(region[1], 10);
636
637     assertTrue(it.hasNext());
638     region = it.next();
639     assertEquals(region[0], 18);
640     assertEquals(region[1], 20);
641
642     assertTrue(it.hasNext());
643     region = it.next();
644     assertEquals(region[0], 24);
645     assertEquals(region[1], 34);
646
647     assertTrue(it.hasNext());
648     region = it.next();
649     assertEquals(region[0], 45);
650     assertEquals(region[1], 46);
651
652     assertFalse(it.hasNext());
653
654     sel = new ColumnSelection();
655     hidden.revealAllHiddenColumns(sel);
656
657     // make a sequence group and hide insertions within the group
658     SequenceGroup sg = new SequenceGroup();
659     sg.setStartRes(8);
660     sg.setEndRes(42);
661     sg.addSequence(seqGap2, false);
662     sg.addSequence(seqGap3, false);
663     parentPanel.av.setSelectionGroup(sg);
664
665     // hide columns outside and within selection
666     // only hidden columns outside the collection will be retained (unless also
667     // gaps in the selection)
668     hidden.hideColumns(1, 10);
669     hidden.hideColumns(31, 40);
670
671     // get the Popup Menu for LessGappySeq in the sequence group
672     testee = new PopupMenu(parentPanel, seqs.get(5), null);
673     testee.hideInsertions_actionPerformed(null);
674     hidden = parentPanel.av.getAlignment().getHiddenColumns();
675     it = hidden.iterator();
676
677     assertTrue(it.hasNext());
678     region = it.next();
679     assertEquals(region[0], 1);
680     assertEquals(region[1], 7);
681
682     assertTrue(it.hasNext());
683     region = it.next();
684     assertEquals(region[0], 13);
685     assertEquals(region[1], 14);
686
687     assertTrue(it.hasNext());
688     region = it.next();
689     assertEquals(region[0], 34);
690     assertEquals(region[1], 34);
691   }
692
693 }