Merge branch 'bug/JAL-98consensusMemory' into develop
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 26 Oct 2016 15:22:45 +0000 (16:22 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 26 Oct 2016 15:22:45 +0000 (16:22 +0100)
26 files changed:
RELEASE
build.xml
examples/exampleFile.jar
examples/exampleFile_2_3.jar
examples/exampleFile_2_7.jar
examples/ferredoxin.nw
examples/plantfdx.fa
examples/uniref50.fa
examples/uniref50_mz.fa
help/help.jhm
help/html/editing/index.html
help/html/releases.html
help/html/whatsNew.html
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/appletgui/IdPanel.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/gui/SeqPanel.java
src/jalview/jbgui/GSequenceLink.java
src/jalview/util/UrlConstants.java [new file with mode: 0644]
src/jalview/util/UrlLink.java
src/jalview/viewmodel/AlignmentViewport.java
test/jalview/gui/AlignViewportTest.java
test/jalview/gui/PopupMenuTest.java
test/jalview/util/UrlLinkTest.java [new file with mode: 0644]

diff --git a/RELEASE b/RELEASE
index c29c5d5..702d6e7 100644 (file)
--- a/RELEASE
+++ b/RELEASE
@@ -1,2 +1,2 @@
-jalview.release=Release_2_10_Branch
-jalview.version=2.10.0
+jalview.release=Release_2_10_0_Branch
+jalview.version=2.10.0b1
index d8f12e0..1d4878b 100755 (executable)
--- a/build.xml
+++ b/build.xml
 </target>
 <target name="sourcedist" description="create jalview source distribution" depends="init">
   <delete file="${source.dist.name}" />
-  <tar destfile="${source.dist.name}" compression="gzip">
-    <tarfileset dir="./" prefix="jalview" preserveLeadingSlashes="true">
+  <!-- temporary copy of source to update timestamps -->
+  <copy todir="_sourcedist">
+    <fileset dir=".">
       <include name="LICENSE" />
       <include name="README" />
       <include name="build.xml" />
       <include name="utils/**/*" />
       <include name="${docDir}/**/*" />
       <include name="examples/**/*" />
+    </fileset>
+  </copy>
+
+  <tstamp prefix="build">
+    <format property="year" pattern="yyyy" />
+  </tstamp>
+  <!-- each replacetoken CDATA body must be on one line - 
+       otherwise the pattern doesn't match -->
+  <replace value="${JALVIEW_VERSION}">
+    <replacetoken><![CDATA[$$Version-Rel$$]]></replacetoken>
+    <fileset dir="_sourcedist">
+      <include name="**/*" />
+    </fileset>
+  </replace>
+  <replace dir="_sourcedist" value="${build.year}">
+    <replacetoken><![CDATA[$$Year-Rel$$]]></replacetoken>
+    <fileset dir="_sourcedist">
+      <include name="**/*" />
+    </fileset>
+  </replace>
+
+  <tar destfile="${source.dist.name}" compression="gzip">
+    <tarfileset dir="_sourcedist/" prefix="jalview" preserveLeadingSlashes="true">
     </tarfileset>
   </tar>
+
+  <delete dir="_sourcedist" />
 </target>
 <target name="prepubapplet_1" depends="makeApplet">
   <copy todir="${packageDir}/examples">
index 3231974..2f9000d 100755 (executable)
Binary files a/examples/exampleFile.jar and b/examples/exampleFile.jar differ
index adf707e..1a8bef0 100644 (file)
Binary files a/examples/exampleFile_2_3.jar and b/examples/exampleFile_2_3.jar differ
index 0b70e66..7cd9d77 100644 (file)
Binary files a/examples/exampleFile_2_7.jar and b/examples/exampleFile_2_7.jar differ
index 0b949de..89ea348 100755 (executable)
@@ -1 +1 @@
-(((FER_BRANA:128.0,FER3_RAPSA:128.0):50.75,FER_CAPAA:178.75):121.94443,(Q93Z60_ARATH:271.45456,((O80429_MAIZE:183.0,FER1_MAIZE:183.0):30.5,((Q7XA98_TRIPR:90.0,FER1_PEA:90.0):83.32143,(((FER2_ARATH:64.0,FER1_ARATH:64.0):94.375,(FER1_SPIOL:124.5,FER1_MESCR:124.5):33.875):6.4166718,((Q93XJ9_SOLTU:33.5,FER1_SOLLC:33.5):49.0,FER_CAPAN:82.5):82.29167):8.529755):40.178574):57.95456):29.239868);
+(((FER_BRANA:128.0,FER3_RAPSA:128.0):50.75,FER_CAPAA:178.75):121.94443,(Q93Z60_ARATH:271.45456,((O80429_MAIZE:183.0,FER1_MAIZE:183.0):30.5,((Q7XA98_TRIPR:90.0,FER1_PEA:90.0):83.32143,(((FER1_ARATH:64.0,FER2_ARATH:64.0):94.375,(FER1_SPIOL:124.5,FER1_MESCR:124.5):33.875):6.4166718,((Q93XJ9_SOLTU:33.5,FER1_SOLLC:33.5):49.0,FER_CAPAN:82.5):82.29167):8.529755):40.178574):57.95456):29.239868);
index f314c85..80d7133 100644 (file)
@@ -34,18 +34,18 @@ IETHKEEELTA-
 ----------------------------------------------------------ATYKVKFITPEGEQ
 EVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDDQIAEGFVLTCAAYPTSDVT
 IETHREEDMV--
->FER1_ARATH/1-148
-----MASTALSSAIVSTSFLRRQQTPISLRSLPFANT-QSLFGLKS-STARGGRVTAMATYKVKFITPEGEQ
-EVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDDEQMSEGYVLTCVAYPTSDVV
-IETHKEEAIM--
->FER_BRANA/1-96
-----------------------------------------------------------ATYKVKFITPEGEQ
-EVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDESFLDDDQIAEGFVLTCAAYPTSDVT
-IETHKEEELV--
 >FER2_ARATH/1-148
 ----MASTALSSAIVGTSFIRRSPAPISLRSLPSANT-QSLFGLKS-GTARGGRVTAMATYKVKFITPEGEL
 EVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDEQIGEGFVLTCAAYPTSDVT
 IETHKEEDIV--
+>FER_BRANA/1-96
+----------------------------------------------------------ATYKVKFITPEGEQ
+EVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDESFLDDDQIAEGFVLTCAAYPTSDVT
+IETHKEEELV--
+>FER1_ARATH/1-148
+----MASTALSSAIVSTSFLRRQQTPISLRSLPFANT-QSLFGLKS-STARGGRVTAMATYKVKFITPEGEQ
+EVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDDEQMSEGYVLTCVAYPTSDVV
+IETHKEEAIM--
 >Q93Z60_ARATH/1-118
 ----MASTALSSAIVSTSFLRRQQTPISLRSLPFANT-QSLFGLKS-STARGGRVTAMATYKVKFITPEGEQ
 EVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDD--------------------
index 4bdbfb4..6e6c670 100755 (executable)
@@ -34,18 +34,18 @@ TIETHKEEELTA-
 -----------------------------------------------------------ATYKVKFITPEGE
 QEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDDQIAEGFVLTCAAYPTSDV
 TIETHREEDMV--
->FER1_ARATH Ferredoxin-1, chloroplast precursor
-MAST----ALSSAIVSTSFLRRQQTPISLRSLPFANTQ--SLFGLKS-STARGGRVTAMATYKVKFITPEGE
-QEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDDEQMSEGYVLTCVAYPTSDV
-VIETHKEEAIM--
->FER_BRANA Ferredoxin
------------------------------------------------------------ATYKVKFITPEGE
-QEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDESFLDDDQIAEGFVLTCAAYPTSDV
-TIETHKEEELV--
 >FER2_ARATH Ferredoxin-2, chloroplast precursor
 MAST----ALSSAIVGTSFIRRSPAPISLRSLPSANTQ--SLFGLKS-GTARGGRVTAMATYKVKFITPEGE
 LEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDEQIGEGFVLTCAAYPTSDV
 TIETHKEEDIV--
+>FER_BRANA Ferredoxin
+-----------------------------------------------------------ATYKVKFITPEGE
+QEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDESFLDDDQIAEGFVLTCAAYPTSDV
+TIETHKEEELV--
+>FER1_ARATH Ferredoxin-1, chloroplast precursor
+MAST----ALSSAIVSTSFLRRQQTPISLRSLPFANTQ--SLFGLKS-STARGGRVTAMATYKVKFITPEGE
+QEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDDEQMSEGYVLTCVAYPTSDV
+VIETHKEEAIM--
 >Q93Z60_ARATH At1g10960/T19D16_12
 MAST----ALSSAIVSTSFLRRQQTPISLRSLPFANTQ--SLFGLKS-STARGGRVTAMATYKVKFITPEGE
 QEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDD-------------------
index 9974fc7..725d210 100644 (file)
@@ -18,11 +18,11 @@ AAYKVTLVTPEGKQELECPDDVYILDAAEEAGIDLPYSCRAGSCSSCAGKVTSGSVNQDDGSFLDD
 AAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLDD
 >FER3_RAPSA/1-66 Ferredoxin, leaf L-A
 ATYKVKFITPEGEQEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDD
->FER1_ARATH/53-118 Ferredoxin-1, chloroplast precursor
+>FER2_ARATH/53-118 Ferredoxin-1, chloroplast precursor
 ATYKVKFITPEGELEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDD
 >FER_BRANA/1-66 Ferredoxin
 ATYKVKFITPEGEQEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDESFLDD
->FER2_ARATH/53-118 Ferredoxin-2, chloroplast precursor
+>FER1_ARATH/53-118 Ferredoxin-2, chloroplast precursor
 ATYKVKFITPEGEQEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDD
 >Q93Z60_ARATH/53-118 At1g10960/T19D16_12
 ATYKVKFITPEGEQEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDD
index 7e14204..407899e 100755 (executable)
@@ -22,7 +22,7 @@
    <mapID target="home" url="html/index.html" />
    
    <mapID target="new" url="html/whatsNew.html"/>
-   <mapID target="release" url="html/releases.html#Jalview.2.9"/>
+   <mapID target="release" url="html/releases.html#Jalview.2.10.0b1"/>
    <mapID target="alannotation" url="html/features/annotation.html"/>
    <mapID target="keys" url="html/keys.html"/>
    <mapID target="newkeys" url="html/features/newkeystrokes.html"/>
index 471e520..fd8c5a3 100755 (executable)
@@ -49,9 +49,8 @@
     right to insert gaps and remove gaps.<br> If the current
     selection is a group over all sequences in the alignment, or a group
     over some sequences or all columns in the alignment, then hold down
-    either &quot;Control&quot; key (or the &quot;Alt;&quot; on OSX if
-    &quot;Control&quot; does not work) and drag the residue left or
-    right to edit all sequences in the defined group at once.
+    &quot;Control&quot; key (&quot;Cmd&quot; key on OSX) and drag the residue 
+    left or right to edit all sequences in the defined group at once.
   </p>
   <p>
     <em>Copy/paste/cut/delete</em> - any sequences which are in the
index 11c7f58..3fe08cb 100755 (executable)
       </td>
       <td><em>Application</em>
         <ul>
-          <li>3D Structure chooser opens with 'Cached structures' view if structures already loaded</li>
+          <li>3D Structure chooser opens with 'Cached structures'
+            view if structures already loaded</li>
+          <li>Progress bar reports models as they are loaded to
+            structure views</li>
         </ul></td>
       <td>
         <div align="left">
+          <em>General</em>
+          <ul>
+            <li>Colour by conservation always enabled and no tick
+              shown in menu when BLOSUM or PID shading applied</li>
+            <li>FER1_ARATH and FER2_ARATH labels were switched in
+              example sequences/projects/trees</li>
+          </ul>
           <em>Application</em>
           <ul>
-            <li>Cannot import or associated local PDB files without a PDB ID HEADER line</li>
-            <li>RMSD is not output in Jmol console when superposition is performed</li> 
-            <li>Drag and drop of URL from Browser fails for Linux and OSX versions earlier than El Capitan</li>
+            <li>Jalview projects with views of local PDB structure
+              files saved on Windows cannot be opened on OSX</li>
+            <li>Multiple structure views can be opened and
+              superposed without timeout for structures with multiple
+              models or multiple sequences in alignment</li>
+            <li>Cannot import or associated local PDB files without
+              a PDB ID HEADER line</li>
+            <li>RMSD is not output in Jmol console when
+              superposition is performed</li>
+            <li>Drag and drop of URL from Browser fails for Linux
+              and OSX versions earlier than El Capitan</li>
             <li>ENA client ignores invalid content from ENA server</li>
-            <li>Exceptions are not raised when ENA client attempts to fetch non-existent IDs via Fetch DB Refs UI option</li>
-            <li>Exceptions are not raised when a new view is created on the alignment</li>
+            <li>Exceptions are not raised in console when ENA
+              client attempts to fetch non-existent IDs via Fetch DB
+              Refs UI option</li>
+            <li>Exceptions are not raised in console when a new
+              view is created on the alignment</li>
+            <li>OSX right-click fixed for group selections:
+              CMD-click to insert/remove gaps in groups and CTRL-click
+              to open group pop-up menu</li>
           </ul>
-          <em>New Known Issues</em>
-          <ul><li>Drag and drop from URL links in browsers do not work on Windows</li></ul>
           <em>Build and deployment</em>
-          <ul><li>URL link checker now copes with multi-line anchor tags</li></ul>
+          <ul>
+            <li>URL link checker now copes with multi-line anchor
+              tags</li>
+          </ul>
+          <em>New Known Issues</em>
+          <ul>
+            <li>Drag and drop from URL links in browsers do not
+              work on Windows</li>
+          </ul>
         </div>
       </td>
     </tr>
index cab871c..448430d 100755 (executable)
 </head>
 <body>
   <p>
-    <strong>What's new in Jalview 2.10 ?</strong>
+    <strong>What's new in Jalview 2.10.0b1 ?</strong>
   </p>
   <p>
-    Jalview 2.10 is the next major release in the Jalview 2 series. Full
-    details are in the <a href="releases.html#Jalview.2.10.0">Jalview
-      2.10 Release Notes</a>, but the highlights are below.
+    Jalview 2.10.0b1 is a patch release for 2.10, the next major release
+    in the Jalview 2 series. Full details are in the <a
+      href="releases.html#Jalview.2.10.0b1">Jalview 2.10b1 Release
+      Notes</a>, but the highlights are below.
   </p>
   <ul>
+    <li>Drag and drop reinstated for the Jalview desktop on
+      Windows, Linux and older OSX systems.</li>
+    <li>Problems loading local PDB files have been fixed</li>
+    <li>Conservation shading can be disabled for PID and consensus
+      based colour scheme</li>
+  </ul>
+  <p><em>Major highlights of the 2.10.0 Release</em></p>
+  <ul>
     <li><strong>Ensembl sequence fetcher</strong><br />Annotated
       Genes, transcripts and proteins can be retrieved via Jalview's new
       <a href="features/ensemblsequencefetcher.html">Ensembl REST
index 7a1f064..bcbc24b 100644 (file)
@@ -788,7 +788,9 @@ label.hide_columns_not_containing = Hide columns that do not contain
 option.trim_retrieved_seqs = Trim retrieved sequences
 label.trim_retrieved_sequences = When the reference sequence is longer than the sequence that you are working with, only keep the relevant subsequences.
 label.use_sequence_id_1 = Use $SEQUENCE_ID$ or $SEQUENCE_ID=/<regex>/=$
-label.use_sequence_id_2 = \nto embed sequence id in URL
+label.use_sequence_id_2 = to embed sequence id in URL
+label.use_sequence_id_3 = Use $SEQUENCE_NAME$ similarly to embed sequence name
+label.use_sequence_id_4 = 
 label.ws_parameters_for = Parameters for {0}
 label.switch_server = Switch server
 label.choose_jabaws_server = Choose a server for running this service
index cf36638..4112d19 100644 (file)
@@ -721,7 +721,9 @@ label.select_columns_not_containing = Seleccione las columnas que no contengan
 option.trim_retrieved_seqs = Ajustar las secuencias recuperadas
 label.trim_retrieved_sequences = Cuando la secuencia de referencia es más larga que la secuencia con la que está trabajando, sólo se mantienen las subsecuencias relevantes.
 label.use_sequence_id_1 = Utilice $SEQUENCE_ID$ o $SEQUENCE_ID=/<regex>/=$
-label.use_sequence_id_2 = \nto para embeber el id de la secuencia en una URL
+label.use_sequence_id_2 = para embeber el id de la secuencia en una URL
+label.use_sequence_id_3 = Utilice $SEQUENCE_NAME$ de manera similar para embeber
+label.use_sequence_id_4 = el nombre de la secuencia
 label.ws_parameters_for = Parámetros para {0}
 label.switch_server = Cambiar servidor
 label.open_jabaws_web_page = Abra el página principal del servidor JABAWS en un navegador web
index ed96b55..2cb3060 100755 (executable)
@@ -20,6 +20,9 @@
  */
 package jalview.appletgui;
 
+import static jalview.util.UrlConstants.EMBLEBI_STRING;
+import static jalview.util.UrlConstants.SRS_STRING;
+
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
@@ -82,19 +85,16 @@ public class IdPanel extends Panel implements MouseListener,
     }
     {
       // upgrade old SRS link
-      int srsPos = links
-              .indexOf("SRS|http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-newId+(([uniprot-all:$SEQUENCE_ID$]))+-view+SwissEntry");
+      int srsPos = links.indexOf(SRS_STRING);
       if (srsPos > -1)
       {
-        links.setElementAt(
-                "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$",
-                srsPos);
+        links.setElementAt(EMBLEBI_STRING, srsPos);
       }
     }
     if (links.size() < 1)
     {
       links = new java.util.Vector();
-      links.addElement("EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$");
+      links.addElement(EMBLEBI_STRING);
     }
   }
 
