if (seq != null)
{
nlinks = Preferences.sequenceUrlLinks.getLinksForMenu();
+ UrlLink.sort(nlinks);
}
else
{
{
// cachedUrlList is in form <label>|<url>|<label>|<url>...
// parse cachedUrlList into labels (used as id) and url links
- HashMap<String, UrlLink> urls = new HashMap<String, UrlLink>();
+ HashMap<String, UrlLink> urls = new HashMap<>();
StringTokenizer st = new StringTokenizer(urlStrings, SEP);
while (st.hasMoreElements())
{
- String name = st.nextToken();
+ String name = st.nextToken().trim();
if (!isMiriamId(name))
{
{
url = url + SEP + st.nextToken();
}
+ url = url.trim();
urls.put(name, new UrlLink(name, url, name));
}
}
private HashMap<String, UrlLink> parseUrlList(Map<String, String> urlList)
{
- HashMap<String, UrlLink> urls = new HashMap<String, UrlLink>();
+ HashMap<String, UrlLink> urls = new HashMap<>();
if (urlList == null)
{
return urls;
@Override
public List<String> getLinksForMenu()
{
- List<String> links = new ArrayList<String>();
+ List<String> links = new ArrayList<>();
Iterator<Map.Entry<String, UrlLink>> it = selectedUrls.entrySet()
.iterator();
while (it.hasNext())
@Override
public List<UrlLinkDisplay> getLinksForTable()
{
- ArrayList<UrlLinkDisplay> displayLinks = new ArrayList<UrlLinkDisplay>();
+ ArrayList<UrlLinkDisplay> displayLinks = new ArrayList<>();
displayLinks = getLinksForTable(selectedUrls, true);
displayLinks.addAll(getLinksForTable(nonselectedUrls, false));
return displayLinks;
@Override
public void setUrlData(List<UrlLinkDisplay> links)
{
- HashMap<String, UrlLink> unselurls = new HashMap<String, UrlLink>();
- HashMap<String, UrlLink> selurls = new HashMap<String, UrlLink>();
+ HashMap<String, UrlLink> unselurls = new HashMap<>();
+ HashMap<String, UrlLink> selurls = new HashMap<>();
Iterator<UrlLinkDisplay> it = links.iterator();
while (it.hasNext())
import jalview.datamodel.SequenceI;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
+/**
+ * A helper class to parse URL Link strings taken from applet parameters or
+ * jalview properties file using the com.stevesoft.pat.Regex implementation.
+ * Jalview 2.4 extension allows regular expressions to be used to parse ID
+ * strings and replace the result in the URL. Regex's operate on the whole ID
+ * string given to the matchURL method, if no regex is supplied, then only text
+ * following the first pipe symbol will be substituted. Usage documentation
+ * todo.
+ */
public class UrlLink
{
/**
- * helper class to parse URL Link strings taken from applet parameters or
- * jalview properties file using the com.stevesoft.pat.Regex implementation.
- * Jalview 2.4 extension allows regular expressions to be used to parse ID
- * strings and replace the result in the URL. Regex's operate on the whole ID
- * string given to the matchURL method, if no regex is supplied, then only
- * text following the first pipe symbol will be substituted. Usage
- * documentation todo.
+ * A comparator that puts SEQUENCE_ID template links before DB_ACCESSION
+ * links, and otherwise orders by link name (not case sensitive). It expects
+ * to compare strings formatted as "Name|URLTemplate" where the template may
+ * include $SEQUENCE_ID$ or $DB_ACCESSION$ or neither.
*/
+ public static final Comparator<String> LINK_COMPARATOR = new Comparator<String>()
+ {
+ @Override
+ public int compare(String link1, String link2)
+ {
+ if (link1 == null || link2 == null)
+ {
+ return 0; // for failsafe only
+ }
+ String[] tokens1 = link1.split("\\|");
+ String[] tokens2 = link2.split("\\|");
+ if (tokens1.length < 2 || tokens2.length < 2)
+ {
+ // for failsafe only
+ return String.CASE_INSENSITIVE_ORDER.compare(link1, link2);
+ }
+ String name1 = tokens1[0];
+ String name2 = tokens2[0];
+ String pattern1 = tokens1[1];
+ String pattern2 = tokens2[1];
+ if (pattern1.contains(UrlConstants.SEQUENCE_ID)
+ && pattern2.contains(UrlConstants.DB_ACCESSION))
+ {
+ return -1;
+ }
+ if (pattern2.contains(UrlConstants.SEQUENCE_ID)
+ && pattern1.contains(UrlConstants.DB_ACCESSION))
+ {
+ return 1;
+ }
+ return String.CASE_INSENSITIVE_ORDER.compare(name1, name2);
+
+ }
+ };
private static final String EQUALS = "=";
+ rg.stringMatched(s) + "'");
}
// try to collate subgroup matches
- Vector<String> subs = new Vector<String>();
+ Vector<String> subs = new Vector<>();
// have to loop through submatches, collating them at top level
// match
int s = 0; // 1;
}
}
}
+
+ /**
+ * Sorts links (formatted as LinkName|LinkPattern) suitable for display in a
+ * menu
+ * <ul>
+ * <li>SEQUENCE_ID links precede DB_ACCESSION links (i.e. canonical lookup
+ * before cross-references)</li>
+ * <li>otherwise by Link name (case insensitive)</li>
+ * </ul>
+ *
+ * @param nlinks
+ */
+ public static void sort(List<String> nlinks)
+ {
+ Collections.sort(nlinks, LINK_COMPARATOR);
+ }
}
}
/**
- * Test for adding feature links
+ * Test for adding sequence id, dbref and feature links
*/
@Test(groups = { "Functional" })
- public void testAddFeatureLinks()
+ public void testConstructor_links()
{
- // sequences from the alignment
List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
-
- // create list of links and list of DBRefs
- List<String> links = new ArrayList<>();
- List<DBRefEntry> refs = new ArrayList<>();
-
- // links as might be added into Preferences | Connections dialog
- links.add("EMBL-EBI Search | http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$"
- + SEQUENCE_ID + "$");
- links.add("UNIPROT | http://www.uniprot.org/uniprot/$" + DB_ACCESSION
- + "$");
- links.add("INTERPRO | http://www.ebi.ac.uk/interpro/entry/$"
- + DB_ACCESSION + "$");
- // Gene3D entry tests for case (in)sensitivity
- links.add("Gene3D | http://gene3d.biochem.ucl.ac.uk/Gene3D/search?sterm=$"
- + DB_ACCESSION + "$&mode=protein");
-
- // make seq0 dbrefs
- refs.add(new DBRefEntry(DBRefSource.UNIPROT, "1", "P83527"));
- refs.add(new DBRefEntry("INTERPRO", "1", "IPR001041"));
- refs.add(new DBRefEntry("INTERPRO", "1", "IPR006058"));
- refs.add(new DBRefEntry("INTERPRO", "1", "IPR012675"));
-
- // make seq1 dbrefs
- refs.add(new DBRefEntry(DBRefSource.UNIPROT, "1", "Q9ZTS2"));
- refs.add(new DBRefEntry("GENE3D", "1", "3.10.20.30"));
-
- // add all the dbrefs to the sequences: Uniprot 1 each, Interpro all 3 to
- // seq0, Gene3D to seq1
- SequenceI seq = seqs.get(0);
- seq.addDBRef(refs.get(0));
-
- seq.addDBRef(refs.get(1));
- seq.addDBRef(refs.get(2));
- seq.addDBRef(refs.get(3));
+ final SequenceI seq0 = seqs.get(0);
+ final SequenceI seq1 = seqs.get(1);
+ final List<SequenceFeature> noFeatures = Collections
+ .<SequenceFeature> emptyList();
+ final String linkText = MessageManager.getString("action.link");
+
+ seq0.addDBRef(new DBRefEntry(DBRefSource.UNIPROT, "1", "P83527"));
+ seq0.addDBRef(new DBRefEntry("INTERPRO", "1", "IPR001041"));
+ seq0.addDBRef(new DBRefEntry("INTERPRO", "1", "IPR012675"));
+ seq0.addDBRef(new DBRefEntry("INTERPRO", "1", "IPR006058"));
+ seq1.addDBRef(new DBRefEntry(DBRefSource.UNIPROT, "1", "Q9ZTS2"));
+ seq1.addDBRef(new DBRefEntry("GENE3D", "1", "3.10.20.30"));
- seqs.get(1).addDBRef(refs.get(4));
- seqs.get(1).addDBRef(refs.get(5));
-
- // get the Popup Menu for first sequence
- List<SequenceFeature> noFeatures = Collections.<SequenceFeature> emptyList();
- testee = new PopupMenu(parentPanel, seq, noFeatures);
+ /*
+ * check the Popup Menu for the first sequence
+ */
+ testee = new PopupMenu(parentPanel, seq0, noFeatures);
Component[] seqItems = testee.sequenceMenu.getMenuComponents();
JMenu linkMenu = (JMenu) seqItems[6];
+ assertEquals(linkText, linkMenu.getText());
Component[] linkItems = linkMenu.getMenuComponents();
- // check the number of links are the expected number
+ /*
+ * menu items are ordered: SEQUENCE_ID search first, then dbrefs in order
+ * of database name (and within that by order of dbref addition)
+ */
assertEquals(5, linkItems.length);
-
- // first entry is EMBL-EBI which just uses sequence id not accession id?
assertEquals("EMBL-EBI Search", ((JMenuItem) linkItems[0]).getText());
+ assertEquals("INTERPRO|IPR001041",
+ ((JMenuItem) linkItems[1]).getText());
+ assertEquals("INTERPRO|IPR012675",
+ ((JMenuItem) linkItems[2]).getText());
+ assertEquals("INTERPRO|IPR006058",
+ ((JMenuItem) linkItems[3]).getText());
+ assertEquals("UNIPROT|P83527", ((JMenuItem) linkItems[4]).getText());
- // sequence id for each link should match corresponding DB accession id
- for (int i = 1; i < 4; i++)
- {
- String msg = seq.getName() + " link[" + i + "]";
- assertEquals(msg, refs.get(i - 1).getSource(),
- ((JMenuItem) linkItems[i])
- .getText().split("\\|")[0]);
- assertEquals(msg, refs.get(i - 1).getAccessionId(),
- ((JMenuItem) linkItems[i])
- .getText().split("\\|")[1]);
- }
-
- // get the Popup Menu for second sequence
- seq = seqs.get(1);
- testee = new PopupMenu(parentPanel, seq, noFeatures);
+ /*
+ * check the Popup Menu for second sequence
+ * note dbref GENE3D is matched to link Gene3D, the latter is displayed
+ */
+ testee = new PopupMenu(parentPanel, seq1, noFeatures);
seqItems = testee.sequenceMenu.getMenuComponents();
linkMenu = (JMenu) seqItems[6];
+ assertEquals(linkText, linkMenu.getText());
linkItems = linkMenu.getMenuComponents();
-
- // check the number of links are the expected number
assertEquals(3, linkItems.length);
-
- // first entry is EMBL-EBI which just uses sequence id not accession id?
assertEquals("EMBL-EBI Search", ((JMenuItem) linkItems[0]).getText());
+ assertEquals("Gene3D|3.10.20.30", ((JMenuItem) linkItems[1]).getText());
+ assertEquals("UNIPROT|Q9ZTS2", ((JMenuItem) linkItems[2]).getText());
- // sequence id for each link should match corresponding DB accession id
- for (int i = 1; i < 3; i++)
- {
- String msg = seq.getName() + " link[" + i + "]";
- assertEquals(msg, refs.get(i + 3).getSource(),
- ((JMenuItem) linkItems[i])
- .getText().split("\\|")[0].toUpperCase());
- assertEquals(msg, refs.get(i + 3).getAccessionId(),
- ((JMenuItem) linkItems[i]).getText().split("\\|")[1]);
- }
-
- // if there are no valid links the Links submenu is disabled
- List<String> nomatchlinks = new ArrayList<>();
- nomatchlinks.add("NOMATCH | http://www.uniprot.org/uniprot/$"
- + DB_ACCESSION + "$");
+ /*
+ * if there are no valid links the Links submenu is still shown, but
+ * reduced to the EMBL-EBI lookup only (inserted by
+ * CustomUrlProvider.choosePrimaryUrl())
+ */
+ String unmatched = "NOMATCH|http://www.uniprot.org/uniprot/$"
+ + DB_ACCESSION + "$";
+ UrlProviderFactoryI factory = new DesktopUrlProviderFactory(null,
+ unmatched, "");
+ Preferences.sequenceUrlLinks = factory.createUrlProvider();
- testee = new PopupMenu(parentPanel, seq, noFeatures);
+ testee = new PopupMenu(parentPanel, seq1, noFeatures);
seqItems = testee.sequenceMenu.getMenuComponents();
linkMenu = (JMenu) seqItems[6];
- assertFalse(linkMenu.isEnabled());
-
+ assertEquals(linkText, linkMenu.getText());
+ linkItems = linkMenu.getMenuComponents();
+ assertEquals(1, linkItems.length);
+ assertEquals("EMBL-EBI Search", ((JMenuItem) linkItems[0]).getText());
}
- /**
- * Test for adding feature links
- */
@Test(groups = { "Functional" })
public void testHideInsertions()
{
import jalview.gui.JvOptionPane;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+ DELIM + URL_SUFFIX);
- Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+ Map<String, List<String>> linkset = new LinkedHashMap<>();
ul.createLinksFromSeq(null, linkset);
String key = DB + SEP + URL_PREFIX;
{
UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + URL_SUFFIX);
- Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+ Map<String, List<String>> linkset = new LinkedHashMap<>();
ul.createLinksFromSeq(null, linkset);
String key = DB + SEP + URL_PREFIX + URL_SUFFIX;
{
// create list of links and list of DBRefs
- List<String> links = new ArrayList<String>();
- List<DBRefEntry> refs = new ArrayList<DBRefEntry>();
+ List<String> links = new ArrayList<>();
+ List<DBRefEntry> refs = new ArrayList<>();
// links as might be added into Preferences | Connections dialog
links.add("EMBL-EBI Search | http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$"
UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+ DELIM + URL_SUFFIX);
- Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+ Map<String, List<String>> linkset = new LinkedHashMap<>();
ul.createLinksFromSeq(seq0, linkset);
String key = seq0.getName() + SEP + URL_PREFIX + seq0.getName()
// Test where link takes a db annotation id and only has one dbref
ul = new UrlLink(links.get(1));
- linkset = new LinkedHashMap<String, List<String>>();
+ linkset = new LinkedHashMap<>();
ul.createLinksFromSeq(seq0, linkset);
key = "P83527|http://www.uniprot.org/uniprot/P83527";
// Test where link takes a db annotation id and has multiple dbrefs
ul = new UrlLink(links.get(2));
- linkset = new LinkedHashMap<String, List<String>>();
+ linkset = new LinkedHashMap<>();
ul.createLinksFromSeq(seq0, linkset);
assertEquals(3, linkset.size());
// Test where there are no matching dbrefs for the link
ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + DB_ACCESSION + DELIM
+ URL_SUFFIX);
- linkset = new LinkedHashMap<String, List<String>>();
+ linkset = new LinkedHashMap<>();
ul.createLinksFromSeq(seq0, linkset);
assertTrue(linkset.isEmpty());
}
}
+ @Test(groups = { "Functional" })
+ public void testLinkComparator()
+ {
+ Comparator<String> c = UrlLink.LINK_COMPARATOR;
+ assertEquals(0, c.compare(null, null));
+ assertEquals(0, c.compare(null, "x"));
+ assertEquals(0, c.compare("y", null));
+
+ /*
+ * SEQUENCE_ID templates should come before DB_ACCESSION templates
+ * (note we are 'pretending' EMBL-EBI is a DB link so the test shows that
+ * these are not ordered by link name)
+ */
+ String seqIdUrl = "Ensembl|https://www.ensembl.org/Multi/Search/Results?q=$SEQUENCE_ID$";
+ String dbRefUrl = "EBI|https://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$DB_ACCESSION$";
+ assertTrue(c.compare(seqIdUrl, dbRefUrl) < 0);
+ assertTrue(c.compare(dbRefUrl, seqIdUrl) > 0);
+
+ String interpro = "Interpro|https://www.ebi.ac.uk/interpro/entry/$DB_ACCESSION$";
+ String prosite = "ProSite|https://prosite.expasy.org/PS00197";
+ assertTrue(c.compare(interpro, prosite) < 0);
+ assertTrue(c.compare(prosite, interpro) > 0);
+ }
}