JAL-4077 translate between Java/windows and Jmol 14.31.53 script/internal model repre...
authorJim Procter <jprocter@dundee.ac.uk>
Wed, 13 Nov 2024 15:54:59 +0000 (15:54 +0000)
committerJim Procter <jprocter@dundee.ac.uk>
Wed, 13 Nov 2024 15:54:59 +0000 (15:54 +0000)
src/jalview/ext/jmol/JmolCommands.java
test/jalview/ext/jmol/JmolCommandsTest.java

index 7c9a4c4..7b9577c 100644 (file)
@@ -316,15 +316,35 @@ public class JmolCommands extends StructureCommandsBase
   public StructureCommandI loadFile(String file)
   {
     // https://chemapps.stolaf.edu/jmol/docs/#loadfiles
+      
     return new StructureCommand(
-            "load FILES \"" + Platform.escapeBackslashes(file) + "\"");
+            "load FILES \"" + escapeQuotedFilename(file) + "\"");
+  }
+
+
+  /**
+   * escape a filename coping with Jmol's quirks (Jmol 14.31.53 NOLOG4J) for
+   * resolving files on network drives
+   * 
+   * @param file
+   * @return escaped file prepended with file: if necessary - needs to be
+   *         wrapped in \\\"
+   */
+  public static String escapeQuotedFilename(String file)
+  {
+    String prepend="";
+    if (file.startsWith("//") || file.startsWith("\\\\"))
+    {
+      prepend = "file:";
+    }
+    return prepend+Platform.escapeBackslashes(file);
   }
 
   @Override
   public StructureCommandI restoreSession(String filePath)
   {
     return new StructureCommand("restore STATE \""
-            + Platform.escapeBackslashes(filePath) + "\"");
+            + escapeQuotedFilename(filePath) + "\"");
   }
 
   @Override
@@ -536,4 +556,50 @@ public class JmolCommands extends StructureCommandsBase
   {
     return null; // not an external viewer
   }
+
+  /**
+   * match up Jmol 14.31.53 NOLOG4J's idea of a filepath with Jalview's
+   * @param jmolFile
+   * @param jalviewFile
+   * @return true if strings resolve to the same resource
+   */
+  public static boolean filePathMatch(String jmolFile,String jalviewFile)
+  {
+    if (jmolFile.equalsIgnoreCase(jalviewFile))
+    {
+      return true;
+    }
+    if (jmolFile.startsWith("file:") && (jalviewFile.startsWith("//") || jalviewFile.startsWith("\\\\")))
+    {
+      String jmolPath = jmolFile.substring(5);
+      // jmol needs file: at beginning for network mounts.
+      if (jmolPath.equalsIgnoreCase(jalviewFile))
+      {
+        return true;
+      }
+      if (jmolPath.startsWith("////"))
+      {
+        // faulty translation from backslash to forward slash - put it back the other way
+        jmolPath = jmolPath.replace("//", "/");
+      }
+      if (jmolPath.equalsIgnoreCase(jalviewFile))
+      {
+        return true;
+      }
+      if (jmolPath.startsWith("\\\\\\"))
+      {
+        // faulty translation from backslash to forward slash - put it back the other way
+        jmolPath = jmolPath.replace("\\\\", "//");
+      }      // also normalises \\ to / for URLs
+      String jalviewPath = jalviewFile.replace("\\","/");
+      if (jmolPath.equalsIgnoreCase(jalviewPath))
+      {
+        return true;
+      }
+      jmolPath = jmolPath.replace("//", "/");
+      return jmolPath.equalsIgnoreCase(jalviewPath);
+        
+    }
+    return false;
+  }
 }
index 71fdaf1..28ce38f 100644 (file)
@@ -30,6 +30,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import jalview.datamodel.Alignment;
@@ -276,6 +277,90 @@ public class JmolCommandsTest
     // single backslash gets escaped to double
     cmd = testee.loadFile("\\some\\filepath");
     assertEquals(cmd.getCommand(), "load FILES \"\\\\some\\\\filepath\"");