index 7ab6022..e2d397f 100644 (file)
@@ -636,20 +636,22 @@ public class PopupMenu extends JPopupMenu
         continue;
       }
       final String label = urlLink.getLabel();
-      if (seq != null && urlLink.isDynamic())
+
+      // collect id string too
+      String id = seq.getName();
+      String descr = seq.getDescription();
+      if (descr != null && descr.length() < 1)
       {
+        descr = null;
+      }
 
+      if (seq != null && urlLink.usesSeqId()) // link is ID
+      {
         // collect matching db-refs
         DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(),
                 new String[] { urlLink.getTarget() });
-        // collect id string too
-        String id = seq.getName();
-        String descr = seq.getDescription();
-        if (descr != null && descr.length() < 1)
-        {
-          descr = null;
-        }
 
+        // if there are any dbrefs which match up with the link
         if (dbr != null)
         {
           for (int r = 0; r < dbr.length; r++)
@@ -661,53 +663,33 @@ public class PopupMenu extends JPopupMenu
               id = null;
             }
             // create Bare ID link for this URL
-            String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true);
-            if (urls != null)
-            {
-              for (int u = 0; u < urls.length; u += 2)
-              {
-                if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
-                {
-                  linkset.add(urls[u] + "|" + urls[u + 1]);
-                  addshowLink(linkMenu, label + "|" + urls[u], urls[u + 1]);
-                }
-              }
-            }
+            createBareURLLink(urlLink, dbr[r].getAccessionId(), linkset,
+                    linkMenu, label, true);
           }
         }
