From: Jim Procter
Date: Fri, 28 Jan 2022 17:08:35 +0000 (+0000)
Subject: Merge branch 'merge/develop_JAL-3725' into develop
X-Git-Tag: Release_2_11_2_0~13^2~6^2~1
X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=0aa7f6fab658c9a203b410d4bead72217da5c9a0;hp=0913cb6ee2033d714c0aa6eb3e152da7485b21a4;p=jalview.git
Merge branch 'merge/develop_JAL-3725' into develop
Conflicts:
src/jalview/gui/PopupMenu.java
---
diff --git a/THIRDPARTYLIBS b/THIRDPARTYLIBS
index c26858d..a202e97 100644
--- a/THIRDPARTYLIBS
+++ b/THIRDPARTYLIBS
@@ -29,7 +29,7 @@ httpclient-4.0.3.jar
httpcore-4.0.1.jar
httpmime-4.0.3.jar
intervalstore-v1.0.jar
-jabaws-min-client-2.2.0.jar
+jabaws-min-client-NO_LOG4J-2.2.0.jar Apache license
java-json.jar
jaxrpc.jar
jersey-client-1.19.4.jar CDDL 1.1 + GPL2 w/ CPE - http://glassfish.java.net/public/CDDL+GPL_1_1.html
@@ -49,15 +49,18 @@ jsr311-api-1.1.1.jar
jswingreader-0.3.jar Apache license - built from http://jswingreader.sourceforge.net/ svn/trunk v12
libquaqua64-8.0.jnilib.jar quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/
libquaqua-8.0.jnilib.jar quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/
-log4j-1.2.8.jar
+log4j-1.2-api-2.16.0.jar Apache license version 2.0
+log4j-api-2.16.0.jar Apache license version 2.0
+log4j-core-2.16.0.jar Apache license version 2.0
+log4j-slf4j18-impl-2.16.0.jar Apache license version 2.0
mail.jar
miglayout-4.0-swing.jar BSD - http://www.migcalendar.com/miglayout/versions/4.0/license.txt
quaqua-filechooser-only-8.0.jar quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/
regex.jar
saaj.jar
servlet-api-3.1.jar
-slf4j-api-1.7.7.jar
-slf4j-log4j12-1.7.7.jar
+slf4j-api-1.7.32.jar MIT license - https://opensource.org/licenses/mit-license.php
+slf4j-log4j12-1.7.32.jar MIT license - https://opensource.org/licenses/mit-license.php
vamsas-client.jar
VAqua5-patch.jar This is a patched version of VAqua v5 (latest stable) by Alan Snyder et al. GPLv3 with Classpath exception, also includes contributions from Quaqua: http://violetlib.org/vaqua/overview.html - see doc/patching-vaqua.txt for patch details, and http://issues.jalview.org/browse/JAL-2988 for details of the bug that the patch addresses.
VARNAv3-93.jar GPL licenced software by K�vin Darty, Alain Denise and Yann Ponty - http://varna.lri.fr
@@ -111,12 +114,9 @@ javax.xml.soap-api.jar CDDL + GPLv2 with classpath exception - https://github.co
jaxb-api-2.3.1.jar CDDL 1.1 + GPL2 w/ CPE - https://oss.oracle.com/licenses/CDDL+GPL-1.1
jaxb-runtime-2.3.2.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
jaxws-api-2.3.1.jar CDDL + GPLv2 with classpath exception - https://github.com/javaee/jax-ws-spec/blob/master/LICENSE.md
-Jmol-14.6.4_2016.10.26-no_netscape.jar GPL/LGPLv2 http://sourceforge.net/projects/jmol/files/
jsr311-api-1.1.1.jar CDDL License - http://www.opensource.org/licenses/cddl1.php
mimepull-1.9.11.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
policy-2.7.6.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
-slf4j-api-1.7.26.jar MIT License - https://opensource.org/licenses/mit-license.php
-slf4j-log4j12-1.7.26.jar MIT License - https://opensource.org/licenses/mit-license.php
stax-ex-1.8.1.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
stax2-api-4.2.jar The BSD License - http://www.opensource.org/licenses/bsd-license.php
streambuffer-1.5.7.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
diff --git a/build.gradle b/build.gradle
index 8efe39d..34a3461 100644
--- a/build.gradle
+++ b/build.gradle
@@ -103,6 +103,7 @@ ext {
// Import channel_properties
channelDir = string("${jalviewDir}/${channel_properties_dir}/${propertiesChannelName}")
channelGradleProperties = string("${channelDir}/channel_gradle.properties")
+ channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
overrideProperties(channelGradleProperties, false)
// local build environment properties
// can be "projectDir/local.properties"
@@ -420,16 +421,16 @@ ext {
'--add-modules', j11modules
]
*/
- } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
- JAVA_INTEGER_VERSION = JAVA_VERSION
- libDir = j11libDir
- libDistDir = j11libDir
- compile_source_compatibility = JAVA_VERSION
- compile_target_compatibility = JAVA_VERSION
+ } else if (JAVA_VERSION.equals("17")) {
+ JAVA_INTEGER_VERSION = string("17")
+ libDir = j17libDir
+ libDistDir = j17libDir
+ compile_source_compatibility = 17
+ compile_target_compatibility = 17
getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
- eclipseJavaRuntimeName = string("JavaSE-11")
+ eclipseJavaRuntimeName = string("JavaSE-17")
/* compile without modules -- using classpath libraries
additional_compiler_args += [
'--module-path', modules_compileClasspath.asPath,
@@ -1511,6 +1512,12 @@ task getdownWebsite() {
}
getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
+ copy {
+ from channelPropsFile
+ into getdownWebsiteDir
+ }
+ getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
+
// set some getdown_txt_ properties then go through all properties looking for getdown_txt_...
def props = project.properties.sort { it.key }
if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
@@ -1684,6 +1691,7 @@ task getdownWebsite() {
from launchJvl
from getdownLauncher
from "${getdownWebsiteDir}/${getdown_build_properties}"
+ from "${getdownWebsiteDir}/${channel_props}"
if (file(getdownLauncher).getName() != getdown_launcher) {
rename(file(getdownLauncher).getName(), getdown_launcher)
}
diff --git a/getdown/lib/FJVL_VERSION b/getdown/lib/FJVL_VERSION
index df225c8..2cac91c 100644
--- a/getdown/lib/FJVL_VERSION
+++ b/getdown/lib/FJVL_VERSION
@@ -1 +1 @@
-1.8.3-1.2.10_FJVL
+1.8.3-1.2.11_FJVL
diff --git a/getdown/lib/JVL_VERSION b/getdown/lib/JVL_VERSION
index 6f6eed4..99f8359 100644
--- a/getdown/lib/JVL_VERSION
+++ b/getdown/lib/JVL_VERSION
@@ -1 +1 @@
-1.8.3-1.2.10_JVL
+1.8.3-1.2.11_JVL
diff --git a/getdown/lib/getdown-core.jar b/getdown/lib/getdown-core.jar
index dadce6e..4edf9b0 100644
Binary files a/getdown/lib/getdown-core.jar and b/getdown/lib/getdown-core.jar differ
diff --git a/getdown/lib/getdown-launcher-local.jar b/getdown/lib/getdown-launcher-local.jar
index 88036f9..500b38b 100644
Binary files a/getdown/lib/getdown-launcher-local.jar and b/getdown/lib/getdown-launcher-local.jar differ
diff --git a/getdown/lib/getdown-launcher.jar b/getdown/lib/getdown-launcher.jar
index 4e2a98c..2ead1c7 100644
Binary files a/getdown/lib/getdown-launcher.jar and b/getdown/lib/getdown-launcher.jar differ
diff --git a/getdown/src/getdown/ant/pom.xml b/getdown/src/getdown/ant/pom.xml
index 9b26d50..e67984c 100644
--- a/getdown/src/getdown/ant/pom.xml
+++ b/getdown/src/getdown/ant/pom.xml
@@ -4,7 +4,7 @@
com.threerings.getdown
getdown
- 1.8.3-1.2.10_FJVL
+ 1.8.3-1.2.11_FJVL
getdown-ant
diff --git a/getdown/src/getdown/core/pom.xml b/getdown/src/getdown/core/pom.xml
index eb6f388..f909444 100644
--- a/getdown/src/getdown/core/pom.xml
+++ b/getdown/src/getdown/core/pom.xml
@@ -4,7 +4,7 @@
com.threerings.getdown
getdown
- 1.8.3-1.2.10_FJVL
+ 1.8.3-1.2.11_FJVL
getdown-core
diff --git a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java
index 2022750..684844a 100644
--- a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java
+++ b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java
@@ -31,7 +31,7 @@ import java.util.zip.GZIPInputStream;
import jalview.bin.HiDPISetting;
import jalview.bin.MemorySetting;
-//import com.install4j.api.launcher.Variables;
+import jalview.util.LaunchUtils;
import com.threerings.getdown.util.*;
// avoid ambiguity with java.util.Base64 which we can't use as it's 1.8+
@@ -1181,6 +1181,17 @@ public class Application
continue;
}
}
+
+ // use saved preferences if no cmdline args
+ LaunchUtils.loadChannelProps(getAppDir());
+ if (LaunchUtils.getBooleanUserPreference(MemorySetting.CUSTOMISED_SETTINGS)) {
+ if (jvmmempc == null) {
+ jvmmempc = LaunchUtils.getUserPreference(MemorySetting.MEMORY_JVMMEMPC);
+ }
+ if (jvmmemmax == null) {
+ jvmmemmax = LaunchUtils.getUserPreference(MemorySetting.MEMORY_JVMMEMMAX);
+ }
+ }
// add the memory setting from jvmmempc and jvmmemmax
long maxMemLong = -1;
diff --git a/getdown/src/getdown/core/src/main/java/jalview/bin/MemorySetting.java b/getdown/src/getdown/core/src/main/java/jalview/bin/MemorySetting.java
index 5d7f14c..55e304d 100644
--- a/getdown/src/getdown/core/src/main/java/jalview/bin/MemorySetting.java
+++ b/getdown/src/getdown/core/src/main/java/jalview/bin/MemorySetting.java
@@ -1,4 +1,6 @@
/*
+
+ private static String ADJUSTMENT_MESSAGE = null;
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
*
@@ -31,6 +33,7 @@ package jalview.bin;
* @author bsoares
*
*/
+
public class MemorySetting
{
public static final String MAX_HEAPSIZE_PERCENT_PROPERTY_NAME = "jvmmempc";
@@ -49,13 +52,33 @@ public class MemorySetting
private static final long NOMEM_MAX_HEAPSIZE_GB_DEFAULT = 8;
+ public static final String NS = "MEMORY";
+
+ public static final String CUSTOMISED_SETTINGS = NS
+ + "_CUSTOMISED_SETTINGS";
+
+ public static final String MEMORY_JVMMEMPC = NS + "_"
+ + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME.toUpperCase();
+
+ public static final String MEMORY_JVMMEMMAX = NS + "_"
+ + MAX_HEAPSIZE_PROPERTY_NAME.toUpperCase();
+
protected static boolean logToClassChecked = false;
+ public static String memorySuffixes = "bkmgt"; // order of the suffixes is
+ // important!
+
public static long getMemorySetting()
{
return getMemorySetting(null, null);
}
+ public static long getMemorySetting(String jvmmemmaxarg,
+ String jvmmempcarg)
+ {
+ return getMemorySetting(jvmmemmaxarg, jvmmempcarg, true, false);
+ }
+
/**
* Decide on appropriate memory setting for Jalview based on the two arguments
* values: jvmmempc - the maximum percentage of total physical memory to
@@ -83,99 +106,66 @@ public class MemorySetting
* @param jvmmempcarg
* Max percentage of physical memory to use. Defaults to "90".
*
+ * @param useProps
+ * boolean to decide whether to look at System properties.
+ *
* @return The amount of memory (in bytes) to allocate to Jalview
*/
public static long getMemorySetting(String jvmmemmaxarg,
- String jvmmempcarg)
+ String jvmmempcarg, boolean useProps, boolean quiet)
{
// actual Xmx value-to-be
long maxMemLong = -1;
+ clearAdjustmentMessage();
// (absolute) jvmmaxmem setting, start with default
long memmax = MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
- if (jvmmemmaxarg == null)
+ if (jvmmemmaxarg == null && useProps)
{
jvmmemmaxarg = System.getProperty(MAX_HEAPSIZE_PROPERTY_NAME);
}
String jvmmemmax = jvmmemmaxarg;
if (jvmmemmax != null && jvmmemmax.length() > 0)
{
- long multiplier = 1;
- switch (jvmmemmax.toLowerCase().substring(jvmmemmax.length() - 1))
- {
- case "t":
- multiplier = 1099511627776L; // 2^40
- jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
- break;
- case "g":
- multiplier = 1073741824; // 2^30
- jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
- break;
- case "m":
- multiplier = 1048576; // 2^20
- jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
- break;
- case "k":
- multiplier = 1024; // 2^10
- jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
- break;
- case "b":
- multiplier = 1; // 2^0
- jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
- break;
- default:
- break;
- }
-
// parse the arg
try
{
- memmax = Long.parseLong(jvmmemmax);
+ memmax = memoryStringToLong(jvmmemmax);
+ if (memmax == 0)
+ {
+ throw (new NumberFormatException("Not allowing 0"));
+ }
} catch (NumberFormatException e)
{
memmax = MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
- System.out.println("MemorySetting Property '"
+ setAdjustmentMessage("MemorySetting Property '"
+ MAX_HEAPSIZE_PROPERTY_NAME + "' (" + jvmmemmaxarg
- + "') badly formatted, using default ("
- + MAX_HEAPSIZE_GB_DEFAULT + "g).");
- }
-
- // apply multiplier if not too big (i.e. bigger than a long)
- if (Long.MAX_VALUE / memmax < multiplier)
- {
- memmax = MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
- System.out.println("MemorySetting Property '"
- + MAX_HEAPSIZE_PROPERTY_NAME + "' (" + jvmmemmaxarg
- + ") too big, using default (" + MAX_HEAPSIZE_GB_DEFAULT
- + "g).");
- }
- else
- {
- memmax = multiplier * memmax;
+ + "') badly formatted or 0, using default ("
+ + MAX_HEAPSIZE_GB_DEFAULT + "g).", quiet);
}
// check at least minimum value (this accounts for negatives too)
if (memmax < APPLICATION_MIN_MEMORY)
{
memmax = APPLICATION_MIN_MEMORY;
- System.out.println("MemorySetting Property '"
+ setAdjustmentMessage("MemorySetting Property '"
+ MAX_HEAPSIZE_PROPERTY_NAME + "' (" + jvmmemmaxarg
+ ") too small, using minimum (" + APPLICATION_MIN_MEMORY
- + ").");
+ + ").", quiet);
}
}
else
{
// no need to warn if no setting
- // System.out.println("MemorySetting Property '" + maxHeapSizeProperty
+ // adjustmentMessage("MemorySetting Property '" + maxHeapSizeProperty
// + "' not
// set.");
}
// get max percent of physical memory, starting with default
float percent = MAX_HEAPSIZE_PERCENT_DEFAULT;
- if (jvmmempcarg == null)
+ if (jvmmempcarg == null && useProps)
{
jvmmempcarg = System.getProperty(MAX_HEAPSIZE_PERCENT_PROPERTY_NAME);
}
@@ -185,24 +175,24 @@ public class MemorySetting
{
if (jvmmempc != null)
{
- float trypercent = Float.parseFloat(jvmmempc);
- if (0 < trypercent && trypercent <= 100f)
+ int trypercent = Integer.parseInt(jvmmempc);
+ if (0 <= trypercent && trypercent <= 100)
{
percent = trypercent;
}
else
{
- System.out.println("MemorySetting Property '"
+ setAdjustmentMessage("MemorySetting Property '"
+ MAX_HEAPSIZE_PERCENT_PROPERTY_NAME
- + "' should be in range 1..100. Using default " + percent
- + "%");
+ + "' should be in range 0..100. Using default " + percent
+ + "%", quiet);
}
}
} catch (NumberFormatException e)
{
- System.out.println("MemorySetting property '"
+ setAdjustmentMessage("MemorySetting property '"
+ MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' (" + jvmmempcarg
- + ") badly formatted");
+ + ") badly formatted", quiet);
}
// catch everything in case of no com.sun.management.OperatingSystemMXBean
@@ -223,10 +213,10 @@ public class MemorySetting
{
mempc = physicalMem - LEAVE_FREE_MIN_MEMORY;
reducedmempc = true;
- System.out.println("MemorySetting Property '"
+ setAdjustmentMessage("MemorySetting Property '"
+ MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' (" + jvmmempcarg
+ ") too large. Leaving free space for OS and reducing to ("
- + mempc + ").");
+ + mempc + ").", quiet);
}
// check for minimum application memsize
@@ -234,16 +224,16 @@ public class MemorySetting
{
if (reducedmempc)
{
- System.out.println("Reduced MemorySetting (" + mempc
+ setAdjustmentMessage("Reduced MemorySetting (" + mempc
+ ") too small. Increasing to application minimum ("
- + APPLICATION_MIN_MEMORY + ").");
+ + APPLICATION_MIN_MEMORY + ").", quiet);
}
else
{
- System.out.println("MemorySetting Property '"
+ setAdjustmentMessage("MemorySetting Property '"
+ MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' ("
+ jvmmempcarg + ") too small. Using minimum ("
- + APPLICATION_MIN_MEMORY + ").");
+ + APPLICATION_MIN_MEMORY + ").", quiet);
}
mempc = APPLICATION_MIN_MEMORY;
}
@@ -252,19 +242,21 @@ public class MemorySetting
{
// not enough memory for application, just try and grab what we can!
mempc = physicalMem;
- System.out.println(
+ setAdjustmentMessage(
"Not enough physical memory for application. Ignoring MemorySetting Property '"
+ MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' ("
+ jvmmempcarg
+ "). Using maximum memory available ("
- + physicalMem + ").");
+ + physicalMem + ").",
+ quiet);
}
} catch (Throwable t)
{
memoryPercentError = true;
- System.out.println(
- "Problem calling GetMemory.getPhysicalMemory(). Likely to be problem with com.sun.management.OperatingSystemMXBean");
+ setAdjustmentMessage(
+ "Problem calling GetMemory.getPhysicalMemory(). Likely to be problem with com.sun.management.OperatingSystemMXBean",
+ quiet);
t.printStackTrace();
}
@@ -281,9 +273,10 @@ public class MemorySetting
// == null))
&& memmax > NOMEM_MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE)
{
- System.out.println(
+ setAdjustmentMessage(
"Capping maximum memory to " + NOMEM_MAX_HEAPSIZE_GB_DEFAULT
- + "g due to failure to read physical memory size.");
+ + "g due to failure to read physical memory size.",
+ quiet);
memmax = NOMEM_MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
}
@@ -299,4 +292,120 @@ public class MemorySetting
return maxMemLong;
}
+ public static boolean isValidMemoryString(String text)
+ {
+ if (text.length() > 0)
+ {
+ char lastChar = text.charAt(text.length() - 1);
+ char[] otherChars = text.substring(0, text.length() - 1)
+ .toCharArray();
+ for (char c : otherChars)
+ {
+ if (c < '0' || c > '9')
+ {
+ return false;
+ }
+ }
+ if ((lastChar < '0' || lastChar > '9') && memorySuffixes
+ .indexOf(Character.toLowerCase(lastChar)) == -1)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static long memoryStringToLong(String memString)
+ throws NumberFormatException
+ {
+ if (!isValidMemoryString(memString)) // not valid
+ {
+ throw (new NumberFormatException("Not a valid memory string"));
+ }
+ char suffix = Character
+ .toLowerCase(memString.charAt(memString.length() - 1));
+ if ('0' <= suffix && suffix <= '9') // no suffix
+ {
+ return Long.valueOf(memString);
+ }
+ if (memorySuffixes.indexOf(suffix) == -1) // suffix is unknown
+ {
+ return -1;
+ }
+
+ long multiplier = (long) Math.pow(2,
+ memorySuffixes.indexOf(suffix) * 10); // note order of suffixes in
+ // memorySuffixes important
+ // here!
+ // parse the arg. NumberFormatExceptions passed on to calling method
+ long mem = Long
+ .parseLong(memString.substring(0, memString.length() - 1));
+ if (mem == 0)
+ {
+ return 0;
+ }
+
+ // apply multiplier only if result is not too big (i.e. bigger than a long)
+ if (Long.MAX_VALUE / mem > multiplier)
+ {
+ return multiplier * mem;
+ }
+ else
+ {
+ // number too big for a Long. Limit to Long.MAX_VALUE
+ System.out.println("Memory parsing of '" + memString
+ + "' produces number too big. Limiting to Long.MAX_VALUE="
+ + Long.MAX_VALUE);
+ return Long.MAX_VALUE;
+ }
+ }
+
+ public static String memoryLongToString(long mem)
+ {
+ return memoryLongToString(mem, "%.1f");
+ }
+
+ public static String memoryLongToString(long mem, String format)
+ {
+ int exponent = 0;
+ float num = mem;
+ char suffix = 'b';
+
+ for (int i = 0; i < memorySuffixes.length(); i++)
+ {
+ char s = Character.toUpperCase(memorySuffixes.charAt(i));
+ if (mem < (long) Math.pow(2, exponent + 10)
+ || i == memorySuffixes.length() - 1) // last suffix
+ {
+ suffix = s;
+ num = (float) (mem / Math.pow(2, exponent));
+ break;
+ }
+ exponent += 10;
+ }
+
+ return String.format(format, num) + suffix;
+ }
+
+ private static String ADJUSTMENT_MESSAGE = null;
+
+ private static void setAdjustmentMessage(String reason, boolean quiet)
+ {
+ ADJUSTMENT_MESSAGE = reason;
+ if (!quiet)
+ {
+ System.out.println(reason);
+ }
+ }
+
+ public static void clearAdjustmentMessage()
+ {
+ ADJUSTMENT_MESSAGE = null;
+ }
+
+ public static String getAdjustmentMessage()
+ {
+ return ADJUSTMENT_MESSAGE;
+ }
+
}
\ No newline at end of file
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java b/getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java
new file mode 100644
index 0000000..40f6110
--- /dev/null
+++ b/getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java
@@ -0,0 +1,288 @@
+package jalview.util;
+
+import java.awt.Image;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.swing.ImageIcon;
+
+public class ChannelProperties
+{
+
+ public static final String CHANNEL_PROPERTIES_FILENAME = "channel.props";
+
+ private static Properties channelProps;
+
+ private static final Properties defaultProps;
+
+ private static Map imageMap = new HashMap();
+
+ private static Map urlMap = new HashMap();
+
+ private static final ArrayList iconList;
+
+ static
+ {
+ defaultProps = new Properties();
+ // these should be kept up to date, but in real life they should never
+ // actually be used anyway.
+ defaultProps.put("app_name", "Jalview");
+ defaultProps.put("banner", "/default_images/jalview_banner.png");
+ defaultProps.put("logo.16", "/default_images/jalview_logo-16.png");
+ defaultProps.put("logo.32", "/default_images/jalview_logo-32.png");
+ defaultProps.put("logo.38", "/default_images/jalview_logo-38.png");
+ defaultProps.put("logo.48", "/default_images/jalview_logo-48.png");
+ defaultProps.put("logo.64", "/default_images/jalview_logo-64.png");
+ defaultProps.put("logo.128", "/default_images/jalview_logo-128.png");
+ defaultProps.put("logo.256", "/default_images/jalview_logo-256.png");
+ defaultProps.put("logo.512", "/default_images/jalview_logo-512.png");
+ defaultProps.put("rotatable_logo.48",
+ "/default_images/rotatable_jalview_logo-38.png");
+ defaultProps.put("bg_logo.28", "/default_images/barton_group-28.png");
+ defaultProps.put("bg_logo.30", "/default_images/barton_group-30.png");
+ defaultProps.put("bg_logo.32", "/default_images/barton_group-32.png");
+ defaultProps.put("uod_banner.28", "/default_images/UoD_banner-28.png");
+ defaultProps.put("uod_banner.30", "/default_images/UoD_banner-30.png");
+ defaultProps.put("uod_banner.32", "/default_images/UoD_banner-32.png");
+ defaultProps.put("default_appbase",
+ "https://www.jalview.org/getdown/release/1.8");
+ defaultProps.put("preferences.filename", ".jalview_properties");
+
+ // load channel_properties
+ Properties tryChannelProps = new Properties();
+ URL channelPropsURL = ChannelProperties.class
+ .getResource("/" + CHANNEL_PROPERTIES_FILENAME);
+ if (channelPropsURL == null)
+ {
+ // complete failure of channel_properties, set all properties to defaults
+ System.err.println("Failed to find '/" + CHANNEL_PROPERTIES_FILENAME
+ + "' file at '"
+ + (channelPropsURL == null ? "null"
+ : channelPropsURL.toString())
+ + "'. Using class defaultProps.");
+ tryChannelProps = defaultProps;
+ }
+ else
+ {
+ try
+ {
+ InputStream channelPropsIS = channelPropsURL.openStream();
+ tryChannelProps.load(channelPropsIS);
+ channelPropsIS.close();
+ } catch (IOException e)
+ {
+ System.err.println(e.getMessage());
+ // return false;
+ }
+ }
+ channelProps = tryChannelProps;
+
+ /*
+ * The following slight palava for caching an icon list is so that all sizes of icons
+ * are the same. i.e. if there are /any/ channel_properties icons to use, then _only_
+ * use those channel_properties icons, don't mix in class default icons for missing
+ * sizes. If there are _no_ (usable) channel icons then we can use the class default icons.
+ */
+ iconList = new ArrayList();
+ List sizes = Arrays.asList("16", "32", "48", "64", "128", "256",
+ "512");
+ for (String size : sizes)
+ {
+ Image logo = null;
+ // not using defaults or class props first time through
+ logo = ChannelProperties.getImage("logo." + size, null, false);
+ if (logo != null)
+ {
+ iconList.add(logo);
+ }
+ }
+ // now add the class defaults if there were no channel icons defined
+ if (iconList.size() == 0)
+ {
+ for (String size : sizes)
+ {
+ Image logo = null;
+ String path = defaultProps.getProperty("logo." + size);
+ URL imageURL = ChannelProperties.class.getResource(path);
+ ImageIcon imgIcon = imageURL == null ? null
+ : new ImageIcon(imageURL);
+ logo = imgIcon == null ? null : imgIcon.getImage();
+ if (logo != null)
+ {
+ iconList.add(logo);
+ }
+ }
+ }
+ }
+
+ protected static void loadProps(File dir)
+ {
+ File channelPropsFile = new File(dir, CHANNEL_PROPERTIES_FILENAME);
+ if (channelPropsFile.exists())
+ {
+ try
+ {
+ InputStream is = new FileInputStream(channelPropsFile);
+ channelProps.load(is);
+ } catch (FileNotFoundException e)
+ {
+ System.err.println(e.getMessage());
+ } catch (IOException e)
+ {
+ System.err.println(e.getMessage());
+ }
+ }
+ }
+
+ private static Properties channelProps()
+ {
+ return channelProps;
+ }
+
+ private static Map imageMap()
+ {
+ return imageMap;
+ }
+
+ private static Map urlMap()
+ {
+ return urlMap;
+ }
+
+ /*
+ * getProperty(key) will get property value from channel_properties for key.
+ * If no property for key is found, it will fall back to using the defaultProps defined for this class.
+ */
+ public static String getProperty(String key)
+ {
+ return getProperty(key, null, true);
+ }
+
+ /*
+ * getProperty(key, defaultVal) will get property value from channel_properties for key.
+ * If no property for key is found, it will return defaultVal and NOT fall back to the class defaultProps.
+ */
+ public static String getProperty(String key, String defaultVal)
+ {
+ return getProperty(key, defaultVal, false);
+ }
+
+ /*
+ * internal method. note that setting useClassDefaultProps=true will ignore the provided defaultVal
+ */
+ private static String getProperty(String key, String defaultVal,
+ boolean useClassDefaultProps)
+ {
+ if (channelProps() != null)
+ {
+ if (channelProps().containsKey(key))
+ {
+ return channelProps().getProperty(key,
+ useClassDefaultProps ? defaultProps.getProperty(key)
+ : defaultVal);
+ }
+ else
+ {
+ System.err.println("Failed to get channel property '" + key + "'");
+ }
+ }
+ return null;
+ }
+
+ /*
+ * getImage(key) returns the channel defined image for property key. If that is null (e.g. due to
+ * no defined channel image or the image file being corrupt/unusable/missing) it uses the image
+ * defined in defaultChannelProps
+ */
+ public static Image getImage(String key)
+ {
+ return getImage(key, null, true);
+ }
+
+ /*
+ * getImage(key, defaultImg) will get image associated with value from channel_properties for key.
+ * If no property or associated image for key is found (or is usable), it will return defaultImg
+ * and NOT fall back to the class defaultProps.
+ */
+ public static Image getImage(String key, Image defaultImg)
+ {
+ return getImage(key, defaultImg, false);
+ }
+
+ /*
+ * internal method. note that setting useClassDefaultImage=true will ignore the provided defaultImg
+ */
+ private static Image getImage(String key, Image defaultImg,
+ boolean useClassDefaultImage)
+ {
+ Image img = null;
+ if (imageMap().containsKey(key))
+ {
+ img = imageMap().get(key);
+ }
+ // Catch a previously untried or failed load
+ if (img == null)
+ {
+ String path = getProperty(key, null, useClassDefaultImage);
+ if (path == null) // no channel property or class default property (if
+ // requested)
+ {
+ return useClassDefaultImage ? null : defaultImg;
+ }
+
+ URL imageURL = ChannelProperties.class.getResource(path);
+ ImageIcon imgIcon = imageURL == null ? null : new ImageIcon(imageURL);
+ img = imgIcon == null ? null : imgIcon.getImage();
+ if (img == null)
+ {
+ System.err.println(
+ "Failed to load channel image " + key + "=" + path);
+ if (!useClassDefaultImage)
+ {
+ return defaultImg;
+ }
+ }
+ else
+ {
+ imageMap().put(key, img);
+ urlMap.put(key, imageURL);
+ }
+ }
+ return img;
+ }
+
+ /*
+ * Public method to get the URL object pointing to a cached image.
+ */
+ public static URL getImageURL(String key)
+ {
+ if (getImage(key) != null)
+ {
+ if (urlMap().containsKey(key))
+ {
+ return urlMap().getOrDefault(key, null);
+ }
+ System.err.println(
+ "Do not use getImageURL(key) before using getImage(key...)");
+ }
+ return null;
+ }
+
+ /*
+ * Get a List of Icon images of different sizes.
+ */
+ public static ArrayList getIconList()
+ {
+ return iconList;
+ }
+}
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java b/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java
new file mode 100644
index 0000000..3302dba
--- /dev/null
+++ b/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java
@@ -0,0 +1,56 @@
+package jalview.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Properties;
+
+public class LaunchUtils
+{
+
+ public static void loadChannelProps(File dir)
+ {
+ ChannelProperties.loadProps(dir);
+ }
+
+ private static Properties userPreferences = null;
+
+ public static String getUserPreference(String key)
+ {
+ if (userPreferences == null)
+ {
+ String channelPrefsFilename = ChannelProperties
+ .getProperty("preferences.filename");
+ if (channelPrefsFilename == null)
+ {
+ return null;
+ }
+ File propertiesFile = new File(System.getProperty("user.home"),
+ channelPrefsFilename);
+ if (!propertiesFile.exists())
+ {
+ return null;
+ }
+ try
+ {
+ userPreferences = new Properties();
+ userPreferences.load(new FileInputStream(propertiesFile));
+ } catch (FileNotFoundException e)
+ {
+ // didn't find user preferences file
+ return null;
+ } catch (IOException e)
+ {
+ System.err.println(e.getMessage());
+ return null;
+ }
+ }
+ return userPreferences.getProperty(key);
+ }
+
+ public static boolean getBooleanUserPreference(String key)
+ {
+ return Boolean.parseBoolean(getUserPreference(key));
+ }
+}
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/StringUtils.java b/getdown/src/getdown/core/src/main/java/jalview/util/StringUtils.java
new file mode 100644
index 0000000..d758395
--- /dev/null
+++ b/getdown/src/getdown/core/src/main/java/jalview/util/StringUtils.java
@@ -0,0 +1,585 @@
+/*
+ * 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 .
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class StringUtils
+{
+ private static final Pattern DELIMITERS_PATTERN = Pattern
+ .compile(".*='[^']*(?!')");
+
+ private static final char PERCENT = '%';
+
+ private static final boolean DEBUG = false;
+
+ /*
+ * URL encoded characters, indexed by char value
+ * e.g. urlEncodings['='] = urlEncodings[61] = "%3D"
+ */
+ private static String[] urlEncodings = new String[255];
+
+ /**
+ * Returns a new character array, after inserting characters into the given
+ * character array.
+ *
+ * @param in
+ * the character array to insert into
+ * @param position
+ * the 0-based position for insertion
+ * @param count
+ * the number of characters to insert
+ * @param ch
+ * the character to insert
+ */
+ public static final char[] insertCharAt(char[] in, int position,
+ int count, char ch)
+ {
+ char[] tmp = new char[in.length + count];
+
+ if (position >= in.length)
+ {
+ System.arraycopy(in, 0, tmp, 0, in.length);
+ position = in.length;
+ }
+ else
+ {
+ System.arraycopy(in, 0, tmp, 0, position);
+ }
+
+ int index = position;
+ while (count > 0)
+ {
+ tmp[index++] = ch;
+ count--;
+ }
+
+ if (position < in.length)
+ {
+ System.arraycopy(in, position, tmp, index, in.length - position);
+ }
+
+ return tmp;
+ }
+
+ /**
+ * Delete
+ *
+ * @param in
+ * @param from
+ * @param to
+ * @return
+ */
+ public static final char[] deleteChars(char[] in, int from, int to)
+ {
+ if (from >= in.length || from < 0)
+ {
+ return in;
+ }
+
+ char[] tmp;
+
+ if (to >= in.length)
+ {
+ tmp = new char[from];
+ System.arraycopy(in, 0, tmp, 0, from);
+ to = in.length;
+ }
+ else
+ {
+ tmp = new char[in.length - to + from];
+ System.arraycopy(in, 0, tmp, 0, from);
+ System.arraycopy(in, to, tmp, from, in.length - to);
+ }
+ return tmp;
+ }
+
+ /**
+ * Returns the last part of 'input' after the last occurrence of 'token'. For
+ * example to extract only the filename from a full path or URL.
+ *
+ * @param input
+ * @param token
+ * a delimiter which must be in regular expression format
+ * @return
+ */
+ public static String getLastToken(String input, String token)
+ {
+ if (input == null)
+ {
+ return null;
+ }
+ if (token == null)
+ {
+ return input;
+ }
+ String[] st = input.split(token);
+ return st[st.length - 1];
+ }
+
+ /**
+ * Parses the input string into components separated by the delimiter. Unlike
+ * String.split(), this method will ignore occurrences of the delimiter which
+ * are nested within single quotes in name-value pair values, e.g. a='b,c'.
+ *
+ * @param input
+ * @param delimiter
+ * @return elements separated by separator
+ */
+ public static String[] separatorListToArray(String input,
+ String delimiter)
+ {
+ int seplen = delimiter.length();
+ if (input == null || input.equals("") || input.equals(delimiter))
+ {
+ return null;
+ }
+ List jv = new ArrayList<>();
+ int cp = 0, pos, escape;
+ boolean wasescaped = false, wasquoted = false;
+ String lstitem = null;
+ while ((pos = input.indexOf(delimiter, cp)) >= cp)
+ {
+ escape = (pos > 0 && input.charAt(pos - 1) == '\\') ? -1 : 0;
+ if (wasescaped || wasquoted)
+ {
+ // append to previous pos
+ jv.set(jv.size() - 1, lstitem = lstitem + delimiter
+ + input.substring(cp, pos + escape));
+ }
+ else
+ {
+ jv.add(lstitem = input.substring(cp, pos + escape));
+ }
+ cp = pos + seplen;
+ wasescaped = escape == -1;
+ // last separator may be in an unmatched quote
+ wasquoted = DELIMITERS_PATTERN.matcher(lstitem).matches();
+ }
+ if (cp < input.length())
+ {
+ String c = input.substring(cp);
+ if (wasescaped || wasquoted)
+ {
+ // append final separator
+ jv.set(jv.size() - 1, lstitem + delimiter + c);
+ }
+ else
+ {
+ if (!c.equals(delimiter))
+ {
+ jv.add(c);
+ }
+ }
+ }
+ if (jv.size() > 0)
+ {
+ String[] v = jv.toArray(new String[jv.size()]);
+ jv.clear();
+ if (DEBUG)
+ {
+ System.err.println("Array from '" + delimiter
+ + "' separated List:\n" + v.length);
+ for (int i = 0; i < v.length; i++)
+ {
+ System.err.println("item " + i + " '" + v[i] + "'");
+ }
+ }
+ return v;
+ }
+ if (DEBUG)
+ {
+ System.err.println(
+ "Empty Array from '" + delimiter + "' separated List");
+ }
+ return null;
+ }
+
+ /**
+ * Returns a string which contains the list elements delimited by the
+ * separator. Null items are ignored. If the input is null or has length zero,
+ * a single delimiter is returned.
+ *
+ * @param list
+ * @param separator
+ * @return concatenated string
+ */
+ public static String arrayToSeparatorList(String[] list, String separator)
+ {
+ StringBuffer v = new StringBuffer();
+ if (list != null && list.length > 0)
+ {
+ for (int i = 0, iSize = list.length; i < iSize; i++)
+ {
+ if (list[i] != null)
+ {
+ if (v.length() > 0)
+ {
+ v.append(separator);
+ }
+ // TODO - escape any separator values in list[i]
+ v.append(list[i]);
+ }
+ }
+ if (DEBUG)
+ {
+ System.err
+ .println("Returning '" + separator + "' separated List:\n");
+ System.err.println(v);
+ }
+ return v.toString();
+ }
+ if (DEBUG)
+ {
+ System.err.println(
+ "Returning empty '" + separator + "' separated List\n");
+ }
+ return "" + separator;
+ }
+
+ /**
+ * Converts a list to a string with a delimiter before each term except the
+ * first. Returns an empty string given a null or zero-length argument. This
+ * can be replaced with StringJoiner in Java 8.
+ *
+ * @param terms
+ * @param delim
+ * @return
+ */
+ public static String listToDelimitedString(List terms,
+ String delim)
+ {
+ StringBuilder sb = new StringBuilder(32);
+ if (terms != null && !terms.isEmpty())
+ {
+ boolean appended = false;
+ for (String term : terms)
+ {
+ if (appended)
+ {
+ sb.append(delim);
+ }
+ appended = true;
+ sb.append(term);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Convenience method to parse a string to an integer, returning 0 if the
+ * input is null or not a valid integer
+ *
+ * @param s
+ * @return
+ */
+ public static int parseInt(String s)
+ {
+ int result = 0;
+ if (s != null && s.length() > 0)
+ {
+ try
+ {
+ result = Integer.parseInt(s);
+ } catch (NumberFormatException ex)
+ {
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Compares two versions formatted as e.g. "3.4.5" and returns -1, 0 or 1 as
+ * the first version precedes, is equal to, or follows the second
+ *
+ * @param v1
+ * @param v2
+ * @return
+ */
+ public static int compareVersions(String v1, String v2)
+ {
+ return compareVersions(v1, v2, null);
+ }
+
+ /**
+ * Compares two versions formatted as e.g. "3.4.5b1" and returns -1, 0 or 1 as
+ * the first version precedes, is equal to, or follows the second
+ *
+ * @param v1
+ * @param v2
+ * @param pointSeparator
+ * a string used to delimit point increments in sub-tokens of the
+ * version
+ * @return
+ */
+ public static int compareVersions(String v1, String v2,
+ String pointSeparator)
+ {
+ if (v1 == null || v2 == null)
+ {
+ return 0;
+ }
+ String[] toks1 = v1.split("\\.");
+ String[] toks2 = v2.split("\\.");
+ int i = 0;
+ for (; i < toks1.length; i++)
+ {
+ if (i >= toks2.length)
+ {
+ /*
+ * extra tokens in v1
+ */
+ return 1;
+ }
+ String tok1 = toks1[i];
+ String tok2 = toks2[i];
+ if (pointSeparator != null)
+ {
+ /*
+ * convert e.g. 5b2 into decimal 5.2 for comparison purposes
+ */
+ tok1 = tok1.replace(pointSeparator, ".");
+ tok2 = tok2.replace(pointSeparator, ".");
+ }
+ try
+ {
+ float f1 = Float.valueOf(tok1);
+ float f2 = Float.valueOf(tok2);
+ int comp = Float.compare(f1, f2);
+ if (comp != 0)
+ {
+ return comp;
+ }
+ } catch (NumberFormatException e)
+ {
+ System.err
+ .println("Invalid version format found: " + e.getMessage());
+ return 0;
+ }
+ }
+
+ if (i < toks2.length)
+ {
+ /*
+ * extra tokens in v2
+ */
+ return -1;
+ }
+
+ /*
+ * same length, all tokens match
+ */
+ return 0;
+ }
+
+ /**
+ * Converts the string to all lower-case except the first character which is
+ * upper-cased
+ *
+ * @param s
+ * @return
+ */
+ public static String toSentenceCase(String s)
+ {
+ if (s == null)
+ {
+ return s;
+ }
+ if (s.length() <= 1)
+ {
+ return s.toUpperCase();
+ }
+ return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
+ }
+
+ /**
+ * A helper method that strips off any leading or trailing html and body tags.
+ * If no html tag is found, then also html-encodes angle bracket characters.
+ *
+ * @param text
+ * @return
+ */
+ public static String stripHtmlTags(String text)
+ {
+ if (text == null)
+ {
+ return null;
+ }
+ String tmp2up = text.toUpperCase();
+ int startTag = tmp2up.indexOf("");
+ if (startTag > -1)
+ {
+ text = text.substring(startTag + 6);
+ tmp2up = tmp2up.substring(startTag + 6);
+ }
+ // is omission of "" intentional here??
+ int endTag = tmp2up.indexOf("");
+ if (endTag > -1)
+ {
+ text = text.substring(0, endTag);
+ tmp2up = tmp2up.substring(0, endTag);
+ }
+ endTag = tmp2up.indexOf("");
+ if (endTag > -1)
+ {
+ text = text.substring(0, endTag);
+ }
+
+ if (startTag == -1 && (text.contains("<") || text.contains(">")))
+ {
+ text = text.replaceAll("<", "<");
+ text = text.replaceAll(">", ">");
+ }
+ return text;
+ }
+
+ /**
+ * Answers the input string with any occurrences of the 'encodeable'
+ * characters replaced by their URL encoding
+ *
+ * @param s
+ * @param encodable
+ * @return
+ */
+ public static String urlEncode(String s, String encodable)
+ {
+ if (s == null || s.isEmpty())
+ {
+ return s;
+ }
+
+ /*
+ * do % encoding first, as otherwise it may double-encode!
+ */
+ if (encodable.indexOf(PERCENT) != -1)
+ {
+ s = urlEncode(s, PERCENT);
+ }
+
+ for (char c : encodable.toCharArray())
+ {
+ if (c != PERCENT)
+ {
+ s = urlEncode(s, c);
+ }
+ }
+ return s;
+ }
+
+ /**
+ * Answers the input string with any occurrences of {@code c} replaced with
+ * their url encoding. Answers the input string if it is unchanged.
+ *
+ * @param s
+ * @param c
+ * @return
+ */
+ static String urlEncode(String s, char c)
+ {
+ String decoded = String.valueOf(c);
+ if (s.indexOf(decoded) != -1)
+ {
+ String encoded = getUrlEncoding(c);
+ if (!encoded.equals(decoded))
+ {
+ s = s.replace(decoded, encoded);
+ }
+ }
+ return s;
+ }
+
+ /**
+ * Answers the input string with any occurrences of the specified (unencoded)
+ * characters replaced by their URL decoding.
+ *
+ * Example: {@code urlDecode("a%3Db%3Bc", "-;=,")} should answer
+ * {@code "a=b;c"}.
+ *
+ * @param s
+ * @param encodable
+ * @return
+ */
+ public static String urlDecode(String s, String encodable)
+ {
+ if (s == null || s.isEmpty())
+ {
+ return s;
+ }
+
+ for (char c : encodable.toCharArray())
+ {
+ String encoded = getUrlEncoding(c);
+ if (s.indexOf(encoded) != -1)
+ {
+ String decoded = String.valueOf(c);
+ s = s.replace(encoded, decoded);
+ }
+ }
+ return s;
+ }
+
+ /**
+ * Does a lazy lookup of the url encoding of the given character, saving the
+ * value for repeat lookups
+ *
+ * @param c
+ * @return
+ */
+ private static String getUrlEncoding(char c)
+ {
+ if (c < 0 || c >= urlEncodings.length)
+ {
+ return String.valueOf(c);
+ }
+
+ String enc = urlEncodings[c];
+ if (enc == null)
+ {
+ try
+ {
+ enc = urlEncodings[c] = URLEncoder.encode(String.valueOf(c),
+ "UTF-8");
+ } catch (UnsupportedEncodingException e)
+ {
+ enc = urlEncodings[c] = String.valueOf(c);
+ }
+ }
+ return enc;
+ }
+
+ public static int firstCharPosIgnoreCase(String text, String chars)
+ {
+ int min = text.length() + 1;
+ for (char c : chars.toLowerCase().toCharArray())
+ {
+ int i = text.toLowerCase().indexOf(c);
+ if (0 <= i && i < min)
+ {
+ min = i;
+ }
+ }
+ return min < text.length() + 1 ? min : -1;
+ }
+}
diff --git a/getdown/src/getdown/launcher/pom.xml b/getdown/src/getdown/launcher/pom.xml
index b5e68f2..5284412 100644
--- a/getdown/src/getdown/launcher/pom.xml
+++ b/getdown/src/getdown/launcher/pom.xml
@@ -4,7 +4,7 @@
com.threerings.getdown
getdown
- 1.8.3-1.2.10_FJVL
+ 1.8.3-1.2.11_FJVL
getdown-launcher
diff --git a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyPanel.java b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyPanel.java
index 2178273..5d697df 100644
--- a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyPanel.java
+++ b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyPanel.java
@@ -40,6 +40,12 @@ public final class ProxyPanel extends JPanel implements ActionListener
_getdown = getdown;
_msgs = msgs;
+ String[] hostPortAuthUser = ProxyUtil.jalviewProxyProperties(getdown._app);
+ String host = hostPortAuthUser[0];
+ String port = hostPortAuthUser[1];
+ boolean proxyAuth = Boolean.parseBoolean(hostPortAuthUser[2]);
+ String username = hostPortAuthUser[3];
+
setLayout(new VGroupLayout());
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
add(new SaneLabelField(get("m.configure_proxy")));
@@ -48,11 +54,13 @@ public final class ProxyPanel extends JPanel implements ActionListener
JPanel row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_host")), BorderLayout.WEST);
row.add(_host = new SaneTextField());
+ _host.setText(host);
add(row);
row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_port")), BorderLayout.WEST);
row.add(_port = new SaneTextField());
+ _port.setText(port);
add(row);
add(new Spacer(5, 5));
@@ -60,20 +68,22 @@ public final class ProxyPanel extends JPanel implements ActionListener
row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_auth_required")), BorderLayout.WEST);
_useAuth = new JCheckBox();
+ _useAuth.setSelected(proxyAuth);
row.add(_useAuth);
add(row);
row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_username")), BorderLayout.WEST);
_username = new SaneTextField();
- _username.setEnabled(false);
+ _username.setText(username);
+ _username.setEnabled(_useAuth.isSelected());
row.add(_username);
add(row);
row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_password")), BorderLayout.WEST);
_password = new SanePasswordField();
- _password.setEnabled(false);
+ _password.setEnabled(_useAuth.isSelected());
row.add(_password);
add(row);
diff --git a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyUtil.java b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyUtil.java
index a36b5fa..cb51ca4 100644
--- a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyUtil.java
+++ b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyUtil.java
@@ -6,8 +6,10 @@
package com.threerings.getdown.launcher;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
@@ -19,6 +21,8 @@ import java.net.URLConnection;
import java.util.Iterator;
import java.util.ServiceLoader;
+import jalview.util.LaunchUtils;
+
import ca.beq.util.win32.registry.RegistryKey;
import ca.beq.util.win32.registry.RegistryValue;
import ca.beq.util.win32.registry.RootKey;
@@ -88,15 +92,43 @@ public class ProxyUtil {
port = hostPort[1];
}
+ // look in jalview_properties
+ String[] hostPortAuthUser = jalviewProxyProperties(app);
+ host = hostPortAuthUser[0];
+ port = hostPortAuthUser[1];
+ boolean proxyAuth = Boolean.parseBoolean(hostPortAuthUser[2]);
+ String username = hostPortAuthUser[3];
+
if (StringUtil.isBlank(host)) {
return false;
}
// yay, we found a proxy configuration, configure it in the app
- initProxy(app, host, port, null, null);
+ initProxy(app, host, port, username, null);
return true;
}
+ public static String[] jalviewProxyProperties(Application app) {
+ String host = null;
+ String port = null;
+ boolean proxyAuth = false;
+ String username = null;
+ LaunchUtils.loadChannelProps(app.getAppDir());
+ if (LaunchUtils.getBooleanUserPreference("USE_PROXY")) {
+ host = LaunchUtils.getUserPreference("PROXY_SERVER_HTTPS");
+ port = LaunchUtils.getUserPreference("PROXY_PORT_HTTPS");
+ if (StringUtil.isBlank(host)) {
+ host = LaunchUtils.getUserPreference("PROXY_SERVER");
+ port = LaunchUtils.getUserPreference("PROXY_PORT");
+ }
+ proxyAuth = LaunchUtils.getBooleanUserPreference("PROXY_AUTH");
+ if (proxyAuth) {
+ username = LaunchUtils.getUserPreference("PROXY_AUTH_USERNAME");
+ }
+ }
+ return new String[]{ host, port, String.valueOf(proxyAuth), username };
+ }
+
public static boolean canLoadWithoutProxy (URL rurl)
{
log.info("Testing whether proxy is needed, via: " + rurl);
@@ -179,6 +211,7 @@ public class ProxyUtil {
public static void initProxy (Application app, String host, String port,
String username, String password)
{
+System.out.println("**** initProxy(app, '"+host+"', "+port+", '"+username+"', "+(password==null?"null":"*x"+password.length())+")");
// check whether we have saved proxy credentials
String appDir = app.getAppDir().getAbsolutePath();
ServiceLoader loader = ServiceLoader.load(ProxyAuth.class);
diff --git a/getdown/src/getdown/mvn_cmd b/getdown/src/getdown/mvn_cmd
index 65e5fb9..4ffb086 100755
--- a/getdown/src/getdown/mvn_cmd
+++ b/getdown/src/getdown/mvn_cmd
@@ -3,7 +3,7 @@
if [ x$JVLVERSION != x ]; then
export VERSION=$JVLVERSION
else
- export VERSION=1.8.3-1.2.10_JVL
+ export VERSION=1.8.3-1.2.11_JVL
fi
if [ x${VERSION%_JVL} = x$VERSION ]; then
diff --git a/getdown/src/getdown/pom.xml b/getdown/src/getdown/pom.xml
index 7a0fd27..61b1440 100644
--- a/getdown/src/getdown/pom.xml
+++ b/getdown/src/getdown/pom.xml
@@ -10,7 +10,7 @@
com.threerings.getdown
getdown
pom
- 1.8.3-1.2.10_FJVL
+ 1.8.3-1.2.11_FJVL
getdown
An application installer and updater.
diff --git a/gradle.properties b/gradle.properties
index d0fb57d..21360df 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -100,8 +100,8 @@ getdown_alt_java8_min_version = 01080000
getdown_alt_java8_max_version = 01089999
getdown_alt_java11_min_version = 11000000
getdown_alt_java11_max_version =
-#getdown_alt_java11_txt_multi_java_location = [windows-amd64] /getdown/jre/windows-jre11.jar,[linux-amd64] /getdown/jre/linux-jre11.tgz,[mac os x] /getdown/jre/macos-jre11.tgz
-#getdown_alt_java8_txt_multi_java_location = [windows-amd64] /getdown/jre/windows-jre1.8.tgz,[linux-amd64] /getdown/jre/linux-jre1.8.tgz,[mac os x] /getdown/jre/macos-jre1.8.tgz
+#getdown_alt_java11_txt_multi_java_location = [windows-amd64] /getdown/jre/jre-11-windows-x64.zip,[linux-amd64] /getdown/jre/jre-11-linux-x64.zip,[mac os x] /getdown/jre/jre-11-mac-x64.zip
+#getdown_alt_java8_txt_multi_java_location = [windows-amd64] /getdown/jre/jre-8-windows-x64.zip,[linux-amd64] /getdown/jre/jre-8-linux-x64.zip,[mac os x] /getdown/jre/jre-8-mac-x64.zip
jre_installs_dir = ~/buildtools/jre
j8libDir = j8lib
@@ -112,6 +112,7 @@ j11modules = com.sun.istack.runtime,com.sun.xml.bind,com.sun.xml.fastinfoset,com
flexmark_css = utils/doc/github.css
channel_properties_dir = utils/channels
+channel_props = channel.props
install4j_home_dir = ~/buildtools/install4j8
install4j_copyright_message = ...
diff --git a/help/help/help.jhm b/help/help/help.jhm
index 7dbb76d..449f34c 100755
--- a/help/help/help.jhm
+++ b/help/help/help.jhm
@@ -55,6 +55,7 @@
+
diff --git a/help/help/helpTOC.xml b/help/help/helpTOC.xml
index a72f5ac..9f1942c 100755
--- a/help/help/helpTOC.xml
+++ b/help/help/helpTOC.xml
@@ -131,9 +131,10 @@
-
+
-
+
+
diff --git a/help/help/html/features/3dbeacons_button.png b/help/help/html/features/3dbeacons_button.png
new file mode 100644
index 0000000..2dae1f6
Binary files /dev/null and b/help/help/html/features/3dbeacons_button.png differ
diff --git a/help/help/html/features/3dbeacons_structurechooser.png b/help/help/html/features/3dbeacons_structurechooser.png
new file mode 100644
index 0000000..cd7fdab
Binary files /dev/null and b/help/help/html/features/3dbeacons_structurechooser.png differ
diff --git a/help/help/html/features/3dstructuredata_popupmenu.png b/help/help/html/features/3dstructuredata_popupmenu.png
new file mode 100644
index 0000000..e5de4ca
Binary files /dev/null and b/help/help/html/features/3dstructuredata_popupmenu.png differ
diff --git a/help/help/html/features/chimera.html b/help/help/html/features/chimera.html
index e1227de..eadfa06 100644
--- a/help/help/html/features/chimera.html
+++ b/help/help/html/features/chimera.html
@@ -24,13 +24,14 @@
- The Chimera Viewer
+ The Chimera and ChimeraX Viewers
Since Jalview 2.8.2, Chimera
(http://www.cgl.ucsf.edu/chimera/) can be used for viewing
structures opened via the "View
- Structure Data.." dialog.
+ Structure Data.." dialog. In Jalview 2.11.2, support
+ was also added for ChimeraX.
You can set a default choice of Jmol or Chimera structure viewer in
diff --git a/help/help/html/features/pymol.html b/help/help/html/features/pymol.html
new file mode 100644
index 0000000..061434f
--- /dev/null
+++ b/help/help/html/features/pymol.html
@@ -0,0 +1,234 @@
+
+
+
+The Pymol PDB Viewer
+
+
+
+ The Pymol Viewer
+
+
+ In Jalview 2.11.2, support was added for Pymol
+ (https://pymol.org/2/) to be used for viewing
+ structures opened via the "View
+ Structure Data.." dialog.
+
+
+ You can configure Pymol as your preferred structure viewer in
+ Preferences. You can also
+ optionally specify the path to the Pymol program here (if it differs
+ from the standard paths searched by Jalview).
Jalview
+ requires Pymol's RPC interface, which is not available in older
+ versions of the Pymol community edition.
Please make sure your
+ version of Pymol is up to date.
+
+
+
+ If you save your Jalview session as a project file, the state of any
+ open Pymol windows will also be saved, and can be reopened by
+ loading the project file on any machine with Pymol installed.
+
+
+ Known Limitations
Jalview provides an easy way
+ to employ Pymol for linked analysis of sequences and structures in the
+ same way as Chimera and ChimeraX. There are
+ some limitations, however:
+
+
+ - Pymol does not support some forms of legacy structural data
+ (e.g. the 1A70 C-alpha only PDB file included in the Jalview example
+ project).
+ - Pymol to Jalview communication does not support transfer of
+ properties or highlighting sequence regions corresponding to
+ structure selections or mouse-overs in Pymol.
+
+
+ Basic screen operations (see Pymol Wiki at
+ https://pymol.org/dokuwiki/doku.php?id=mouse
+ for full details).
+
+
+ Action |
+ Windows |
+ Unix |
+ Mac/OSX |
+
+
+ Rotate View |
+ Left Click and Drag |
+ Left Click and Drag |
+ Left Click and Drag |
+
+
+ Zoom |
+ Right Click drag mouse up or down
+ |
+ Right Click drag mouse up or down
+ |
+ cmd or Right + Click and drag mouse up or down, or
+ use mouse scroll button
+ |
+
+
+ Move Origin |
+ Middle Button + Drag |
+ Middle Button and drag |
+ alt + Click and drag
+ |
+
+
+ Select Residues |
+ Ctrl + Click (and drag to select a region) |
+ Ctrl + Click (and drag) |
+ Ctrl + Click (and drag) |
+
+
+
+
+ Jalview Controls
+
The Jalview Pymol View window has up to five menus:
+
+ - File
+
+
+ - View Mapping
+ Opens a text window showing the alignment between the
+ residues corresponding to alpha-carbon atoms in the PDB
+ structure and the residues in the associated sequence.
+
+ - View
+
+ - Show Chains
+ Select which of the PDB file's chains (if more than
+ one) are to be displayed.
+ - Colour by ..
Submenu
+ allowing specific alignment views to be selected for
+ colouring associated chains in the structure display. This
+ menu contains all the alignment views associated with the
+ structure view, with those used to colour the view indicated
+ by ticks. Addditionally, it contains the following menu
+ entries:
+
+ - Select many views
When
+ this option is enabled, selecting an alignment view adds
+ it to the set used to colour the structures. Use this
+ when colouring structures related to a number of
+ alignments involving different domains or chains which
+ are shown in the same structure view.
+ - Select all views
This
+ is only enabled when Select many views
+ is also enabled, and will add all associated views to
+ the set used to colour the structure display.
+ - Invert selection
This
+ is only enabled when Select many views
+ is also enabled, and will replace the current set of
+ views with any remaining views not currently used to
+ colour the structure display.
+
+
+ - Colours
+
+
+ - By Sequence
+ Colours each residue in the structure with the colour
+ of its corresponding residue in the associated sequence as
+ rendered in the associated alignment views, including any
+ UniProt sequence features or region colourings.
Pick
+ which of the associated alignment views are used to colour
+ the structures using the View→Colour
+ by .. sub menu.
+
Residues which only exist in the PDB structure are
+ coloured white if they are insertions (relative to the
+ associated sequence in the alignment) and grey if they are N
+ or C terminal flanks outside the region mapped to the
+ alignment window's sequence.
+ - By Chain
+ Uses Pymol's 'spectrum(chain)' command to apply a
+ different colour to each chain.
+ - Charge & Cysteine
+ Highlights cysteines in yellow, anionic (Aspartic Acid
+ or Glutamic Acid) residues in red, and cationic (Lysine or
+ Arginine) residues in blue.
+ - Colour with Pymol
Defers
+ any colouring operations to Pymol. Select this if you want
+ to use the Pymol scripting interface or menu to modify the
+ view directly.
+ - Standard and User Defined Jalview
+ colourschemes.
+ The remaining entries apply the colourschemes available
+ from the standard and user defined amino acid
+ colours.
+
+
+ - Pymol
+ This pulldown menu provides access to Pymol's capabilities from Jalview.
+
+ - Align
+ When selected, the associated alignment will be used to
+ superimpose all the structures in the view onto the first
+ structure in the alignment. The regions used to calculate
+ the superposition will be highlighted using the 'Cartoon'
+ rendering style, and the remaining data shown as a chain
+ trace.
+
+
+ - Write Jalview
+ features
Selecting this option will create
+ new atom properties for any features currently visible in
+ the associated alignment views. This allows those atoms to
+ be selected and analysed in Pymol directly.
+
+ - Feature transfer in Pymol is experimental.
- To select by a particular feature use the string matching syntax:
+ select foo,p.jv_helix in helix
+
+ - To view transferred properties use Pymol's Properties Inspector
-
+ For more information see Property based selection in Pymol's Documentation.
+
+
+
+
+ - Help
+
+
+ - Pymol Help
+ Access the Pymol Help documentation in a new browser window.
+ window.
+
+
+
+ Pymol and Windows Firewall
+
+ Jalview and Pymol communicate using the Pymol's XML-RPC over HTTP interface(https://pymolwiki.org/index.php/RPC).
+
+
Technically this requires both Pymol and Jalview to open
+ ports on the local network, and this may be blocked by Windows
+ Firewall with a warning message such as
+
"Windows Firewall has blocked some features of this program"
+ (where the program may be java.exe or javaw.exe).
+
To allow Jalview and Pymol to interact, you may need to add
+ permission for the program to communicate over the network. This can
+ be done from the warning dialogue, or in Control Panel, Firewall
+ settings.
+
+
diff --git a/help/help/html/features/schooser_main.png b/help/help/html/features/schooser_main.png
index ca793fd..07a1a3c 100644
Binary files a/help/help/html/features/schooser_main.png and b/help/help/html/features/schooser_main.png differ
diff --git a/help/help/html/features/schooser_viewbutton.png b/help/help/html/features/schooser_viewbutton.png
new file mode 100644
index 0000000..f14481e
Binary files /dev/null and b/help/help/html/features/schooser_viewbutton.png differ
diff --git a/help/help/html/features/selectfetchdb.gif b/help/help/html/features/selectfetchdb.gif
index de0a7e6..6103b31 100644
Binary files a/help/help/html/features/selectfetchdb.gif and b/help/help/html/features/selectfetchdb.gif differ
diff --git a/help/help/html/features/seqfetch.html b/help/help/html/features/seqfetch.html
index 4e9a75f..7d4a389 100755
--- a/help/help/html/features/seqfetch.html
+++ b/help/help/html/features/seqfetch.html
@@ -38,7 +38,7 @@
the database you want to retrieve sequences from the database
chooser.
-
The databases are shown as a tree, and ordered alphabetically;
@@ -69,7 +69,10 @@
accession ids (as a semi-colon separated list), or press the
"Example" button to paste the example accession for the
currently selected database into the retrieval box. Finally, press
- "OK" to initiate the retrieval.
+ "OK" to initiate the retrieval.
+
+ For the PDB and UniProt sequence fetchers, choose the "Retrieve IDs" tab
+ to search for accession ids.
If you use the Sequence Fetcher, please remember to cite the
diff --git a/help/help/html/features/seqfetcher.gif b/help/help/html/features/seqfetcher.gif
index 03ddd79..6b9ff21 100644
Binary files a/help/help/html/features/seqfetcher.gif and b/help/help/html/features/seqfetcher.gif differ
diff --git a/help/help/html/features/structurechooser.html b/help/help/html/features/structurechooser.html
index 785c429..11cad6b 100644
--- a/help/help/html/features/structurechooser.html
+++ b/help/help/html/features/structurechooser.html
@@ -32,8 +32,11 @@
The Structure Chooser allows you to select
3D structures to view for the currently selected set of
sequences. It is opened by selecting the "3D
- Structure Data..." option from the Sequence ID panel's pop-up menu. The dialog
+ Structure Data..." option from the Sequence ID panel's
+ pop-up menu.
+
+
+ The dialog
provides:
@@ -69,6 +72,9 @@
associated with the sequence. It does this based on the sequence's
ID string, and any other associated database IDs.
+ Since Jalview 2.11.2, you can also initiate a search
+ of the 3D-Beacons Network.
+
Viewing existing
structures for your sequences
@@ -86,7 +92,7 @@
Jalview can automatically select the best structures according
to meta-data provided by the PDB. For alignments with no existing
- structure data, the 'Best Quality' structure for each sequence will
+ structure data, the 'PDBe Best Quality' structure for each sequence will
by default be selected, but clicking on the drop down menu allows
other criteria to be chosen, including Resolution (only defined for
X-Ray structures), Highest Protein Chain etc. When 'Invert' is
@@ -103,7 +109,39 @@
The screenshot above shows the Structure Chooser displayed after
selecting all the sequences in the Jalview example project. If no
structures were auto-discovered, options for manually associating
- PDB records will be shown (see below).
+ PDB records will be shown (see below).
+
+
+ 3D-Beacons Network Search
+
+
+ To initiate a search of the 3D-Beacons Network—which searches
+ across experimentally determined and predicted structure models from
+ several resources including PDBe, AlphaFold DB, SWISS-MODEL, PED, SASDB, Genome3D and
+ PDBe-KB—click on the 3D-Beacons Search button at the top of the
+ Structure Chooser window.
+
+
+
+ The 3D-Beacons Network search requires UniProt references and Jalview will ask
+ to attempt to fetch these references for the selected sequences.
+ UniProt references might not always be found in which case you can revert to the PDB
+ search.
+
+
+
+ If structures are found through the 3D-Beacons network you can filter which structures
+ are shown using the drop-down filter at the top of the Structure Chooser window.
+
+ You can view information about each related model, such as the resource providing
+ each model, in the columns displayed. You can sort the list of models by clicking on
+ column headings.
+
+ Select and view the structures in the usual way using the open structure options at
+ the bottom of the Structure Chooser window.
+
+
+
Exploration of meta-data for available structures
Information on each structure available is displayed in columns
@@ -135,4 +173,4 @@
2.9.
-