+
+    // double backslash gets escaped to file:\\\\
+    cmd = testee.loadFile("\\\\some\\filepath");
+    assertEquals(cmd.getCommand(),
+            "load FILES \"file:\\\\\\\\some\\\\filepath\"");
+
+    // double forward slash is escaped to file:////
+    cmd = testee.loadFile("//some/filepath");
+    assertEquals(cmd.getCommand(), "load FILES \"file://some/filepath\"");
+
+  }
+
+  @Test(
+    groups = "Functional",
+    dataProvider = "testFilePathEquivalence",
+    singleThreaded = true)
+  public void testFilePathEquivalence(String jalviewpath, String jmolpath)
+  {
+    assertEquals(JmolCommands.escapeQuotedFilename(jalviewpath), jmolpath,
+            "for " + jalviewpath);
+    // simple unescape
+    assertTrue(JmolCommands.filePathMatch(jmolpath.replace("\\\\", "\\"),
+            jalviewpath));
+  }
+
+  /**
+   * Windows path transformations for Jmol 14.31.53 NOLOG4J positive examples
+   * for escapeQuotedFilename - results of escaping should, after a simple
+   * unescape (remove escape backslashes) also work for filePathMatch
+   * 
+   * @return
+   */
+
+  @DataProvider(name = "testFilePathEquivalence")
+  public Object[][] fileEquivalences()
+  {
+    return new String[][] {
+        new String[]
+        { "/some/filepath", "/some/filepath" },
+        new String[]
+        { "\\some\\filepath", "\\\\some\\\\filepath" },
+        new String[]
+        { "\\\\some\\filepath", "file:\\\\\\\\some\\\\filepath" },
+        new String[]
+        { "//some/filepath", "file://some/filepath" } };
+  }
+
+  @Test(
+    groups = "Functional",
+    dataProvider = "testForwardBackslashFilePathEquivalence")
+  public void filePathMatchTest(String jmolPath, String jalviewPath)
+  {
+    assertTrue(JmolCommands.filePathMatch(jmolPath, jalviewPath));
+  }
+
+  /**
+   * Windows path transformations for Jmol 14.31.53 NOLOG4J positive examples
+   * for JmolCommands.filePathMatch - handles windows network drive
+   * transformations
+   * 
+   * @return
+   */
+  @DataProvider(name = "testForwardBackslashFilePathEquivalence")
+  public Object[][] forwardBackslashFilePathEquivalence()
+  {
+    return new String[][] {
+        new String[]
+        { "file:\\\\some\\filepath", "\\\\some\\filepath" },
+        new String[]
+        { "file://some/filepath", "\\\\some\\filepath" },
+        new String[]
+        { "file:////some//filepath", "\\\\some\\filepath" },
+        new String[]
+        { "file:\\\\\\\\estorage.dundee.ac.uk\\\\cluster-gjb_lab\\\\jprocter\\\\public_html\\\\1QIP.cif",
+            "//estorage.dundee.ac.uk/cluster-gjb_lab/jprocter/public_html/1QIP.cif" },
+        new String[]
+        { "file:\\\\\\\\estorage.dundee.ac.uk\\\\cluster-gjb_lab\\\\jprocter\\\\public_html\\\\1QIP.cif",
+            "\\\\estorage.dundee.ac.uk\\cluster-gjb_lab\\jprocter\\public_html\\1QIP.cif" },
+        new String[]
+        { "file://estorage.dundee.ac.uk/cluster-gjb_lab/jprocter/public_html/1QIP.cif",
+            "\\\\estorage.dundee.ac.uk\\cluster-gjb_lab\\jprocter\\public_html\\1QIP.cif" },
+        new String[]
+        { "file:////estorage.dundee.ac.uk//cluster-gjb_lab//jprocter//public_html//1QIP.cif",
+            "\\\\estorage.dundee.ac.uk\\cluster-gjb_lab\\jprocter\\public_html\\1QIP.cif" } };
   }
 
   @Test(groups = "Functional")