+
+        // Create urls from description but only for URL links which are regex
+        // links
+        if (descr != null && urlLink.getRegexReplace() != null)
+        {
+          // create link for this URL from description where regex matches
+          createBareURLLink(urlLink, descr, linkset, linkMenu, label, false);
+        }
+
+      }
+      else if (seq != null && !urlLink.usesSeqId()) // link is name
+      {
         if (id != null)
         {
           // create Bare ID link for this URL
-          String[] urls = urlLink.makeUrls(id, true);
-          if (urls != null)
-          {
-            for (int u = 0; u < urls.length; u += 2)
-            {
-              if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
-              {
-                linkset.add(urls[u] + "|" + urls[u + 1]);
-                addshowLink(linkMenu, label, urls[u + 1]);
-              }
-            }
-          }
+          createBareURLLink(urlLink, id, linkset, linkMenu, label, false);
         }
         // Create urls from description but only for URL links which are regex
         // links
         if (descr != null && urlLink.getRegexReplace() != null)
         {
           // create link for this URL from description where regex matches
-          String[] urls = urlLink.makeUrls(descr, true);
-          if (urls != null)
-          {
-            for (int u = 0; u < urls.length; u += 2)
-            {
-              if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
-              {
-                linkset.add(urls[u] + "|" + urls[u + 1]);
-                addshowLink(linkMenu, label, urls[u + 1]);
-              }
-            }
-          }
+          createBareURLLink(urlLink, descr, linkset, linkMenu, label, false);
         }
       }
       else
