From cf1d19a283a24106e119d430685188a86e5a266f Mon Sep 17 00:00:00 2001 From: Jim Procter Date: Wed, 13 Nov 2024 15:54:59 +0000 Subject: [PATCH] JAL-4077 translate between Java/windows and Jmol 14.31.53 script/internal model representation of local and network file paths --- src/jalview/ext/jmol/JmolCommands.java | 70 +++++++++++++++++++++- test/jalview/ext/jmol/JmolCommandsTest.java | 85 +++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 2 deletions(-) diff --git a/src/jalview/ext/jmol/JmolCommands.java b/src/jalview/ext/jmol/JmolCommands.java index 7c9a4c4..7b9577c 100644 --- a/src/jalview/ext/jmol/JmolCommands.java +++ b/src/jalview/ext/jmol/JmolCommands.java @@ -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; + } } diff --git a/test/jalview/ext/jmol/JmolCommandsTest.java b/test/jalview/ext/jmol/JmolCommandsTest.java index 71fdaf1..28ce38f 100644 --- a/test/jalview/ext/jmol/JmolCommandsTest.java +++ b/test/jalview/ext/jmol/JmolCommandsTest.java @@ -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") -- 1.7.10.2