@@ -719,6 +701,7 @@ public class PopupMenu extends JPopupMenu
           addshowLink(linkMenu, label, urlLink.getUrl_prefix());
         }
       }
+
     }
     if (sequence != null)
     {
@@ -730,6 +713,34 @@ public class PopupMenu extends JPopupMenu
     }
   }
 
+  /*
+   * Create a bare URL Link
+   */
+  private void createBareURLLink(UrlLink urlLink, String id,
+          List<String> linkset, JMenu linkMenu, String label,
+          Boolean addSepToLabel)
+  {
+    String[] urls = urlLink.makeUrls(id, true);
+    if (urls != null)
+    {
+      for (int u = 0; u < urls.length; u += 2)
+      {
+        if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
+        {
+          linkset.add(urls[u] + "|" + urls[u + 1]);
+          if (addSepToLabel)
+          {
+            addshowLink(linkMenu, label + "|" + urls[u], urls[u + 1]);
+          }
+          else
+          {
+            addshowLink(linkMenu, label, urls[u + 1]);
+          }
+        }
+      }
+    }
+  }
+
   /**
    * Add annotation types to 'Show annotations' and/or 'Hide annotations' menus.
    * "All" is added first, followed by a separator. Then add any annotation
index 8dbe5e2..b57b951 100755 (executable)
  */
 package jalview.gui;
 
+import static jalview.util.UrlConstants.EMBLEBI_STRING;
+import static jalview.util.UrlConstants.OLD_EMBLEBI_STRING;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+import static jalview.util.UrlConstants.SEQUENCE_NAME;
+import static jalview.util.UrlConstants.SRS_STRING;
+
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.bin.Cache;
 import jalview.gui.Help.HelpId;
@@ -110,10 +116,7 @@ public class Preferences extends GPreferences
   public static List<String> groupURLLinks;
   static
   {
-    String string = Cache
-            .getDefault(
-                    "SEQUENCE_LINKS",
-                    "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$");
+    String string = Cache.getDefault("SEQUENCE_LINKS", EMBLEBI_STRING);
     sequenceURLLinks = new Vector<String>();
 
     try
@@ -124,7 +127,11 @@ public class Preferences extends GPreferences
         String name = st.nextToken();
         String url = st.nextToken();
         // check for '|' within a regex
-        int rxstart = url.indexOf("$SEQUENCE_ID$");
+        int rxstart = url.indexOf("$" + SEQUENCE_ID + "$");
+        if (rxstart == -1)
+        {
+          rxstart = url.indexOf("$" + SEQUENCE_NAME + "$");
+        }
         while (rxstart == -1 && url.indexOf("/=$") == -1)
         {
           url = url + "|" + st.nextToken();
@@ -137,14 +144,16 @@ public class Preferences extends GPreferences
     }
     {
       // upgrade old SRS link
-      int srsPos = sequenceURLLinks
-              .indexOf("SRS|http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-newId+(([uniprot-all:$SEQUENCE_ID$]))+-view+SwissEntry");
+      int srsPos = sequenceURLLinks.indexOf(SRS_STRING);
       if (srsPos > -1)
       {
-        sequenceURLLinks
-                .setElementAt(
-                        "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$",
-                        srsPos);
+        sequenceURLLinks.setElementAt(EMBLEBI_STRING, srsPos);
+      }
+      // upgrade old EMBL-EBI link
+      int emblPos = sequenceURLLinks.indexOf(OLD_EMBLEBI_STRING);
+      if (emblPos > -1)
+      {
+        sequenceURLLinks.setElementAt(EMBLEBI_STRING, emblPos);
       }
     }
 
index bae80db..3266fab 100644 (file)
@@ -616,13 +616,14 @@ public class SeqPanel extends JPanel implements MouseListener,
       return;
     }
 
-    if (evt.isShiftDown() || evt.isAltDown() || evt.isControlDown())
+    boolean isControlDown = Platform.isControlDown(evt);
+    if (evt.isShiftDown() || isControlDown)
     {
-      if (evt.isAltDown() || evt.isControlDown())
+      editingSeqs = true;
+      if (isControlDown)
       {
         groupEditing = true;
       }
-      editingSeqs = true;
     }
     else
     {
index 46580a2..b27752e 100755 (executable)
@@ -60,6 +60,7 @@ public class GSequenceLink extends Panel
     nameTB.setBounds(new Rectangle(77, 10, 310, 23));
     nameTB.addKeyListener(new KeyAdapter()
     {
+      @Override
       public void keyTyped(KeyEvent e)
       {
         nameTB_keyTyped(e);
@@ -70,6 +71,7 @@ public class GSequenceLink extends Panel
     urlTB.setBounds(new Rectangle(78, 40, 309, 23));
     urlTB.addKeyListener(new KeyAdapter()
     {
+      @Override
       public void keyTyped(KeyEvent e)
       {
         urlTB_keyTyped(e);
@@ -88,7 +90,20 @@ public class GSequenceLink extends Panel
     jLabel3.setBounds(new Rectangle(21, 72, 351, 15));
     jLabel4.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
     jLabel4.setText(MessageManager.getString("label.use_sequence_id_2"));
-    jLabel4.setBounds(new Rectangle(21, 93, 351, 15));
+    jLabel4.setBounds(new Rectangle(21, 88, 351, 15));
+    jLabel5.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
+    jLabel5.setText(MessageManager.getString("label.use_sequence_id_3"));
+    jLabel5.setBounds(new Rectangle(21, 106, 351, 15));
+
+    String lastLabel = MessageManager.getString("label.use_sequence_id_4");
+    if (lastLabel.length() > 0)
+    {
+      // e.g. Spanish version has longer text
+      jLabel6.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
+      jLabel6.setText(lastLabel);
+      jLabel6.setBounds(new Rectangle(21, 122, 351, 15));
+    }
+
     jPanel1.setBorder(BorderFactory.createEtchedBorder());
     jPanel1.setLayout(null);
     jPanel1.add(jLabel1);
@@ -97,11 +112,21 @@ public class GSequenceLink extends Panel
     jPanel1.add(jLabel2);
     jPanel1.add(jLabel3);
     jPanel1.add(jLabel4);
+    jPanel1.add(jLabel5);
+
+    int height = 130;
+    if (lastLabel.length() > 0)
+    {
+      jPanel1.add(jLabel6);
+      height = 146;
+    }
+
     this.add(jPanel1, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
             GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
-                    5, 4, 6, 5), 390, 130));
+                    5, 4, 6, 5), 390, height));
   }
 
+  @Override
   public void setName(String name)
   {
     nameTB.setText(name);
@@ -112,6 +137,7 @@ public class GSequenceLink extends Panel
     urlTB.setText(url);
   }
 
+  @Override
   public String getName()
   {
     return nameTB.getText();
@@ -149,6 +175,10 @@ public class GSequenceLink extends Panel
 
   JLabel jLabel4 = new JLabel();
 
+  JLabel jLabel5 = new JLabel();
+
+  JLabel jLabel6 = new JLabel();
+
   JPanel jPanel1 = new JPanel();
 
   GridBagLayout gridBagLayout1 = new GridBagLayout();
diff --git a/src/jalview/util/UrlConstants.java b/src/jalview/util/UrlConstants.java
new file mode 100644 (file)
index 0000000..ce6d980
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util;
+
+/**
+ * A class to hold constants relating to Url links used in Jalview
+ */
+public class UrlConstants
+{
+
+  /*
+   * Sequence ID string
+   */
+  public static final String SEQUENCE_ID = "SEQUENCE_ID";
+
+  /*
+   * Sequence Name string
+   */
+  public static final String SEQUENCE_NAME = "SEQUENCE_NAME";
+
+  /*
+   * Default sequence URL link string for EMBL-EBI search
+   */
+  public static final String EMBLEBI_STRING = "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_NAME$";
+
+  /*
+   * Default sequence URL link string for EMBL-EBI search
+   */
+  public static final String OLD_EMBLEBI_STRING = "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$";
+
+  /*
+   * Default sequence URL link string for SRS 
+   */
+  public static final String SRS_STRING = "SRS|http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-newId+(([uniprot-all:$SEQUENCE_ID$]))+-view+SwissEntry";
+
+  /*
+   * not instantiable
+   */
+  private UrlConstants()
+  {
+  }
+}
index 4297090..872f432 100644 (file)
@@ -20,6 +20,9 @@
  */
 package jalview.util;
 
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+import static jalview.util.UrlConstants.SEQUENCE_NAME;
+
 import java.util.Vector;
 
 public class UrlLink
@@ -37,6 +40,8 @@ public class UrlLink
 
   private boolean dynamic = false;
 
+  private boolean uses_seq_id = false;
+
   private String invalidMessage = null;
 
   /**
@@ -48,81 +53,40 @@ public class UrlLink
    */
   public UrlLink(String link)
   {
-    int sep = link.indexOf("|"), psqid = link.indexOf("$SEQUENCE_ID");
+    int sep = link.indexOf("|");
+    int psqid = link.indexOf("$" + SEQUENCE_ID);
+    int nsqid = link.indexOf("$" + SEQUENCE_NAME);
     if (psqid > -1)
     {
       dynamic = true;
-      int p = sep;
-      do
-      {
-        sep = p;
-        p = link.indexOf("|", sep + 1);
-      } while (p > sep && p < psqid);
-      // Assuming that the URL itself does not contain any '|' symbols
-      // sep now contains last pipe symbol position prior to any regex symbols
-      label = link.substring(0, sep);
-      if (label.indexOf("|") > -1)
-      {
-        // | terminated database name / www target at start of Label
-        target = label.substring(0, label.indexOf("|"));
-      }
-      else if (label.indexOf(" ") > 2)
-      {
-        // space separated Label - matches database name
-        target = label.substring(0, label.indexOf(" "));
-      }
-      else
-      {
-        target = label;
-      }
-      // Parse URL : Whole URL string first
-      url_prefix = link.substring(sep + 1, psqid);
-      if (link.indexOf("$SEQUENCE_ID=/") == psqid
-              && (p = link.indexOf("/=$", psqid + 14)) > psqid + 14)
-      {
-        // Extract Regex and suffix
-        url_suffix = link.substring(p + 3);
-        regexReplace = link.substring(psqid + 14, p);
-        try
-        {
-          com.stevesoft.pat.Regex rg = com.stevesoft.pat.Regex.perlCode("/"
-                  + regexReplace + "/");
-          if (rg == null)
-          {
-            invalidMessage = "Invalid Regular Expression : '"
-                    + regexReplace + "'\n";
-          }
-        } catch (Exception e)
-        {
-          invalidMessage = "Invalid Regular Expression : '" + regexReplace
-                  + "'\n";
-        }
-      }
-      else
-      {
-        regexReplace = null;
-        // verify format is really correct.
-        if (link.indexOf("$SEQUENCE_ID$") == psqid)
-        {
-          url_suffix = link.substring(psqid + 13);
-          regexReplace = null;
-        }
-        else
-        {
-          invalidMessage = "Warning: invalid regex structure for URL link : "
-                  + link;
-        }
-      }
+      uses_seq_id = true;
+
+      sep = parseTargetAndLabel(sep, psqid, link);
+
+      parseUrl(link, SEQUENCE_ID, psqid, sep);
+    }
+    else if (nsqid > -1)
+    {
+      dynamic = true;
+      sep = parseTargetAndLabel(sep, nsqid, link);
+
+      parseUrl(link, SEQUENCE_NAME, nsqid, sep);
     }
     else
     {
       target = link.substring(0, sep);
-      label = link.substring(0, sep = link.lastIndexOf("|"));
+      sep = link.lastIndexOf("|");
+      label = link.substring(0, sep);
       url_prefix = link.substring(sep + 1);
       regexReplace = null; // implies we trim any prefix if necessary //
       // regexReplace=".*\\|?(.*)";
       url_suffix = null;
     }
+
+    label = label.trim();
+    target = target.trim();
+    target = target.toUpperCase(); // DBRefEntry uppercases DB names
+    // NB getCanonicalName might be better but does not currently change case
   }
 
   /**
@@ -295,15 +259,122 @@ public class UrlLink
     }
   }
 
+  @Override
   public String toString()
   {
+    String var = (uses_seq_id ? SEQUENCE_ID : SEQUENCE_NAME);
+
     return label
             + "|"
             + url_prefix
-            + (dynamic ? ("$SEQUENCE_ID" + ((regexReplace != null) ? "="
+            + (dynamic ? ("$" + var + ((regexReplace != null) ? "="
                     + regexReplace + "=$" : "$")) : "")
             + ((url_suffix == null) ? "" : url_suffix);
+  }
+
+  /**
+   * 
+   * @param firstSep
+   *          Location of first occurrence of separator in link string
+   * @param psqid
+   *          Position of sequence id or name in link string
+   * @param link
+   *          Link string containing database name and url
+   * @return Position of last separator symbol prior to any regex symbols
+   */
+  protected int parseTargetAndLabel(int firstSep, int psqid, String link)
+  {
+    int p = firstSep;
+    int sep = firstSep;
+    do
+    {
+      sep = p;
+      p = link.indexOf("|", sep + 1);
+    } while (p > sep && p < psqid);
+    // Assuming that the URL itself does not contain any '|' symbols
+    // sep now contains last pipe symbol position prior to any regex symbols
+    label = link.substring(0, sep);
+    if (label.indexOf("|") > -1)
+    {
+      // | terminated database name / www target at start of Label
+      target = label.substring(0, label.indexOf("|"));
+    }
+    else if (label.indexOf(" ") > 2)
+    {
+      // space separated Label - matches database name
+      target = label.substring(0, label.indexOf(" "));
+    }
+    else
+    {
+      target = label;
+    }
+    return sep;
+  }
+
+  /**
+   * Parse the URL part of the link string
+   * 
+   * @param link
+   *          Link string containing database name and url
+   * @param varName
+   *          Name of variable in url string (e.g. SEQUENCE_ID, SEQUENCE_NAME)
+   * @param sqidPos
+   *          Position of id or name in link string
+   * @param sep
+   *          Position of separator in link string
+   */
+  protected void parseUrl(String link, String varName, int sqidPos, int sep)
+  {
+    url_prefix = link.substring(sep + 1, sqidPos);
+
+    // delimiter at start of regex: e.g. $SEQUENCE_ID=/
+    String startDelimiter = "$" + varName + "=/";
 
+    // delimiter at end of regex: /=$
+    String endDelimiter = "/=$";
+
+    int startLength = startDelimiter.length();
+
+    // Parse URL : Whole URL string first
+    int p = link.indexOf(endDelimiter, sqidPos + startLength);
+
+    if (link.indexOf(startDelimiter) == sqidPos
+            && (p > sqidPos + startLength))
+    {
+      // Extract Regex and suffix
+      url_suffix = link.substring(p + endDelimiter.length());
+      regexReplace = link.substring(sqidPos + startLength, p);
+      try
+      {
+        com.stevesoft.pat.Regex rg = com.stevesoft.pat.Regex.perlCode("/"
+                + regexReplace + "/");
+        if (rg == null)
+        {
+          invalidMessage = "Invalid Regular Expression : '" + regexReplace
+                  + "'\n";
+        }
+      } catch (Exception e)
+      {
+        invalidMessage = "Invalid Regular Expression : '" + regexReplace
+                + "'\n";
+      }
+    }
+    else
+    {
+      // no regex
+      regexReplace = null;
+      // verify format is really correct.
+      if (link.indexOf("$" + varName + "$") == sqidPos)
+      {
+        url_suffix = link.substring(sqidPos + startLength - 1);
+        regexReplace = null;
+      }
+      else
+      {
+        invalidMessage = "Warning: invalid regex structure for URL link : "
+                + link;
+      }
+    }
   }
 
   private static void testUrls(UrlLink ul, String idstring, String[] urls)
@@ -341,7 +412,8 @@ public class UrlLink
      * "PF3|http://us.expasy.org/cgi-bin/niceprot.pl?$SEQUENCE_ID=/PFAM:(.+)/=$"
      * , "NOTFER|http://notfer.org/$SEQUENCE_ID=/(?<!\\s)(.+)/=$",
      */
-    "NESTED|http://nested/$SEQUENCE_ID=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=$/nested" };
+    "NESTED|http://nested/$" + SEQUENCE_ID
+            + "=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=$/nested" };
     String[] idstrings = new String[] {
     /*
      * //"LGUL_human", //"QWIQW_123123", "uniprot|why_do+_12313_foo",
@@ -389,6 +461,11 @@ public class UrlLink
     return dynamic;
   }
 
+  public boolean usesSeqId()
+  {
+    return uses_seq_id;
+  }
+
   public void setLabel(String newlabel)
   {
     this.label = newlabel;
index 1afe586..c01be4e 100644 (file)
@@ -613,7 +613,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     boolean recalc = false;
     if (cs != null)
     {
-      cs.setConservationApplied(recalc = getConservationSelected());
+      recalc = getConservationSelected();
       if (getAbovePIDThreshold() || cs instanceof PIDColourScheme
               || cs instanceof Blosum62ColourScheme)
       {
@@ -630,6 +630,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
         cs.setConsensus(hconsensus);
         cs.setConservation(hconservation);
       }
+      cs.setConservationApplied(getConservationSelected());
       cs.alignmentChanged(alignment, hiddenRepSequences);
     }
     if (getColourAppliesToAllGroups())
index 341a814..00c52ed 100644 (file)
@@ -39,6 +39,8 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.io.FileLoader;
 import jalview.io.FormatAdapter;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.PIDColourScheme;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MapList;
 
@@ -329,4 +331,20 @@ public class AlignViewportTest
     assertNotNull("Quality in column 1 is null", annotations[0]);
     assertTrue("No quality value in column 1", annotations[0].value > 10f);
   }
+
+  @Test(groups = { "Functional" })
+  public void testSetGlobalColourScheme()
+  {
+    /*
+     * test for JAL-2283 don't inadvertently turn on colour by conservation
+     */
+    Cache.applicationProperties.setProperty("DEFAULT_COLOUR_PROT", "NONE");
+    Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
+            Boolean.TRUE.toString());
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", FormatAdapter.FILE);
+    ColourSchemeI cs = new PIDColourScheme();
+    af.getViewport().setGlobalColourScheme(cs);
+    assertFalse(cs.conservationApplied());
+  }
 }
index edf3202..b4e8629 100644 (file)
@@ -27,6 +27,9 @@ import static org.testng.AssertJUnit.assertTrue;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.FormatAdapter;
@@ -440,4 +443,91 @@ public class PopupMenuTest
     assertEquals(JSeparator.HORIZONTAL,
             ((JSeparator) hideOptions[1]).getOrientation());
   }
+
+  /**
+   * Test for adding feature links
+   */
+  @Test(groups = { "Functional" })
+  public void testAddFeatureLinks()
+  {
+    // sequences from the alignment
+    List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
+
+    // create list of links and list of DBRefs
+    List<String> links = new ArrayList<String>();
+    List<DBRefEntry> refs = new ArrayList<DBRefEntry>();
+
+    // 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_NAME$");
+    links.add("UNIPROT | http://www.uniprot.org/uniprot/$SEQUENCE_ID$");
+    links.add("INTERPRO | http://www.ebi.ac.uk/interpro/entry/$SEQUENCE_ID$");
+    // Gene3D entry tests for case (in)sensitivity
+    links.add("Gene3D | http://gene3d.biochem.ucl.ac.uk/Gene3D/search?sterm=$SEQUENCE_ID$&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
+    seqs.get(0).addDBRef(refs.get(0));
+
+    seqs.get(0).addDBRef(refs.get(1));
+    seqs.get(0).addDBRef(refs.get(2));
+    seqs.get(0).addDBRef(refs.get(3));
+    
+    seqs.get(1).addDBRef(refs.get(4));
+    seqs.get(1).addDBRef(refs.get(5));
+    
+    // get the Popup Menu for first sequence
+    testee = new PopupMenu(parentPanel, (Sequence) seqs.get(0), links);
+    Component[] seqItems = testee.sequenceMenu.getMenuComponents();
+    JMenu linkMenu = (JMenu) seqItems[6];
+    Component[] linkItems = linkMenu.getMenuComponents();
+    
+    // check the number of links are the expected number
+    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());
+
+    // sequence id for each link should match corresponding DB accession id
+    for (int i = 1; i < 4; i++)
+    {
+      assertEquals(refs.get(i - 1).getSource(), ((JMenuItem) linkItems[i])
+              .getText().split("\\|")[0]);
+      assertEquals(refs.get(i - 1).getAccessionId(),
+              ((JMenuItem) linkItems[i])
+              .getText().split("\\|")[1]);
+    }
+
+    // get the Popup Menu for second sequence
+    testee = new PopupMenu(parentPanel, (Sequence) seqs.get(1), links);
+    seqItems = testee.sequenceMenu.getMenuComponents();
+    linkMenu = (JMenu) seqItems[6];
+    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());
+
+    // sequence id for each link should match corresponding DB accession id
+    for (int i = 1; i < 3; i++)
+    {
+      assertEquals(refs.get(i + 3).getSource(), ((JMenuItem) linkItems[i])
+              .getText().split("\\|")[0].toUpperCase());
+      assertEquals(refs.get(i + 3).getAccessionId(),
+              ((JMenuItem) linkItems[i]).getText().split("\\|")[1]);
+    }
+
+
+  }
 }
diff --git a/test/jalview/util/UrlLinkTest.java b/test/jalview/util/UrlLinkTest.java
new file mode 100644 (file)
index 0000000..45ef6af
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util;
+
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+import static jalview.util.UrlConstants.SEQUENCE_NAME;
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+import org.testng.annotations.Test;
+
+public class UrlLinkTest
+{
+
+  final static String DB = "Test";
+
+  final static String URL_PREFIX = "http://www.jalview.org/";
+
+  final static String URL_SUFFIX = "/blah";
+
+  final static String SEP = "|";
+
+  final static String DELIM = "$";
+
+  final static String REGEX_NESTED = "=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=";
+  
+  final static String REGEX_RUBBISH = "=/[0-9]++/=";
+
+  /**
+   * Test URL link creation when the input string has no regex
+   */
+  @Test(groups = { "Functional" })
+  public void testUrlLinkCreationNoRegex()
+  {
+    // SEQUENCE_NAME
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_NAME
+            + DELIM + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertFalse(ul.usesSeqId());
+    assertNull(ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // SEQUENCE_ID
+    ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID + DELIM
+            + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertTrue(ul.usesSeqId());
+    assertNull(ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // Not dynamic
+    ul = new UrlLink(DB + SEP + URL_PREFIX + URL_SUFFIX.substring(1));
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX + URL_SUFFIX.substring(1), ul.getUrl_prefix());
+    assertFalse(ul.isDynamic());
+    assertFalse(ul.usesSeqId());
+    assertNull(ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+  }
+
+  /**
+   * Test URL link creation when the input string has regex
+   */
+  @Test(groups = { "Functional" })
+  public void testUrlLinkCreationWithRegex()
+  {
+    // SEQUENCE_NAME
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_NAME
+            + REGEX_NESTED + DELIM + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertFalse(ul.usesSeqId());
+    assertEquals(REGEX_NESTED.substring(2, REGEX_NESTED.length() - 2),
+            ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // SEQUENCE_ID
+    ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + REGEX_NESTED + DELIM + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertTrue(ul.usesSeqId());
+    assertEquals(REGEX_NESTED.substring(2, REGEX_NESTED.length() - 2),
+            ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // invalid regex
+    ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + REGEX_RUBBISH + DELIM + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertTrue(ul.usesSeqId());
+    assertEquals(REGEX_RUBBISH.substring(2, REGEX_RUBBISH.length() - 2),
+            ul.getRegexReplace());
+    assertFalse(ul.isValid());
+    assertEquals(
+            "Invalid Regular Expression : '"
+                    + REGEX_RUBBISH.substring(2, REGEX_RUBBISH.length() - 2)
+                    + "'\n",
+            ul.getInvalidMessage());
+  }
+
+  /**
+   * Test construction of link by substituting sequence id or name
+   */
+  @Test(groups = { "Functional" })
+  public void testMakeUrlNoRegex()
+  {
+    // Single non-regex
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_NAME
+            + DELIM + URL_SUFFIX);
+    String idstring = "FER_CAPAA";
+    String[] urls = ul.makeUrls(idstring, true);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+  }
+
+  /**
+   * Test construction of link by substituting sequence id or name
+   */
+  @Test(groups = { "Functional" })
+  public void testMakeUrlWithRegex()
+  {
+    // Unused regex
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + REGEX_NESTED + DELIM + URL_SUFFIX);
+    String idstring = "FER_CAPAA";
+    String[] urls = ul.makeUrls(idstring, true);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // nested regex
+    idstring = "Label:gi|9234|pdb|102L|A";
+    urls = ul.makeUrls(idstring, true);
+
+    assertEquals(2, urls.length);
+    assertEquals("9234", urls[0]);
+    assertEquals(URL_PREFIX + "9234" + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals("9234", urls[0]);
+    assertEquals(URL_PREFIX + "9234" + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // unmatched regex
+    idstring = "this does not match";
+    urls = ul.makeUrls(idstring, true);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // empty idstring
+    idstring = "";
+    urls = ul.makeUrls(idstring, true);
+
+    assertNull(urls);
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals("", urls[0]);
+    assertEquals(URL_PREFIX + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+  }
+
+}