From: Renia Correya Date: Tue, 3 Sep 2024 10:37:49 +0000 (+0530) Subject: Resolved merge conflicts from develop into JAL-4386 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=bd2650d414b4687c32f580751fc0de7f65f8d1f3;p=jalview.git Resolved merge conflicts from develop into JAL-4386 --- diff --git a/build.gradle b/build.gradle index 3625ffc..b9b3ad9 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,6 @@ buildscript { dependencies { classpath "com.vladsch.flexmark:flexmark-all:0.62.0" classpath "org.jsoup:jsoup:1.14.3" - classpath "com.eowise:gradle-imagemagick:0.5.1" classpath 'ru.vyarus:gradle-use-python-plugin:4.0.0' } } @@ -61,7 +60,6 @@ plugins { } repositories { - jcenter() mavenCentral() mavenLocal() } @@ -2313,7 +2311,7 @@ task getdownWebsiteBuild() { } getdownWebsiteResourceFilenames += file(channelPropsFile).getName() - // set some getdownTxt_ properties then go through all properties looking for getdownTxt_... + // set some getdownTxt_ properties then go through all properties looking for getdown_txt_... def props = project.properties.sort { it.key } if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) { props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion) @@ -2387,8 +2385,15 @@ task getdownWebsiteBuild() { into getdownResourceDir } } - - def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ] + + def getdownWrapperScripts = [ + getdown_bash_wrapper_script, + getdown_powershell_wrapper_script, + getdown_bash_update_script, + getdown_powershell_update_script, + ] + def run_powershell = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${getdown_run_powershell}" ) + def run_other_script = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${getdown_run_other_script}" ) getdownWrapperScripts.each{ script -> def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" ) if (s.exists()) { @@ -2398,6 +2403,31 @@ task getdownWebsiteBuild() { } getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${script}" } + def ext = script.toLowerCase(Locale.ROOT).substring(script.lastIndexOf(".") + 1) + if ("ps1".equals(ext)) { + def base = script.take(script.lastIndexOf(".")) + def newbase = "update".equals(base) ? "${install4jUnixApplicationFolder}_update" : install4jUnixApplicationFolder + if (!newbase.equals(base)) { + copy { + from run_other_script + rename(run_other_script.getName(), "${newbase}.${ext}") + into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}" + getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${newbase}.${ext}" + filter(ReplaceTokens, + beginToken: '__', + endToken: '__', + tokens: [ + 'OTHERSCRIPT': script + ] + ) } + } + copy { + from run_powershell + rename(run_powershell.getName(), "${newbase}.bat") + into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}" + getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${newbase}.bat" + } + } } def codeFiles = [] @@ -2924,9 +2954,52 @@ task install4jCustomiseDS_Store { dependsOn install4jCustomiseDS_StoreAarch64 } +task install4jDMGVmoptionsFile(type: Copy) { + def inputDir = "${jalviewDir}/${install4j_utils_dir}" + def outputDir = "${jalviewDir}/${install4j_build_dir}/tmp" + + def installDateTime = getDate("yyyy-MM-dd HH:mm:ss") + " (build time)" + + from(inputDir) { + include(string("${install4j_default_vmoptions}")) + rename(string("${install4j_default_vmoptions}"), string("${install4j_default_vmoptions}.X64")) + + filter(ReplaceTokens, + beginToken: '__', + endToken: '__', + tokens: [ + 'INSTALLERFILENAME': string("${install4jmacOSArchiveX64DMGFilename}.dmg"), + 'INSTALLDATETIME': installDateTime + ] + ) + + } + + from(inputDir) { + include(string("${install4j_default_vmoptions}")) + rename(string("${install4j_default_vmoptions}"), string("${install4j_default_vmoptions}.AARCH64")) + + filter(ReplaceTokens, + beginToken: '__', + endToken: '__', + tokens: [ + 'INSTALLERFILENAME': string("${install4jmacOSArchiveAarch64DMGFilename}.dmg"), + 'INSTALLDATETIME': installDateTime + ] + ) + } + + into outputDir + + inputs.file("${inputDir}/${install4j_default_vmoptions}") + outputs.file("${outputDir}/${install4j_default_vmoptions}.X64") + outputs.file("${outputDir}/${install4j_default_vmoptions}.AARCH64") +} + task install4jDMGProcesses { dependsOn install4jDMGBackgroundImageProcess dependsOn install4jCustomiseDS_Store + dependsOn install4jDMGVmoptionsFile } task installerFiles(type: com.install4j.gradle.Install4jTask) { @@ -2981,7 +3054,8 @@ task installerFiles(type: com.install4j.gradle.Install4jTask) { 'WRAPPER_LINK': getdownWrapperLink, 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script, 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script, - 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script, + 'BASH_UPDATE_SCRIPT': getdown_bash_update_script, + 'POWERSHELL_UPDATE_SCRIPT': getdown_powershell_update_script, 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir, 'MACOSARCHIVE_X64_NAME': install4jmacOSArchiveX64Name, 'MACOSARCHIVE_AARCH64_NAME': install4jmacOSArchiveAarch64Name, @@ -2993,7 +3067,7 @@ task installerFiles(type: com.install4j.gradle.Install4jTask) { 'GETDOWN_ALT_DIR': getdown_app_dir_alt, 'GETDOWN_INSTALL_DIR': getdown_install_dir, 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations, - 'BUILD_DIR': install4jBuildDir, + 'BUILD_DIR': install4j_build_dir, 'APPLICATION_CATEGORIES': install4j_application_categories, 'APPLICATION_FOLDER': install4jApplicationFolder, 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder, @@ -3010,6 +3084,7 @@ task installerFiles(type: com.install4j.gradle.Install4jTask) { 'INSTALLER_ICON': "${getdownImagesDir}/${install4j_installer_icon}", 'INSTALLER_MAC_ICON': "${getdownImagesDir}/${install4j_installer_mac_icon}", 'INSTALLER_WINDOWS_ICON': "${getdownImagesDir}/${install4j_installer_windows_icon}", + 'TITLE_ICON': "${getdownImagesDir}/${install4j_title_icon}", 'LOG_FILE': "${install4jUnixApplicationFolder}.log", ] diff --git a/getdown/lib/FJVL_VERSION b/getdown/lib/FJVL_VERSION index 9a27132..3e5faf8 100644 --- a/getdown/lib/FJVL_VERSION +++ b/getdown/lib/FJVL_VERSION @@ -1 +1 @@ -1.8.3-1.5.0_FJVL +1.8.3-1.5.3_FJVL diff --git a/getdown/lib/JVL_VERSION b/getdown/lib/JVL_VERSION index 5446e8b..32c1fa5 100644 --- a/getdown/lib/JVL_VERSION +++ b/getdown/lib/JVL_VERSION @@ -1 +1 @@ -1.8.3-1.5.0_JVL +1.8.3-1.5.3_JVL diff --git a/getdown/lib/getdown-core.jar b/getdown/lib/getdown-core.jar index 124cf70..652c6c4 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 45ae248..a393030 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 0057e24..faaba1e 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 95aea5a..ff88d94 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.5.0_FJVL + 1.8.3-1.5.3_FJVL getdown-ant diff --git a/getdown/src/getdown/core/pom.xml b/getdown/src/getdown/core/pom.xml index 6cd52f7..8a80df5 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.5.0_FJVL + 1.8.3-1.5.3_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 12c2b64..19f4030 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 @@ -23,8 +23,8 @@ import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.security.*; import java.security.cert.Certificate; -import java.util.*; import java.util.concurrent.*; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; @@ -1092,7 +1092,7 @@ public class Application args.add("-Dlauncher.version=" + Build.version()); addSystemPropertyIfNotNull(args, "installer.appdir"); // add the marker indicating the app is running in getdown - args.add("-D" + Properties.GETDOWN + "=true"); + args.add("-D" + com.threerings.getdown.data.Properties.GETDOWN + "=true"); args.add("-Dsys.install4jVersion=" + Application.i4jVersion); addSystemPropertyIfNotNull(args, "installer.template_version"); addSystemPropertyIfNotNull(args, "installer.logfile"); @@ -2139,6 +2139,27 @@ public class Application } } + final String installerPropsFilename = "installer.properties"; + log.info("Creating " + installerPropsFilename); + java.util.Properties installerProps = new java.util.Properties(); + installerProps.setProperty("installer.appdir", applicationAppDir.getAbsolutePath()); + installerProps.setProperty("installer.appdirhash", EnvConfig.getAppDirHash()); + for ( String key: new String[] {"installer.template_version", "installer.application_folder", "installer.icon", "installer.mac_icons", "installer.logfile", "installer.logfile_append"}) { + String val = System.getProperty(key); + if (val != null) { + installerProps.put(key, val); + } + } + for (String prop: installerProps.stringPropertyNames()) { + log.info("Adding property '" + prop + "'='" + installerProps.getProperty(prop) + "' to " + installerPropsFilename); + } + File installerPropsFile = new File(userAppDir, installerPropsFilename); + try { + installerProps.store(new FileOutputStream(installerPropsFile.getAbsolutePath()), "Created by installer launcher in " + applicationAppDir); + } catch (IOException e) { + log.warning("Could not write installer properties file '" + installerPropsFile.getAbsolutePath() + "'"); + } + MessageDigest md = Digest.getMessageDigest(Digest.VERSION); for (Resource rsc: copyResources) { String digestHash = digest2.getDigest(rsc); diff --git a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/EnvConfig.java b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/EnvConfig.java index e5051de..dd163d3 100644 --- a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/EnvConfig.java +++ b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/EnvConfig.java @@ -5,6 +5,8 @@ package com.threerings.getdown.data; +import static java.nio.charset.StandardCharsets.UTF_8; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -75,10 +77,7 @@ public final class EnvConfig { String appIdProv = null; String appBase = null; String appBaseProv = null; - applicationFolder = System.getProperty("installer.application_folder"); - installerAppdir = System.getProperty(APPLICATION_APPDIR_PROPERTY); - - appName = System.getProperty("channel.app_name"); + setVarsFromProperties(); // start with bootstrap.properties config, if avaialble try { @@ -177,10 +176,11 @@ public final class EnvConfig { } // forced by system property to not use user default appdir - if (SysProps.noUpdate() && Boolean.valueOf(System.getProperty("no" + USER_DEFAULT_APPDIR_PROPERTY))) { + if (appDir == null && Boolean.valueOf(System.getProperty("no" + USER_DEFAULT_APPDIR_PROPERTY))) { appDir = installerAppdir; - appDirProv = "no user default"; + appDirProv = "installer appdir"; userAppDir = false; + notes.add(Note.info("Not using " + USER_DEFAULT_APPDIR_PROPERTY + ", resorting to " + appDirProv + " '" + appDir +"'")); } else if (userAppDir && installerAppdir != null) { // we're going to try and use a different appdir, check if newer getdown-launcher.jar found there, and restart using that one final String getdown = "getdown-launcher.jar"; @@ -255,6 +255,9 @@ public final class EnvConfig { // ensure that we were able to find an app dir if (appDir == null) { + if (!SysProps.noUpdate()) { + notes.add(Note.error("No appDir could be determined. You may need to set -Dsilent=noupdate -Dno"+USER_DEFAULT_APPDIR_PROPERTY)); + } return null; // caller will report problem to user } @@ -344,7 +347,20 @@ public final class EnvConfig { this.appArgs = appArgs; } - private static final String getUserAppdir() { + /** + * compute a hash for the given path string using the getdown digest + * @param install_app_dir + * @return 8-character hex hash + */ + public static final String getFullPathToDirectoryHash(String install_app_dir) + { + MessageDigest md = Digest.getMessageDigest(Digest.VERSION); + byte[] contents = install_app_dir.getBytes(UTF_8); + String hash = StringUtil.hexlate(md.digest(contents)); + return hash.substring(0,8); + } + + public static final String getUserAppdir() { final String noUseDefaultAppDirProperty = "no" + USER_DEFAULT_APPDIR_PROPERTY; if (Boolean.valueOf(System.getProperty(noUseDefaultAppDirProperty))) { System.err.println("Not using default user appdir because property '" + noUseDefaultAppDirProperty + "' is '" + System.getProperty(noUseDefaultAppDirProperty) + "'"); @@ -356,10 +372,25 @@ public final class EnvConfig { } String appdirname = applicationFolder == null || applicationFolder.length() == 0 ? ChannelProperties.FALLBACK_APPNAME : applicationFolder; String home = System.getProperty("user.home"); + // for times when using this method without running GetdownApp + if (appName == null) { + appName = System.getProperty("channel.app_name"); + } + if (installerAppdir == null) { + installerAppdir = System.getProperty(APPLICATION_APPDIR_PROPERTY); + } String appname = StringUtil.isBlank(appName) ? ChannelProperties.FALLBACK_APPNAME : appName; final String FS = File.separator; + try { + setAppDirHash(installerAppdir); + } catch (IOException ioex) { + System.err.println("Unable to resolve '"+installerAppdir+"' as a proper path on this system.\nNot generating a user local appdir - getdown may fail to update!"); + return null; + } + String appDataPath; String append; + boolean addHome = true; if (LaunchUtil.isMacOS()) { appDataPath = osAppDataPathMap.get("macos"); append = appname; @@ -373,8 +404,25 @@ public final class EnvConfig { appDataPath = osAppDataPathMap.get("other"); append = appdirname.toLowerCase(Locale.ROOT); } - String returnString = home + FS + appDataPath + FS + append + FS + "app"; - return returnString; + String setUserAppDirPath = System.getProperty(SET_USER_APPDIR_PATH); + // do not use a setUserAppDirPath with ".." in it + if (!StringUtil.isBlank(setUserAppDirPath) && setUserAppDirPath.indexOf("..") == -1) { + if (setUserAppDirPath.startsWith("~" + FS)) { + setUserAppDirPath = home + setUserAppDirPath.substring(1); + } + appDataPath = setUserAppDirPath.replaceAll("%u", System.getProperty("user.name")).replaceAll("%h", home); + addHome = false; + } + + StringBuilder sb = new StringBuilder(); + if (addHome) { + sb.append(home).append(FS); + } + sb.append(appDataPath).append(FS); + sb.append(append).append(FS); + sb.append(getAppDirHash()).append(FS); + sb.append("app"); + return sb.toString(); } public static void setRelaunched(boolean b) { @@ -399,6 +447,20 @@ public final class EnvConfig { return appName; } + public static void setVarsFromProperties() { + applicationFolder = System.getProperty("installer.application_folder"); + installerAppdir = System.getProperty(APPLICATION_APPDIR_PROPERTY); + appName = System.getProperty("channel.app_name"); + } + + public static String getAppDirHash() { + return appDirHash; + } + + public static void setAppDirHash(String path) throws IOException { + appDirHash = getFullPathToDirectoryHash(new File(path).getCanonicalPath()); + } + private static boolean relaunched = false; private static final String USER_HOME_KEY = "${user.home}"; @@ -409,11 +471,15 @@ public final class EnvConfig { private static String appName = null; - private static final String USER_DEFAULT_APPDIR_PROPERTY = "userdefaultappdir"; + private static String appDirHash = null; + + public static final String USER_DEFAULT_APPDIR_PROPERTY = "userdefaultappdir"; + + protected static final String APPLICATION_APPDIR_PROPERTY = "installer.appdir"; - private static final String APPLICATION_APPDIR_PROPERTY = "installer.appdir"; + protected static final String POPULATE_DEFAULT_APPDIR_PROPERTY = "populatedefaultappdir"; - private static final String POPULATE_DEFAULT_APPDIR_PROPERTY= "populatedefaultappdir"; + protected static final String SET_USER_APPDIR_PATH = "setuserappdirpath"; private static final Map osAppDataPathMap; diff --git a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java index d6ad03d..3fbff0a 100644 --- a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java +++ b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java @@ -13,8 +13,6 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Locale; -import javax.xml.bind.DatatypeConverter; - import java.security.MessageDigest; import jalview.util.ChannelProperties; @@ -149,7 +147,7 @@ public class LaunchUtil MessageDigest md = MessageDigest.getInstance(algo); md.update(Files.readAllBytes(Paths.get(file.getAbsolutePath()))); byte[] digest = md.digest(); - checksum = DatatypeConverter.printHexBinary(digest).toUpperCase(Locale.ROOT); + checksum = printHexBinary(digest).toUpperCase(Locale.ROOT); } catch (Exception e) { System.out.println("Couldn't create "+algo+" digest of "+file.getPath()); } @@ -322,4 +320,23 @@ public class LaunchUtil // can't grab system properties; we'll just pretend we're not on any of these OSes } } + + private static String printHexBinary(byte[] bytes) { + if (bytes == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < bytes.length; i++) { + sb.append(byteToHex(bytes[i])); + } + return sb.toString(); + } + + private static String byteToHex(byte num) { + char[] hexDigits = new char[2]; + hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16); + hexDigits[1] = Character.forDigit((num & 0xF), 16); + return new String(hexDigits); + } + } diff --git a/getdown/src/getdown/core/src/main/java/jalview/bin/GetdownLauncherUpdate.java b/getdown/src/getdown/core/src/main/java/jalview/bin/GetdownLauncherUpdate.java new file mode 100644 index 0000000..ec1f322 --- /dev/null +++ b/getdown/src/getdown/core/src/main/java/jalview/bin/GetdownLauncherUpdate.java @@ -0,0 +1,75 @@ +/* + * 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.bin; + +import java.io.File; + +import com.threerings.getdown.data.EnvConfig; +import com.threerings.getdown.util.LaunchUtil; + +public class GetdownLauncherUpdate +{ + public static void main(String[] args) + { + EnvConfig.setVarsFromProperties(); + + String appdir = args.length > 0 ? args[0] : null; + if (appdir == null || appdir.length() == 0) + { + appdir = System.getProperty("launcher.appdir", null); + } + if (appdir == null) + { + appdir = EnvConfig.getUserAppdir(); + } + if (appdir == null) + { + System.err.println("Not running upgradeGetdown"); + return; + } + boolean debug = false; + for (int i = 0; i < args.length; i++) + { + if ("--debug".equals(args[i])) + { + debug = true; + break; + } + } + if (debug) + { + System.err.println("Running upgradeGetdown"); + } + File appdirFile = new File(appdir); + if (!appdirFile.exists()) + { + System.err.println("Directory '" + appdirFile.getAbsolutePath() + + "' doesn't exist, cannot update getdown-launcher.jar."); + if (Boolean.valueOf(System.getProperty("launcher.update"))) + { + System.exit(1); + } + } + LaunchUtil.upgradeGetdown(new File(appdir, "getdown-launcher-old.jar"), + new File(appdir, "getdown-launcher.jar"), + new File(appdir, "getdown-launcher-new.jar")); + } +} diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java b/getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java index c204783..651073f 100644 --- a/getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java +++ b/getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java @@ -1,3 +1,23 @@ +/* + * 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.lang.reflect.InvocationTargetException; @@ -17,11 +37,18 @@ public class ErrorLog private static String prefix = null; + private static boolean quiet = false; + public static void setHasConsole(boolean b) { hasConsole = b; } + public static void setQuiet(boolean b) + { + quiet = b; + } + public static void setPrefix(String s) { prefix = s; @@ -45,6 +72,10 @@ public class ErrorLog public static void println(String message0, boolean err, boolean thisHasConsole) { + if (!err && quiet) + { + return; + } String message = prefix == null ? message0 : prefix + message0; if (thisHasConsole && hasConsole) { 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 index 186745d..ccf9992 100644 --- a/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java +++ b/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java @@ -621,7 +621,7 @@ public class LaunchUtils } String v0 = getJarImplementationVersion(f0); String v1 = getJarImplementationVersion(f1); - syserr(true, false, + syserr(v0 != null && !v0.equals(v1), false, "Got launcher versions '" + v0 + "' and '" + v1 + "'"); return compareGetdownLauncherJarVersions(v0, v1); } diff --git a/getdown/src/getdown/core/src/test/java/com/threerings/getdown/data/EnvConfigTest.java b/getdown/src/getdown/core/src/test/java/com/threerings/getdown/data/EnvConfigTest.java index 6178651..02deaa8 100644 --- a/getdown/src/getdown/core/src/test/java/com/threerings/getdown/data/EnvConfigTest.java +++ b/getdown/src/getdown/core/src/test/java/com/threerings/getdown/data/EnvConfigTest.java @@ -139,4 +139,42 @@ public class EnvConfigTest { checkAppBase(cfg, TESTBASE); checkNoAppArgs(cfg); } + + /** + * check that the appdir hash distinguishes between different base-app paths + */ + @Test public void testDifferentUserappdirHash() { + String envhash1 = EnvConfig.getFullPathToDirectoryHash("/Applications/Getdown.app/"); + String envhash2 = EnvConfig.getFullPathToDirectoryHash("/Applications/Getdown 1.app/"); + assertTrue(!envhash1.equals(envhash2)); + } + + /** + * check whether userdefaultappdir can be overrridden by nouserdefaultappdir + */ + @Test public void checkUserAppDir() { + List notes = new ArrayList<>(); + System.getProperties().setProperty(EnvConfig.APPLICATION_APPDIR_PROPERTY, "/Applications/Getdown.app"); + System.getProperties().setProperty("userdefaultappdir","true"); + EnvConfig cfg = sysPropsConfig(notes, "appdir", CWD); + assertTrue(cfg!=null); + hasUserAppDir(); + + System.getProperties().setProperty("nouserdefaultappdir","true"); + cfg = sysPropsConfig(notes, "appdir", CWD); + assertTrue(cfg!=null); + noUserAppDir(); + + System.getProperties().remove("nouserdefaultappdir"); + cfg = sysPropsConfig(notes, "appdir", CWD); + assertTrue(cfg!=null); + hasUserAppDir(); + } + + public void noUserAppDir() { + assertTrue(EnvConfig.getUserAppdir()==null); + } + public void hasUserAppDir() { + assertTrue(EnvConfig.getUserAppdir()!=null && !"".equals(EnvConfig.getUserAppdir())); + } } diff --git a/getdown/src/getdown/launcher/pom.xml b/getdown/src/getdown/launcher/pom.xml index fbd20cf..9c72413 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.5.0_FJVL + 1.8.3-1.5.3_FJVL getdown-launcher diff --git a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java index 653bf7a..b0b9a36 100644 --- a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java +++ b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java @@ -135,7 +135,7 @@ public abstract class Getdown extends Thread // determine whether or not we can write to our install directory File instdir = _app.getLocalPath(""); - if (!instdir.canWrite()) { + if (!instdir.canWrite() && !SysProps.noUpdate()) { String path = instdir.getPath(); if (path.equals(".")) { path = System.getProperty("user.dir"); diff --git a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java index 1283f11..bcb0f75 100644 --- a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java +++ b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java @@ -65,7 +65,11 @@ public class GetdownApp public static Getdown start (String[] argv) throws Exception { jalview.util.ErrorLog.setHasConsole(false); jalview.util.ErrorLog.setPrefix("LAUNCHER: "); - jalview.util.ErrorLog.outPrintln("start of logging"); + if (SysProps.silent() && !SysProps.launchInSilent() && "true".equals(System.getProperty("launcher.update", "false"))) { + jalview.util.ErrorLog.outPrintln("Running update only"); + } else { + jalview.util.ErrorLog.outPrintln("Start of logging"); + } List notes = new ArrayList<>(); boolean append = false; EnvConfig envc = EnvConfig.create(argv, notes, GetdownApp.class); 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 cb51ca4..291f854 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 @@ -28,6 +28,7 @@ import ca.beq.util.win32.registry.RegistryValue; import ca.beq.util.win32.registry.RootKey; import com.threerings.getdown.data.Application; +import com.threerings.getdown.data.SysProps; import com.threerings.getdown.spi.ProxyAuth; import com.threerings.getdown.util.Config; import com.threerings.getdown.util.ConnectionUtil; @@ -165,7 +166,9 @@ public class ProxyUtil { public static void configProxy (Application app, String host, String port, String username, String password) { // save our proxy host and port in a local file - saveProxy(app, host, port); + if (!SysProps.noUpdate()) { + saveProxy(app, host, port); + } // save our credentials via the SPI if (!StringUtil.isBlank(username) && !StringUtil.isBlank(password)) { @@ -211,7 +214,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())+")"); + log.info("initProxy:", "app", app, "host", host, "port", port, "username", username, "password", "("+(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/lib/SOURCE_HEADER b/getdown/src/getdown/lib/SOURCE_HEADER deleted file mode 100644 index 43271fe..0000000 --- a/getdown/src/getdown/lib/SOURCE_HEADER +++ /dev/null @@ -1,5 +0,0 @@ -// -// Getdown - application installer, patcher and launcher -// Copyright (C) 2004-2018 Getdown authors -// https://github.com/threerings/getdown/blob/master/LICENSE - diff --git a/getdown/src/getdown/lib/jRegistryKey.dll b/getdown/src/getdown/lib/jRegistryKey.dll deleted file mode 100644 index 5746728..0000000 Binary files a/getdown/src/getdown/lib/jRegistryKey.dll and /dev/null differ diff --git a/getdown/src/getdown/lib/jregistrykey/jregistrykey/1.0/jregistrykey-1.0.jar b/getdown/src/getdown/lib/jregistrykey/jregistrykey/1.0/jregistrykey-1.0.jar deleted file mode 100644 index 5100795..0000000 Binary files a/getdown/src/getdown/lib/jregistrykey/jregistrykey/1.0/jregistrykey-1.0.jar and /dev/null differ diff --git a/getdown/src/getdown/lib/jregistrykey/jregistrykey/1.0/jregistrykey-1.0.pom b/getdown/src/getdown/lib/jregistrykey/jregistrykey/1.0/jregistrykey-1.0.pom deleted file mode 100644 index 226a7d7..0000000 --- a/getdown/src/getdown/lib/jregistrykey/jregistrykey/1.0/jregistrykey-1.0.pom +++ /dev/null @@ -1,9 +0,0 @@ - - - 4.0.0 - jregistrykey - jregistrykey - 1.0 - POM was created from install:install-file - diff --git a/getdown/src/getdown/lib/jregistrykey/jregistrykey/maven-metadata-local.xml b/getdown/src/getdown/lib/jregistrykey/jregistrykey/maven-metadata-local.xml deleted file mode 100644 index 1a8a725..0000000 --- a/getdown/src/getdown/lib/jregistrykey/jregistrykey/maven-metadata-local.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - jregistrykey - jregistrykey - 1.0 - - - 1.0 - - 20101118155146 - - diff --git a/getdown/src/getdown/lib/manifest.mf b/getdown/src/getdown/lib/manifest.mf deleted file mode 100644 index 3be50cc..0000000 --- a/getdown/src/getdown/lib/manifest.mf +++ /dev/null @@ -1,6 +0,0 @@ -Main-Class: com.threerings.getdown.launcher.Getdown -Permissions: all-permissions -Application-Name: Getdown -Codebase: * -Application-Library-Allowable-Codebase: * -Caller-Allowable-Codebase: * diff --git a/getdown/src/getdown/mvn_cmd b/getdown/src/getdown/mvn_cmd index 41725cf..cd2a39a 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.5.0_JVL + export VERSION=1.8.3-1.5.3_JVL fi if [ x${VERSION%_JVL} = x$VERSION ]; then diff --git a/getdown/src/getdown/pom.xml b/getdown/src/getdown/pom.xml index 3eb0565..6f2cd69 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.5.0_FJVL + 1.8.3-1.5.3_FJVL getdown An application installer and updater. diff --git a/gradle.properties b/gradle.properties index 041dc13..823264c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -83,7 +83,6 @@ getdown_lib_dir = getdown/lib getdown_launcher = getdown-launcher.jar getdown_launcher_local = getdown-launcher-local.jar getdown_launcher_new = getdown-launcher-new.jar -getdown_core = getdown/lib/getdown-core.jar getdown_build_properties = build_properties getdown_launch_jvl_name = channel_launch getdown_images_dir = utils/getdown @@ -98,6 +97,7 @@ getdown_txt_max_concurrent_downloads = 10 # now got better (dynamic) defaults when jvmmem* not set #getdown_txt_jalview.jvmmempc = 90 #getdown_txt_jalview.jvmmemmax = 32G +getdown_txt_resource = getdown/lib/getdown-core.jar getdown_txt_strict_comments = true getdown_txt_ui.progress_sync_before_shown = true getdown_txt_ui.progress_sync_after_shown = false @@ -158,13 +158,17 @@ install4j_dmg_volume_icon = jalview-VolumeIcon.icns install4j_installer_icon = jalview_installer.png install4j_installer_mac_icon = jalview_installer.icns install4j_installer_windows_icon = jalview_installer.ico +install4j_default_vmoptions = default.vmoptions jalview_customise_ds_store = utils/macos_dmg/jalview_customise_dsstore.py getdown_wrapper_script_dir = bin getdown_bash_wrapper_script = jalview.sh getdown_powershell_wrapper_script = jalview.ps1 -getdown_batch_wrapper_script = jalview.bat +getdown_bash_update_script = update.sh +getdown_powershell_update_script = update.ps1 +getdown_run_other_script = run_other_script.ps1 +getdown_run_powershell = run_powershell.bat OSX_KEYSTORE = OSX_KEYPASS = diff --git a/help/markdown/releases/release-2_11_4_0.md b/help/markdown/releases/release-2_11_4_0.md index 0d4017a..f27b140 100644 --- a/help/markdown/releases/release-2_11_4_0.md +++ b/help/markdown/releases/release-2_11_4_0.md @@ -1,23 +1,51 @@ --- version: 2.11.4.0 -date: 2024-06-30 +date: 2024-09-03 channel: "develop" --- ## New Features +- Calculate PASiMap projection for sequences - ported by Thomas Morell ( U. Konstanz) - Consensus secondary structure visualization for alignments +- Show data source for 'reference annotation' from 3D structure (e.g. Secondary Structure) - Calculate tree or PCA using secondary structure annotation -- Calculate PASiMap projection for sequences - ported by Thomas Morell ( U. Konstanz) - allow adjustment of gap opening, extension, and score model for built in pairwise alignment +### Experimental Features (enable via Desktop's tools menu) + +- Jalview sensibly handles opening or a drag'n'drop of several .features, .annotations and .newick files onto an alignment + ### development and deployment +- Add a command-line wrapper script to macOS bundle, linux and Windows installations (bash, powershell and .bat wrappers) +- Redirect stdout and stderr to file when launched from getdown +- Add error message when launched directly from Jalview Installer DMG volume +- Allow jalview auto-updates to download to and work from separate user-space directory +- Gradle build with install4j launchers +- Implement in Jalview (and getdown for JVL) the use of specific scheme names for different channels (e.g. jalviewd://) +- integrate OSX codesigning scripts in jalview's repository +- new documentation describing how jalview project XML schema is maintained (in doc/jalview-projects.md) +- updated Jalview's Ensembl's client for v15.8 of the REST API - change in BRAF query returned by ensembl Genes for chicken for GRCg7b (now ENSGALG00010013466, was ENSGALG00000012865) ## Issues Resolved +- jalview does not fetch from a URL containing a redirect +- HTTP errors are often interpreted to the user as a file format error - and FileNotFound errors are not propagated from Web or Local file import +- launcher.log from jalview runtime missing newlines and also lacks stdout/stderr reported in Jalview Console +- Possible "Zip Slip Vulnerability" in getdown +- jalview.bin.CommandsTest.headlessOrGuiImageOutputTest produces different images for --gui and --headless when using certain .jalview_properties +- Release installer DMG does not display the background image +- Getdown splash screen should disappear as soon as the Jalview Desktop is created/visible +### development and deployment -### New Known Issues +- removed gradle build's dependency on gradle-imagemagick plugin to allow building on windows (still need imagemagick installed on path for splashscreen commit watermark) +- fixed inconsistencies in test suite on different platforms +- The rendering of the text "Window" for the Window menu item is different to the other menus when testing in Linux +### New Known Issues +- PaSiMap not available in JalviewJS +- Jalview ignores ncrna genes when importing from genbank format files +- Sequence letter aspect ratio not set correctly when aspect ratio is very narrow after middle-mouse drag diff --git a/j11lib/getdown-core.jar b/j11lib/getdown-core.jar index 124cf70..652c6c4 100644 Binary files a/j11lib/getdown-core.jar and b/j11lib/getdown-core.jar differ diff --git a/j8lib/getdown-core.jar b/j8lib/getdown-core.jar index 124cf70..652c6c4 100644 Binary files a/j8lib/getdown-core.jar and b/j8lib/getdown-core.jar differ diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index 7278a80..b3a912c 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -192,13 +192,12 @@ public class AAFrequency // jalview.bin.Console.outPrintln(elapsed); } - public static final ProfilesI calculateSS(List list, int start, int end, String source) { return calculateSS(list, start, end, false, source); } - + public static final ProfilesI calculateSS(List sequences, int start, int end, boolean profile, String source) { @@ -226,7 +225,7 @@ public class AAFrequency return reply; } } - + public static final ProfilesI calculateSS(final SequenceI[] sequences, int width, int start, int end, boolean saveFullProfile, String source) { @@ -234,14 +233,14 @@ public class AAFrequency int seqCount = sequences.length; int seqWithSSCount = 0; - + ProfileI[] result = new ProfileI[width]; for (int column = start; column < end; column++) { - + int ssCount = 0; - + SecondaryStructureCount ssCounts = new SecondaryStructureCount(); for (int row = 0; row < seqCount; row++) @@ -252,7 +251,7 @@ public class AAFrequency "WARNING: Consensus skipping null sequence - possible race condition."); continue; } - + char c = sequences[row].getCharAt(column); List annots = AlignmentUtils.getAlignmentAnnotationForSource(sequences[row], source); if(annots!=null) { @@ -287,7 +286,6 @@ public class AAFrequency ProfileI profile = new Profile(maxSS, ssCount, gapCount, maxSSCount, seqWithSSCount); - if (saveFullProfile) { profile.setSSCounts(ssCounts); @@ -394,29 +392,28 @@ public class AAFrequency // long elapsed = System.currentTimeMillis() - now; // jalview.bin.Console.outPrintln(-elapsed); } - - - public static void completeSSConsensus(AlignmentAnnotation ssConsensus, - ProfilesI profiles, int startCol, int endCol, boolean ignoreGaps, - boolean showSequenceLogo, long nseq) - { - // long now = System.currentTimeMillis(); - if (ssConsensus == null || ssConsensus.annotations == null - || ssConsensus.annotations.length < endCol) - { - /* + + public static void completeSSConsensus(AlignmentAnnotation ssConsensus, + ProfilesI profiles, int startCol, int endCol, boolean ignoreGaps, + boolean showSequenceLogo, long nseq) + { + // long now = System.currentTimeMillis(); + if (ssConsensus == null || ssConsensus.annotations == null + || ssConsensus.annotations.length < endCol) + { + /* * called with a bad alignment annotation row * wait for it to be initialised properly */ - return; - } + return; + } - for (int i = startCol; i < endCol; i++) - { - ProfileI profile = profiles.get(i); - if (profile == null) - { - /* + for (int i = startCol; i < endCol; i++) + { + ProfileI profile = profiles.get(i); + if (profile == null) + { + /* * happens if sequences calculated over were * shorter than alignment width */ @@ -430,10 +427,10 @@ public class AAFrequency final int dp = getPercentageDp(nseq); - float value = profile.getSSPercentageIdentity(ignoreGaps); + float value = profile.getSSPercentageIdentity(ignoreGaps); - String description = getSSTooltip(profile, value, showSequenceLogo, - ignoreGaps, dp); + String description = getSSTooltip(profile, value, showSequenceLogo, + ignoreGaps, dp); String modalSS = profile.getModalSS(); if ("".equals(modalSS)) @@ -560,7 +557,7 @@ public class AAFrequency } return description; } - + static String getSSTooltip(ProfileI profile, float pid, boolean showSequenceLogo, boolean ignoreGaps, int dp) { @@ -616,27 +613,28 @@ public class AAFrequency { char[] symbols; int[] values; - + if (profile.getCounts() != null) { ResidueCount counts = profile.getCounts(); SymbolCounts symbolCounts = counts.getSymbolCounts(); symbols = symbolCounts.symbols; values = symbolCounts.values; - + } - else if(profile.getSSCounts() != null) + else if (profile.getSSCounts() != null) { SecondaryStructureCount counts = profile.getSSCounts(); // to do - SecondaryStructureCount.SymbolCounts symbolCounts = counts.getSymbolCounts(); + SecondaryStructureCount.SymbolCounts symbolCounts = counts + .getSymbolCounts(); symbols = symbolCounts.symbols; values = symbolCounts.values; } - else { + else + { return null; } - QuickSort.sort(values, symbols); int totalPercentage = 0; diff --git a/src/jalview/analysis/AlignSeq.java b/src/jalview/analysis/AlignSeq.java index e806d2b..1a12681 100755 --- a/src/jalview/analysis/AlignSeq.java +++ b/src/jalview/analysis/AlignSeq.java @@ -58,10 +58,10 @@ public class AlignSeq private static final int DEFAULT_OPENCOST = 120; private static final int DEFAULT_EXTENDCOST = 20; - - private int GAP_OPEN_COST=DEFAULT_OPENCOST; - private int GAP_EXTEND_COST=DEFAULT_EXTENDCOST; + private int GAP_OPEN_COST = DEFAULT_OPENCOST; + + private int GAP_EXTEND_COST = DEFAULT_EXTENDCOST; private static final int GAP_INDEX = -1; @@ -100,11 +100,11 @@ public class AlignSeq int[] aseq1; int[] aseq2; - + /* * matches in alignment */ - int match=-1; + int match = -1; public String astr1 = ""; @@ -129,9 +129,9 @@ public class AlignSeq public float maxscore; - public float meanScore; //needed for PaSiMap + public float meanScore; // needed for PaSiMap - public int hypotheticMaxScore; // needed for PaSiMap + public int hypotheticMaxScore; // needed for PaSiMap int prev = 0; @@ -156,6 +156,7 @@ public class AlignSeq GAP_OPEN_COST = opencost; GAP_EXTEND_COST = extcost; } + public AlignSeq(SequenceI s1, SequenceI s2, String type) { seqInit(s1, s1.getSequenceAsString(), s2, s2.getSequenceAsString(), @@ -182,18 +183,18 @@ public class AlignSeq public AlignSeq(SequenceI s1, SequenceI s2, String type, int opencost, int extcost) { - this(s1,s2,type); - GAP_OPEN_COST=opencost; - GAP_EXTEND_COST=extcost; + this(s1, s2, type); + GAP_OPEN_COST = opencost; + GAP_EXTEND_COST = extcost; } public AlignSeq(SequenceI s12, String string1, SequenceI s22, String string2, String type2, int defaultOpencost, int defaultExtendcost) { - this(s12,string1,s22,string2,type2); - GAP_OPEN_COST=defaultOpencost; - GAP_EXTEND_COST=defaultExtendcost; + this(s12, string1, s22, string2, type2); + GAP_OPEN_COST = defaultOpencost; + GAP_EXTEND_COST = defaultExtendcost; } /** @@ -207,10 +208,10 @@ public class AlignSeq } /** - * returns the overall score of the alignment - * - * @return - */ + * returns the overall score of the alignment + * + * @return + */ public float getAlignmentScore() { return alignmentScore; @@ -333,27 +334,31 @@ public class AlignSeq s2.getDatasetSequence() == null ? s2 : s2.getDatasetSequence()); return alSeq2; } + /** * fraction of seq2 matched in the alignment + * * @return NaN or [0..1] */ public double getS2Coverage() { - if (match>=0) + if (match >= 0) { - return ((double)match)/((double)s2.getEnd()-s2.getStart()+1); + return ((double) match) / ((double) s2.getEnd() - s2.getStart() + 1); } return Double.NaN; } + /** * fraction of seq1 matched in the alignment + * * @return NaN or [0..1] */ public double getS1Coverage() { - if (match>=0) + if (match >= 0) { - return ((double)match)/((double)s1.getEnd()-s1.getStart()+1); + return ((double) match) / ((double) s1.getEnd() - s1.getStart() + 1); } return Double.NaN; } @@ -375,13 +380,14 @@ public class AlignSeq public void seqInit(SequenceI s1, String string1, SequenceI s2, String string2, String type) { - seqInit(s1,string1,s2,string2,type,GAP_OPEN_COST,GAP_EXTEND_COST); + seqInit(s1, string1, s2, string2, type, GAP_OPEN_COST, GAP_EXTEND_COST); } + public void seqInit(SequenceI s1, String string1, SequenceI s2, - String string2, String type, int opening,int extension) + String string2, String type, int opening, int extension) { - GAP_OPEN_COST=opening; - GAP_EXTEND_COST=extension; + GAP_OPEN_COST = opening; + GAP_EXTEND_COST = extension; this.s1 = s1; this.s2 = s2; setDefaultParams(type); @@ -473,13 +479,12 @@ public class AlignSeq aseq1 = new int[seq1.length + seq2.length]; aseq2 = new int[seq1.length + seq2.length]; - match=0; + match = 0; StringBuilder sb1 = new StringBuilder(aseq1.length); StringBuilder sb2 = new StringBuilder(aseq2.length); count = (seq1.length + seq2.length) - 1; - while (i > 0 && j > 0) { aseq1[count] = seq1[i]; @@ -523,12 +528,12 @@ public class AlignSeq { aseq2[count] = seq2[j]; sb2.append(s2str.charAt(j)); - if (aseq1[count]!=GAP_INDEX) { + if (aseq1[count] != GAP_INDEX) + { match++; } } - /* * we built the character strings backwards, so now * reverse them to convert to sequence strings @@ -570,7 +575,7 @@ public class AlignSeq int trace; maxscore = score[i][j] / 10f; - //prepare trailing gaps + // prepare trailing gaps while ((i < seq1.length - 1) || (j < seq2.length - 1)) { i++; @@ -587,20 +592,22 @@ public class AlignSeq count = (seq1.length + seq2.length) - 1; - //get trailing gaps + // get trailing gaps while ((i >= seq1.length) || (j >= seq2.length)) { if (i >= seq1.length) { - aseq1[count] = GAP_INDEX; - sb1.append("-"); - aseq2[count] = seq2[j]; - sb2.append(s2str.charAt(j)); - } else if (j >= seq2.length) { - aseq1[count] = seq1[i]; - sb1.append(s1str.charAt(i)); - aseq2[count] = GAP_INDEX; - sb2.append("-"); + aseq1[count] = GAP_INDEX; + sb1.append("-"); + aseq2[count] = seq2[j]; + sb2.append(s2str.charAt(j)); + } + else if (j >= seq2.length) + { + aseq1[count] = seq1[i]; + sb1.append(s1str.charAt(i)); + aseq2[count] = GAP_INDEX; + sb2.append("-"); } i--; j--; @@ -644,18 +651,20 @@ public class AlignSeq aseq2[count] = seq2[j]; sb2.append(s2str.charAt(j)); - //get initial gaps + // get initial gaps while (j > 0 || i > 0) { if (j > 0) { - j--; - sb1.append("-"); - sb2.append(s2str.charAt(j)); - } else if (i > 0) { - i--; - sb1.append(s1str.charAt(i)); - sb2.append("-"); + j--; + sb1.append("-"); + sb2.append(s2str.charAt(j)); + } + else if (i > 0) + { + i--; + sb1.append(s1str.charAt(i)); + sb2.append("-"); } } @@ -853,7 +862,7 @@ public class AlignSeq { int n = seq1.length; int m = seq2.length; - final int GAP_EX_COST=GAP_EXTEND_COST; + final int GAP_EX_COST = GAP_EXTEND_COST; final int GAP_OP_COST = GAP_OPEN_COST; // top left hand element score[0][0] = scoreMatrix.getPairwiseScore(s1str.charAt(0), @@ -871,8 +880,7 @@ public class AlignSeq float pairwiseScore = scoreMatrix.getPairwiseScore(s1str.charAt(0), s2str.charAt(j)); - score[0][j] = max(pairwiseScore * 10, -GAP_OP_COST, - -GAP_EX_COST); + score[0][j] = max(pairwiseScore * 10, -GAP_OP_COST, -GAP_EX_COST); traceback[0][j] = 1; } @@ -1076,13 +1084,15 @@ public class AlignSeq public static AlignSeq doGlobalNWAlignment(SequenceI s1, SequenceI s2, String type) { - return doGlobalNWAlignment(s1, s2, type, DEFAULT_OPENCOST,DEFAULT_EXTENDCOST); + return doGlobalNWAlignment(s1, s2, type, DEFAULT_OPENCOST, + DEFAULT_EXTENDCOST); } + public static AlignSeq doGlobalNWAlignment(SequenceI s1, SequenceI s2, - String type, int opencost,int extcost) + String type, int opencost, int extcost) { - - AlignSeq as = new AlignSeq(s1, s2, type,opencost,extcost); + + AlignSeq as = new AlignSeq(s1, s2, type, opencost, extcost); as.calcScoreMatrix(); as.traceAlignment(); @@ -1359,42 +1369,45 @@ public class AlignSeq } /** - * calculate the mean score of the alignment - * mean score is equal to the score of an alignmenet of two sequences with randomly shuffled AA sequence composited of the same AA as the two original sequences - * - */ + * calculate the mean score of the alignment mean score is equal to the score + * of an alignmenet of two sequences with randomly shuffled AA sequence + * composited of the same AA as the two original sequences + * + */ public void meanScore() { - int length = indelfreeAstr1.length(); //both have the same length - //create HashMap for counting residues in each sequence + int length = indelfreeAstr1.length(); // both have the same length + // create HashMap for counting residues in each sequence HashMap seq1ResCount = new HashMap(); HashMap seq2ResCount = new HashMap(); - // for both sequences (String indelfreeAstr1 or 2) create a key for the residue and add 1 each time its encountered - for (char residue: indelfreeAstr1.toCharArray()) + // for both sequences (String indelfreeAstr1 or 2) create a key for the + // residue and add 1 each time its encountered + for (char residue : indelfreeAstr1.toCharArray()) { seq1ResCount.putIfAbsent(residue, 0); seq1ResCount.replace(residue, seq1ResCount.get(residue) + 1); } - for (char residue: indelfreeAstr2.toCharArray()) + for (char residue : indelfreeAstr2.toCharArray()) { seq2ResCount.putIfAbsent(residue, 0); seq2ResCount.replace(residue, seq2ResCount.get(residue) + 1); } - // meanscore = for each residue pair get the number of appearance and add (countA * countB * pairwiseScore(AB)) + // meanscore = for each residue pair get the number of appearance and add + // (countA * countB * pairwiseScore(AB)) // divide the meanscore by the sequence length afterwards float _meanscore = 0; for (char resA : seq1ResCount.keySet()) { for (char resB : seq2ResCount.keySet()) { - int countA = seq1ResCount.get(resA); - int countB = seq2ResCount.get(resB); + int countA = seq1ResCount.get(resA); + int countB = seq2ResCount.get(resB); float scoreAB = scoreMatrix.getPairwiseScore(resA, resB); - _meanscore += countA * countB * scoreAB; + _meanscore += countA * countB * scoreAB; } } _meanscore /= length; @@ -1407,21 +1420,23 @@ public class AlignSeq } /** - * calculate the hypothetic max score using the self-alignment of the sequences - */ + * calculate the hypothetic max score using the self-alignment of the + * sequences + */ public void hypotheticMaxScore() { int _hmsA = 0; int _hmsB = 0; - for (char residue: indelfreeAstr1.toCharArray()) + for (char residue : indelfreeAstr1.toCharArray()) { _hmsA += scoreMatrix.getPairwiseScore(residue, residue); } - for (char residue: indelfreeAstr2.toCharArray()) + for (char residue : indelfreeAstr2.toCharArray()) { _hmsB += scoreMatrix.getPairwiseScore(residue, residue); } - this.hypotheticMaxScore = (_hmsA < _hmsB) ? _hmsA : _hmsB; // take the lower self alignment + this.hypotheticMaxScore = (_hmsA < _hmsB) ? _hmsA : _hmsB; // take the lower + // self alignment } @@ -1431,27 +1446,30 @@ public class AlignSeq } /** - * create strings based of astr1 and astr2 but without gaps - */ + * create strings based of astr1 and astr2 but without gaps + */ public void getIndelfreeAstr() { - int n = astr1.length(); // both have the same length + int n = astr1.length(); // both have the same length for (int i = 0; i < n; i++) { - if (Character.isLetter(astr1.charAt(i)) && Character.isLetter(astr2.charAt(i))) // if both sequences dont have a gap -> add to indelfreeAstr + if (Character.isLetter(astr1.charAt(i)) + && Character.isLetter(astr2.charAt(i))) // if both sequences dont + // have a gap -> add to + // indelfreeAstr { - this.indelfreeAstr1 += astr1.charAt(i); - this.indelfreeAstr2 += astr2.charAt(i); + this.indelfreeAstr1 += astr1.charAt(i); + this.indelfreeAstr2 += astr2.charAt(i); } } } /** - * calculates the overall score of the alignment - * preprescore = sum of all scores - all penalties - * if preprescore < 1 ~ alignmentScore = Float.NaN > - * alignmentScore = ((preprescore - meanScore) / (hypotheticMaxScore - meanScore)) * coverage - */ + * calculates the overall score of the alignment preprescore = sum of all + * scores - all penalties if preprescore < 1 ~ alignmentScore = Float.NaN > + * alignmentScore = ((preprescore - meanScore) / (hypotheticMaxScore - + * meanScore)) * coverage + */ public void scoreAlignment() { @@ -1475,36 +1493,51 @@ public class AlignSeq char char2 = indelfreeAstr2.charAt(i); boolean aIsLetter = Character.isLetter(char1); boolean bIsLetter = Character.isLetter(char2); - if (aIsLetter && bIsLetter) // if pair -> get score + if (aIsLetter && bIsLetter) // if pair -> get score { score += scoreMatrix.getPairwiseScore(char1, char2); - } else if (!aIsLetter && !bIsLetter) { // both are gap -> skip - } else if ((!aIsLetter && aGapOpen) || (!bIsLetter && bGapOpen)) { // one side gapopen -> score - gap_extend - score -= GAP_EXTEND_COST; - } else { // no gap open -> score - gap_open - score -= GAP_OPEN_COST; + } + else if (!aIsLetter && !bIsLetter) + { // both are gap -> skip + } + else if ((!aIsLetter && aGapOpen) || (!bIsLetter && bGapOpen)) + { // one side gapopen -> score - gap_extend + score -= GAP_EXTEND_COST; + } + else + { // no gap open -> score - gap_open + score -= GAP_OPEN_COST; } // adjust GapOpen status in both sequences aGapOpen = (!aIsLetter) ? true : false; bGapOpen = (!bIsLetter) ? true : false; } - float preprescore = score; // if this score < 1 --> alignment score = Float.NaN - score = (score - this.meanScore) / (this.hypotheticMaxScore - this.meanScore); - int[] _max = MiscMath.findMax(new int[]{astr1.replace("-","").length(), astr2.replace("-","").length()}); // {index of max, max} - float coverage = (float) n / (float) _max[1]; // indelfreeAstr length / longest sequence length - float prescore = score; // only debug + float preprescore = score; // if this score < 1 --> alignment score = + // Float.NaN + score = (score - this.meanScore) + / (this.hypotheticMaxScore - this.meanScore); + int[] _max = MiscMath + .findMax(new int[] + { astr1.replace("-", "").length(), + astr2.replace("-", "").length() }); // {index of max, max} + float coverage = (float) n / (float) _max[1]; // indelfreeAstr length / + // longest sequence length + float prescore = score; // only debug score *= coverage; - //System.out.println(String.format("prepre-score: %f, pre-score: %f, longlength: %d\nscore: %1.16f, mean: %f, max: %d", preprescore, prescore, _max[1], score, this.meanScore, this.hypotheticMaxScore)); + // System.out.println(String.format("prepre-score: %f, pre-score: %f, + // longlength: %d\nscore: %1.16f, mean: %f, max: %d", preprescore, prescore, + // _max[1], score, this.meanScore, this.hypotheticMaxScore)); float minScore = 0f; this.alignmentScore = (score <= minScore) ? Float.NaN : score; } public void setScoreMatrix(ScoreMatrix sm) { - if (sm != null) { - scoreMatrix = sm; - } + if (sm != null) + { + scoreMatrix = sm; + } } } diff --git a/src/jalview/analysis/AlignmentUtils.java b/src/jalview/analysis/AlignmentUtils.java index d78bcdc..4d2b1aa 100644 --- a/src/jalview/analysis/AlignmentUtils.java +++ b/src/jalview/analysis/AlignmentUtils.java @@ -84,7 +84,7 @@ public class AlignmentUtils { private static final int CODON_LENGTH = 3; - private static final String SEQUENCE_VARIANT = "sequence_variant:"; + private static final String SEQUENCE_VARIANT = "sequence_variant:"; /* * the 'id' attribute is provided for variant features fetched from @@ -1542,13 +1542,15 @@ public class AlignmentUtils } } } - - - public static boolean isSSAnnotationPresent( Map> annotations) { - + + public static boolean isSSAnnotationPresent( + Map> annotations) + { + for (SequenceI seq : annotations.keySet()) { - if(isSecondaryStructurePresent(annotations.get(seq).toArray(new AlignmentAnnotation[0]))) + if (isSecondaryStructurePresent( + annotations.get(seq).toArray(new AlignmentAnnotation[0]))) { return true; } @@ -2920,7 +2922,7 @@ public class AlignmentUtils return ssPresent; } - + public static Color getSecondaryStructureAnnotationColour(char symbol) { @@ -2938,10 +2940,11 @@ public class AlignmentUtils } return Color.white; + } - public static char findSSAnnotationForGivenSeqposition(AlignmentAnnotation aa, - int seqPosition) + public static char findSSAnnotationForGivenSeqposition( + AlignmentAnnotation aa, int seqPosition) { char ss = '*'; @@ -3187,5 +3190,32 @@ public class AlignmentUtils return ssAlignmentAnnotationForSequences; } - + + + // to do set priority for labels + public static AlignmentAnnotation getDisplayedAlignmentAnnotation( + SequenceI seq) + { + + for (String ssLabel : Constants.SECONDARY_STRUCTURE_LABELS.keySet()) + { + + AlignmentAnnotation[] aa = seq.getAnnotation(ssLabel); + if (aa != null) + { + + for (AlignmentAnnotation annot : aa) + { + if (annot.visible) + { + return annot; + } + } + } + } + + return null; + + } + } diff --git a/src/jalview/analysis/ConnectivityException.java b/src/jalview/analysis/ConnectivityException.java index 9915f2a..5f371c8 100644 --- a/src/jalview/analysis/ConnectivityException.java +++ b/src/jalview/analysis/ConnectivityException.java @@ -23,7 +23,9 @@ package jalview.analysis; public class ConnectivityException extends RuntimeException { private String sequence; + private int connection; + private byte dim; public ConnectivityException(String sequence, int connection, byte dim) @@ -31,9 +33,11 @@ public class ConnectivityException extends RuntimeException this("Insufficient number of connections", sequence, connection, dim); } - public ConnectivityException(String message, String sequence, int connection, byte dim) + public ConnectivityException(String message, String sequence, + int connection, byte dim) { - super(String.format("%s for %s (%d, should be %d or more)", message, sequence, connection, dim)); + super(String.format("%s for %s (%d, should be %d or more)", message, + sequence, connection, dim)); this.sequence = sequence; this.connection = connection; this.dim = dim; diff --git a/src/jalview/analysis/Finder.java b/src/jalview/analysis/Finder.java index c84c69a..32d4cf3 100644 --- a/src/jalview/analysis/Finder.java +++ b/src/jalview/analysis/Finder.java @@ -606,7 +606,7 @@ public class Finder implements FinderI } else { - //allFeatures = sf.getAllFeatures(null); + // allFeatures = sf.getAllFeatures(null); allFeatures = sf.getAllFeatures(); } // so we can check we are advancing when debugging diff --git a/src/jalview/analysis/PaSiMap.java b/src/jalview/analysis/PaSiMap.java index 48ec899..5be8c7b 100755 --- a/src/jalview/analysis/PaSiMap.java +++ b/src/jalview/analysis/PaSiMap.java @@ -38,7 +38,8 @@ import java.util.Hashtable; /** * Performs Principal Component Analysis on given sequences - * @AUTHOR MorellThomas + * + * @AUTHOR MorellThomas */ public class PaSiMap implements Runnable { @@ -72,14 +73,17 @@ public class PaSiMap implements Runnable * @param sm * @param options */ - public PaSiMap(AlignmentViewport sequences, ScoreModelI sm, PairwiseAlignPanel pap) + public PaSiMap(AlignmentViewport sequences, ScoreModelI sm, + PairwiseAlignPanel pap) { this.seqs = sequences; - if (sm!=null && sm instanceof ScoreMatrix) + if (sm != null && sm instanceof ScoreMatrix) { this.scoreMatrix = ((ScoreMatrix) sm); - } else { + } + else + { this.scoreMatrix = null; } @@ -108,7 +112,8 @@ public class PaSiMap implements Runnable * DOCUMENT ME! * @param mm * DOCUMENT ME! - * @param factor ~ is 1 + * @param factor + * ~ is 1 * * @return DOCUMENT ME! */ @@ -164,8 +169,8 @@ public class PaSiMap implements Runnable } /** - * Answers a formatted text report of the PaSiMap calculation results (matrices - * and eigenvalues) suitable for display + * Answers a formatted text report of the PaSiMap calculation results + * (matrices and eigenvalues) suitable for display * * @return */ @@ -197,13 +202,25 @@ public class PaSiMap implements Runnable /** * Performs the PaSiMap calculation * - * creates a new gui/PairwiseAlignPanel with the input sequences (AlignmentViewport) - * uses analysis/AlignSeq to creatue the pairwise alignments and calculate the AlignmentScores (float for each pair) + * creates a new gui/PairwiseAlignPanel with the input sequences + * (AlignmentViewport) + * + * uses analysis/AlignSeq to creatue the pairwise alignments and calculate the + * AlignmentScores (float for each pair) + * * gets all float[][] scores from the gui/PairwiseAlignPanel - * checks the connections for each sequence with AlignmentViewport seqs.calculateConnectivity(float[][] scores, int dim) (from analysis/Connectivity) -- throws an Exception if insufficient + * + * checks the connections for each sequence with AlignmentViewport + * seqs.calculateConnectivity(float[][] scores, int dim) (from + * analysis/Connectivity) -- throws an Exception if insufficient + * * creates a math/MatrixI pairwiseScores of the float[][] scores - * copys the scores and fills the diagonal to create a symmetric matrix using math/Matrix.fillDiagonal() + * + * copys the scores and fills the diagonal to create a symmetric matrix using + * math/Matrix.fillDiagonal() + * * performs the analysis/ccAnalysis with the symmetric matrix + * * gets the eigenmatrix and the eigenvalues using math/Matrix.tqli() */ @Override @@ -211,9 +228,10 @@ public class PaSiMap implements Runnable { try { - //alignment = new PairwiseAlignPanel(seqs, true, 100, 5); + // alignment = new PairwiseAlignPanel(seqs, true, 100, 5); alignment.calculate(scoreMatrix); - float[][] scores = alignment.getAlignmentScores(); //bigger index first -- eg scores[14][13] + float[][] scores = alignment.getAlignmentScores(); // bigger index first + // -- eg scores[14][13] SequenceI[] iseqs = alignment.getInputSequences(); Connectivity.getConnectivity(iseqs, scores, dim); diff --git a/src/jalview/analysis/ccAnalysis.java b/src/jalview/analysis/ccAnalysis.java index 4922a54..62e1913 100755 --- a/src/jalview/analysis/ccAnalysis.java +++ b/src/jalview/analysis/ccAnalysis.java @@ -55,11 +55,11 @@ import org.apache.commons.math3.linear.SingularValueDecomposition; /** * A class to model rectangular matrices of double values and operations on them */ -public class ccAnalysis +public class ccAnalysis { - private byte dim = 0; //dimensions + private byte dim = 0; // dimensions - private MatrixI scoresOld; //input scores + private MatrixI scoresOld; // input scores public ccAnalysis(MatrixI scores, byte dim) { @@ -68,29 +68,33 @@ public class ccAnalysis { for (int j = 0; j < scores.width(); j++) { - if (!Double.isNaN(scores.getValue(i,j))) - { - scores.setValue(i, j, (double) Math.round(scores.getValue(i,j) * (int) 10000) / 10000); - } + if (!Double.isNaN(scores.getValue(i, j))) + { + scores.setValue(i, j, + (double) Math.round(scores.getValue(i, j) * (int) 10000) + / 10000); + } } } this.scoresOld = scores; this.dim = dim; } - /** - * Initialise a distrust-score for each hypothesis (h) of hSigns - * distrust = conHypNum - proHypNum - * - * @param hSigns ~ hypothesis signs (+/-) for each sequence - * @param scores ~ input score matrix - * - * @return distrustScores - */ + /** + * Initialise a distrust-score for each hypothesis (h) of hSigns distrust = + * conHypNum - proHypNum + * + * @param hSigns + * ~ hypothesis signs (+/-) for each sequence + * @param scores + * ~ input score matrix + * + * @return distrustScores + */ private int[] initialiseDistrusts(byte[] hSigns, MatrixI scores) { int[] distrustScores = new int[scores.width()]; - + // loop over symmetric matrix for (int i = 0; i < scores.width(); i++) { @@ -100,34 +104,43 @@ public class ccAnalysis for (int j = 0; j < scores.width(); j++) { - double cell = scores.getRow(i)[j]; // value at [i][j] in scores - byte hBSign = hSigns[j]; - if (!Double.isNaN(cell)) - { - byte cellSign = (byte) Math.signum(cell); //check if sign of matrix value fits hyptohesis - if (cellSign == hASign * hBSign) - { - proHypNum++; - } else { - conHypNum++; - } - } + double cell = scores.getRow(i)[j]; // value at [i][j] in scores + byte hBSign = hSigns[j]; + if (!Double.isNaN(cell)) + { + byte cellSign = (byte) Math.signum(cell); // check if sign of matrix + // value fits hyptohesis + if (cellSign == hASign * hBSign) + { + proHypNum++; + } + else + { + conHypNum++; + } + } } - distrustScores[i] = conHypNum - proHypNum; //create distrust score for each sequence + distrustScores[i] = conHypNum - proHypNum; // create distrust score for + // each sequence } return distrustScores; } /** - * Optemise hypothesis concerning the sign of the hypothetical value for each hSigns by interpreting the pairwise correlation coefficients as scalar products - * - * @param hSigns ~ hypothesis signs (+/-) - * @param distrustScores - * @param scores ~ input score matrix - * - * @return hSigns - */ - private byte[] optimiseHypothesis(byte[] hSigns, int[] distrustScores, MatrixI scores) + * Optimise hypothesis concerning the sign of the hypothetical value for each + * hSigns by interpreting the pairwise correlation coefficients as scalar + * products + * + * @param hSigns + * ~ hypothesis signs (+/-) + * @param distrustScores + * @param scores + * ~ input score matrix + * + * @return hSigns + */ + private byte[] optimiseHypothesis(byte[] hSigns, int[] distrustScores, + MatrixI scores) { // get maximum distrust score int[] maxes = MiscMath.findMax(distrustScores); @@ -137,7 +150,7 @@ public class ccAnalysis // if hypothesis is not optimal yet if (maxDistrust > 0) { - //toggle sign for hI with maximum distrust + // toggle sign for hI with maximum distrust hSigns[maxDistrustIndex] *= -1; // update distrust at same position distrustScores[maxDistrustIndex] *= -1; @@ -146,299 +159,327 @@ public class ccAnalysis byte hASign = hSigns[maxDistrustIndex]; for (int NOTmaxDistrustIndex = 0; NOTmaxDistrustIndex < distrustScores.length; NOTmaxDistrustIndex++) { - if (NOTmaxDistrustIndex != maxDistrustIndex) - { - byte hBSign = hSigns[NOTmaxDistrustIndex]; - double cell = scores.getValue(maxDistrustIndex, NOTmaxDistrustIndex); - - // distrust only changed if not NaN - if (!Double.isNaN(cell)) - { - byte cellSign = (byte) Math.signum(cell); - // if sign of cell matches hypothesis decrease distrust by 2 because 1 more value supporting and 1 less contradicting - // else increase by 2 - if (cellSign == hASign * hBSign) - { - distrustScores[NOTmaxDistrustIndex] -= 2; - } else { - distrustScores[NOTmaxDistrustIndex] += 2; - } - } - } + if (NOTmaxDistrustIndex != maxDistrustIndex) + { + byte hBSign = hSigns[NOTmaxDistrustIndex]; + double cell = scores.getValue(maxDistrustIndex, + NOTmaxDistrustIndex); + + // distrust only changed if not NaN + if (!Double.isNaN(cell)) + { + byte cellSign = (byte) Math.signum(cell); + // if sign of cell matches hypothesis decrease distrust by 2 because + // 1 more value supporting and 1 less contradicting + // else increase by 2 + if (cellSign == hASign * hBSign) + { + distrustScores[NOTmaxDistrustIndex] -= 2; + } + else + { + distrustScores[NOTmaxDistrustIndex] += 2; + } + } + } } - //further optimisation necessary + // further optimisation necessary return optimiseHypothesis(hSigns, distrustScores, scores); - } else { + } + else + { return hSigns; } } - /** - * takes the a symmetric MatrixI as input scores which may contain Double.NaN - * approximate the missing values using hypothesis optimisation - * - * runs analysis - * - * @param scores ~ score matrix - * - * @return - */ - public MatrixI run () throws Exception + /** + * takes the a symmetric MatrixI as input scores which may contain Double.NaN + * approximate the missing values using hypothesis optimisation + * + * runs analysis + * + * @param scores + * ~ score matrix + * + * @return + */ + public MatrixI run() throws Exception { - //initialse eigenMatrix and repMatrix + // initialse eigenMatrix and repMatrix MatrixI eigenMatrix = scoresOld.copy(); MatrixI repMatrix = scoresOld.copy(); try { - /* - * Calculate correction factor for 2nd and higher eigenvalue(s). - * This correction is NOT needed for the 1st eigenvalue, because the - * unknown (=NaN) values of the matrix are approximated by presuming - * 1-dimensional vectors as the basis of the matrix interpretation as dot - * products. - */ - - System.out.println("Input correlation matrix:"); - eigenMatrix.print(System.out, "%1.4f "); - - int matrixWidth = eigenMatrix.width(); // square matrix, so width == height - int matrixElementsTotal = (int) Math.pow(matrixWidth, 2); //total number of elemts - - float correctionFactor = (float) (matrixElementsTotal - eigenMatrix.countNaN()) / (float) matrixElementsTotal; - - /* - * Calculate hypothetical value (1-dimensional vector) h_i for each - * dataset by interpreting the given correlation coefficients as scalar - * products. - */ - - /* - * Memory for current hypothesis concerning sign of each h_i. - * List of signs for all h_i in the encoding: + /* + * Calculate correction factor for 2nd and higher eigenvalue(s). + * This correction is NOT needed for the 1st eigenvalue, because the + * unknown (=NaN) values of the matrix are approximated by presuming + * 1-dimensional vectors as the basis of the matrix interpretation as dot + * products. + */ + + System.out.println("Input correlation matrix:"); + eigenMatrix.print(System.out, "%1.4f "); + + int matrixWidth = eigenMatrix.width(); // square matrix, so width == + // height + int matrixElementsTotal = (int) Math.pow(matrixWidth, 2); // total number + // of elemts + + float correctionFactor = (float) (matrixElementsTotal + - eigenMatrix.countNaN()) / (float) matrixElementsTotal; + + /* + * Calculate hypothetical value (1-dimensional vector) h_i for each + * dataset by interpreting the given correlation coefficients as scalar + * products. + */ + + /* + * Memory for current hypothesis concerning sign of each h_i. + * List of signs for all h_i in the encoding: * * 1: positive * * 0: zero * * -1: negative - * Initial hypothesis: all signs are positive. - */ - byte[] hSigns = new byte[matrixWidth]; - Arrays.fill(hSigns, (byte) 1); - - //Estimate signs for each h_i by refining hypothesis on signs. - hSigns = optimiseHypothesis(hSigns, initialiseDistrusts(hSigns, eigenMatrix), eigenMatrix); - - - //Estimate absolute values for each h_i by determining sqrt of mean of - //non-NaN absolute values for every row. - double[] hAbs = MiscMath.sqrt(eigenMatrix.absolute().meanRow()); - - //Combine estimated signs with absolute values in obtain total value for - //each h_i. - double[] hValues = MiscMath.elementwiseMultiply(hSigns, hAbs); - - /*Complement symmetric matrix by using the scalar products of estimated - *values of h_i to replace NaN-cells. - *Matrix positions that have estimated values - *(only for diagonal and upper off-diagonal values, due to the symmetry - *the positions of the lower-diagonal values can be inferred). - List of tuples (row_idx, column_idx).*/ - - ArrayList estimatedPositions = new ArrayList(); - - // for off-diagonal cells - for (int rowIndex = 0; rowIndex < matrixWidth - 1; rowIndex++) - { - for (int columnIndex = rowIndex + 1; columnIndex < matrixWidth; columnIndex++) + * Initial hypothesis: all signs are positive. + */ + byte[] hSigns = new byte[matrixWidth]; + Arrays.fill(hSigns, (byte) 1); + + // Estimate signs for each h_i by refining hypothesis on signs. + hSigns = optimiseHypothesis(hSigns, + initialiseDistrusts(hSigns, eigenMatrix), eigenMatrix); + + // Estimate absolute values for each h_i by determining sqrt of mean of + // non-NaN absolute values for every row. + double[] hAbs = MiscMath.sqrt(eigenMatrix.absolute().meanRow()); + + // Combine estimated signs with absolute values in obtain total value for + // each h_i. + double[] hValues = MiscMath.elementwiseMultiply(hSigns, hAbs); + + /*Complement symmetric matrix by using the scalar products of estimated + *values of h_i to replace NaN-cells. + *Matrix positions that have estimated values + *(only for diagonal and upper off-diagonal values, due to the symmetry + *the positions of the lower-diagonal values can be inferred). + List of tuples (row_idx, column_idx).*/ + + ArrayList estimatedPositions = new ArrayList(); + + // for off-diagonal cells + for (int rowIndex = 0; rowIndex < matrixWidth - 1; rowIndex++) { - double cell = eigenMatrix.getValue(rowIndex, columnIndex); - if (Double.isNaN(cell)) - { - //calculate scalar product as new cell value - cell = hValues[rowIndex] * hValues[columnIndex]; - //fill in new value in cell and symmetric partner - eigenMatrix.setValue(rowIndex, columnIndex, cell); - eigenMatrix.setValue(columnIndex, rowIndex, cell); - //save positions of estimated values - estimatedPositions.add(new int[]{rowIndex, columnIndex}); - } + for (int columnIndex = rowIndex + + 1; columnIndex < matrixWidth; columnIndex++) + { + double cell = eigenMatrix.getValue(rowIndex, columnIndex); + if (Double.isNaN(cell)) + { + // calculate scalar product as new cell value + cell = hValues[rowIndex] * hValues[columnIndex]; + // fill in new value in cell and symmetric partner + eigenMatrix.setValue(rowIndex, columnIndex, cell); + eigenMatrix.setValue(columnIndex, rowIndex, cell); + // save positions of estimated values + estimatedPositions.add(new int[] { rowIndex, columnIndex }); + } + } } - } - // for diagonal cells - for (int diagonalIndex = 0; diagonalIndex < matrixWidth; diagonalIndex++) + // for diagonal cells + for (int diagonalIndex = 0; diagonalIndex < matrixWidth; diagonalIndex++) { double cell = Math.pow(hValues[diagonalIndex], 2); - eigenMatrix.setValue(diagonalIndex, diagonalIndex, cell); - estimatedPositions.add(new int[]{diagonalIndex, diagonalIndex}); + eigenMatrix.setValue(diagonalIndex, diagonalIndex, cell); + estimatedPositions.add(new int[] { diagonalIndex, diagonalIndex }); } - /*Refine total values of each h_i: - *Initialise h_values of the hypothetical non-existant previous iteration - *with the correct format but with impossible values. - Needed for exit condition of otherwise endless loop.*/ - System.out.print("initial values: [ "); - for (double h : hValues) - { - System.out.print(String.format("%1.4f, ", h)); - } - System.out.println(" ]"); - - - double[] hValuesOld = new double[matrixWidth]; - - int iterationCount = 0; - - // repeat unitl values of h do not significantly change anymore - while (true) - { - for (int hIndex = 0; hIndex < matrixWidth; hIndex++) - { - double newH = Arrays.stream(MiscMath.elementwiseMultiply(hValues, eigenMatrix.getRow(hIndex))).sum() / Arrays.stream(MiscMath.elementwiseMultiply(hValues, hValues)).sum(); - hValues[hIndex] = newH; - } - - System.out.print(String.format("iteration %d: [ ", iterationCount)); + /*Refine total values of each h_i: + *Initialise h_values of the hypothetical non-existant previous iteration + *with the correct format but with impossible values. + Needed for exit condition of otherwise endless loop.*/ + System.out.print("initial values: [ "); for (double h : hValues) { - System.out.print(String.format("%1.4f, ", h)); + System.out.print(String.format("%1.4f, ", h)); } System.out.println(" ]"); - //update values of estimated positions - for (int[] pair : estimatedPositions) // pair ~ row, col - { - double newVal = hValues[pair[0]] * hValues[pair[1]]; - eigenMatrix.setValue(pair[0], pair[1], newVal); - eigenMatrix.setValue(pair[1], pair[0], newVal); - } + double[] hValuesOld = new double[matrixWidth]; - iterationCount++; + int iterationCount = 0; - //exit loop as soon as new values are similar to the last iteration - if (MiscMath.allClose(hValues, hValuesOld, 0d, 1e-05d, false)) + // FIXME JAL-4443 - spliterators could be coded out or patched with j2s + // annotation + // repeat unitl values of h do not significantly change anymore + while (true) { - break; + for (int hIndex = 0; hIndex < matrixWidth; hIndex++) + { + double newH = Arrays + .stream(MiscMath.elementwiseMultiply(hValues, + eigenMatrix.getRow(hIndex))) + .sum() + / Arrays.stream( + MiscMath.elementwiseMultiply(hValues, hValues)) + .sum(); + hValues[hIndex] = newH; + } + + System.out.print(String.format("iteration %d: [ ", iterationCount)); + for (double h : hValues) + { + System.out.print(String.format("%1.4f, ", h)); + } + System.out.println(" ]"); + + // update values of estimated positions + for (int[] pair : estimatedPositions) // pair ~ row, col + { + double newVal = hValues[pair[0]] * hValues[pair[1]]; + eigenMatrix.setValue(pair[0], pair[1], newVal); + eigenMatrix.setValue(pair[1], pair[0], newVal); + } + + iterationCount++; + + // exit loop as soon as new values are similar to the last iteration + if (MiscMath.allClose(hValues, hValuesOld, 0d, 1e-05d, false)) + { + break; + } + + // save hValues for comparison in the next iteration + System.arraycopy(hValues, 0, hValuesOld, 0, hValues.length); } - //save hValues for comparison in the next iteration - System.arraycopy(hValues, 0, hValuesOld, 0, hValues.length); - } - - //----------------------------- - //Use complemented symmetric matrix to calculate final representative - //vectors. - - //Eigendecomposition. - eigenMatrix.tred(); - eigenMatrix.tqli(); + // ----------------------------- + // Use complemented symmetric matrix to calculate final representative + // vectors. - System.out.println("eigenmatrix"); - eigenMatrix.print(System.out, "%8.2f"); - System.out.println(); - System.out.println("uncorrected eigenvalues"); - eigenMatrix.printD(System.out, "%2.4f "); - System.out.println(); + // Eigendecomposition. + eigenMatrix.tred(); + eigenMatrix.tqli(); - double[] eigenVals = eigenMatrix.getD(); + System.out.println("eigenmatrix"); + eigenMatrix.print(System.out, "%8.2f"); + System.out.println(); + System.out.println("uncorrected eigenvalues"); + eigenMatrix.printD(System.out, "%2.4f "); + System.out.println(); - TreeMap eigenPairs = new TreeMap<>(Comparator.reverseOrder()); - for (int i = 0; i < eigenVals.length; i++) - { - eigenPairs.put(eigenVals[i], i); - } + double[] eigenVals = eigenMatrix.getD(); - // matrix of representative eigenvectors (each row is a vector) - double[][] _repMatrix = new double[eigenVals.length][dim]; - double[][] _oldMatrix = new double[eigenVals.length][dim]; - double[] correctedEigenValues = new double[dim]; - - int l = 0; - for (Entry pair : eigenPairs.entrySet()) - { - double eigenValue = pair.getKey(); - int column = pair.getValue(); - double[] eigenVector = eigenMatrix.getColumn(column); - //for 2nd and higher eigenvalues - if (l >= 1) + TreeMap eigenPairs = new TreeMap<>( + Comparator.reverseOrder()); + for (int i = 0; i < eigenVals.length; i++) { - eigenValue /= correctionFactor; + eigenPairs.put(eigenVals[i], i); } - correctedEigenValues[l] = eigenValue; - for (int j = 0; j < eigenVector.length; j++) - { - _repMatrix[j][l] = (eigenValue < 0) ? 0.0 : - Math.sqrt(eigenValue) * eigenVector[j]; - double tmpOldScore = scoresOld.getColumn(column)[j]; - _oldMatrix[j][dim - l - 1] = (Double.isNaN(tmpOldScore)) ? 0.0 : tmpOldScore; - } - l++; - if (l >= dim) - { - break; - } - } - System.out.println("correctedEigenValues"); - MiscMath.print(correctedEigenValues, "%2.4f "); - - repMatrix = new Matrix(_repMatrix); - repMatrix.setD(correctedEigenValues); - MatrixI oldMatrix = new Matrix(_oldMatrix); - - MatrixI dotMatrix = repMatrix.postMultiply(repMatrix.transpose()); - - double rmsd = scoresOld.rmsd(dotMatrix); - - System.out.println("iteration, rmsd, maxDiff, rmsdDiff"); - System.out.println(String.format("0, %8.5f, -, -", rmsd)); - // Refine representative vectors by minimising sum-of-squared deviates between dotMatrix and original score matrix - for (int iteration = 1; iteration < 21; iteration++) // arbitrarily set to 20 - { - MatrixI repMatrixOLD = repMatrix.copy(); - MatrixI dotMatrixOLD = dotMatrix.copy(); + // matrix of representative eigenvectors (each row is a vector) + double[][] _repMatrix = new double[eigenVals.length][dim]; + double[][] _oldMatrix = new double[eigenVals.length][dim]; + double[] correctedEigenValues = new double[dim]; - // for all rows/hA in the original matrix - for (int hAIndex = 0; hAIndex < oldMatrix.height(); hAIndex++) + int l = 0; + for (Entry pair : eigenPairs.entrySet()) { - double[] row = oldMatrix.getRow(hAIndex); - double[] hA = repMatrix.getRow(hAIndex); - hAIndex = hAIndex; - //find least-squares-solution fo rdifferences between original scores and representative vectors - double[] hAlsm = leastSquaresOptimisation(repMatrix, scoresOld, hAIndex); - // update repMatrix with new hAlsm - for (int j = 0; j < repMatrix.width(); j++) - { - repMatrix.setValue(hAIndex, j, hAlsm[j]); - } - } - - // dot product of representative vecotrs yields a matrix with values approximating the correlation matrix - dotMatrix = repMatrix.postMultiply(repMatrix.transpose()); - // calculate rmsd between approximation and correlation matrix - rmsd = scoresOld.rmsd(dotMatrix); - - // calculate maximum change of representative vectors of current iteration - MatrixI diff = repMatrix.subtract(repMatrixOLD).absolute(); - double maxDiff = 0.0; - for (int i = 0; i < diff.height(); i++) - { - for (int j = 0; j < diff.width(); j++) - { - maxDiff = (diff.getValue(i, j) > maxDiff) ? diff.getValue(i, j) : maxDiff; - } + double eigenValue = pair.getKey(); + int column = pair.getValue(); + double[] eigenVector = eigenMatrix.getColumn(column); + // for 2nd and higher eigenvalues + if (l >= 1) + { + eigenValue /= correctionFactor; + } + correctedEigenValues[l] = eigenValue; + for (int j = 0; j < eigenVector.length; j++) + { + _repMatrix[j][l] = (eigenValue < 0) ? 0.0 + : -Math.sqrt(eigenValue) * eigenVector[j]; + double tmpOldScore = scoresOld.getColumn(column)[j]; + _oldMatrix[j][dim - l - 1] = (Double.isNaN(tmpOldScore)) ? 0.0 + : tmpOldScore; + } + l++; + if (l >= dim) + { + break; + } } - // calculate rmsd between current and previous estimation - double rmsdDiff = dotMatrix.rmsd(dotMatrixOLD); + System.out.println("correctedEigenValues"); + MiscMath.print(correctedEigenValues, "%2.4f "); + + repMatrix = new Matrix(_repMatrix); + repMatrix.setD(correctedEigenValues); + MatrixI oldMatrix = new Matrix(_oldMatrix); - System.out.println(String.format("%d, %8.5f, %8.5f, %8.5f", iteration, rmsd, maxDiff, rmsdDiff)); + MatrixI dotMatrix = repMatrix.postMultiply(repMatrix.transpose()); - if (!(Math.abs(maxDiff) > 1e-06)) + double rmsd = scoresOld.rmsd(dotMatrix); + + System.out.println("iteration, rmsd, maxDiff, rmsdDiff"); + System.out.println(String.format("0, %8.5f, -, -", rmsd)); + // Refine representative vectors by minimising sum-of-squared deviates + // between dotMatrix and original score matrix + for (int iteration = 1; iteration < 21; iteration++) // arbitrarily set to + // 20 { - repMatrix = repMatrixOLD.copy(); - break; + MatrixI repMatrixOLD = repMatrix.copy(); + MatrixI dotMatrixOLD = dotMatrix.copy(); + + // for all rows/hA in the original matrix + for (int hAIndex = 0; hAIndex < oldMatrix.height(); hAIndex++) + { + double[] row = oldMatrix.getRow(hAIndex); + double[] hA = repMatrix.getRow(hAIndex); + hAIndex = hAIndex; + // find least-squares-solution fo rdifferences between original scores + // and representative vectors + double[] hAlsm = leastSquaresOptimisation(repMatrix, scoresOld, + hAIndex); + // update repMatrix with new hAlsm + for (int j = 0; j < repMatrix.width(); j++) + { + repMatrix.setValue(hAIndex, j, hAlsm[j]); + } + } + + // dot product of representative vecotrs yields a matrix with values + // approximating the correlation matrix + dotMatrix = repMatrix.postMultiply(repMatrix.transpose()); + // calculate rmsd between approximation and correlation matrix + rmsd = scoresOld.rmsd(dotMatrix); + + // calculate maximum change of representative vectors of current + // iteration + MatrixI diff = repMatrix.subtract(repMatrixOLD).absolute(); + double maxDiff = 0.0; + for (int i = 0; i < diff.height(); i++) + { + for (int j = 0; j < diff.width(); j++) + { + maxDiff = (diff.getValue(i, j) > maxDiff) ? diff.getValue(i, j) + : maxDiff; + } + } + + // calculate rmsd between current and previous estimation + double rmsdDiff = dotMatrix.rmsd(dotMatrixOLD); + + System.out.println(String.format("%d, %8.5f, %8.5f, %8.5f", + iteration, rmsd, maxDiff, rmsdDiff)); + + if (!(Math.abs(maxDiff) > 1e-06)) + { + repMatrix = repMatrixOLD.copy(); + break; + } } - } - } catch (Exception q) { @@ -451,35 +492,48 @@ public class ccAnalysis } /** - * Create equations system using information on originally known - * pairwise correlation coefficients (parsed from infile) and the - * representative result vectors - * - * Each equation has the format: - * hA * hA - pairwiseCC = 0 - * with: - * hA: unknown variable - * hB: known representative vector - * pairwiseCC: known pairwise correlation coefficien - * - * The resulting equations system is overdetermined, if there are more - * equations than unknown elements - * - * @param x ~ unknown n-dimensional column-vector - * (needed for generating equations system, NOT to be specified by user). - * @param hAIndex ~ index of currently optimised representative result vector. - * @param h ~ matrix with row-wise listing of representative result vectors. - * @param originalRow ~ matrix-row of originally parsed pairwise correlation coefficients. - * - * @return - */ - private double[] originalToEquasionSystem(double[] hA, MatrixI repMatrix, MatrixI scoresOld, int hAIndex) + * Create equations system using information on originally known pairwise + * correlation coefficients (parsed from infile) and the representative result + * vectors + * + * Each equation has the format: + * + * hA * hA - pairwiseCC = 0 + * + * with: + * + * hA: unknown variable + * + * hB: known representative vector + * + * pairwiseCC: known pairwise correlation coefficien + * + * The resulting equations system is overdetermined, if there are more + * equations than unknown elements + * + * x is the user input. Remaining parameters are needed for generating + * equations system, NOT to be specified by user). + * + * @param x + * ~ unknown n-dimensional column-vector + * @param hAIndex + * ~ index of currently optimised representative result vector. + * @param h + * ~ matrix with row-wise listing of representative result vectors. + * @param originalRow + * ~ matrix-row of originally parsed pairwise correlation + * coefficients. + * + * @return + */ + private double[] originalToEquasionSystem(double[] hA, MatrixI repMatrix, + MatrixI scoresOld, int hAIndex) { double[] originalRow = scoresOld.getRow(hAIndex); int nans = MiscMath.countNaN(originalRow); double[] result = new double[originalRow.length - nans]; - //for all pairwiseCC in originalRow + // for all pairwiseCC in originalRow int resultIndex = 0; for (int hBIndex = 0; hBIndex < originalRow.length; hBIndex++) { @@ -488,40 +542,48 @@ public class ccAnalysis if (!Double.isNaN(pairwiseCC)) { double[] hB = repMatrix.getRow(hBIndex); - result[resultIndex++] = MiscMath.sum(MiscMath.elementwiseMultiply(hA, hB)) - pairwiseCC; - } else { + result[resultIndex++] = MiscMath + .sum(MiscMath.elementwiseMultiply(hA, hB)) - pairwiseCC; + } + else + { } } return result; } /** - * returns the jacobian matrix - * @param repMatrix ~ matrix of representative vectors - * @param hAIndex ~ current row index - * - * @return - */ - private MatrixI approximateDerivative(MatrixI repMatrix, MatrixI scoresOld, int hAIndex) + * returns the jacobian matrix + * + * @param repMatrix + * ~ matrix of representative vectors + * @param hAIndex + * ~ current row index + * + * @return + */ + private MatrixI approximateDerivative(MatrixI repMatrix, + MatrixI scoresOld, int hAIndex) { - //hA = x0 + // hA = x0 double[] hA = repMatrix.getRow(hAIndex); - double[] f0 = originalToEquasionSystem(hA, repMatrix, scoresOld, hAIndex); + double[] f0 = originalToEquasionSystem(hA, repMatrix, scoresOld, + hAIndex); double[] signX0 = new double[hA.length]; double[] xAbs = new double[hA.length]; for (int i = 0; i < hA.length; i++) { signX0[i] = (hA[i] >= 0) ? 1 : -1; xAbs[i] = (Math.abs(hA[i]) >= 1.0) ? Math.abs(hA[i]) : 1.0; - } + } double rstep = Math.pow(Math.ulp(1.0), 0.5); - double[] h = new double [hA.length]; + double[] h = new double[hA.length]; for (int i = 0; i < hA.length; i++) { h[i] = rstep * signX0[i] * xAbs[i]; } - + int m = f0.length; int n = hA.length; double[][] jTransposed = new double[n][m]; @@ -531,11 +593,12 @@ public class ccAnalysis System.arraycopy(hA, 0, x, 0, h.length); x[i] += h[i]; double dx = x[i] - hA[i]; - double[] df = originalToEquasionSystem(x, repMatrix, scoresOld, hAIndex); + double[] df = originalToEquasionSystem(x, repMatrix, scoresOld, + hAIndex); for (int j = 0; j < df.length; j++) { - df[j] -= f0[j]; - jTransposed[i][j] = df[j] / dx; + df[j] -= f0[j]; + jTransposed[i][j] = df[j] / dx; } } MatrixI J = new Matrix(jTransposed).transpose(); @@ -543,31 +606,40 @@ public class ccAnalysis } /** - * norm of regularized (by alpha) least-squares solution minus Delta - * @param alpha - * @param suf - * @param s - * @param Delta - * - * @return - */ - private double[] phiAndDerivative(double alpha, double[] suf, double[] s, double Delta) + * norm of regularized (by alpha) least-squares solution minus Delta + * + * @param alpha + * @param suf + * @param s + * @param Delta + * + * @return + */ + private double[] phiAndDerivative(double alpha, double[] suf, double[] s, + double Delta) { - double[] denom = MiscMath.elementwiseAdd(MiscMath.elementwiseMultiply(s, s), alpha); + double[] denom = MiscMath + .elementwiseAdd(MiscMath.elementwiseMultiply(s, s), alpha); double pNorm = MiscMath.norm(MiscMath.elementwiseDivide(suf, denom)); double phi = pNorm - Delta; // - sum ( suf**2 / denom**3) / pNorm - double phiPrime = - MiscMath.sum(MiscMath.elementwiseDivide(MiscMath.elementwiseMultiply(suf, suf), MiscMath.elementwiseMultiply(MiscMath.elementwiseMultiply(denom, denom), denom))) / pNorm; - return new double[]{phi, phiPrime}; + double phiPrime = -MiscMath.sum(MiscMath.elementwiseDivide( + MiscMath.elementwiseMultiply(suf, suf), + MiscMath.elementwiseMultiply( + MiscMath.elementwiseMultiply(denom, denom), denom))) + / pNorm; + return new double[] { phi, phiPrime }; } /** - * class holding the result of solveLsqTrustRegion - */ + * class holding the result of solveLsqTrustRegion + */ private class TrustRegion { private double[] step; + private double alpha; + private int iteration; public TrustRegion(double[] step, double alpha, int iteration) @@ -586,7 +658,7 @@ public class ccAnalysis { return this.alpha; } - + public int getIteration() { return this.iteration; @@ -594,22 +666,30 @@ public class ccAnalysis } /** - * solve a trust-region problem arising in least-squares optimisation - * @param n ~ number of variables - * @param m ~ number of residuals - * @param uf - * @param s ~ singular values of J - * @param V ~ transpose of VT - * @param Delta ~ radius of a trust region - * @param alpha ~ initial guess for alpha - * - * @return - */ - private TrustRegion solveLsqTrustRegion(int n, int m, double[] uf, double[] s, MatrixI V, double Delta, double alpha) + * solve a trust-region problem arising in least-squares optimisation + * + * @param n + * ~ number of variables + * @param m + * ~ number of residuals + * @param uf + * @param s + * ~ singular values of J + * @param V + * ~ transpose of VT + * @param Delta + * ~ radius of a trust region + * @param alpha + * ~ initial guess for alpha + * + * @return + */ + private TrustRegion solveLsqTrustRegion(int n, int m, double[] uf, + double[] s, MatrixI V, double Delta, double alpha) { double[] suf = MiscMath.elementwiseMultiply(s, uf); - //check if J has full rank and tr Gauss-Newton step + // check if J has full rank and tr Gauss-Newton step boolean fullRank = false; if (m >= n) { @@ -618,7 +698,8 @@ public class ccAnalysis } if (fullRank) { - double[] p = MiscMath.elementwiseMultiply(V.sumProduct(MiscMath.elementwiseDivide(uf, s)), -1); + double[] p = MiscMath.elementwiseMultiply( + V.sumProduct(MiscMath.elementwiseDivide(uf, s)), -1); if (MiscMath.norm(p) <= Delta) { TrustRegion result = new TrustRegion(p, 0.0, 0); @@ -631,15 +712,21 @@ public class ccAnalysis if (fullRank) { double[] phiAndPrime = phiAndDerivative(0.0, suf, s, Delta); - alphaLower = - phiAndPrime[0] / phiAndPrime[1]; + alphaLower = -phiAndPrime[0] / phiAndPrime[1]; } - alpha = (!fullRank && alpha == 0.0) ? alpha = Math.max(0.001 * alphaUpper, Math.pow(alphaLower * alphaUpper, 0.5)) : alpha; + alpha = (!fullRank && alpha == 0.0) + ? alpha = Math.max(0.001 * alphaUpper, + Math.pow(alphaLower * alphaUpper, 0.5)) + : alpha; int iteration = 0; - while (iteration < 10) // 10 is default max_iter + while (iteration < 10) // 10 is default max_iter { - alpha = (alpha < alphaLower || alpha > alphaUpper) ? alpha = Math.max(0.001 * alphaUpper, Math.pow(alphaLower * alphaUpper, 0.5)) : alpha; + alpha = (alpha < alphaLower || alpha > alphaUpper) + ? alpha = Math.max(0.001 * alphaUpper, + Math.pow(alphaLower * alphaUpper, 0.5)) + : alpha; double[] phiAndPrime = phiAndDerivative(alpha, suf, s, Delta); double phi = phiAndPrime[0]; double phiPrime = phiAndPrime[1]; @@ -649,18 +736,20 @@ public class ccAnalysis alphaLower = Math.max(alphaLower, alpha - ratio); alpha -= (phi + Delta) * ratio / Delta; - if (Math.abs(phi) < 0.01 * Delta) // default rtol set to 0.01 + if (Math.abs(phi) < 0.01 * Delta) // default rtol set to 0.01 { - break; + break; } iteration++; } // p = - V.dot( suf / (s**2 + alpha)) - double[] tmp = MiscMath.elementwiseDivide(suf, MiscMath.elementwiseAdd(MiscMath.elementwiseMultiply(s, s), alpha)); + double[] tmp = MiscMath.elementwiseDivide(suf, MiscMath + .elementwiseAdd(MiscMath.elementwiseMultiply(s, s), alpha)); double[] p = MiscMath.elementwiseMultiply(V.sumProduct(tmp), -1); - // Make the norm of p equal to Delta, p is changed only slightly during this. + // Make the norm of p equal to Delta, p is changed only slightly during + // this. // It is done to prevent p lie outside of the trust region p = MiscMath.elementwiseMultiply(p, Delta / MiscMath.norm(p)); @@ -669,15 +758,18 @@ public class ccAnalysis } /** - * compute values of a quadratic function arising in least squares - * function: 0.5 * s.T * (J.T * J + diag) * s + g.T * s - * - * @param J ~ jacobian matrix - * @param g ~ gradient - * @param s ~ steps and rows - * - * @return - */ + * compute values of a quadratic function arising in least squares function: + * 0.5 * s.T * (J.T * J + diag) * s + g.T * s + * + * @param J + * ~ jacobian matrix + * @param g + * ~ gradient + * @param s + * ~ steps and rows + * + * @return + */ private double evaluateQuadratic(MatrixI J, double[] g, double[] s) { @@ -689,50 +781,64 @@ public class ccAnalysis } /** - * update the radius of a trust region based on the cost reduction - * - * @param Delta - * @param actualReduction - * @param predictedReduction - * @param stepNorm - * @param boundHit - * - * @return - */ - private double[] updateTrustRegionRadius(double Delta, double actualReduction, double predictedReduction, double stepNorm, boolean boundHit) + * update the radius of a trust region based on the cost reduction + * + * @param Delta + * @param actualReduction + * @param predictedReduction + * @param stepNorm + * @param boundHit + * + * @return + */ + private double[] updateTrustRegionRadius(double Delta, + double actualReduction, double predictedReduction, + double stepNorm, boolean boundHit) { double ratio = 0; if (predictedReduction > 0) { ratio = actualReduction / predictedReduction; - } else if (predictedReduction == 0 && actualReduction == 0) { + } + else if (predictedReduction == 0 && actualReduction == 0) + { ratio = 1; - } else { + } + else + { ratio = 0; } if (ratio < 0.25) { Delta = 0.25 * stepNorm; - } else if (ratio > 0.75 && boundHit) { + } + else if (ratio > 0.75 && boundHit) + { Delta *= 2.0; } - return new double[]{Delta, ratio}; + return new double[] { Delta, ratio }; } /** - * trust region reflective algorithm - * @param repMatrix ~ Matrix containing representative vectors - * @param scoresOld ~ Matrix containing initial observations - * @param index ~ current row index - * @param J ~ jacobian matrix - * - * @return - */ - private double[] trf(MatrixI repMatrix, MatrixI scoresOld, int index, MatrixI J) + * trust region reflective algorithm + * + * @param repMatrix + * ~ Matrix containing representative vectors + * @param scoresOld + * ~ Matrix containing initial observations + * @param index + * ~ current row index + * @param J + * ~ jacobian matrix + * + * @return + */ + private double[] trf(MatrixI repMatrix, MatrixI scoresOld, int index, + MatrixI J) { - //hA = x0 + // hA = x0 double[] hA = repMatrix.getRow(index); double[] f0 = originalToEquasionSystem(hA, repMatrix, scoresOld, index); int nfev = 1; @@ -742,7 +848,7 @@ public class ccAnalysis double[] g = J.transpose().sumProduct(f0); double Delta = MiscMath.norm(hA); int maxNfev = hA.length * 100; - double alpha = 0.0; // "Levenberg-Marquardt" parameter + double alpha = 0.0; // "Levenberg-Marquardt" parameter double gNorm = 0; boolean terminationStatus = false; @@ -753,11 +859,12 @@ public class ccAnalysis gNorm = MiscMath.norm(g); if (terminationStatus || nfev == maxNfev) { - break; + break; } - SingularValueDecomposition svd = new SingularValueDecomposition(new Array2DRowRealMatrix(J.asArray())); + SingularValueDecomposition svd = new SingularValueDecomposition( + new Array2DRowRealMatrix(J.asArray())); MatrixI U = new Matrix(svd.getU().getData()); - double[] s = svd.getSingularValues(); + double[] s = svd.getSingularValues(); MatrixI V = new Matrix(svd.getV().getData()).transpose(); double[] uf = U.transpose().sumProduct(f0); @@ -766,60 +873,67 @@ public class ccAnalysis double[] fNew = new double[f0.length]; double costNew = 0; double stepHnorm = 0; - + while (actualReduction <= 0 && nfev < maxNfev) { - TrustRegion trustRegion = solveLsqTrustRegion(n, m, uf, s, V, Delta, alpha); - double[] stepH = trustRegion.getStep(); - alpha = trustRegion.getAlpha(); - int nIterations = trustRegion.getIteration(); - double predictedReduction = - (evaluateQuadratic(J, g, stepH)); + TrustRegion trustRegion = solveLsqTrustRegion(n, m, uf, s, V, Delta, + alpha); + double[] stepH = trustRegion.getStep(); + alpha = trustRegion.getAlpha(); + int nIterations = trustRegion.getIteration(); + double predictedReduction = -(evaluateQuadratic(J, g, stepH)); xNew = MiscMath.elementwiseAdd(hA, stepH); - fNew = originalToEquasionSystem(xNew, repMatrix, scoresOld, index); - nfev++; - - stepHnorm = MiscMath.norm(stepH); + fNew = originalToEquasionSystem(xNew, repMatrix, scoresOld, index); + nfev++; - if (MiscMath.countNaN(fNew) > 0) - { - Delta = 0.25 * stepHnorm; - continue; - } + stepHnorm = MiscMath.norm(stepH); - // usual trust-region step quality estimation - costNew = 0.5 * MiscMath.dot(fNew, fNew); - actualReduction = cost - costNew; + if (MiscMath.countNaN(fNew) > 0) + { + Delta = 0.25 * stepHnorm; + continue; + } - double[] updatedTrustRegion = updateTrustRegionRadius(Delta, actualReduction, predictedReduction, stepHnorm, stepHnorm > (0.95 * Delta)); - double DeltaNew = updatedTrustRegion[0]; - double ratio = updatedTrustRegion[1]; + // usual trust-region step quality estimation + costNew = 0.5 * MiscMath.dot(fNew, fNew); + actualReduction = cost - costNew; - // default ftol and xtol = 1e-8 - boolean ftolSatisfied = actualReduction < (1e-8 * cost) && ratio > 0.25; - boolean xtolSatisfied = stepHnorm < (1e-8 * (1e-8 + MiscMath.norm(hA))); - terminationStatus = ftolSatisfied || xtolSatisfied; - if (terminationStatus) - { - break; - } + double[] updatedTrustRegion = updateTrustRegionRadius(Delta, + actualReduction, predictedReduction, stepHnorm, + stepHnorm > (0.95 * Delta)); + double DeltaNew = updatedTrustRegion[0]; + double ratio = updatedTrustRegion[1]; - alpha *= Delta / DeltaNew; - Delta = DeltaNew; + // default ftol and xtol = 1e-8 + boolean ftolSatisfied = actualReduction < (1e-8 * cost) + && ratio > 0.25; + boolean xtolSatisfied = stepHnorm < (1e-8 + * (1e-8 + MiscMath.norm(hA))); + terminationStatus = ftolSatisfied || xtolSatisfied; + if (terminationStatus) + { + break; + } + + alpha *= Delta / DeltaNew; + Delta = DeltaNew; } if (actualReduction > 0) { - hA = xNew; - f0 = fNew; - cost = costNew; + hA = xNew; + f0 = fNew; + cost = costNew; - J = approximateDerivative(repMatrix, scoresOld, index); + J = approximateDerivative(repMatrix, scoresOld, index); g = J.transpose().sumProduct(f0); - } else { + } + else + { stepHnorm = 0; - actualReduction = 0; + actualReduction = 0; } iteration++; } @@ -828,16 +942,20 @@ public class ccAnalysis } /** - * performs the least squares optimisation - * adapted from https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.least_squares.html#scipy.optimize.least_squares - * - * @param repMatrix ~ Matrix containing representative vectors - * @param scoresOld ~ Matrix containing initial observations - * @param index ~ current row index - * - * @return - */ - private double[] leastSquaresOptimisation(MatrixI repMatrix, MatrixI scoresOld, int index) + * performs the least squares optimisation adapted from + * https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.least_squares.html#scipy.optimize.least_squares + * + * @param repMatrix + * ~ Matrix containing representative vectors + * @param scoresOld + * ~ Matrix containing initial observations + * @param index + * ~ current row index + * + * @return + */ + private double[] leastSquaresOptimisation(MatrixI repMatrix, + MatrixI scoresOld, int index) { MatrixI J = approximateDerivative(repMatrix, scoresOld, index); double[] result = trf(repMatrix, scoresOld, index, J); diff --git a/src/jalview/analysis/scoremodels/DistanceScoreModel.java b/src/jalview/analysis/scoremodels/DistanceScoreModel.java index 55510bd..1bdaad6 100644 --- a/src/jalview/analysis/scoremodels/DistanceScoreModel.java +++ b/src/jalview/analysis/scoremodels/DistanceScoreModel.java @@ -57,5 +57,5 @@ public abstract class DistanceScoreModel implements ScoreModelI return similarities; } - + } diff --git a/src/jalview/analysis/scoremodels/FeatureDistanceModel.java b/src/jalview/analysis/scoremodels/FeatureDistanceModel.java index df45a72..bcc0855 100644 --- a/src/jalview/analysis/scoremodels/FeatureDistanceModel.java +++ b/src/jalview/analysis/scoremodels/FeatureDistanceModel.java @@ -235,7 +235,7 @@ public class FeatureDistanceModel extends DistanceScoreModel public boolean isProtein() { return true; - } + } @Override public String toString() diff --git a/src/jalview/analysis/scoremodels/ScoreModels.java b/src/jalview/analysis/scoremodels/ScoreModels.java index f591c8e..490ec00 100644 --- a/src/jalview/analysis/scoremodels/ScoreModels.java +++ b/src/jalview/analysis/scoremodels/ScoreModels.java @@ -40,7 +40,7 @@ public class ScoreModels private final ScoreMatrix PAM250; private final ScoreMatrix DNA; - + private final ScoreMatrix SECONDARYSTRUCTURE; private static ScoreModels instance; @@ -70,7 +70,7 @@ public class ScoreModels *
  • PAM250
  • *
  • PID
  • *
  • DNA
  • - *
  • Sequence Feature Similarity
  • * + *
  • Sequence Feature Similarity
  • * *
  • Secondary Structure Similarity
  • * */ @@ -85,8 +85,9 @@ public class ScoreModels DNA = loadScoreMatrix("scoreModel/dna.scm"); registerScoreModel(new PIDModel()); registerScoreModel(new FeatureDistanceModel()); - SECONDARYSTRUCTURE = loadScoreMatrix("scoreModel/secondarystructure.scm"); - registerScoreModel(new SecondaryStructureDistanceModel()); + SECONDARYSTRUCTURE = loadScoreMatrix( + "scoreModel/secondarystructure.scm"); + registerScoreModel(new SecondaryStructureDistanceModel()); } @@ -146,7 +147,8 @@ public class ScoreModels public void registerScoreModel(ScoreModelI sm) { - if(sm.getName().equals("SECONDARYSTRUCTURE")) { + if (sm.getName().equals("SECONDARYSTRUCTURE")) + { return; } ScoreModelI sm2 = models.get(sm.getName()); @@ -187,7 +189,7 @@ public class ScoreModels { return PAM250; } - + public ScoreMatrix getSecondaryStructureMatrix() { return SECONDARYSTRUCTURE; diff --git a/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java b/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java index d7859f1..36d55de 100644 --- a/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java +++ b/src/jalview/analysis/scoremodels/SecondaryStructureDistanceModel.java @@ -47,20 +47,19 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel private static final String NAME = "Secondary Structure Similarity"; private ScoreMatrix ssRateMatrix; - - private String description; - + + private String description; + FeatureRenderer fr; - - + /** * Constructor */ public SecondaryStructureDistanceModel() { - + } - + @Override public ScoreModelI getInstance(AlignmentViewPanel view) { @@ -87,27 +86,31 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel fr = view.cloneFeatureRenderer(); return true; } - + /** - * Calculates distance score [i][j] between each pair of protein sequences - * based on their secondary structure annotations (H, E, C). - * The final score is normalised by the number of - * alignment columns processed, providing an average similarity score. + * Calculates distance score [i][j] between each pair of protein sequences + * based on their secondary structure annotations (H, E, C). The final score + * is normalised by the number of alignment columns processed, providing an + * average similarity score. *

    - * The parameters argument can include settings for handling gap-residue aligned - * positions and may determine if the score calculation is based on the longer or shorter - * sequence in each pair. This can be important for handling partial alignments or - * sequences of significantly different lengths. + * The parameters argument can include settings for handling gap-residue + * aligned positions and may determine if the score calculation is based on + * the longer or shorter sequence in each pair. This can be important for + * handling partial alignments or sequences of significantly different + * lengths. * - * @param seqData The aligned sequence data including secondary structure annotations. - * @param params Additional parameters for customising the scoring process, such as gap - * handling and sequence length consideration. + * @param seqData + * The aligned sequence data including secondary structure + * annotations. + * @param params + * Additional parameters for customising the scoring process, such as + * gap handling and sequence length consideration. */ @Override public MatrixI findDistances(AlignmentView seqData, SimilarityParamsI params) - { - + { + SeqCigar[] seqs = seqData.getSequences(); int noseqs = seqs.length; //no of sequences int cpwidth = 0; @@ -125,7 +128,6 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel AlignmentAnnotation[] alignAnnotList = fr.getViewport().getAlignment() .getAlignmentAnnotation(); - /* * Add secondary structure annotations that are added to the annotation track @@ -134,6 +136,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel Map> ssAlignmentAnnotationForSequences = AlignmentUtils.getSequenceAssociatedAlignmentAnnotations(alignAnnotList, ssSource); + /* * scan each column, compute and add to each similarity[i, j] * the number of secondary structure annotation that seqi @@ -141,15 +144,16 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel */ for (int vc = 0; vc < viscont.length; vc += 2) { - //Iterates for each column position - for (int cpos = viscont[vc]; cpos <= viscont[vc + 1]; cpos++) + // Iterates for each column position + for (int cpos = viscont[vc]; cpos <= viscont[vc + 1]; cpos++) { - cpwidth++; //used to normalise the similarity score + cpwidth++; // used to normalise the similarity score /* * get set of sequences without gap in the current column */ - Set seqsWithoutGapAtCol = findSeqsWithoutGapAtColumn(seqs, cpos); + Set seqsWithoutGapAtCol = findSeqsWithoutGapAtColumn(seqs, + cpos); /* * calculate similarity score for each secondary structure annotation on i'th and j'th @@ -158,7 +162,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel */ for (int i = 0; i < (noseqs - 1); i++) { - //Iterates for each sequences + // Iterates for each sequences for (int j = i + 1; j < noseqs; j++) { @@ -167,15 +171,10 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel boolean undefinedSS2 = ssAlignmentAnnotationForSequences.get(seqs[j].getRefSeq()) == null; // Set similarity to max score if both SS are not defined - if (undefinedSS1 && undefinedSS2) { - similarities[i][j] += ssRateMatrix.getMaximumScore(); - continue; - } - - // Set similarity to minimum score if either one SS is not defined - else if(undefinedSS1 || undefinedSS2) { - similarities[i][j] += ssRateMatrix.getMinimumScore(); - continue; + if (undefinedSS1 && undefinedSS2) + { + similarities[i][j] += ssRateMatrix.getMaximumScore(); + continue; } //check if the sequence contains gap in the current column @@ -183,23 +182,27 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel boolean gap2 = !seqsWithoutGapAtCol.contains(seqs[j]); //Variable to store secondary structure at the current column + char ss1 = '*'; char ss2 = '*'; - - //secondary structure is fetched only if the current column is not - //gap for the sequence - if(!gap1 && !undefinedSS1) { - //fetch the position in sequence for the column and finds the - //corresponding secondary structure annotation - //TO DO - consider based on priority and displayed + + // secondary structure is fetched only if the current column is not + // gap for the sequence + if (!gap1 && !undefinedSS1) + { + // fetch the position in sequence for the column and finds the + // corresponding secondary structure annotation + // TO DO - consider based on priority and displayed int seqPosition = seqs[i].findPosition(cpos); AlignmentAnnotation aa = ssAlignmentAnnotationForSequences.get(seqs[i].getRefSeq()).get(0); if(aa!=null) ss1 = AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition); + } - - if(!gap2 && !undefinedSS2) { + + if (!gap2 && !undefinedSS2) + { int seqPosition = seqs[j].findPosition(cpos); AlignmentAnnotation aa = ssAlignmentAnnotationForSequences.get(seqs[j].getRefSeq()).get(0); if(aa!=null) @@ -207,10 +210,12 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel AlignmentUtils.findSSAnnotationForGivenSeqposition(aa, seqPosition); } + if ((!gap1 && !gap2) || params.includeGaps()) { // Calculate similarity score based on the substitution matrix - double similarityScore = ssRateMatrix.getPairwiseScore(ss1, ss2); + double similarityScore = ssRateMatrix.getPairwiseScore(ss1, + ss2); similarities[i][j] += similarityScore; } } @@ -224,30 +229,30 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel * and fill in the bottom half of the matrix */ // TODO JAL-2424 cpwidth may be out by 1 - affects scores but not tree shape - + for (int i = 0; i < noseqs; i++) { for (int j = i + 1; j < noseqs; j++) - { + { similarities[i][j] /= cpwidth; similarities[j][i] = similarities[i][j]; } } return ssRateMatrix.similarityToDistance(new Matrix(similarities)); - + } /** - * Builds and returns a set containing sequences (SeqCigar) which do not - * have a gap at the given column position. + * Builds and returns a set containing sequences (SeqCigar) which do not have + * a gap at the given column position. * * @param seqs * @param columnPosition * (0..) * @return */ - private Set findSeqsWithoutGapAtColumn( - SeqCigar[] seqs, int columnPosition) + private Set findSeqsWithoutGapAtColumn(SeqCigar[] seqs, + int columnPosition) { Set seqsWithoutGapAtCol = new HashSet<>(); for (SeqCigar seq : seqs) @@ -257,14 +262,13 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel { /* * position is not a gap - */ + */ seqsWithoutGapAtCol.add(seq); } } return seqsWithoutGapAtCol; } - @Override public String getName() { @@ -280,7 +284,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel @Override public boolean isDNA() { - return false; + return false; } @Override @@ -288,7 +292,7 @@ public class SecondaryStructureDistanceModel extends DistanceScoreModel { return false; } - + @Override public boolean isSecondaryStructure() { diff --git a/src/jalview/analysis/scoremodels/SimilarityParams.java b/src/jalview/analysis/scoremodels/SimilarityParams.java index 2a25fa8..40a4636 100644 --- a/src/jalview/analysis/scoremodels/SimilarityParams.java +++ b/src/jalview/analysis/scoremodels/SimilarityParams.java @@ -103,7 +103,7 @@ public class SimilarityParams implements SimilarityParamsI private boolean includeGaps; private boolean denominateByShortestLength; - + private String secondaryStructureSource; /** diff --git a/src/jalview/api/AlignViewControllerI.java b/src/jalview/api/AlignViewControllerI.java index 25e4873..098024c 100644 --- a/src/jalview/api/AlignViewControllerI.java +++ b/src/jalview/api/AlignViewControllerI.java @@ -121,7 +121,9 @@ public interface AlignViewControllerI /** * Justify alignment or currently selected region left or right - * @param left - true - means justify left + * + * @param left + * - true - means justify left * @return */ boolean justify_Region(boolean left); diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java index 2cdb251..64e06ee 100644 --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@ -132,7 +132,6 @@ public interface AlignViewportI extends ViewStyleI List getAlignmentSecondaryStructureConsensusAnnotation(); - /** * get the container for alignment gap annotation * @@ -180,7 +179,6 @@ public interface AlignViewportI extends ViewStyleI void setSequenceConsensusHash(ProfilesI hconsensus); void setSequenceSSConsensusHash(Map hSSConsesnusProfileMap); - /** * Set the cDNA complement consensus for the viewport @@ -571,6 +569,7 @@ public interface AlignViewportI extends ViewStyleI * @return */ Iterator getViewAsVisibleContigs(boolean selectedRegionOnly); + /** * notify all concerned that the alignment data has changed and derived data * needs to be recalculated @@ -578,7 +577,8 @@ public interface AlignViewportI extends ViewStyleI public void notifyAlignmentChanged(); /** - * retrieve a matrix associated with the view's alignment's annotation + * retrieve a matrix associated with the view's alignment's annotation + * * @param alignmentAnnotation * @return contact matrix or NULL */ diff --git a/src/jalview/api/analysis/ScoreModelI.java b/src/jalview/api/analysis/ScoreModelI.java index a243c0c..ce415c2 100644 --- a/src/jalview/api/analysis/ScoreModelI.java +++ b/src/jalview/api/analysis/ScoreModelI.java @@ -62,21 +62,18 @@ public interface ScoreModelI // TODO getName, isDNA, isProtein can be static methods in Java 8 - default public boolean isSecondaryStructure() { return false; } /** - * Answers false by default - * Answers true if the data has secondary structure (so should be - * shown in menus in that context) + * Answers false by default Answers true if the data has secondary structure + * (so should be shown in menus in that context) * * @return */ - - + /** * Returns a distance score for the given sequence regions, that is, a matrix * whose value [i][j] is the distance of sequence i from sequence j by some diff --git a/src/jalview/api/analysis/SimilarityParamsI.java b/src/jalview/api/analysis/SimilarityParamsI.java index 43f2866..2558515 100644 --- a/src/jalview/api/analysis/SimilarityParamsI.java +++ b/src/jalview/api/analysis/SimilarityParamsI.java @@ -60,7 +60,7 @@ public interface SimilarityParamsI * @return */ boolean denominateByShortestLength(); - + String getSecondaryStructureSource(); void setSecondaryStructureSource(String secondaryStructureSource); diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index 55a5364..b77ee85 100644 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -3432,8 +3432,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, Menu autoAnnMenu = new Menu( MessageManager.getString("label.autocalculated_annotation")); - Menu selectSS = new Menu( - MessageManager.getString("label.select_secondary_structure_source")); + Menu selectSS = new Menu(MessageManager + .getString("label.select_secondary_structure_source")); showGroupConsensus.addItemListener(this); showGroupConservation.addItemListener(this); showConsensusHistogram.addItemListener(this); diff --git a/src/jalview/bin/Cache.java b/src/jalview/bin/Cache.java index a45fc42..6a82e7d 100755 --- a/src/jalview/bin/Cache.java +++ b/src/jalview/bin/Cache.java @@ -68,6 +68,7 @@ import jalview.urls.IdOrgSettings; import jalview.util.ChannelProperties; import jalview.util.ColorUtils; import jalview.util.HttpUtils; +import jalview.util.LaunchUtils; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.ws.sifts.SiftsSettings; @@ -1273,6 +1274,14 @@ public class Cache sb.append(" ("); sb.append(lafClass); sb.append(")\n"); + // pid() only available in Java 9+ + if (LaunchUtils.getJavaVersion() > 8) + { + sb.append("Java Virtual Machine PID: "); + sb.append(ProcessHandle.current().pid()); + sb.append("\n"); + } + } appendIfNotNull(sb, "Installer version: ", System.getProperty("sys.install4jVersion"), "\n", null); @@ -1309,6 +1318,8 @@ public class Cache System.getProperty("launcher.distdir"), "\n", null); appendIfNotNull(sb, "Launcher appbase: ", System.getProperty("launcher.appbase"), "\n", null); + appendIfNotNull(sb, "Launcher script: ", + System.getProperty("launcher.script"), "\n", null); } return sb.toString(); } @@ -1489,11 +1500,10 @@ public class Cache if (customProxySet && // we have a username but no password for the scheme being // requested - (protocol.equalsIgnoreCase("http") - && (httpUser != null - && httpUser.length() > 0 - && (httpPassword == null - || httpPassword.length == 0))) + (protocol.equalsIgnoreCase("http") + && (httpUser != null && httpUser.length() > 0 + && (httpPassword == null + || httpPassword.length == 0))) || (protocol.equalsIgnoreCase("https") && (httpsUser != null && httpsUser.length() > 0 diff --git a/src/jalview/bin/GetdownLauncherUpdate.java b/src/jalview/bin/GetdownLauncherUpdate.java new file mode 100644 index 0000000..ec1f322 --- /dev/null +++ b/src/jalview/bin/GetdownLauncherUpdate.java @@ -0,0 +1,75 @@ +/* + * 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.bin; + +import java.io.File; + +import com.threerings.getdown.data.EnvConfig; +import com.threerings.getdown.util.LaunchUtil; + +public class GetdownLauncherUpdate +{ + public static void main(String[] args) + { + EnvConfig.setVarsFromProperties(); + + String appdir = args.length > 0 ? args[0] : null; + if (appdir == null || appdir.length() == 0) + { + appdir = System.getProperty("launcher.appdir", null); + } + if (appdir == null) + { + appdir = EnvConfig.getUserAppdir(); + } + if (appdir == null) + { + System.err.println("Not running upgradeGetdown"); + return; + } + boolean debug = false; + for (int i = 0; i < args.length; i++) + { + if ("--debug".equals(args[i])) + { + debug = true; + break; + } + } + if (debug) + { + System.err.println("Running upgradeGetdown"); + } + File appdirFile = new File(appdir); + if (!appdirFile.exists()) + { + System.err.println("Directory '" + appdirFile.getAbsolutePath() + + "' doesn't exist, cannot update getdown-launcher.jar."); + if (Boolean.valueOf(System.getProperty("launcher.update"))) + { + System.exit(1); + } + } + LaunchUtil.upgradeGetdown(new File(appdir, "getdown-launcher-old.jar"), + new File(appdir, "getdown-launcher.jar"), + new File(appdir, "getdown-launcher-new.jar")); + } +} diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index 0e3b30a..8bddae3 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -64,7 +64,6 @@ import javax.swing.UnsupportedLookAndFeelException; import com.formdev.flatlaf.FlatLightLaf; import com.formdev.flatlaf.themes.FlatMacLightLaf; import com.formdev.flatlaf.util.SystemInfo; -import com.threerings.getdown.util.LaunchUtil; //import edu.stanford.ejalbert.launching.IBrowserLaunching; import groovy.lang.Binding; @@ -383,17 +382,13 @@ public class Jalview implements JalviewObjectI String appdirString = System.getProperty("launcher.appdir"); if (appdirString != null && appdirString.length() > 0) { - final File appdir = new File(appdirString); new Thread() { @Override public void run() { - LaunchUtil.upgradeGetdown( - new File(appdir, "getdown-launcher-old.jar"), - new File(appdir, "getdown-launcher.jar"), - new File(appdir, "getdown-launcher-new.jar")); + GetdownLauncherUpdate.main(new String[] { appdirString }); } }.start(); } diff --git a/src/jalview/bin/JalviewLite.java b/src/jalview/bin/JalviewLite.java index 7e1296e..2e2dd49 100644 --- a/src/jalview/bin/JalviewLite.java +++ b/src/jalview/bin/JalviewLite.java @@ -2251,8 +2251,8 @@ public class JalviewLite extends Applet PDBEntry[] pdb = new PDBEntry[pdbs.size()]; String[][] chains = new String[pdbs.size()][]; String[] protocols = new String[pdbs.size()]; - for (int pdbsi = 0, - pdbsiSize = pdbs.size(); pdbsi < pdbsiSize; pdbsi++) + for (int pdbsi = 0, pdbsiSize = pdbs + .size(); pdbsi < pdbsiSize; pdbsi++) { Object[] o = (Object[]) pdbs.elementAt(pdbsi); pdb[pdbsi] = (PDBEntry) o[0]; diff --git a/src/jalview/bin/Launcher.java b/src/jalview/bin/Launcher.java index ec53219..579b682 100644 --- a/src/jalview/bin/Launcher.java +++ b/src/jalview/bin/Launcher.java @@ -210,6 +210,8 @@ public class Launcher headless = assumeheadless; } + ErrorLog.setQuiet(quiet); + final String appName = ChannelProperties.getProperty("app_name"); // if we're using jalview.bin.Launcher we always assume a console is in use @@ -327,8 +329,8 @@ public class Launcher String scalePropertyArg = HiDPISetting.getScalePropertyArg(); if (scalePropertyArg != null) { - LaunchUtils.syserr(debug, quiet, "Running " + startClass - + " with scale setting " + scalePropertyArg); + ErrorLog.errPrintln("Running " + startClass + " with scale setting " + + scalePropertyArg); addJvmArgs.add(scalePropertyArg); } @@ -336,7 +338,7 @@ public class Launcher addJvmArgs, null, null, null, startClass, null, null, arguments, launcherprint, launcherwait, launcherstop, debug, quiet); - LaunchUtils.syserr(debug, quiet, "JVM exited with value " + exitValue); + ErrorLog.errPrintln("JVM exited with value " + exitValue); } } diff --git a/src/jalview/commands/JustifyLeftOrRightCommand.java b/src/jalview/commands/JustifyLeftOrRightCommand.java index 2559662..c1eb655 100644 --- a/src/jalview/commands/JustifyLeftOrRightCommand.java +++ b/src/jalview/commands/JustifyLeftOrRightCommand.java @@ -58,8 +58,8 @@ public class JustifyLeftOrRightCommand extends EditCommand { continue; } - char[] range = seq.getSequence(from, to+1); - if (range==null || range.length==0) + char[] range = seq.getSequence(from, to + 1); + if (range == null || range.length == 0) { continue; } @@ -78,7 +78,7 @@ public class JustifyLeftOrRightCommand extends EditCommand alseq[gapstart + gp] = gc; } - for (int sqp = 0,insp=0; sqp. + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ package jalview.datamodel; import java.util.Collection; diff --git a/src/jalview/datamodel/ContactMapHolderI.java b/src/jalview/datamodel/ContactMapHolderI.java index 342abf8..ffd49ea 100644 --- a/src/jalview/datamodel/ContactMapHolderI.java +++ b/src/jalview/datamodel/ContactMapHolderI.java @@ -1,3 +1,23 @@ +/* + * 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.datamodel; import java.util.Collection; diff --git a/src/jalview/datamodel/GroupSetHolder.java b/src/jalview/datamodel/GroupSetHolder.java index faeb7c0..bf047d6 100644 --- a/src/jalview/datamodel/GroupSetHolder.java +++ b/src/jalview/datamodel/GroupSetHolder.java @@ -1,3 +1,23 @@ +/* + * 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.datamodel; /** diff --git a/src/jalview/datamodel/PDBEntry.java b/src/jalview/datamodel/PDBEntry.java index c3906f9..b6b13c9 100755 --- a/src/jalview/datamodel/PDBEntry.java +++ b/src/jalview/datamodel/PDBEntry.java @@ -649,9 +649,9 @@ public class PDBEntry public void setProviderCategory(String providerCategory) { - setProperty(PROVIDERCATEGORY, providerCategory); + setProperty(PROVIDERCATEGORY, providerCategory); } - + public String getProviderCategory() { return (String) getProperty(PROVIDERCATEGORY); @@ -661,5 +661,5 @@ public class PDBEntry { return _hasProperty(PROVIDERCATEGORY); } - + } diff --git a/src/jalview/datamodel/Profile.java b/src/jalview/datamodel/Profile.java index bc87204..ae538f9 100644 --- a/src/jalview/datamodel/Profile.java +++ b/src/jalview/datamodel/Profile.java @@ -32,7 +32,7 @@ public class Profile implements ProfileI * an object holding counts of symbols in the profile */ private ResidueCount counts; - + private SecondaryStructureCount ssCounts; private int seqWithSSCount = -1; @@ -51,15 +51,15 @@ public class Profile implements ProfileI * the highest count for any residue in the profile */ private int maxCount; + private int maxSSCount; - /* * the residue (e.g. K) or residues (e.g. KQW) with the * highest count in the profile */ private String modalResidue; - + private String modalSS; /** @@ -100,7 +100,7 @@ public class Profile implements ProfileI { this.counts = residueCounts; } - + @Override public void setSSCounts(SecondaryStructureCount secondaryStructureCount) { @@ -128,7 +128,7 @@ public class Profile implements ProfileI } return pid; } - + @Override public float getSSPercentageIdentity(boolean ignoreGaps) { @@ -156,7 +156,7 @@ public class Profile implements ProfileI { return counts; } - + @Override public SecondaryStructureCount getSSCounts() { @@ -189,7 +189,7 @@ public class Profile implements ProfileI { return maxCount; } - + @Override public int getMaxSSCount() { @@ -204,7 +204,7 @@ public class Profile implements ProfileI { return modalResidue; } - + @Override public String getModalSS() { diff --git a/src/jalview/datamodel/ProfileI.java b/src/jalview/datamodel/ProfileI.java index 9046f23..084cfde 100644 --- a/src/jalview/datamodel/ProfileI.java +++ b/src/jalview/datamodel/ProfileI.java @@ -29,8 +29,9 @@ public interface ProfileI * @param residueCounts */ public abstract void setCounts(ResidueCount residueCounts); - public abstract void setSSCounts(SecondaryStructureCount secondaryStructureCount); - + + public abstract void setSSCounts( + SecondaryStructureCount secondaryStructureCount); /** * Returns the percentage identity of the profile, i.e. the highest proportion @@ -41,7 +42,7 @@ public interface ProfileI * @return */ public abstract float getPercentageIdentity(boolean ignoreGaps); - + public abstract float getSSPercentageIdentity(boolean ignoreGaps); /** @@ -74,6 +75,7 @@ public interface ProfileI * @return */ public abstract int getMaxCount(); + public abstract int getMaxSSCount(); /** @@ -83,6 +85,7 @@ public interface ProfileI * @return */ public abstract String getModalResidue(); + public abstract String getModalSS(); /** @@ -91,6 +94,7 @@ public interface ProfileI * @return */ public abstract int getNonGapped(); + SecondaryStructureCount getSSCounts(); } \ No newline at end of file diff --git a/src/jalview/datamodel/SecondaryStructureCount.java b/src/jalview/datamodel/SecondaryStructureCount.java index 52e9746..7d1b43c 100644 --- a/src/jalview/datamodel/SecondaryStructureCount.java +++ b/src/jalview/datamodel/SecondaryStructureCount.java @@ -63,7 +63,6 @@ public class SecondaryStructureCount */ private static final String SS_SYMBOLS = "HEC"; - static final int GAP_COUNT = 0; /* @@ -116,7 +115,7 @@ public class SecondaryStructureCount */ public SecondaryStructureCount() { - //isSS = true; + // isSS = true; int charsToCount = SS_SYMBOLS.length(); counts = new short[charsToCount + 1]; } @@ -419,8 +418,7 @@ public class SecondaryStructureCount { if (intCounts[i] == count) { - modal.append( - SS_SYMBOLS.charAt(i - 1)); + modal.append(SS_SYMBOLS.charAt(i - 1)); } } } @@ -430,8 +428,7 @@ public class SecondaryStructureCount { if (counts[i] == count) { - modal.append( - SS_SYMBOLS.charAt(i - 1)); + modal.append(SS_SYMBOLS.charAt(i - 1)); } } } diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java index 38104e5..5248a58 100755 --- a/src/jalview/datamodel/SequenceGroup.java +++ b/src/jalview/datamodel/SequenceGroup.java @@ -136,7 +136,6 @@ public class SequenceGroup implements AnnotatedCollectionI * consensus calculation property */ private boolean showSequenceLogo = false; - /** * flag indicating if logo should be rendered normalised @@ -154,7 +153,6 @@ public class SequenceGroup implements AnnotatedCollectionI private boolean hidecols = false; AlignmentAnnotation consensus = null; - List ssConsensus = null; @@ -163,7 +161,7 @@ public class SequenceGroup implements AnnotatedCollectionI AlignmentAnnotation conservation = null; private boolean showConsensusHistogram; - + private AnnotatedCollectionI context; public Map hSSConsensusProfileMap; @@ -651,7 +649,6 @@ public class SequenceGroup implements AnnotatedCollectionI hSSConsensusProfileMap.put(ssSource, hSSConsensus); } } - if (ssConsensus != null) { @@ -664,7 +661,6 @@ public class SequenceGroup implements AnnotatedCollectionI cs.setSSConsensusProfileMap(hSSConsensusProfileMap); upd = true; } - if ((conservation != null) || (cs != null && cs.conservationApplied())) @@ -1429,7 +1425,7 @@ public class SequenceGroup implements AnnotatedCollectionI } this.showSequenceLogo = showSequenceLogo; } - + /** * * @param showConsHist @@ -1447,6 +1443,7 @@ public class SequenceGroup implements AnnotatedCollectionI this.showConsensusHistogram = showConsHist; } + /** * @return the showConsensusHistogram */ diff --git a/src/jalview/datamodel/annotations/AlphaFoldAnnotationRowBuilder.java b/src/jalview/datamodel/annotations/AlphaFoldAnnotationRowBuilder.java index 4e9553e..11d58d9 100644 --- a/src/jalview/datamodel/annotations/AlphaFoldAnnotationRowBuilder.java +++ b/src/jalview/datamodel/annotations/AlphaFoldAnnotationRowBuilder.java @@ -1,3 +1,23 @@ +/* + * 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.datamodel.annotations; import jalview.datamodel.Annotation; diff --git a/src/jalview/ext/ensembl/EnsemblRestClient.java b/src/jalview/ext/ensembl/EnsemblRestClient.java index 3cc778a..9521305 100644 --- a/src/jalview/ext/ensembl/EnsemblRestClient.java +++ b/src/jalview/ext/ensembl/EnsemblRestClient.java @@ -70,9 +70,9 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher * @see https://github.com/Ensembl/ensembl-rest/wiki/Change-log * @see http://rest.ensembl.org/info/rest?content-type=application/json */ - private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "15.2"; + private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "15.8"; - private static final String LATEST_ENSEMBL_REST_VERSION = "15.2"; + private static final String LATEST_ENSEMBL_REST_VERSION = "15.8"; private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log"; diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 7a06638..a624a66 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -5915,7 +5915,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { viewport.setShowSSConsensus(showSSConsensus.getState()); alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState()); - } /* @@ -5969,6 +5968,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState()); } + /* * (non-Javadoc) * diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 9430a8b..fa48bab 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -282,12 +282,13 @@ public class AlignViewport extends AlignmentViewport } showConsensusHistogram = Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM", true); + showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", true); normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO", false); showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false); showConsensus = Cache.getDefault("SHOW_IDENTITY", true); - + showSSConsensus = Cache.getDefault("SHOW_SS_CONSENSUS", false); showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true); diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index 4d0de1b..d37c9c0 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -423,12 +423,13 @@ public class AppJmol extends StructureViewerBase public boolean isRepainting() { - if (renderPanel!=null && renderPanel.isVisible()) + if (renderPanel != null && renderPanel.isVisible()) { return renderPanel.repainting; } return false; } + /** * Outputs the Jmol viewer image as an image file, after prompting the user to * choose a file and (for EPS) choice of Text or Lineart character rendering @@ -441,10 +442,12 @@ public class AppJmol extends StructureViewerBase { while (!isRepainting()) { - try { + try + { Thread.sleep(2); } catch (Exception q) - {} + { + } } try { @@ -642,17 +645,18 @@ public class AppJmol extends StructureViewerBase } else { - repainting=true; + repainting = true; synchronized (jmb) { jmb.jmolViewer.renderScreenImage(g, currentSize.width, currentSize.height); - + } - repainting=false; + repainting = false; } } - volatile boolean repainting=false; + + volatile boolean repainting = false; } @Override diff --git a/src/jalview/gui/CalculationChooser.java b/src/jalview/gui/CalculationChooser.java index b831f43..14c2e1e 100644 --- a/src/jalview/gui/CalculationChooser.java +++ b/src/jalview/gui/CalculationChooser.java @@ -28,6 +28,7 @@ import jalview.api.analysis.SimilarityParamsI; import jalview.bin.Cache; import jalview.datamodel.SequenceGroup; import jalview.util.MessageManager; +import jalview.util.Platform; import jalview.viewmodel.AlignmentViewport; import java.awt.BorderLayout; import java.awt.Color; @@ -261,12 +262,17 @@ public class CalculationChooser extends JPanel pasimapBorderless.setOpaque(false); // false -> stops every pixel inside // border from being painted pasimapBorderless.add(pasimap, FlowLayout.LEFT); // add pasimap button to - // the JPanel - calcChoicePanel.add(pasimapBorderless, FlowLayout.LEFT); // add button with - // border and - // everything to - // the overall - // ChoicePanel + // the JPanel + if (!Platform.isJS()) + { + // FIXME JAL-4443 + calcChoicePanel.add(pasimapBorderless, FlowLayout.LEFT); // add button + // with + // border and + // everything to + // the overall + // ChoicePanel + } treePanel.add(neighbourJoining); treePanel.add(averageDistance); @@ -276,7 +282,11 @@ public class CalculationChooser extends JPanel ButtonGroup calcTypes = new ButtonGroup(); calcTypes.add(pca); - calcTypes.add(pasimap); + if (!Platform.isJS()) + { + // FIXME JAL-4443 + calcTypes.add(pasimap); + } calcTypes.add(neighbourJoining); calcTypes.add(averageDistance); calcTypes.add(pairwise); @@ -639,8 +649,10 @@ public class CalculationChooser extends JPanel * * @param nucleotide * @param forPca - * @param ssPresent - include secondary structure similarity model - * @param forPasimap - limit to ScoreMatrix based models - allows use of AlignSeq + * @param ssPresent + * - include secondary structure similarity model + * @param forPasimap + * - limit to ScoreMatrix based models - allows use of AlignSeq * @return */ protected static List getApplicableScoreModels( @@ -652,7 +664,7 @@ public class CalculationChooser extends JPanel ScoreModels scoreModels = ScoreModels.getInstance(); for (ScoreModelI sm : scoreModels.getModels()) { - if ((!forPasimap || sm instanceof ScoreMatrix) + if ((!forPasimap || sm instanceof ScoreMatrix) && (!nucleotide && sm.isProtein() || nucleotide && sm.isDNA() || sm.isSecondaryStructure() && ssPresent)) diff --git a/src/jalview/gui/CutAndPasteTransfer.java b/src/jalview/gui/CutAndPasteTransfer.java index 299af6b..10aa229 100644 --- a/src/jalview/gui/CutAndPasteTransfer.java +++ b/src/jalview/gui/CutAndPasteTransfer.java @@ -94,13 +94,14 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer /** * set font size of the textarea + * * @param size */ public void setFont(Font font) { textarea.setFont(font); } - + /** * DOCUMENT ME! */ @@ -217,11 +218,12 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer { } } - + /** - * show menu for changing the font - * @param e - */ + * show menu for changing the font + * + * @param e + */ @Override public void fontSizeMenu_actionPerformed(ActionEvent e) { diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index c144268..10067cf 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -1214,185 +1214,261 @@ public class Desktop extends jalview.jbgui.GDesktop } /** - * DOCUMENT ME! - * - * @param evt - * DOCUMENT ME! + * load all files dropped (2.11.4.0 behaviour) + * @return false if any file resulted in an error */ - @Override - public void drop(DropTargetDropEvent evt) + public boolean loadDroppedFiles(List files, + List protocols, List failed, + List failed_exceptions) { - boolean success = true; - // JAL-1552 - acceptDrop required before getTransferable call for - // Java's Transferable for native dnd - evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); - Transferable t = evt.getTransferable(); - List files = new ArrayList<>(); - List protocols = new ArrayList<>(); - - try + for (int i = 0; i < files.size(); i++) { - Desktop.transferFromDropTarget(files, protocols, evt, t); - } catch (Exception e) + Object file = files.get(i); + try + { + // BH 2018 File or String + String fileName = file.toString(); + DataSourceType protocol = (protocols == null) ? DataSourceType.FILE + : protocols.get(i); + FileFormatI format = null; + + if (fileName.endsWith(".jar")) + { + format = FileFormat.Jalview; + } + else + { + format = new IdentifyFile().identify(file, protocol); + } + if (file instanceof File) + { + Platform.cacheFileData((File) file); + } + new FileLoader().LoadFile(null, file, protocol, format); + } catch (Exception x) + { + failed.add(file); + failed_exceptions.add(x); + jalview.bin.Console.warn( + "Unexpected Exception when handling " + file.toString(), x); + } + } + return failed.size()==0; // at least one was loaded. + } + + /** + * analyse dropped files and process them according to type: load alignments, + * add annotation, trees or features to alignments with the same basename + * + * @return false if any exception was raised + */ + public boolean processAndLoadDroppedFiles(List files, + List protocols, List failed, + List failed_exceptions) + { + // map list to list of strings + List filenames = new ArrayList<>(); + for (int i = 0; i < files.size(); i++) { - e.printStackTrace(); - success = false; + filenames.add(files.get(i).toString()); } - if (files != null) + // processFilenames will take likely associated files OUT of the list of + // filenames and return them in a BaseInfo object in the Map + Map baseInfoMap = ArgParserUtils + .processFilenames(filenames, false, files); + // so we can catch exceptions for this file + Object file = null; + try { - try + + for (int i = 0; i < files.size(); i++) { - // map list to list of strings - List filenames = new ArrayList<>(); - for (int i = 0; i < files.size(); i++) + // BH 2018 File or String + file = files.get(i); + String fileName = file.toString(); + DataSourceType protocol = (protocols == null) ? DataSourceType.FILE + : protocols.get(i); + FileFormatI format = null; + + if (fileName.toLowerCase(Locale.ROOT).endsWith(".jar")) { - filenames.add(files.get(i).toString()); + format = FileFormat.Jalview; } - - // processFilenames will take likely associated files OUT of the list of - // filenames and return them in a BaseInfo object in the Map - Map baseInfoMap = ArgParserUtils - .processFilenames(filenames, false, files); - for (int i = 0; i < files.size(); i++) + else { - // BH 2018 File or String - Object file = files.get(i); - String fileName = file.toString(); - DataSourceType protocol = (protocols == null) - ? DataSourceType.FILE - : protocols.get(i); - FileFormatI format = null; - - if (fileName.toLowerCase(Locale.ROOT).endsWith(".jar")) - { - format = FileFormat.Jalview; - } - else + format = new IdentifyFile().identify(file, protocol); + } + // If features/annotations/tree file that hasn't been put into the + // baseInfoMap, look through titles of opened AlignFrames to add. + String ext = FileUtils.getExtension(fileName); + boolean isFeatures = ArgParserUtils.featuresExtensions + .contains(ext); + boolean isAnnotations = ArgParserUtils.annotationsExtensions + .contains(ext); + boolean isTree = ArgParserUtils.treeExtensions.contains(ext); + if (isFeatures || isAnnotations || isTree) + { + String base = FileUtils.getBase(fileName); + AlignFrame matchingAf = null; + AlignFrame[] afs = Desktop.instance.getAlignFrames(); + boolean dontSkip = false; + for (AlignFrame af : afs) { - format = new IdentifyFile().identify(file, protocol); + String afFilename = af.fileName; + String afTitle = af.getTitle(); + /** + * don't need to check the matching afFilename or afTitle has an + * alignment extenstion. It's obviously an alignment! + */ + /* + if ((base.equals(FileUtils.getBase(afFilename)) + && ArgParserUtils.alignmentExtensions + .contains(FileUtils.getExtension(afFilename))) + || (base.equals(FileUtils.getBase(afTitle)) + && ArgParserUtils.alignmentExtensions + .contains(FileUtils + .getExtension(afTitle)))) + */ + if (base.equals(FileUtils.getBase(afFilename)) + || base.equals(FileUtils.getBase(afTitle))) + { + matchingAf = af; + break; + } } - // If features/annotations/tree file that hasn't been put into the - // baseInfoMap, look through titles of opened AlignFrames to add. - String ext = FileUtils.getExtension(fileName); - boolean isFeatures = ArgParserUtils.featuresExtensions - .contains(ext); - boolean isAnnotations = ArgParserUtils.annotationsExtensions - .contains(ext); - boolean isTree = ArgParserUtils.treeExtensions.contains(ext); - if (isFeatures || isAnnotations || isTree) + if (matchingAf != null) { - String base = FileUtils.getBase(fileName); - AlignFrame matchingAf = null; - AlignFrame[] afs = Desktop.instance.getAlignFrames(); - boolean dontSkip = false; - for (AlignFrame af : afs) + if (isFeatures) { - String afFilename = af.fileName; - String afTitle = af.getTitle(); - /** - * don't need to check the matching afFilename or afTitle has an - * alignment extenstion. It's obviously an alignment! - */ - /* - if ((base.equals(FileUtils.getBase(afFilename)) - && ArgParserUtils.alignmentExtensions - .contains(FileUtils.getExtension(afFilename))) - || (base.equals(FileUtils.getBase(afTitle)) - && ArgParserUtils.alignmentExtensions - .contains(FileUtils - .getExtension(afTitle)))) - */ - if (base.equals(FileUtils.getBase(afFilename)) - || base.equals(FileUtils.getBase(afTitle))) - { - matchingAf = af; - break; - } + matchingAf.parseFeaturesFile(fileName, + AppletFormatAdapter.checkProtocol(fileName)); + } + else if (isAnnotations) + { + matchingAf.loadJalviewDataFile(fileName, null, null, null); } - if (matchingAf != null) + else if (isTree) { - if (isFeatures) + try { - matchingAf.parseFeaturesFile(fileName, + NewickFile nf = new NewickFile(fileName, AppletFormatAdapter.checkProtocol(fileName)); - } - else if (isAnnotations) - { - matchingAf.loadJalviewDataFile(fileName, null, null, null); - } - else if (isTree) - { - try - { - NewickFile nf = new NewickFile(fileName, - AppletFormatAdapter.checkProtocol(fileName)); - matchingAf.getViewport().setCurrentTree(matchingAf - .showNewickTree(nf, fileName).getTree()); - } catch (IOException e) - { - jalview.bin.Console.warn( - "Couldn't add potential tree '" + fileName + "'"); - dontSkip = true; - } - } - if (!dontSkip) + matchingAf.getViewport().setCurrentTree( + matchingAf.showNewickTree(nf, fileName).getTree()); + } catch (IOException e) { - // skip to next file - continue; + jalview.bin.Console.warn( + "Couldn't add potential tree '" + fileName + "'"); + dontSkip = true; } } + if (!dontSkip) + { + // skip to next file + continue; + } } + } - if (file instanceof File) + if (file instanceof File) + { + Platform.cacheFileData((File) file); + } + // new FileLoader().LoadFile(null, file, protocol, format); + AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(fileName, + protocol, format); + // now we add any associated files to the alignframe + if (baseInfoMap.containsKey(fileName) && baseInfoMap.get(fileName) + .getAssociatedFilesMap() != null) + { + BaseInfo bi = baseInfoMap.get(fileName); + if (bi.getAssociatedFilesMap().containsKey(Arg.FEATURES)) { - Platform.cacheFileData((File) file); + String featuresfile = bi.getAssociatedFilesMap() + .get(Arg.FEATURES); + af.parseFeaturesFile(featuresfile, + AppletFormatAdapter.checkProtocol(featuresfile)); } - // new FileLoader().LoadFile(null, file, protocol, format); - AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(fileName, - protocol, format); - // now we add any associated files to the alignframe - if (baseInfoMap.containsKey(fileName) && baseInfoMap.get(fileName) - .getAssociatedFilesMap() != null) + if (bi.getAssociatedFilesMap().containsKey(Arg.ANNOTATIONS)) { - BaseInfo bi = baseInfoMap.get(fileName); - if (bi.getAssociatedFilesMap().containsKey(Arg.FEATURES)) - { - String featuresfile = bi.getAssociatedFilesMap() - .get(Arg.FEATURES); - af.parseFeaturesFile(featuresfile, - AppletFormatAdapter.checkProtocol(featuresfile)); - } - if (bi.getAssociatedFilesMap().containsKey(Arg.ANNOTATIONS)) + String annotationsfile = bi.getAssociatedFilesMap() + .get(Arg.ANNOTATIONS); + af.loadJalviewDataFile(annotationsfile, null, null, null); + } + if (bi.getAssociatedFilesMap().containsKey(Arg.TREE)) + { + String treefile = bi.getAssociatedFilesMap().get(Arg.TREE); + try { - String annotationsfile = bi.getAssociatedFilesMap() - .get(Arg.ANNOTATIONS); - af.loadJalviewDataFile(annotationsfile, null, null, null); - } - if (bi.getAssociatedFilesMap().containsKey(Arg.TREE)) + NewickFile nf = new NewickFile(treefile, + AppletFormatAdapter.checkProtocol(treefile)); + af.getViewport().setCurrentTree( + af.showNewickTree(nf, treefile).getTree()); + } catch (IOException e) { - String treefile = bi.getAssociatedFilesMap().get(Arg.TREE); - try - { - NewickFile nf = new NewickFile(treefile, - AppletFormatAdapter.checkProtocol(treefile)); - af.getViewport().setCurrentTree( - af.showNewickTree(nf, treefile).getTree()); - } catch (IOException e) - { - jalview.bin.Console.warn( - "Couldn't add potential tree '" + treefile + "'"); - } - + jalview.bin.Console.warn( + "Couldn't add potential tree '" + treefile + "'"); } } } - } catch (Exception ex) + + } + } catch (Exception ex) + { + + jalview.bin.Console.warn( + "Unexpected exception whilst handling drop to Desktop.", ex); + failed.add(file); + failed_exceptions.add(ex); + return false; + } + return failed.size() == 0; // redundant for 2.11.4.0 implementation + } + + @Override + public void drop(DropTargetDropEvent evt) + { + boolean success = true; + // JAL-1552 - acceptDrop required before getTransferable call for + // Java's Transferable for native dnd + evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); + Transferable t = evt.getTransferable(); + List files = new ArrayList<>(); + List protocols = new ArrayList<>(); + + try + { + Desktop.transferFromDropTarget(files, protocols, evt, t); + } catch (Exception e) + { + e.printStackTrace(); + success = false; + } + try + { + if (files != null) { - success = false; + List failed = new ArrayList(); + List failed_exceptions = new ArrayList(); + if (!showExperimental()) + { + success = loadDroppedFiles(files, protocols, failed, + failed_exceptions); + } + else + { + success = processAndLoadDroppedFiles(files, protocols, failed, + failed_exceptions); + } } + } catch (Throwable ex) + { + jalview.bin.Console.warn( + "Unexpected exception whilst handling drop to Desktop.", ex); + success = false; } evt.dropComplete(success); // need this to ensure input focus is properly // transfered to any new windows created @@ -2945,11 +3021,11 @@ public class Desktop extends jalview.jbgui.GDesktop if (progressBars.get(Long.valueOf(id)) == null) return null; - + for (Component c : progressBars.get(Long.valueOf(id)).getComponents()) { if (c.getClass() == JProgressBar.class) - return (JProgressBar) c; + return (JProgressBar) c; } return null; } diff --git a/src/jalview/gui/FontChooser.java b/src/jalview/gui/FontChooser.java index 853d4aa..1ec4881 100755 --- a/src/jalview/gui/FontChooser.java +++ b/src/jalview/gui/FontChooser.java @@ -113,8 +113,9 @@ public class FontChooser extends GFontChooser /** * Creates a new FontChooser for a CutAndPasteTransfer + * * @param cap - */ + */ public FontChooser(CutAndPasteTransfer cap) { oldFont = new Font("Monospaced", Font.PLAIN, 12); @@ -131,7 +132,7 @@ public class FontChooser extends GFontChooser if (!isCapFont()) { smoothFont.setSelected(ap.av.antiAlias); - + /* * Enable 'scale protein as cDNA' in a SplitFrame view. The selection is * stored in the ViewStyle of both dna and protein Viewport. Also enable @@ -289,6 +290,7 @@ public class FontChooser extends GFontChooser { return cap != null; } + /** * DOCUMENT ME! */ diff --git a/src/jalview/gui/PaSiMapPanel.java b/src/jalview/gui/PaSiMapPanel.java index 702c4f4..7926efc 100644 --- a/src/jalview/gui/PaSiMapPanel.java +++ b/src/jalview/gui/PaSiMapPanel.java @@ -101,12 +101,12 @@ public class PaSiMapPanel extends GPaSiMapPanel */ public PaSiMapPanel(AlignmentPanel alignPanel, String modelName) { - super(8); // dim = 8 + super(8); // dim = 8 this.av = alignPanel.av; this.ap = alignPanel; boolean nucleotide = av.getAlignment().isNucleotide(); - //progressBar = new ProgressBar(statusPanel, statusBar); + // progressBar = new ProgressBar(statusPanel, statusBar); addInternalFrameListener(new InternalFrameAdapter() { @@ -131,8 +131,7 @@ public class PaSiMapPanel extends GPaSiMapPanel ScoreModelI scoreModel = ScoreModels.getInstance() .getScoreModel(modelName, ap); - setPasimapModel( - new PaSiMapModel(av, seqs, nucleotide, scoreModel)); + setPasimapModel(new PaSiMapModel(av, seqs, nucleotide, scoreModel)); PaintRefresher.Register(this, av.getSequenceSetId()); setRotatableCanvas(new RotatableCanvas(alignPanel)); @@ -143,8 +142,8 @@ public class PaSiMapPanel extends GPaSiMapPanel } /** - * Ensure references to potentially very large objects (the PaSiMap matrices) are - * nulled when the frame is closed + * Ensure references to potentially very large objects (the PaSiMap matrices) + * are nulled when the frame is closed */ protected void close_actionPerformed() { @@ -193,29 +192,31 @@ public class PaSiMapPanel extends GPaSiMapPanel progressBar.setProgressBar(message, progId); try { - SequenceGroup selGroup=av.getSelectionGroup(); - - if (selGroup==null) + SequenceGroup selGroup = av.getSelectionGroup(); + + if (selGroup == null) { selGroup = new SequenceGroup(av.getAlignment().getSequences()); selGroup.setStartRes(0); - selGroup.setEndRes(av.getAlignment().getWidth()-1); + selGroup.setEndRes(av.getAlignment().getWidth() - 1); } - - if (selGroup.getSize()>MAX_PASIMAP_SEQ) + + if (selGroup.getSize() > MAX_PASIMAP_SEQ) { - int start = selGroup.getStartRes(),end=selGroup.getEndRes(); - selGroup = new SequenceGroup(selGroup.getSequences().subList(0, MAX_PASIMAP_SEQ)); - selGroup.setStartRes(start); - selGroup.setEndRes(end); - Console.warn("Truncated input sequences for PASIMAP analysis to "+MAX_PASIMAP_SEQ); + int start = selGroup.getStartRes(), end = selGroup.getEndRes(); + selGroup = new SequenceGroup( + selGroup.getSequences().subList(0, MAX_PASIMAP_SEQ)); + selGroup.setStartRes(start); + selGroup.setEndRes(end); + Console.warn("Truncated input sequences for PASIMAP analysis to " + + MAX_PASIMAP_SEQ); } - + PairwiseAlignPanel pap = new PairwiseAlignPanel(av, selGroup, true, GAP_OPEN_COST, GAP_EXTEND_COST, false, null); pap.setDiscardAlignments(true); pap.setQuiet(true); - + System.out.println(pap != null); setPairwiseAlignPanel(pap); getPasimapModel().calculate(pap); @@ -241,9 +242,9 @@ public class PaSiMapPanel extends GPaSiMapPanel repaint(); if (getParent() == null) { - Desktop.addInternalFrame( - this, MessageManager.formatMessage("label.calc_title", - "PaSiMap", ap.alignFrame.getTitle()), + Desktop.addInternalFrame(this, + MessageManager.formatMessage("label.calc_title", "PaSiMap", + ap.alignFrame.getTitle()), 475, 450); this.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); } @@ -251,8 +252,8 @@ public class PaSiMapPanel extends GPaSiMapPanel } /** - * Updates the PaSiMap display after a change of component to use for x, y or z - * axis + * Updates the PaSiMap display after a change of component to use for x, y or + * z axis */ @Override protected void doDimensionChange() @@ -270,8 +271,8 @@ public class PaSiMapPanel extends GPaSiMapPanel } /** - * Sets the selected checkbox item index for PaSiMap dimension (1, 2, 3...) for - * the given axis (X/Y/Z) + * Sets the selected checkbox item index for PaSiMap dimension (1, 2, 3...) + * for the given axis (X/Y/Z) * * @param index * @param axis @@ -323,8 +324,8 @@ public class PaSiMapPanel extends GPaSiMapPanel } /** - * If available, shows the data which formed the inputs for the PaSiMap as a new - * alignment + * If available, shows the data which formed the inputs for the PaSiMap as a + * new alignment */ @Override public void originalSeqData_actionPerformed() @@ -452,7 +453,7 @@ public class PaSiMapPanel extends GPaSiMapPanel } } - public void makePaSiMapImage(ImageMaker.TYPE type) throws Exception + public void makePaSiMapImage(ImageMaker.TYPE type) throws Exception { int width = getRotatableCanvas().getWidth(); int height = getRotatableCanvas().getHeight(); @@ -612,7 +613,8 @@ public class PaSiMapPanel extends GPaSiMapPanel { cap.setText(getPasimapModel().getAlignmentOutput()); Desktop.addInternalFrame(cap, MessageManager.formatMessage( - "label.pairwise_alignment_for_params", new String[] { this.getTitle() }), 500, 500); + "label.pairwise_alignment_for_params", new String[] + { this.getTitle() }), 500, 500); } catch (OutOfMemoryError oom) { new OOMWarning("exporting pairwise alignments", oom); @@ -680,7 +682,7 @@ public class PaSiMapPanel extends GPaSiMapPanel public void updateProgressBar(int lengthOfTask, int progress) { JProgressBar pBar = progressBar.getProgressBar(progId); - if (pBar==null) + if (pBar == null) { return; } @@ -692,22 +694,24 @@ public class PaSiMapPanel extends GPaSiMapPanel } updateProgressBar(progress); } + public void updateProgressBar(int progress) { JProgressBar pBar = progressBar.getProgressBar(progId); - - if (pBar==null) + + if (pBar == null) { return; } - + pBar.setValue(progress); pBar.repaint(); } /** - * adds a listener for a pairwise alignment panel's progress - * TODO: generalise for anything that can report progress ? + * adds a listener for a pairwise alignment panel's progress TODO: generalise + * for anything that can report progress ? + * * @param pap */ public void setPairwiseAlignPanel(PairwiseAlignPanel pap) @@ -794,8 +798,8 @@ public class PaSiMapPanel extends GPaSiMapPanel } /** - * Answers the selected checkbox item index for PaSiMap dimension for the X, Y or - * Z axis of the display + * Answers the selected checkbox item index for PaSiMap dimension for the X, Y + * or Z axis of the display * * @param axis * @return diff --git a/src/jalview/gui/PairwiseAlignPanel.java b/src/jalview/gui/PairwiseAlignPanel.java index 3e8fb02..77ec0f5 100755 --- a/src/jalview/gui/PairwiseAlignPanel.java +++ b/src/jalview/gui/PairwiseAlignPanel.java @@ -47,7 +47,7 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel private float[][] scores; - private float[][] alignmentScores; // scores used by PaSiMap + private float[][] alignmentScores; // scores used by PaSiMap private int GAP_OPEN_COST; @@ -60,7 +60,7 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel private String alignmentOutput; private boolean quiet; - + private boolean discardAlignments; private boolean endGaps; @@ -73,12 +73,13 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel private int total; private int progress; - + private SequenceGroup selection; + /** * input sequences */ - private SequenceI[] seqs=null; + private SequenceI[] seqs = null; private ScoreMatrix scoreMatrix; @@ -87,23 +88,31 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel * * @param viewport * contains selected sequences to align - * @param endGaps ~ toggle gaps and the beginning and end of sequences + * @param endGaps + * ~ toggle gaps and the beginning and end of sequences */ public PairwiseAlignPanel(AlignmentViewport viewport) { - this(viewport, null, false, 120, 20, true, null); // default penalties used in AlignSeq + this(viewport, null, false, 120, 20, true, null); // default penalties used + // in AlignSeq } + public PairwiseAlignPanel(AlignmentViewport viewport, ScoreMatrix params) { - this(viewport, null, false, 120, 20, true,params); // default penalties used in AlignSeq + this(viewport, null, false, 120, 20, true, params); // default penalties + // used in AlignSeq } - public PairwiseAlignPanel(AlignmentViewport viewport, boolean endGaps, int gapOpenCost, int gapExtendCost) + + public PairwiseAlignPanel(AlignmentViewport viewport, boolean endGaps, + int gapOpenCost, int gapExtendCost) { this(viewport, null, endGaps, gapOpenCost, gapExtendCost, true, null); } /** - * Create a new pairwise alignpanel with specified parameters and score model, and optionally start the calculation + * Create a new pairwise alignpanel with specified parameters and score model, + * and optionally start the calculation + * * @param viewport * @param selection * @param endGaps @@ -112,8 +121,9 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel * @param run * @param scoreMatrix */ - public PairwiseAlignPanel(AlignmentViewport viewport, SequenceGroup selection, boolean endGaps, - int gapOpenCost, int gapExtendCost, boolean run, ScoreMatrix scoreMatrix) + public PairwiseAlignPanel(AlignmentViewport viewport, + SequenceGroup selection, boolean endGaps, int gapOpenCost, + int gapExtendCost, boolean run, ScoreMatrix scoreMatrix) { super(); this.av = viewport; @@ -123,23 +133,25 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel this.selection = selection; this.total = MiscMath.combinations(av.getAlignment().getHeight(), 2); this.scoreMatrix = scoreMatrix; - if (run) { + if (run) + { calculate(); } } - + public void calculate() { calculate(scoreMatrix); } - public void calculate (ScoreMatrix sm) + + public void calculate(ScoreMatrix sm) { StringBuilder sb = new StringBuilder(1024); sequences = new Vector(); String[] seqStrings; - seqs=null; + seqs = null; if (selection != null) { @@ -169,7 +181,7 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel seqs = av.getAlignment().getSequencesArray(); } } - + String type = (av.getAlignment().isNucleotide()) ? AlignSeq.DNA : AlignSeq.PEP; @@ -177,7 +189,7 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel float[][] alignmentScores = new float[seqs.length][seqs.length]; double totscore = 0D; int count = seqs.length; - + boolean first = true; progress = 0; @@ -192,11 +204,12 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel AlignSeq as = new AlignSeq(seqs[i], seqStrings[i], seqs[j], seqStrings[j], type, GAP_OPEN_COST, GAP_EXTEND_COST); - if (sm != null) { - as.setScoreMatrix(sm); - } + if (sm != null) + { + as.setScoreMatrix(sm); + } - if (as.s1str.length() == 0 || as.s2str.length() == 0) + if (as.s1str.length() == 0 || as.s2str.length() == 0) { continue; } @@ -219,7 +232,8 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel sb.append(DASHES); } first = false; - if (!discardAlignments) { + if (!discardAlignments) + { as.printAlignment(System.out); } scores[i][j] = as.getMaxScore() / as.getASeq1().length; @@ -243,7 +257,7 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel this.scores = scores; this.alignmentScores = alignmentScores; - if (count > 2 && !quiet) + if (count > 2 && !quiet) { printScoreMatrix(seqs, scores, totscore); } @@ -344,24 +358,29 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel { return progress; } + public SequenceI[] getInputSequences() { return seqs; } + /** - * Set to true to suppress output of progress to Console.stdout or GUI - * @param quiet + * Set to true to suppress output of progress to Console.stdout or GUI + * + * @param quiet */ public void setQuiet(boolean quiet) { - this.quiet=quiet; + this.quiet = quiet; } + /** * set this if you are only interested in final alignment scores + * * @param discard */ public void setDiscardAlignments(boolean discard) { - discardAlignments=discard; + discardAlignments = discard; } } diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index a47a0a1..cc60400 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -1973,7 +1973,6 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener AlignmentUtils.addReferenceAnnotations(candidates, alignment, null); if(AlignmentUtils.isSSAnnotationPresent(candidates)) { - restartSSConsensusWorker(); ap.validateAnnotationDimensions(true); ap.fontChanged(); @@ -1982,23 +1981,23 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener restartSSConsensusWorker(); //ap.alignFrame.getViewport().getCalcManager().restartWorkers(); } - } - - - private void restartSSConsensusWorker() { - - List workers = ap.alignFrame.getViewport().getCalcManager() - .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class); - if (!workers.isEmpty()) { - - ap.alignFrame.getViewport().getCalcManager().startWorker(workers.remove(0)); + + private void restartSSConsensusWorker() + { + + List workers = ap.alignFrame.getViewport() + .getCalcManager().getRegisteredWorkersOfClass( + SecondaryStructureConsensusThread.class); + if (!workers.isEmpty()) + { + + ap.alignFrame.getViewport().getCalcManager() + .startWorker(workers.remove(0)); } - + } - - protected void makeReferenceSeq_actionPerformed(ActionEvent actionEvent) { diff --git a/src/jalview/gui/ProgressBar.java b/src/jalview/gui/ProgressBar.java index 73cd496..9d2cb2c 100644 --- a/src/jalview/gui/ProgressBar.java +++ b/src/jalview/gui/ProgressBar.java @@ -274,7 +274,7 @@ public class ProgressBar implements IProgressIndicator public JProgressBar getProgressBar(long id) { Container progBar = progressBars.get(id); - if (progBar==null || progBar.getComponentCount()==0) + if (progBar == null || progBar.getComponentCount() == 0) { return null; } diff --git a/src/jalview/gui/RotatableCanvas.java b/src/jalview/gui/RotatableCanvas.java index 5261b23..03d8d87 100755 --- a/src/jalview/gui/RotatableCanvas.java +++ b/src/jalview/gui/RotatableCanvas.java @@ -119,10 +119,13 @@ public class RotatableCanvas extends JPanel private Point[] axisEndPoints; // fields for 'select rectangle' (JAL-1124) - int rectx1; - int recty1; - int rectx2; - int recty2; + int rectx1; + + int recty1; + + int rectx2; + + int recty2; AlignmentViewport av; @@ -405,11 +408,12 @@ public class RotatableCanvas extends JPanel } } // //Now the rectangle - if (rectx2 != -1 && recty2 != -1) { - g.setColor(Color.white); - - g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1); - } + if (rectx2 != -1 && recty2 != -1) + { + g.setColor(Color.white); + + g.drawRect(rectx1, recty1, rectx2 - rectx1, recty2 - recty1); + } } /** @@ -566,10 +570,10 @@ public class RotatableCanvas extends JPanel mouseX = x; mouseY = y; - rectx1 = x; - recty1 = y; - rectx2 = -1; - recty2 = -1; + rectx1 = x; + recty1 = y; + rectx2 = -1; + recty2 = -1; SequenceI found = findSequenceAtPoint(x, y); @@ -634,12 +638,12 @@ public class RotatableCanvas extends JPanel // Check if this is a rectangle drawing drag if ((evt.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0) { - rectx2 = evt.getX(); - recty2 = evt.getY(); - if ((rectx2 != -1) && (recty2 != -1)) - { - rectSelect(rectx1, recty1, rectx2, recty2); - } + rectx2 = evt.getX(); + recty2 = evt.getY(); + if ((rectx2 != -1) && (recty2 != -1)) + { + rectSelect(rectx1, recty1, rectx2, recty2); + } } else { @@ -649,7 +653,7 @@ public class RotatableCanvas extends JPanel mouseY = yPos; // findWidths(); } - repaint(); + repaint(); } @Override @@ -753,12 +757,10 @@ public class RotatableCanvas extends JPanel { SequencePoint sp = sequencePoints.get(i); int tmp1 = (int) (((sp.coord.x - centre[0]) * getScaleFactor()) - * (getWidth() / 3.15) - + (getWidth() / 2.0)); + * (getWidth() / 3.15) + (getWidth() / 2.0)); float pre1 = ((sp.coord.x - centre[0]) * getScaleFactor()); int tmp2 = (int) (((sp.coord.y - centre[1]) * getScaleFactor()) - * (getHeight() / 1.70) - + (getHeight() / 2.0)); + * (getHeight() / 1.70) + (getHeight() / 2.0)); float pre2 = ((sp.coord.y - centre[1]) * getScaleFactor()); if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2)) diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java index 9658a92..ce043fe 100644 --- a/src/jalview/gui/StructureChooser.java +++ b/src/jalview/gui/StructureChooser.java @@ -1347,8 +1347,9 @@ public class StructureChooser extends GStructureChooser String pdbFilename = selectedPdbFileName; // TODO - tidy up this ugly hack so we call launchStructureViewer too StructureChooser.openStructureFileForSequence(ssm, sc, ap, - selectedSequence, true, pdbFilename, tft, paeFilename,false, - true,false,getTargetedStructureViewer(ssm).getViewerType()); + selectedSequence, true, pdbFilename, tft, paeFilename, + false, true, false, + getTargetedStructureViewer(ssm).getViewerType()); } SwingUtilities.invokeLater(new Runnable() { @@ -1820,7 +1821,9 @@ public class StructureChooser extends GStructureChooser * @param forceHeadless * @param showRefAnnotations * @param doXferSettings - * @param viewerType - when not null means the viewer will be opened, providing forceHeadless/headless is not true + * @param viewerType + * - when not null means the viewer will be opened, providing + * forceHeadless/headless is not true * @return */ public static StructureViewer openStructureFileForSequence( @@ -1845,7 +1848,7 @@ public class StructureChooser extends GStructureChooser ssm = ap.getStructureSelectionManager(); StructureSelectionManager.doConfigureStructurePrefs(ssm); } - + PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq( sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance, tft, paeFilename, doXferSettings); @@ -1863,7 +1866,8 @@ public class StructureChooser extends GStructureChooser sc.mainFrame.dispose(); - // TODO should honor preferences - only show reference annotation that is requested - JAL-4415 JAL-3124 + // TODO should honor preferences - only show reference annotation that is + // requested - JAL-4415 JAL-3124 if (showRefAnnotations) { showReferenceAnnotationsForSequence(ap.alignFrame, seq); diff --git a/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java b/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java index 333f995..2bd5a91 100644 --- a/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java +++ b/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java @@ -426,8 +426,9 @@ public class ThreeDBStructureChooserQuerySource String modelPage = humanUrl < 1 ? null : (String) restable.getValueAt(row, humanUrl); - String modelCategory = idx_mcat < 1 ? null :(String) restable.getValueAt(row,idx_mcat); - + String modelCategory = idx_mcat < 1 ? null + : (String) restable.getValueAt(row, idx_mcat); + String strucFormat = restable.getValueAt(row, modelformat).toString(); SequenceI selectedSeq = (SequenceI) restable.getValueAt(row, diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index fa9626b..d1ced96 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -210,7 +210,7 @@ public class GAlignFrame extends JInternalFrame protected JCheckBoxMenuItem showGroupConservation = new JCheckBoxMenuItem(); - protected JCheckBoxMenuItem showConsensusHistogram = new JCheckBoxMenuItem(); + protected JCheckBoxMenuItem showConsensusHistogram = new JCheckBoxMenuItem(); protected JCheckBoxMenuItem showSequenceLogo = new JCheckBoxMenuItem(); @@ -925,8 +925,8 @@ public class GAlignFrame extends JInternalFrame { showConsensusHistogram_actionPerformed(e); } - }); + showSequenceLogo .setText(MessageManager.getString("label.show_consensus_logo")); showSequenceLogo.addActionListener(new ActionListener() @@ -1887,7 +1887,7 @@ public class GAlignFrame extends JInternalFrame } }); - + JMenu exportImageMenu = new JMenu( MessageManager.getString("label.export_image")); JMenu fileMenu = new JMenu(MessageManager.getString("action.file")); @@ -2957,6 +2957,6 @@ public class GAlignFrame extends JInternalFrame ButtonGroup ssButtonGroup) { // TODO Auto-generated method stub - + } } diff --git a/src/jalview/jbgui/GCutAndPasteTransfer.java b/src/jalview/jbgui/GCutAndPasteTransfer.java index 5daea78..106ad7c 100755 --- a/src/jalview/jbgui/GCutAndPasteTransfer.java +++ b/src/jalview/jbgui/GCutAndPasteTransfer.java @@ -198,7 +198,7 @@ public class GCutAndPasteTransfer extends JInternalFrame @Override public void actionPerformed(ActionEvent e) { - fontSizeMenu_actionPerformed(e); + fontSizeMenu_actionPerformed(e); } }); copyItem.setText(MessageManager.getString("action.copy")); @@ -256,6 +256,7 @@ public class GCutAndPasteTransfer extends JInternalFrame /** * shows a menu for changing the font + * * @param e */ public void fontSizeMenu_actionPerformed(ActionEvent e) diff --git a/src/jalview/jbgui/GDesktop.java b/src/jalview/jbgui/GDesktop.java index 3d606e3..90b8024 100755 --- a/src/jalview/jbgui/GDesktop.java +++ b/src/jalview/jbgui/GDesktop.java @@ -48,7 +48,7 @@ import jalview.util.Platform; public class GDesktop extends JFrame { - protected static JMenu windowMenu = new JMenu(); + protected static JMenu windowMenu = null; JMenuBar desktopMenubar = new JMenuBar(); @@ -110,6 +110,13 @@ public class GDesktop extends JFrame public GDesktop() { super(); + + // instantiate here to set same context (e.g. font) as other menus + if (windowMenu == null) + { + windowMenu = new JMenu(); + } + try { jbInit(); diff --git a/src/jalview/jbgui/GPCAPanel.java b/src/jalview/jbgui/GPCAPanel.java index ec5b209..65394ed 100755 --- a/src/jalview/jbgui/GPCAPanel.java +++ b/src/jalview/jbgui/GPCAPanel.java @@ -85,6 +85,7 @@ public class GPCAPanel extends JInternalFrame zCombobox.addItem("dim " + i); } } + public GPCAPanel(int dim) { try diff --git a/src/jalview/jbgui/GPaSiMapPanel.java b/src/jalview/jbgui/GPaSiMapPanel.java index 369a005..3c7fb5a 100755 --- a/src/jalview/jbgui/GPaSiMapPanel.java +++ b/src/jalview/jbgui/GPaSiMapPanel.java @@ -85,6 +85,7 @@ public class GPaSiMapPanel extends JInternalFrame zCombobox.addItem("dim " + i); } } + public GPaSiMapPanel(int dim) { try @@ -223,8 +224,8 @@ public class GPaSiMapPanel extends JInternalFrame } }); JMenuItem outputAlignment = new JMenuItem(); - outputAlignment.setText( - MessageManager.getString("label.output_alignment")); + outputAlignment + .setText(MessageManager.getString("label.output_alignment")); outputAlignment.addActionListener(new ActionListener() { @Override diff --git a/src/jalview/jbgui/GPreferences.java b/src/jalview/jbgui/GPreferences.java index e574327..c644e3c 100755 --- a/src/jalview/jbgui/GPreferences.java +++ b/src/jalview/jbgui/GPreferences.java @@ -160,7 +160,7 @@ public class GPreferences extends JPanel protected JCheckBox conservation = new JCheckBox(); - protected JCheckBox identity = new JCheckBox(); + protected JCheckBox identity = new JCheckBox(); protected JCheckBox ssConsensus = new JCheckBox(); diff --git a/src/jalview/math/Matrix.java b/src/jalview/math/Matrix.java index 7ae4b94..f767444 100755 --- a/src/jalview/math/Matrix.java +++ b/src/jalview/math/Matrix.java @@ -123,12 +123,12 @@ public class Matrix implements MatrixI if (row != null) { value[i] = new double[row.length]; - int j = 0; - for (float oldValue : row) - { - value[i][j] = oldValue; - j++; - } + int j = 0; + for (float oldValue : row) + { + value[i][j] = oldValue; + j++; + } } i++; } @@ -191,10 +191,11 @@ public class Matrix implements MatrixI */ for (int k = 0; k < in.width(); k++) { - if (!Double.isNaN(in.getValue(i,k)) && !Double.isNaN(this.value[k][j])) - { + if (!Double.isNaN(in.getValue(i, k)) + && !Double.isNaN(this.value[k][j])) + { tmp[i][j] += (in.getValue(i, k) * this.value[k][j]); - } + } } } } @@ -833,10 +834,10 @@ public class Matrix implements MatrixI } /** - * returns the matrix as a double[][] array - * - * @return - */ + * returns the matrix as a double[][] array + * + * @return + */ @Override public double[][] asArray() { @@ -1018,7 +1019,8 @@ public class Matrix implements MatrixI /** * Add d to all entries of this matrix * - * @param d ~ value to add + * @param d + * ~ value to add */ @Override public void add(double d) @@ -1086,7 +1088,7 @@ public class Matrix implements MatrixI } /** - * Returns a copy in which every value in the matrix is its absolute + * Returns a copy in which every value in the matrix is its absolute * * @return */ @@ -1122,7 +1124,7 @@ public class Matrix implements MatrixI { if (row != null) { - mean[i++] = MiscMath.mean(row); + mean[i++] = MiscMath.mean(row); } } return mean; @@ -1142,17 +1144,17 @@ public class Matrix implements MatrixI double[] column = getColumn(j); if (column != null) { - mean[j] = MiscMath.mean(column); + mean[j] = MiscMath.mean(column); } } return mean; } /** - * return a flattened matrix containing the sum of each column - * - * @return - */ + * return a flattened matrix containing the sum of each column + * + * @return + */ @Override public double[] sumCol() { @@ -1162,17 +1164,17 @@ public class Matrix implements MatrixI double[] column = getColumn(j); if (column != null) { - sum[j] = MiscMath.sum(column); + sum[j] = MiscMath.sum(column); } - } + } return sum; } /** - * returns the mean value of the complete matrix - * - * @return - */ + * returns the mean value of the complete matrix + * + * @return + */ @Override public double mean() { @@ -1182,47 +1184,51 @@ public class Matrix implements MatrixI { for (double col : row) { - if (!Double.isNaN(col)) - { - sum += col; - } else { - nanCount++; - } + if (!Double.isNaN(col)) + { + sum += col; + } + else + { + nanCount++; + } } } return sum / (double) (this.rows * this.cols - nanCount); } /** - * fills up a diagonal matrix with its transposed copy - * !other side should be filled with 0 - * !keeps Double.NaN found in either side - * - * TODO check on which side it was diagonal and only do calculations for the other side - */ + * fills up a diagonal matrix with its transposed copy !other side should be + * filled with 0 !keeps Double.NaN found in either side + * + * TODO check on which side it was diagonal and only do calculations for the + * other side + */ @Override public void fillDiagonal() { int n = this.rows; int m = this.cols; - MatrixI copy = this.transpose(); // goes through each element in the matrix and - for (int i = 0; i < n; i++) // adds the value in the transposed copy to the original value + MatrixI copy = this.transpose(); // goes through each element in the matrix + // and + for (int i = 0; i < n; i++) // adds the value in the transposed copy to the + // original value { for (int j = 0; j < m; j++) { - if (i != j) - { - this.addValue(i, j, copy.getValue(i,j)); - } + if (i != j) + { + this.addValue(i, j, copy.getValue(i, j)); + } } } } /** - * counts the number of Double.NaN in the matrix - * - * @return - */ + * counts the number of Double.NaN in the matrix + * + * @return + */ @Override public int countNaN() { @@ -1231,117 +1237,139 @@ public class Matrix implements MatrixI { for (int j = 0; j < this.cols; j++) { - if (Double.isNaN(this.getValue(i,j))) - { - NaN++; - } + if (Double.isNaN(this.getValue(i, j))) + { + NaN++; + } } } return NaN; } /** - * performs an element-wise addition of this matrix by another matrix ~ this - m - * @param m ~ other matrix - * - * @return - */ + * performs an element-wise addition of this matrix by another matrix ~ this - + * m + * + * @param m + * ~ other matrix + * + * @return + */ @Override public MatrixI add(MatrixI m) { if (m.width() != cols || m.height() != rows) { - throw new IllegalArgumentException("Can't add a " + m.height() + "x" + m.width() + " to a " + this.rows + "x" + this.cols + " matrix"); + throw new IllegalArgumentException( + "Can't add a " + m.height() + "x" + m.width() + " to a " + + this.rows + "x" + this.cols + " matrix"); } double[][] tmp = new double[this.rows][this.cols]; for (int i = 0; i < this.rows; i++) { for (int j = 0; j < this.cols; j++) { - tmp[i][j] = this.getValue(i,j) + m.getValue(i,j); + tmp[i][j] = this.getValue(i, j) + m.getValue(i, j); } } return new Matrix(tmp); } /** - * performs an element-wise subtraction of this matrix by another matrix ~ this - m - * @param m ~ other matrix - * - * @return - */ + * performs an element-wise subtraction of this matrix by another matrix ~ + * this - m + * + * @param m + * ~ other matrix + * + * @return + */ @Override public MatrixI subtract(MatrixI m) { if (m.width() != cols || m.height() != rows) { - throw new IllegalArgumentException("Can't subtract a " + m.height() + "x" + m.width() + " from a " + this.rows + "x" + this.cols + " matrix"); + throw new IllegalArgumentException("Can't subtract a " + m.height() + + "x" + m.width() + " from a " + this.rows + "x" + this.cols + + " matrix"); } double[][] tmp = new double[this.rows][this.cols]; for (int i = 0; i < this.rows; i++) { for (int j = 0; j < this.cols; j++) { - tmp[i][j] = this.getValue(i,j) - m.getValue(i,j); + tmp[i][j] = this.getValue(i, j) - m.getValue(i, j); } } return new Matrix(tmp); } /** - * performs an element-wise multiplication of this matrix by another matrix ~ this * m - * @param m ~ other matrix - * - * @return - */ + * performs an element-wise multiplication of this matrix by another matrix ~ + * this * m + * + * @param m + * ~ other matrix + * + * @return + */ @Override public MatrixI elementwiseMultiply(MatrixI m) { if (m.width() != cols || m.height() != rows) { - throw new IllegalArgumentException("Can't multiply a " + this.rows + "x" + this.cols + " by a " + m.height() + "x" + m.width() + " matrix"); + throw new IllegalArgumentException( + "Can't multiply a " + this.rows + "x" + this.cols + " by a " + + m.height() + "x" + m.width() + " matrix"); } double[][] tmp = new double[this.rows][this.cols]; for (int i = 0; i < this.rows; i++) { for (int j = 0; j < this.cols; j++) { - tmp[i][j] = this.getValue(i, j) * m.getValue(i,j); + tmp[i][j] = this.getValue(i, j) * m.getValue(i, j); } } return new Matrix(tmp); } /** - * performs an element-wise division of this matrix by another matrix ~ this / m - * @param m ~ other matrix - * - * @return - */ + * performs an element-wise division of this matrix by another matrix ~ this / + * m + * + * @param m + * ~ other matrix + * + * @return + */ @Override public MatrixI elementwiseDivide(MatrixI m) { if (m.width() != cols || m.height() != rows) { - throw new IllegalArgumentException("Can't divide a " + this.rows + "x" + this.cols + " by a " + m.height() + "x" + m.width() + " matrix"); + throw new IllegalArgumentException( + "Can't divide a " + this.rows + "x" + this.cols + " by a " + + m.height() + "x" + m.width() + " matrix"); } double[][] tmp = new double[this.rows][this.cols]; for (int i = 0; i < this.rows; i++) { for (int j = 0; j < this.cols; j++) { - tmp[i][j] = this.getValue(i, j) / m.getValue(i,j); + tmp[i][j] = this.getValue(i, j) / m.getValue(i, j); } } return new Matrix(tmp); } /** - * calculate the root-mean-square for tow matrices - * @param m ~ other matrix - * - * @return - */ + * calculate the root-mean-square for tow matrices + * + * @param m + * ~ other matrix + * + * @return + */ @Override public double rmsd(MatrixI m) { @@ -1351,10 +1379,10 @@ public class Matrix implements MatrixI } /** - * calculates the Frobenius norm of this matrix - * - * @return - */ + * calculates the Frobenius norm of this matrix + * + * @return + */ @Override public double norm() { @@ -1363,17 +1391,17 @@ public class Matrix implements MatrixI { for (double val : row) { - result += Math.pow(val, 2); + result += Math.pow(val, 2); } } return Math.sqrt(result); } /** - * returns the sum of all values in this matrix - * - * @return - */ + * returns the sum of all values in this matrix + * + * @return + */ @Override public double sum() { @@ -1382,24 +1410,28 @@ public class Matrix implements MatrixI { for (double val : row) { - sum += (Double.isNaN(val)) ? 0.0 : val; + sum += (Double.isNaN(val)) ? 0.0 : val; } } return sum; } /** - * returns the sum-product of this matrix with vector v - * @param v ~ vector - * - * @return - */ + * returns the sum-product of this matrix with vector v + * + * @param v + * ~ vector + * + * @return + */ @Override public double[] sumProduct(double[] v) { if (v.length != cols) { - throw new IllegalArgumentException("Vector and matrix do not have the same dimension! (" + v.length + " != " + cols + ")"); + throw new IllegalArgumentException( + "Vector and matrix do not have the same dimension! (" + + v.length + " != " + cols + ")"); } double[] result = new double[rows]; for (int i = 0; i < rows; i++) @@ -1408,7 +1440,7 @@ public class Matrix implements MatrixI double sum = 0; for (int j = 0; j < row.length; j++) { - sum += row[j] * v[j]; + sum += row[j] * v[j]; } result[i] = sum; } @@ -1416,20 +1448,20 @@ public class Matrix implements MatrixI } /** - * mirrors columns of the matrix - * - * @return - */ + * mirrors columns of the matrix + * + * @return + */ @Override public MatrixI mirrorCol() { double[][] result = new double[rows][cols]; for (int i = 0; i < rows; i++) { - int k = cols - 1; // reverse col + int k = cols - 1; // reverse col for (int j = 0; j < cols; j++) { - result[i][k--] = this.getValue(i,j); + result[i][k--] = this.getValue(i, j); } } MatrixI resultMatrix = new Matrix(result); diff --git a/src/jalview/math/MatrixI.java b/src/jalview/math/MatrixI.java index 7faac73..b932b33 100644 --- a/src/jalview/math/MatrixI.java +++ b/src/jalview/math/MatrixI.java @@ -61,10 +61,10 @@ public interface MatrixI void setValue(int i, int j, double d); /** - * Returns the matrix as a double[][] array - * - * @return - */ + * Returns the matrix as a double[][] array + * + * @return + */ double[][] asArray(); /** @@ -175,10 +175,11 @@ public interface MatrixI void multiply(double d); /** - * Add d to all entries of this matrix - * - * @param d ~ value to add - */ + * Add d to all entries of this matrix + * + * @param d + * ~ value to add + */ void add(double d); /** @@ -193,7 +194,7 @@ public interface MatrixI boolean equals(MatrixI m2, double delta); /** - * Returns a copy in which every value in the matrix is its absolute + * Returns a copy in which every value in the matrix is its absolute */ MatrixI absolute(); @@ -208,110 +209,122 @@ public interface MatrixI double[] meanCol(); /** - * Returns a flattened matrix containing the sum of each column - * - * @return - */ + * Returns a flattened matrix containing the sum of each column + * + * @return + */ double[] sumCol(); /** - * returns the mean value of the complete matrix - */ + * returns the mean value of the complete matrix + */ double mean(); /** - * fills up a diagonal matrix with its transposed copy - * !other side should be filled with either 0 or Double.NaN - */ + * fills up a diagonal matrix with its transposed copy !other side should be + * filled with either 0 or Double.NaN + */ void fillDiagonal(); /** - * counts the number of Double.NaN in the matrix - * - * @return - */ + * counts the number of Double.NaN in the matrix + * + * @return + */ int countNaN(); /** - * performs an element-wise addition of this matrix by another matrix - * !matrices have to be the same size - * @param m ~ other matrix - * - * @return - * @throws IllegalArgumentException - * if this and m do not have the same dimensions - */ + * performs an element-wise addition of this matrix by another matrix + * !matrices have to be the same size + * + * @param m + * ~ other matrix + * + * @return + * @throws IllegalArgumentException + * if this and m do not have the same dimensions + */ MatrixI add(MatrixI m); /** - * performs an element-wise subtraction of this matrix by another matrix - * !matrices have to be the same size - * @param m ~ other matrix - * - * @return - * @throws IllegalArgumentException - * if this and m do not have the same dimensions - */ + * performs an element-wise subtraction of this matrix by another matrix + * !matrices have to be the same size + * + * @param m + * ~ other matrix + * + * @return + * @throws IllegalArgumentException + * if this and m do not have the same dimensions + */ MatrixI subtract(MatrixI m); - + /** - * performs an element-wise multiplication of this matrix by another matrix ~ this * m - * !matrices have to be the same size - * @param m ~ other matrix - * - * @return - * @throws IllegalArgumentException - * if this and m do not have the same dimensions - */ + * performs an element-wise multiplication of this matrix by another matrix ~ + * this * m !matrices have to be the same size + * + * @param m + * ~ other matrix + * + * @return + * @throws IllegalArgumentException + * if this and m do not have the same dimensions + */ MatrixI elementwiseMultiply(MatrixI m); /** - * performs an element-wise division of this matrix by another matrix ~ this / m - * !matrices have to be the same size - * @param m ~ other matrix - * - * @return - * @throws IllegalArgumentException - * if this and m do not have the same dimensions - */ + * performs an element-wise division of this matrix by another matrix ~ this / + * m !matrices have to be the same size + * + * @param m + * ~ other matrix + * + * @return + * @throws IllegalArgumentException + * if this and m do not have the same dimensions + */ MatrixI elementwiseDivide(MatrixI m); /** - * calculates the root-mean-square for two matrices - * @param m ~ other matrix - * - * @return - */ + * calculates the root-mean-square for two matrices + * + * @param m + * ~ other matrix + * + * @return + */ double rmsd(MatrixI m); /** - * calculates the Frobenius norm of this matrix - * - * @return - */ + * calculates the Frobenius norm of this matrix + * + * @return + */ double norm(); - + /** - * returns the sum of all values in this matrix - * - * @return - */ + * returns the sum of all values in this matrix + * + * @return + */ double sum(); /** - * returns the sum-product of this matrix with vector v - * @param v ~ vector - * - * @return - * @throws IllegalArgumentException - * if this.cols and v do not have the same length - */ + * returns the sum-product of this matrix with vector v + * + * @param v + * ~ vector + * + * @return + * @throws IllegalArgumentException + * if this.cols and v do not have the same length + */ double[] sumProduct(double[] v); /** - * mirrors the columns of this matrix - * - * @return - */ + * mirrors the columns of this matrix + * + * @return + */ MatrixI mirrorCol(); } diff --git a/src/jalview/math/MiscMath.java b/src/jalview/math/MiscMath.java index b5218d5..eee7ef8 100755 --- a/src/jalview/math/MiscMath.java +++ b/src/jalview/math/MiscMath.java @@ -27,14 +27,17 @@ import java.util.Arrays; /** * A collection of miscellaneous mathematical operations + * * @AUTHOR MorellThomas */ public class MiscMath { /** - * prints an array - * @param m ~ array - */ + * prints an array + * + * @param m + * ~ array + */ public static void print(double[] m, String format) { System.out.print("[ "); @@ -46,39 +49,43 @@ public class MiscMath } /** - * calculates the mean of an array - * - * @param m ~ array - * @return - */ + * calculates the mean of an array + * + * @param m + * ~ array + * @return + */ public static double mean(double[] m) { double sum = 0; int nanCount = 0; for (int i = 0; i < m.length; i++) { - if (!Double.isNaN(m[i])) // ignore NaN values in the array + if (!Double.isNaN(m[i])) // ignore NaN values in the array { sum += m[i]; - } else { - nanCount++; + } + else + { + nanCount++; } } return sum / (double) (m.length - nanCount); } /** - * calculates the sum of an array - * - * @param m ~ array - * @return - */ + * calculates the sum of an array + * + * @param m + * ~ array + * @return + */ public static double sum(double[] m) { double sum = 0; for (int i = 0; i < m.length; i++) { - if (!Double.isNaN(m[i])) // ignore NaN values in the array + if (!Double.isNaN(m[i])) // ignore NaN values in the array { sum += m[i]; } @@ -87,14 +94,14 @@ public class MiscMath } /** - * calculates the square root of each element in an array - * - * @param m ~ array - * - * @return - * TODO - * make general with function passed -> apply function to each element - */ + * calculates the square root of each element in an array + * + * @param m + * ~ array + * + * @return TODO make general with function passed -> apply function to each + * element + */ public static double[] sqrt(double[] m) { double[] sqrts = new double[m.length]; @@ -106,16 +113,20 @@ public class MiscMath } /** - * calculate element wise multiplication of two arrays with the same length - * - * @param a ~ array - * @param b ~ array - * - * @return - */ - public static double[] elementwiseMultiply(byte[] a, double[] b) throws RuntimeException + * calculate element wise multiplication of two arrays with the same length + * + * @param a + * ~ array + * @param b + * ~ array + * + * @return + */ + public static double[] elementwiseMultiply(byte[] a, double[] b) + throws RuntimeException { - if (a.length != b.length) // throw exception if the arrays do not have the same length + if (a.length != b.length) // throw exception if the arrays do not have the + // same length { throw new SameLengthException(a.length, b.length); } @@ -126,9 +137,12 @@ public class MiscMath } return result; } - public static double[] elementwiseMultiply(double[] a, double[] b) throws RuntimeException + + public static double[] elementwiseMultiply(double[] a, double[] b) + throws RuntimeException { - if (a.length != b.length) // throw exception if the arrays do not have the same length + if (a.length != b.length) // throw exception if the arrays do not have the + // same length { throw new SameLengthException(a.length, b.length); } @@ -139,9 +153,12 @@ public class MiscMath } return result; } - public static byte[] elementwiseMultiply(byte[] a, byte[] b) throws RuntimeException + + public static byte[] elementwiseMultiply(byte[] a, byte[] b) + throws RuntimeException { - if (a.length != b.length) // throw exception if the arrays do not have the same length + if (a.length != b.length) // throw exception if the arrays do not have the + // same length { throw new SameLengthException(a.length, b.length); } @@ -152,6 +169,7 @@ public class MiscMath } return result; } + public static double[] elementwiseMultiply(double[] a, double b) { double[] result = new double[a.length]; @@ -163,16 +181,20 @@ public class MiscMath } /** - * calculate element wise division of two arrays ~ a / b - * - * @param a ~ array - * @param b ~ array - * - * @return - */ - public static double[] elementwiseDivide(double[] a, double[] b) throws RuntimeException + * calculate element wise division of two arrays ~ a / b + * + * @param a + * ~ array + * @param b + * ~ array + * + * @return + */ + public static double[] elementwiseDivide(double[] a, double[] b) + throws RuntimeException { - if (a.length != b.length) // throw exception if the arrays do not have the same length + if (a.length != b.length) // throw exception if the arrays do not have the + // same length { throw new SameLengthException(a.length, b.length); } @@ -185,16 +207,20 @@ public class MiscMath } /** - * calculate element wise addition of two arrays - * - * @param a ~ array - * @param b ~ array - * - * @return - */ - public static double[] elementwiseAdd(double[] a, double[] b) throws RuntimeException + * calculate element wise addition of two arrays + * + * @param a + * ~ array + * @param b + * ~ array + * + * @return + */ + public static double[] elementwiseAdd(double[] a, double[] b) + throws RuntimeException { - if (a.length != b.length) // throw exception if the arrays do not have the same length + if (a.length != b.length) // throw exception if the arrays do not have the + // same length { throw new SameLengthException(a.length, b.length); } @@ -206,6 +232,7 @@ public class MiscMath } return result; } + public static double[] elementwiseAdd(double[] a, double b) { double[] result = new double[a.length]; @@ -217,41 +244,59 @@ public class MiscMath } /** - * returns true if two arrays are element wise within a tolerance - * - * @param a ~ array - * @param b ~ array - * @param rtol ~ relative tolerance - * @param atol ~ absolute tolerance - * @param equalNAN ~ whether NaN at the same position return true - * - * @return - */ - public static boolean allClose(double[] a, double[] b, double rtol, double atol, boolean equalNAN) + * returns true if two arrays are element wise within a tolerance + * + * @param a + * ~ array + * @param b + * ~ array + * @param rtol + * ~ relative tolerance + * @param atol + * ~ absolute tolerance + * @param equalNAN + * ~ whether NaN at the same position return true + * + * @return + */ + public static boolean allClose(double[] a, double[] b, double rtol, + double atol, boolean equalNAN) { boolean areEqual = true; for (int i = 0; i < a.length; i++) { - if (equalNAN && (Double.isNaN(a[i]) && Double.isNaN(b[i]))) // if equalNAN == true -> skip the NaN pair + if (equalNAN && (Double.isNaN(a[i]) && Double.isNaN(b[i]))) // if equalNAN + // == true -> + // skip the + // NaN pair { - continue; + continue; } - if (Math.abs(a[i] - b[i]) > (atol + rtol * Math.abs(b[i]))) // check for the similarity condition -> if not met -> break and return false + if (Math.abs(a[i] - b[i]) > (atol + rtol * Math.abs(b[i]))) // check for + // the + // similarity + // condition + // -> if not + // met -> + // break and + // return + // false { - areEqual = false; - break; + areEqual = false; + break; } } return areEqual; } /** - * returns the index of the maximum and the maximum value of an array - * - * @param a ~ array - * - * @return - */ + * returns the index of the maximum and the maximum value of an array + * + * @param a + * ~ array + * + * @return + */ public static int[] findMax(int[] a) { int max = 0; @@ -260,25 +305,30 @@ public class MiscMath { if (a[i] > max) { - max = a[i]; - maxIndex = i; + max = a[i]; + maxIndex = i; } } - return new int[]{maxIndex, max}; + return new int[] { maxIndex, max }; } /** - * returns the dot product of two arrays - * @param a ~ array a - * @param b ~ array b - * - * @return - */ + * returns the dot product of two arrays + * + * @param a + * ~ array a + * @param b + * ~ array b + * + * @return + */ public static double dot(double[] a, double[] b) { if (a.length != b.length) { - throw new IllegalArgumentException(String.format("Vectors do not have the same length (%d, %d)!", a.length, b.length)); + throw new IllegalArgumentException( + String.format("Vectors do not have the same length (%d, %d)!", + a.length, b.length)); } double aibi = 0; @@ -290,11 +340,13 @@ public class MiscMath } /** - * returns the euklidian norm of the vector - * @param v ~ vector - * - * @return - */ + * returns the euklidian norm of the vector + * + * @param v + * ~ vector + * + * @return + */ public static double norm(double[] v) { double result = 0; @@ -302,15 +354,17 @@ public class MiscMath { result += Math.pow(i, 2); } - return Math.sqrt(result); + return Math.sqrt(result); } /** - * returns the number of NaN in the vector - * @param v ~ vector - * - * @return - */ + * returns the number of NaN in the vector + * + * @param v + * ~ vector + * + * @return + */ public static int countNaN(double[] v) { int cnt = 0; @@ -318,20 +372,21 @@ public class MiscMath { if (Double.isNaN(i)) { - cnt++; + cnt++; } } return cnt; } /** - * recursively calculates the permutations of total n items with r items per combination - * according to n!/(n-r)! by only multiplying the relevant terms - * @param n - * @param r - * - * @return permutations - */ + * recursively calculates the permutations of total n items with r items per + * combination according to n!/(n-r)! by only multiplying the relevant terms + * + * @param n + * @param r + * + * @return permutations + */ public static long permutations(int n, int r) { if (n < r) @@ -340,13 +395,14 @@ public class MiscMath long result = 1l; for (int i = 0; i < r; i++) { - result *= (n-i); + result *= (n - i); } return result; } /** * calculate all unique combinations of n elements into r sized groups + * * @param n * @param r * @@ -357,13 +413,14 @@ public class MiscMath int result = 1; for (int i = 0; i < r; i++) { - result *= (n-1); + result *= (n - 1); } return (int) (result / MiscMath.factorial(r)); } /** * calculate the factorial of n (n >= 0) + * * @param n * * @return diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index 2a2225e..90a12f2 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -2011,13 +2011,14 @@ public class Jalview2XML } /** - * Writes PaSiMap viewer attributes and computed values to an XML model object and - * adds it to the JalviewModel. Any exceptions are reported by logging. + * Writes PaSiMap viewer attributes and computed values to an XML model object + * and adds it to the JalviewModel. Any exceptions are reported by logging. * uses the functions from PCA */ protected void savePaSiMap(PaSiMapPanel panel, JalviewModel object) { - // TODO: this should be merged with above savePCAPanel - otherwise it is essentially redundant code + // TODO: this should be merged with above savePCAPanel - otherwise it is + // essentially redundant code try { PcaViewer viewer = new PcaViewer(); @@ -2107,6 +2108,7 @@ public class Jalview2XML Console.error("Error saving PaSiMap: " + t.getMessage()); } } + /** * Stores values from a matrix into an XML element, including (if present) the * D or E vectors @@ -6751,9 +6753,9 @@ public class Jalview2XML private boolean isPasimap(PcaViewer viewer) { - return viewer.getTitle().toLowerCase(Locale.ROOT) - .startsWith("pasimap"); + return viewer.getTitle().toLowerCase(Locale.ROOT).startsWith("pasimap"); } + /** * Loads any saved PaSiMAp viewers using the function from PCA * @@ -6777,7 +6779,7 @@ public class Jalview2XML viewer.isIncludeGappedColumns(), viewer.isMatchGaps(), viewer.isIncludeGaps(), viewer.isDenominateByShortestLength()); - */ + */ /* * create the panel (without computing the PaSiMAp) @@ -6804,7 +6806,8 @@ public class Jalview2XML PaSiMap pasimap = new PaSiMap(null, scoreModel, null); PcaDataType pasimapData = viewer.getPcaData(); - MatrixI pairwise = loadDoubleMatrix(pasimapData.getPairwiseMatrix()); + MatrixI pairwise = loadDoubleMatrix( + pasimapData.getPairwiseMatrix()); pasimap.setPairwiseScores(pairwise); MatrixI result = loadDoubleMatrix(pasimapData.getEigenMatrix()); diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 7c9ecd7..b9411c3 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -1560,8 +1560,6 @@ public class AnnotationRenderer * {profile type, #values, total count, char1, pct1, char2, pct2...} */ int profl[] = getProfileFor(_aa, column); - - // just try to draw the logo if profl is not null if (profl != null && profl[2] != 0) @@ -1648,7 +1646,7 @@ public class AnnotationRenderer } else { - + colour = profcolour.findColour(dc[0], column, null); } diff --git a/src/jalview/renderer/ResidueShader.java b/src/jalview/renderer/ResidueShader.java index 91f38c5..511a55c 100644 --- a/src/jalview/renderer/ResidueShader.java +++ b/src/jalview/renderer/ResidueShader.java @@ -63,13 +63,14 @@ public class ResidueShader implements ResidueShaderI * the consensus data for each column */ private ProfilesI consensus; - + /* * the ss consensus data for each column for each source */ private Map ssConsensusProfileMap; + /* * if true, apply shading of colour by conservation */ @@ -158,7 +159,7 @@ public class ResidueShader implements ResidueShaderI public void setConsensus(ProfilesI cons) { consensus = cons; - + } /** @@ -303,7 +304,7 @@ public class ResidueShader implements ResidueShaderI return colour; } - + @Override public Color findSSColour(char symbol, int position) { diff --git a/src/jalview/schemes/ClustalxColourScheme.java b/src/jalview/schemes/ClustalxColourScheme.java index 04097a8..8e64f8f 100755 --- a/src/jalview/schemes/ClustalxColourScheme.java +++ b/src/jalview/schemes/ClustalxColourScheme.java @@ -364,62 +364,72 @@ public class ClustalxColourScheme extends ResidueColourScheme { return false; } + public String toRuleRep() { makeColours(); - HashMap cols=new HashMap(); - for (String res:ResidueProperties.aa) { + HashMap cols = new HashMap(); + for (String res : ResidueProperties.aa) + { StringBuilder sb = new StringBuilder(); - - int rnum=ResidueProperties.aaIndex[res.charAt(0)]; - if (rnum<0 || rnum>=residueColour.length) + + int rnum = ResidueProperties.aaIndex[res.charAt(0)]; + if (rnum < 0 || rnum >= residueColour.length) { continue; } - + ConsensusColour cc = residueColour[rnum]; - if (cc==null) + if (cc == null) { continue; } - //sb.append("Residue "+res+" ("+rnum+")"); - //sb.append("\t"); + // sb.append("Residue "+res+" ("+rnum+")"); + // sb.append("\t"); sb.append(cc.c.toString()); - double f=0; + double f = 0; sb.append("\t"); - for (Consensus cons: cc.cons) { - if (cons.threshold==0 || f!=cons.threshold) + for (Consensus cons : cc.cons) + { + if (cons.threshold == 0 || f != cons.threshold) { - if (f!=0) + if (f != 0) { - sb.append("}, {"); - } else { - sb.append("{"); + sb.append("}, {"); + } + else + { + sb.append("{"); } - sb.append(cons.threshold); - sb.append(","); - f=cons.threshold; - } else { + sb.append(cons.threshold); + sb.append(","); + f = cons.threshold; + } + else + { sb.append(","); } sb.append(cons.maskstr); } sb.append("}"); - String clxrep=sb.toString(); + String clxrep = sb.toString(); String xres = cols.get(clxrep); - if (xres==null) { xres = "";} - xres+=res; + if (xres == null) + { + xres = ""; + } + xres += res; cols.put(clxrep, xres); } StringBuilder sb = new StringBuilder(); - for (String clxrep:cols.keySet()) + for (String clxrep : cols.keySet()) { sb.append(cols.get(clxrep)); sb.append("\t"); sb.append(clxrep); sb.append("\n"); - + } return sb.toString(); } diff --git a/src/jalview/schemes/ResidueProperties.java b/src/jalview/schemes/ResidueProperties.java index 2fcb95f..9d83069 100755 --- a/src/jalview/schemes/ResidueProperties.java +++ b/src/jalview/schemes/ResidueProperties.java @@ -41,7 +41,7 @@ public class ResidueProperties public static final int[] nucleotideIndex; public static final int[] purinepyrimidineIndex; - + public static final int[] secondaryStructureIndex; public static final Map aa3Hash = new HashMap<>(); @@ -197,13 +197,13 @@ public class ResidueProperties purinepyrimidineIndex['N'] = 2; purinepyrimidineIndex['n'] = 2; } - + static { secondaryStructureIndex = new int[255]; for (int i = 0; i < 255; i++) { - secondaryStructureIndex[i] = 3; + secondaryStructureIndex[i] = 3; } secondaryStructureIndex['H'] = 0; @@ -398,12 +398,12 @@ public class ResidueProperties Color.white, // all other nucleotides Color.white // Gap }; - - //Secondary structure - public static final Color[] secondarystructure = { Color.red, // H - Color.green, // E - Color.gray // C - }; + + // Secondary structure + public static final Color[] secondarystructure = { Color.red, // H + Color.green, // E + Color.gray // C + }; // Zappo public static final Color[] zappo = { Color.pink, // A diff --git a/src/jalview/util/ArgParserUtils.java b/src/jalview/util/ArgParserUtils.java index a71b462..710c054 100644 --- a/src/jalview/util/ArgParserUtils.java +++ b/src/jalview/util/ArgParserUtils.java @@ -1,3 +1,23 @@ +/* + * 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.util.ArrayList; diff --git a/src/jalview/util/Constants.java b/src/jalview/util/Constants.java index 27513ab..f066892 100644 --- a/src/jalview/util/Constants.java +++ b/src/jalview/util/Constants.java @@ -28,19 +28,22 @@ import java.util.Map; */ public class Constants { - - //character used to represent secondary structures + + // character used to represent secondary structures public static final char HELIX = 'H'; + public static final char SHEET = 'E'; + public static final char COIL = 'C'; - //label in secondary structure annotation data model from 3d structures + // label in secondary structure annotation data model from 3d structures public static final String SS_ANNOTATION_LABEL = "Secondary Structure"; - - //label in secondary structure annotation data model from JPred - public static final String SS_ANNOTATION_FROM_JPRED_LABEL = "jnetpred"; - + + // label in secondary structure annotation data model from JPred + public static final String SS_ANNOTATION_FROM_JPRED_LABEL = "jnetpred"; + public static final Map SECONDARY_STRUCTURE_LABELS = new HashMap<>(); + static { SECONDARY_STRUCTURE_LABELS.put(SS_ANNOTATION_LABEL, "3D Structures"); SECONDARY_STRUCTURE_LABELS.put(SS_ANNOTATION_FROM_JPRED_LABEL, "JPred"); diff --git a/src/jalview/util/ErrorLog.java b/src/jalview/util/ErrorLog.java index c204783..651073f 100644 --- a/src/jalview/util/ErrorLog.java +++ b/src/jalview/util/ErrorLog.java @@ -1,3 +1,23 @@ +/* + * 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.lang.reflect.InvocationTargetException; @@ -17,11 +37,18 @@ public class ErrorLog private static String prefix = null; + private static boolean quiet = false; + public static void setHasConsole(boolean b) { hasConsole = b; } + public static void setQuiet(boolean b) + { + quiet = b; + } + public static void setPrefix(String s) { prefix = s; @@ -45,6 +72,10 @@ public class ErrorLog public static void println(String message0, boolean err, boolean thisHasConsole) { + if (!err && quiet) + { + return; + } String message = prefix == null ? message0 : prefix + message0; if (thisHasConsole && hasConsole) { diff --git a/src/jalview/util/HttpUtils.java b/src/jalview/util/HttpUtils.java index ec35948..1d9f8d0 100644 --- a/src/jalview/util/HttpUtils.java +++ b/src/jalview/util/HttpUtils.java @@ -30,6 +30,8 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; +import jalview.bin.Console; + public class HttpUtils { public final static String JALVIEWSCHEMEPREFIX = "jalview"; @@ -129,7 +131,9 @@ public class HttpUtils } /** - * wrapper to follow a URL connection ALLOWING redirects from http to https + * wrapper to return a new HttpURLConnection to a new URL when there is a + * redirect from http to https, otherwise return the unused original + * HttpURLConnection * * @param HttpURLConnection * conn0 @@ -139,34 +143,54 @@ public class HttpUtils throws IOException { URL url = conn0.getURL(); - if (url == null) + // we are only checking for a redirect from http to https otherwise the java + // connection will follow when called (if not unset) + if (url == null || !"http".equals(url.getProtocol()) + || !conn0.getInstanceFollowRedirects()) { - return null; + return conn0; } - HttpURLConnection conn = null; - int response = conn0.getResponseCode(); - boolean followed = false; - if (response >= 300 && response < 400 && conn0.getFollowRedirects()) + + // check the response code + HttpURLConnection checkConn = (HttpURLConnection) url.openConnection(); + httpURLConnectionCopyAttributes(conn0, checkConn); + + boolean redirectToHttps = false; + int response = checkConn.getResponseCode(); + checkConn.disconnect(); + if (response >= 300 && response < 400) { // we are only checking for a redirect from http to https - if ("http".equals(url.getProtocol())) + URL loc = new URL(conn0.getHeaderField("Location")); + if (loc != null && "https".equals(loc.getProtocol())) { - URL loc = new URL(conn0.getHeaderField("Location")); - if (loc != null && "https".equals(loc.getProtocol())) - { - conn = (HttpURLConnection) loc.openConnection(); - conn.setRequestMethod(conn0.getRequestMethod()); - conn.setDoInput(conn0.getDoInput()); - conn.setUseCaches(conn0.getUseCaches()); - conn.setConnectTimeout(conn0.getConnectTimeout()); - conn.setReadTimeout(conn0.getReadTimeout()); - conn.setInstanceFollowRedirects( - conn0.getInstanceFollowRedirects()); - followed = true; - } + redirectToHttps = true; + url = loc; } } - return followed && conn != null ? conn : conn0; + + if (!redirectToHttps) + { + return conn0; + } + + // We want to return an HttpURLConnection to the new https URL that is + // unconnected in case further manipulation of the request is required + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + httpURLConnectionCopyAttributes(conn0, conn); + return conn; + } + + private static void httpURLConnectionCopyAttributes( + HttpURLConnection conn0, HttpURLConnection conn1) + throws ProtocolException + { + conn1.setRequestMethod(conn0.getRequestMethod()); + conn1.setDoInput(conn0.getDoInput()); + conn1.setUseCaches(conn0.getUseCaches()); + conn1.setConnectTimeout(conn0.getConnectTimeout()); + conn1.setReadTimeout(conn0.getReadTimeout()); + conn1.setInstanceFollowRedirects(conn0.getInstanceFollowRedirects()); } /** @@ -180,8 +204,11 @@ public class HttpUtils { if (url == null) { + Console.debug("HttpUtils.openConnection(url) called with null url"); return null; } + Console.debug("HttpUtils.openConnection(url) called with url=" + + url.toString()); URLConnection conn = null; String protocol = url.getProtocol(); if ("http".equals(protocol) || "https".equals(protocol)) diff --git a/src/jalview/util/LaunchUtils.java b/src/jalview/util/LaunchUtils.java index 186745d..ccf9992 100644 --- a/src/jalview/util/LaunchUtils.java +++ b/src/jalview/util/LaunchUtils.java @@ -621,7 +621,7 @@ public class LaunchUtils } String v0 = getJarImplementationVersion(f0); String v1 = getJarImplementationVersion(f1); - syserr(true, false, + syserr(v0 != null && !v0.equals(v1), false, "Got launcher versions '" + v0 + "' and '" + v1 + "'"); return compareGetdownLauncherJarVersions(v0, v1); } diff --git a/src/jalview/util/UserAgent.java b/src/jalview/util/UserAgent.java index b488b00..f943e2e 100644 --- a/src/jalview/util/UserAgent.java +++ b/src/jalview/util/UserAgent.java @@ -1,3 +1,23 @@ +/* + * 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 jalview.bin.Cache; diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 94a1424..2d34db5 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -757,7 +757,7 @@ public abstract class AlignmentViewport protected AlignmentAnnotation quality; protected AlignmentAnnotation[] groupConsensus; - + protected AlignmentAnnotation[] groupSSConsensus; protected AlignmentAnnotation[] groupConservation; @@ -768,8 +768,6 @@ public abstract class AlignmentViewport protected ProfilesI hconsensus = null; protected Map hSSConsensusProfileMap = null; - - /** * results of cDNA complement consensus visible portion of view @@ -833,13 +831,13 @@ public abstract class AlignmentViewport { this.hconsensus = hconsensus; } - + @Override public void setSequenceSSConsensusHash(Map hSSConsensusProfileMap) { this.hSSConsensusProfileMap = hSSConsensusProfileMap; } - + @Override public void setComplementConsensusHash( Hashtable[] hconsensus) @@ -898,13 +896,11 @@ public abstract class AlignmentViewport return consensus; } - @Override public List getAlignmentSecondaryStructureConsensusAnnotation() { return secondaryStructureConsensus; } - @Override public AlignmentAnnotation getAlignmentGapAnnotation() @@ -997,9 +993,6 @@ public abstract class AlignmentViewport } } } - - - /** * trigger update of Secondary Structure consensus annotation @@ -1043,7 +1036,8 @@ public abstract class AlignmentViewport if (calculator .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class) == null) { - calculator.registerWorker(new SecondaryStructureConsensusThread(this, ap)); + calculator.registerWorker( + new SecondaryStructureConsensusThread(this, ap)); } ap.adjustAnnotationHeight(); @@ -1162,7 +1156,7 @@ public abstract class AlignmentViewport * should consensus profile be rendered by default */ protected boolean showSequenceLogo = false; - + /** * should consensus profile be rendered normalised to row height */ @@ -1172,7 +1166,7 @@ public abstract class AlignmentViewport * should consensus histograms be rendered by default */ protected boolean showConsensusHistogram = true; - + /** * @return the showConsensusProfile */ @@ -1181,7 +1175,7 @@ public abstract class AlignmentViewport { return showSequenceLogo; } - + /** * @param showSequenceLogo * the new value @@ -1203,7 +1197,7 @@ public abstract class AlignmentViewport } this.showSequenceLogo = showSequenceLogo; } - + /** * @param showConsensusHistogram * the showConsensusHistogram to set @@ -1501,7 +1495,7 @@ public abstract class AlignmentViewport protected boolean showQuality = true; - protected boolean showConsensus = true; + protected boolean showConsensus = true; protected boolean showSSConsensus = true; @@ -2169,7 +2163,6 @@ public abstract class AlignmentViewport } } - /** * If this is a protein alignment and there are mappings to cDNA, adds the * cDNA consensus annotation and returns true, else returns false. diff --git a/src/jalview/viewmodel/PaSiMapModel.java b/src/jalview/viewmodel/PaSiMapModel.java index a0e5174..8568af4 100644 --- a/src/jalview/viewmodel/PaSiMapModel.java +++ b/src/jalview/viewmodel/PaSiMapModel.java @@ -69,8 +69,8 @@ public class PaSiMapModel * @param modelName * @param params */ - public PaSiMapModel(AlignmentViewport seqData, SequenceI[] sqs, boolean nuc, - ScoreModelI modelName) + public PaSiMapModel(AlignmentViewport seqData, SequenceI[] sqs, + boolean nuc, ScoreModelI modelName) { inputData = seqData; seqs = sqs; @@ -79,8 +79,8 @@ public class PaSiMapModel } /** - * Performs the PaSiMap calculation (in the same thread) and extracts result data - * needed for visualisation by PaSiMapPanel + * Performs the PaSiMap calculation (in the same thread) and extracts result + * data needed for visualisation by PaSiMapPanel */ public void calculate(PairwiseAlignPanel pap) { @@ -100,7 +100,8 @@ public class PaSiMapModel top = width; points = new Vector<>(); - Point[] scores = pasimap.getComponents(width - 1, width - 2, width - 3, 1); + Point[] scores = pasimap.getComponents(width - 1, width - 2, width - 3, + 1); for (int i = 0; i < height; i++) { @@ -142,8 +143,9 @@ public class PaSiMapModel /** * Updates the 3D coordinates for the list of points to the given dimensions. * Principal dimension is getTop(). Next greatest eigenvector is getTop()-1. - * Note - pasimap.getComponents starts counting the spectrum from rank-2 to zero, - * rather than rank-1, so getComponents(dimN ...) == updateRcView(dimN+1 ..) + * Note - pasimap.getComponents starts counting the spectrum from rank-2 to + * zero, rather than rank-1, so getComponents(dimN ...) == updateRcView(dimN+1 + * ..) * * @param dim1 * @param dim2 @@ -207,13 +209,15 @@ public class PaSiMapModel csv.append("\"" + seqs[s].getName() + "\""); if (!transformed) { - double[] fl = pasimap.component(s); - for (int d = fl.length - 1; d >= 0; d--) - { - csv.append(","); - csv.append(fl[d]); - } - } else { + double[] fl = pasimap.component(s); + for (int d = fl.length - 1; d >= 0; d--) + { + csv.append(","); + csv.append(fl[d]); + } + } + else + { Point p = points.get(s).coord; csv.append(",").append(p.x); csv.append(",").append(p.y); diff --git a/src/jalview/workers/SecondaryStructureConsensusThread.java b/src/jalview/workers/SecondaryStructureConsensusThread.java index 6629f27..259d96b 100644 --- a/src/jalview/workers/SecondaryStructureConsensusThread.java +++ b/src/jalview/workers/SecondaryStructureConsensusThread.java @@ -186,7 +186,8 @@ public class SecondaryStructureConsensusThread extends AlignCalcWorker */ protected List getSSConsensusAnnotation() { - return alignViewport.getAlignmentSecondaryStructureConsensusAnnotation(); + return alignViewport + .getAlignmentSecondaryStructureConsensusAnnotation(); } /** diff --git a/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java b/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java index c299a4d..1ead049 100644 --- a/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java +++ b/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java @@ -1,3 +1,23 @@ +/* + * 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.ws.datamodel.alphafold; import java.awt.Color; diff --git a/src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java b/src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java index 397a84b..017a20f 100644 --- a/src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java +++ b/src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java @@ -1,3 +1,23 @@ +/* + * 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.ws.datamodel.alphafold; import java.io.File; diff --git a/test/jalview/analysis/AlignSeqTest.java b/test/jalview/analysis/AlignSeqTest.java index 03bdd0b..1f94601 100644 --- a/test/jalview/analysis/AlignSeqTest.java +++ b/test/jalview/analysis/AlignSeqTest.java @@ -76,16 +76,18 @@ public class AlignSeqTest String s = "aArRnNzZxX *.-?"; assertArrayEquals(expected, as.indexEncode(s)); } - @Test(groups= {"Functional"}) + + @Test(groups = { "Functional" }) public void testGlobalAlignment() { - String seq1="CAGCTAGCG",seq2="CCATACGA"; - Sequence sq1=new Sequence("s1",seq1),sq2=new Sequence("s2",seq2); + String seq1 = "CAGCTAGCG", seq2 = "CCATACGA"; + Sequence sq1 = new Sequence("s1", seq1), sq2 = new Sequence("s2", seq2); // AlignSeq doesn't report the unaligned regions at either end of sequences - //String alseq1="-CAGCTAGCG-",alseq2="CCA--TA-CGA"; + // String alseq1="-CAGCTAGCG-",alseq2="CCA--TA-CGA"; // so we check we have the aligned segment correct only - String alseq1="CAGCTAGCG",alseq2="CA--TA-CG"; - AlignSeq as = AlignSeq.doGlobalNWAlignment(sq1,sq2,AlignSeq.DNA); - assertEquals(as.getAStr1()+"\n"+as.getAStr2(),alseq1+"\n"+alseq2); + String alseq1 = "CAGCTAGCG", alseq2 = "CA--TA-CG"; + AlignSeq as = AlignSeq.doGlobalNWAlignment(sq1, sq2, AlignSeq.DNA); + assertEquals(as.getAStr1() + "\n" + as.getAStr2(), + alseq1 + "\n" + alseq2); } } diff --git a/test/jalview/analysis/AlignmentUtilsTests.java b/test/jalview/analysis/AlignmentUtilsTests.java index 1cf9a80..863356e 100644 --- a/test/jalview/analysis/AlignmentUtilsTests.java +++ b/test/jalview/analysis/AlignmentUtilsTests.java @@ -83,25 +83,29 @@ public class AlignmentUtilsTests { JvOptionPane.setInteractiveMode(false); JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); - - AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure", "Secondary Structure", - new Annotation[] {}); - AlignmentAnnotation ann2 = new AlignmentAnnotation("jnetpred", "jnetpred", + + AlignmentAnnotation ann1 = new AlignmentAnnotation( + "Secondary Structure", "Secondary Structure", new Annotation[] {}); + AlignmentAnnotation ann2 = new AlignmentAnnotation("jnetpred", + "jnetpred", new Annotation[] {}); AlignmentAnnotation ann3 = new AlignmentAnnotation("Temp", "Temp", new Annotation[] {}); AlignmentAnnotation ann4 = new AlignmentAnnotation("Temp", "Temp", new Annotation[] {}); - - AlignmentAnnotation[] anns1 = new AlignmentAnnotation[] {ann1, ann3, ann4}; - AlignmentAnnotation[] anns2 = new AlignmentAnnotation[] {ann2, ann3, ann4}; - - AlignmentAnnotation[] anns3 = new AlignmentAnnotation[] {ann3, ann4}; - + AlignmentAnnotation[] anns1 = new AlignmentAnnotation[] { ann1, ann3, + ann4 }; + + AlignmentAnnotation[] anns2 = new AlignmentAnnotation[] { ann2, ann3, + ann4 }; + + AlignmentAnnotation[] anns3 = new AlignmentAnnotation[] { ann3, ann4 }; + AlignmentAnnotation[] anns4 = new AlignmentAnnotation[0]; - - AlignmentAnnotation[] anns5 = new AlignmentAnnotation[] {ann1, ann2, ann3, ann4}; + + AlignmentAnnotation[] anns5 = new AlignmentAnnotation[] { ann1, ann2, + ann3, ann4 }; } @Test(groups = { "Functional" }) @@ -2781,133 +2785,180 @@ public class AlignmentUtilsTests Assert.assertEquals(expectedSSPresent, AlignmentUtils.isSecondaryStructurePresent(annotations)); } - @DataProvider(name = "SecondaryStructureAnnotations") - public static Object[][] provideSecondaryStructureAnnotations() { - AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure", "Secondary Structure", new Annotation[]{}); - AlignmentAnnotation ann2 = new AlignmentAnnotation("jnetpred", "jnetpred", new Annotation[]{}); - AlignmentAnnotation ann3 = new AlignmentAnnotation("Temp", "Temp", new Annotation[]{}); - AlignmentAnnotation ann4 = new AlignmentAnnotation("Temp", "Temp", new Annotation[]{}); - - List ssSources1 = new ArrayList<>(Arrays.asList("3D Structures")); - List ssSources2 = new ArrayList<>(Arrays.asList("JPred")); - List ssSources3 = new ArrayList<>(Arrays.asList("3D Structures", "JPred")); - List ssSources4 = new ArrayList<>(); - - return new Object[][]{ - {new AlignmentAnnotation[]{ann1, ann3, ann4}, true, ssSources1}, - {new AlignmentAnnotation[]{ann2, ann3, ann4}, true, ssSources2}, - {new AlignmentAnnotation[]{ann3, ann4}, false, ssSources4}, - {new AlignmentAnnotation[]{}, false, ssSources4}, - {new AlignmentAnnotation[]{ann1, ann2, ann3, ann4}, true, ssSources3} - }; - } - - @Test(dataProvider = "SecondaryStructureAnnotationColours") - public void testSecondaryStructureAnnotationColour(char symbol, Color expectedColor) { - Color actualColor = AlignmentUtils.getSecondaryStructureAnnotationColour(symbol); - Assert.assertEquals(actualColor, expectedColor); - } + @Test( + groups = "Functional", + dataProvider = "SecondaryStructureAnnotations") + public void testSecondaryStructurePresentAndSources( + AlignmentAnnotation[] annotations, boolean expectedSSPresent, + ArrayList expectedSSSources) + { + Assert.assertEquals(expectedSSPresent, + AlignmentUtils.isSecondaryStructurePresent(annotations)); + Assert.assertEquals(expectedSSSources, + AlignmentUtils.getSecondaryStructureSources(annotations)); + } - @DataProvider(name = "SecondaryStructureAnnotationColours") - public static Object[][] provideSecondaryStructureAnnotationColours() { - return new Object[][]{ - {'C', Color.gray}, - {'E', Color.green}, - {'H', Color.red}, - {'-', Color.gray} - }; - } - - @Test(dataProvider = "SSAnnotationPresence") - public void testIsSSAnnotationPresent(Map> annotations, boolean expectedPresence) { - boolean actualPresence = AlignmentUtils.isSSAnnotationPresent(annotations); - Assert.assertEquals(actualPresence, expectedPresence); - } + @DataProvider(name = "SecondaryStructureAnnotations") + public static Object[][] provideSecondaryStructureAnnotations() + { + AlignmentAnnotation ann1 = new AlignmentAnnotation( + "Secondary Structure", "Secondary Structure", + new Annotation[] {}); + AlignmentAnnotation ann2 = new AlignmentAnnotation("jnetpred", + "jnetpred", new Annotation[] {}); + AlignmentAnnotation ann3 = new AlignmentAnnotation("Temp", "Temp", + new Annotation[] {}); + AlignmentAnnotation ann4 = new AlignmentAnnotation("Temp", "Temp", + new Annotation[] {}); - @DataProvider(name = "SSAnnotationPresence") - public static Object[][] provideSSAnnotationPresence() { - Map> annotations1 = new HashMap<>(); - SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45); - List annotationsList1 = new ArrayList<>(); - annotationsList1.add(new AlignmentAnnotation("Secondary Structure", "Secondary Structure", new Annotation[]{})); - annotations1.put(seq1, annotationsList1); // Annotation present secondary structure for seq1 - - Map> annotations2 = new HashMap<>(); - SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42); - List annotationsList2 = new ArrayList<>(); - annotationsList2.add(new AlignmentAnnotation("Other Annotation", "Other Annotation", new Annotation[]{})); - annotations2.put(seq2, annotationsList2); // Annotation not related to any of secondary structure for seq2 - - Map> annotations3 = new HashMap<>(); - // Empty annotation map - - Map> annotations4 = new HashMap<>(); - SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44); - List annotationsList4 = new ArrayList<>(); - annotationsList4.add(new AlignmentAnnotation("jnetpred", "jnetpred", new Annotation[]{})); - annotations4.put(seq4, annotationsList4); // Annotation present from JPred for seq4 - - - return new Object[][]{ - {annotations1, true}, // Annotations present secondary structure present - {annotations2, false}, // No annotations related to any of the secondary structure present - {annotations3, false}, // Empty annotation map - {annotations4, true}, // Annotations present from JPred secondary structure present - }; - } - - @Test - public void testGetSSSourceFromAnnotationDescription(AlignmentAnnotation[] annotations, String expectedSSSource) { - List actualSSSource = AlignmentUtils.extractSSSourceInAlignmentAnnotation(annotations); - Assert.assertEquals(actualSSSource, expectedSSSource); - } - - @DataProvider(name = "SSSourceFromAnnotationDescription") - public static Object[][] provideSSSourceFromAnnotationDescription() { - Map> annotations1 = new HashMap<>(); - SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45); - List annotationsList1 = new ArrayList<>(); - annotationsList1.add(new AlignmentAnnotation("jnetpred", "JPred Output", new Annotation[]{})); - annotations1.put(seq1, annotationsList1); // Annotation present from JPred for seq1 - - Map> annotations2 = new HashMap<>(); - SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42); - List annotationsList2 = new ArrayList<>(); - annotationsList2.add(new AlignmentAnnotation("Secondary Structure", - "Secondary Structure for af-q43517-f1A", new Annotation[]{})); - annotations2.put(seq2, annotationsList2); // Annotation present secondary structure from Alphafold for seq2 - - Map> annotations3 = new HashMap<>(); - // Empty annotation map - - Map> annotations4 = new HashMap<>(); - SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44); - List annotationsList4 = new ArrayList<>(); - annotationsList4.add(new AlignmentAnnotation("Secondary Structure", - "Secondary Structure for 4zhpA", new Annotation[]{})); - annotations4.put(seq4, annotationsList4); // Annotation present secondary structure from pdb for seq4 - - Map> annotations5 = new HashMap<>(); - SequenceI seq5 = new Sequence("Seq5", "ASD---ASD---AS-", 37, 44); - List annotationsList5 = new ArrayList<>(); - annotationsList5.add(new AlignmentAnnotation("Secondary Structure", - "Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P", - new Annotation[]{})); - annotations5.put(seq5, annotationsList5); // Annotation present secondary structure from Swiss model for seq5 - - - //JPred Output - JPred - //Secondary Structure for af-q43517-f1A - Alphafold - //Secondary Structure for 4zhpA - Experimental - //Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P - Swiss Model - - return new Object[][]{ - {annotations1, "JPred"}, - {annotations2, "Alphafold"}, - {annotations3, null}, - {annotations4, "PDB"}, - {annotations5, "Swiss Model"} - }; - } + List ssSources1 = new ArrayList<>( + Arrays.asList("3D Structures")); + List ssSources2 = new ArrayList<>(Arrays.asList("JPred")); + List ssSources3 = new ArrayList<>( + Arrays.asList("3D Structures", "JPred")); + List ssSources4 = new ArrayList<>(); + + return new Object[][] { + { new AlignmentAnnotation[] + { ann1, ann3, ann4 }, true, ssSources1 }, + { new AlignmentAnnotation[] + { ann2, ann3, ann4 }, true, ssSources2 }, + { new AlignmentAnnotation[] + { ann3, ann4 }, false, ssSources4 }, + { new AlignmentAnnotation[] {}, false, ssSources4 }, + { new AlignmentAnnotation[] + { ann1, ann2, ann3, ann4 }, true, ssSources3 } }; + } + + @Test(dataProvider = "SecondaryStructureAnnotationColours") + public void testSecondaryStructureAnnotationColour(char symbol, + Color expectedColor) + { + Color actualColor = AlignmentUtils + .getSecondaryStructureAnnotationColour(symbol); + Assert.assertEquals(actualColor, expectedColor); + } + + @DataProvider(name = "SecondaryStructureAnnotationColours") + public static Object[][] provideSecondaryStructureAnnotationColours() + { + return new Object[][] { { 'C', Color.gray }, { 'E', Color.green }, + { 'H', Color.red }, + { '-', Color.gray } }; + } + + @Test(dataProvider = "SSAnnotationPresence") + public void testIsSSAnnotationPresent( + Map> annotations, + boolean expectedPresence) + { + boolean actualPresence = AlignmentUtils + .isSSAnnotationPresent(annotations); + Assert.assertEquals(actualPresence, expectedPresence); + } + + @DataProvider(name = "SSAnnotationPresence") + public static Object[][] provideSSAnnotationPresence() + { + Map> annotations1 = new HashMap<>(); + SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45); + List annotationsList1 = new ArrayList<>(); + annotationsList1.add(new AlignmentAnnotation("Secondary Structure", + "Secondary Structure", new Annotation[] {})); + annotations1.put(seq1, annotationsList1); // Annotation present secondary + // structure for seq1 + + Map> annotations2 = new HashMap<>(); + SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42); + List annotationsList2 = new ArrayList<>(); + annotationsList2.add(new AlignmentAnnotation("Other Annotation", + "Other Annotation", new Annotation[] {})); + annotations2.put(seq2, annotationsList2); // Annotation not related to any + // of secondary structure for seq2 + + Map> annotations3 = new HashMap<>(); + // Empty annotation map + + Map> annotations4 = new HashMap<>(); + SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44); + List annotationsList4 = new ArrayList<>(); + annotationsList4.add(new AlignmentAnnotation("jnetpred", "jnetpred", + new Annotation[] {})); + annotations4.put(seq4, annotationsList4); // Annotation present from JPred + // for seq4 + + return new Object[][] { { annotations1, true }, // Annotations present + // secondary structure + // present + { annotations2, false }, // No annotations related to any of the + // secondary structure present + { annotations3, false }, // Empty annotation map + { annotations4, true }, // Annotations present from JPred secondary + // structure present + }; + } + + @Test + public void testGetSSSourceFromAnnotationDescription( + AlignmentAnnotation[] annotations, String expectedSSSource) + { + List actualSSSource = AlignmentUtils + .extractSSSourceInAlignmentAnnotation(annotations); + Assert.assertEquals(actualSSSource, expectedSSSource); + } + + @DataProvider(name = "SSSourceFromAnnotationDescription") + public static Object[][] provideSSSourceFromAnnotationDescription() + { + Map> annotations1 = new HashMap<>(); + SequenceI seq1 = new Sequence("Seq1", "ASD---ASD---ASD", 37, 45); + List annotationsList1 = new ArrayList<>(); + annotationsList1.add(new AlignmentAnnotation("jnetpred", "JPred Output", + new Annotation[] {})); + annotations1.put(seq1, annotationsList1); // Annotation present from JPred + // for seq1 + + Map> annotations2 = new HashMap<>(); + SequenceI seq2 = new Sequence("Seq2", "ASD---ASD------", 37, 42); + List annotationsList2 = new ArrayList<>(); + annotationsList2.add(new AlignmentAnnotation("Secondary Structure", + "Secondary Structure for af-q43517-f1A", new Annotation[] {})); + annotations2.put(seq2, annotationsList2); // Annotation present secondary + // structure from Alphafold for + // seq2 + + Map> annotations3 = new HashMap<>(); + // Empty annotation map + + Map> annotations4 = new HashMap<>(); + SequenceI seq4 = new Sequence("Seq4", "ASD---ASD---AS-", 37, 44); + List annotationsList4 = new ArrayList<>(); + annotationsList4.add(new AlignmentAnnotation("Secondary Structure", + "Secondary Structure for 4zhpA", new Annotation[] {})); + annotations4.put(seq4, annotationsList4); // Annotation present secondary + // structure from pdb for seq4 + + Map> annotations5 = new HashMap<>(); + SequenceI seq5 = new Sequence("Seq5", "ASD---ASD---AS-", 37, 44); + List annotationsList5 = new ArrayList<>(); + annotationsList5.add(new AlignmentAnnotation("Secondary Structure", + "Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P", + new Annotation[] {})); + annotations5.put(seq5, annotationsList5); // Annotation present secondary + // structure from Swiss model for + // seq5 + + // JPred Output - JPred + // Secondary Structure for af-q43517-f1A - Alphafold + // Secondary Structure for 4zhpA - Experimental + // Secondary Structure for p09911_54-147__3a7wzn.1.p3502557454997462030P - + // Swiss Model + + return new Object[][] { { annotations1, "JPred" }, + { annotations2, "Alphafold" }, + { annotations3, null }, + { annotations4, "PDB" }, + { annotations5, "Swiss Model" } }; + } } diff --git a/test/jalview/analysis/scoremodels/ScoreModelsTest.java b/test/jalview/analysis/scoremodels/ScoreModelsTest.java index d0a8047..f82a18a 100644 --- a/test/jalview/analysis/scoremodels/ScoreModelsTest.java +++ b/test/jalview/analysis/scoremodels/ScoreModelsTest.java @@ -83,7 +83,7 @@ public class ScoreModelsTest assertFalse(sm instanceof PairwiseScoreModelI); assertTrue(sm instanceof DistanceScoreModel); assertEquals(sm.getName(), "Sequence Feature Similarity"); - + sm = models.next(); assertFalse(sm instanceof SimilarityScoreModel); assertFalse(sm instanceof PairwiseScoreModelI); diff --git a/test/jalview/analysis/scoremodels/SecondaryStructureDistanceModelTest.java b/test/jalview/analysis/scoremodels/SecondaryStructureDistanceModelTest.java index f32be37..03dcdc7 100644 --- a/test/jalview/analysis/scoremodels/SecondaryStructureDistanceModelTest.java +++ b/test/jalview/analysis/scoremodels/SecondaryStructureDistanceModelTest.java @@ -48,7 +48,7 @@ import org.testng.annotations.Test; // This class tests methods in Class SecondaryStructureDistanceModel public class SecondaryStructureDistanceModelTest { - + /** * Verify computed distances of sequences with gap */ @@ -62,7 +62,7 @@ public class SecondaryStructureDistanceModelTest ScoreModelI sm = new SecondaryStructureDistanceModel(); sm = ScoreModels.getInstance().getScoreModel(sm.getName(), af.alignPanel); - + /* * feature distance model always normalises by region width * gap-gap is always included (but scores zero) @@ -73,27 +73,28 @@ public class SecondaryStructureDistanceModelTest * include gaps * score = 0 + 0 + 1 + 0 = 1/4 */ - SimilarityParamsI params = new SimilarityParams(false, true, true, true); + SimilarityParamsI params = new SimilarityParams(false, true, true, + true); params.setSecondaryStructureSource("3D Structures"); MatrixI distances = sm.findDistances(view, params); assertEquals(distances.getValue(0, 0), 1d); assertEquals(distances.getValue(1, 1), 1d); - assertEquals(distances.getValue(0, 1), 0d); + assertEquals(distances.getValue(0, 1), 0d); assertEquals(distances.getValue(1, 0), 0d); - + /* * exclude gaps * score = 0 + 0 + 0 + 0 = 0/4 */ - - SimilarityParamsI params2 = new SimilarityParams(false, true, false, true); + + SimilarityParamsI params2 = new SimilarityParams(false, true, false, + true); params2.setSecondaryStructureSource("3D Structures"); MatrixI distances2 = sm.findDistances(view, params2); - assertEquals(distances2.getValue(0, 1), 0d); + assertEquals(distances2.getValue(0, 1), 0d); assertEquals(distances2.getValue(1, 0), 0d); } - - + /** * Verify computed distances of sequences with gap */ @@ -107,7 +108,7 @@ public class SecondaryStructureDistanceModelTest ScoreModelI sm = new SecondaryStructureDistanceModel(); sm = ScoreModels.getInstance().getScoreModel(sm.getName(), af.alignPanel); - + /* * feature distance model always normalises by region width * gap-gap is always included (but scores zero) @@ -118,27 +119,28 @@ public class SecondaryStructureDistanceModelTest * include gaps * score = 0 + 0 + 2 + 2 = 2/4 */ - SimilarityParamsI params = new SimilarityParams(false, true, true, true); + SimilarityParamsI params = new SimilarityParams(false, true, true, + true); params.setSecondaryStructureSource("3D Structures"); MatrixI distances = sm.findDistances(view, params); assertEquals(distances.getValue(0, 0), 1d); assertEquals(distances.getValue(1, 1), 1d); - assertEquals(distances.getValue(0, 1), 0d); + assertEquals(distances.getValue(0, 1), 0d); assertEquals(distances.getValue(1, 0), 0d); - + /* * exclude gaps * score = 0 + 0 + 2 + 2 = 2/4 */ - - SimilarityParamsI params2 = new SimilarityParams(false, true, false, true); + + SimilarityParamsI params2 = new SimilarityParams(false, true, false, + true); params2.setSecondaryStructureSource("3D Structures"); MatrixI distances2 = sm.findDistances(view, params2); - assertEquals(distances2.getValue(0, 1), 0d); + assertEquals(distances2.getValue(0, 1), 0d); assertEquals(distances2.getValue(1, 0), 0d); } - /** * Verify computed distances of sequences with gap */ @@ -152,7 +154,7 @@ public class SecondaryStructureDistanceModelTest ScoreModelI sm = new SecondaryStructureDistanceModel(); sm = ScoreModels.getInstance().getScoreModel(sm.getName(), af.alignPanel); - + /* * feature distance model always normalises by region width * gap-gap is always included (but scores zero) @@ -163,28 +165,28 @@ public class SecondaryStructureDistanceModelTest * include gaps * score = 0 + 0 + 2 + 2 = 2/4 */ - SimilarityParamsI params = new SimilarityParams(false, true, true, true); + SimilarityParamsI params = new SimilarityParams(false, true, true, + true); params.setSecondaryStructureSource("3D Structures"); MatrixI distances = sm.findDistances(view, params); assertEquals(distances.getValue(0, 0), 1d); assertEquals(distances.getValue(1, 1), 1d); - assertEquals(distances.getValue(0, 1), 0d); + assertEquals(distances.getValue(0, 1), 0d); assertEquals(distances.getValue(1, 0), 0d); - + /* * exclude gaps * score = 0 + 0 + 2 + 2 = 2/4 */ - - SimilarityParamsI params2 = new SimilarityParams(false, true, false, true); + + SimilarityParamsI params2 = new SimilarityParams(false, true, false, + true); params2.setSecondaryStructureSource("3D Structures"); MatrixI distances2 = sm.findDistances(view, params2); - assertEquals(distances2.getValue(0, 1), 0d); + assertEquals(distances2.getValue(0, 1), 0d); assertEquals(distances2.getValue(1, 0), 0d); } - - /** *
        * Set up
    @@ -214,18 +216,17 @@ public class SecondaryStructureDistanceModelTest
                 new SequenceFeature("metal", null, 1, 4, 0f, null));
         s2.addSequenceFeature(
                 new SequenceFeature("Pfam", null, 1, 4, 0f, null));
    -    
    -    
    +
         /*
          * Set up secondary structure annotations
          */
    -    Annotation ssE = new Annotation("","",'E',0);
    -    Annotation ssH = new Annotation("","",'H',0);
    -    Annotation ssC = new Annotation(".","",' ',0);
    -    
    +    Annotation ssE = new Annotation("", "", 'E', 0);
    +    Annotation ssH = new Annotation("", "", 'H', 0);
    +    Annotation ssC = new Annotation(".", "", ' ', 0);
    +
         Annotation[] anns1;
         Annotation[] anns2;
    -    
    +
         /* All secondary structure annotations are similar for each column
          * Set up
         *   column      1 2 3 4 
    @@ -235,13 +236,14 @@ public class SecondaryStructureDistanceModelTest
         *        seq s2 F S J L
         *        	 ss E H S E
         */
    -    if(similar == "All Similar") {
    -    
    -    	anns1 = new Annotation[] { ssE, ssH, ssC, ssE};
    -    	anns2 = new Annotation[] { ssE, ssH, ssC, ssE};
    -    
    +    if (similar == "All Similar")
    +    {
    +
    +      anns1 = new Annotation[] { ssE, ssH, ssC, ssE };
    +      anns2 = new Annotation[] { ssE, ssH, ssC, ssE };
    +
         }
    -    
    +
         /* All secondary structure annotations are dissimilar for each column
          * Set up
          *   column      1 2 3 4 
    @@ -251,13 +253,14 @@ public class SecondaryStructureDistanceModelTest
          *        seq s2 F S J L
          *        	  ss H E E C
          */
    -    else if(similar == "Not Similar") {
    -        
    -    	anns1 = new Annotation[] { ssE, ssE, ssC, ssE};
    -    	anns2 = new Annotation[] { ssH, ssH, ssE, ssC};
    -    
    +    else if (similar == "Not Similar")
    +    {
    +
    +      anns1 = new Annotation[] { ssE, ssE, ssC, ssE };
    +      anns2 = new Annotation[] { ssH, ssH, ssE, ssC };
    +
         }
    -    
    +
         /* All secondary structure annotations are dissimilar for each column
          * Set up
          *   column      1 2 3 4 
    @@ -267,13 +270,14 @@ public class SecondaryStructureDistanceModelTest
          *        seq s2 F S J L
          *            ss H E E C
          */
    -    else if(similar == "With Coil") {
    -        
    -      anns1 = new Annotation[] { ssE, ssE, null, ssE};
    -      anns2 = new Annotation[] { ssH, ssH, ssE, null};
    -    
    +    else if (similar == "With Coil")
    +    {
    +
    +      anns1 = new Annotation[] { ssE, ssE, null, ssE };
    +      anns2 = new Annotation[] { ssH, ssH, ssE, null };
    +
         }
    -    
    +
         /*  Set up
          *   column      1 2 3 4 
          *        seq s1 F R K S
    @@ -282,28 +286,27 @@ public class SecondaryStructureDistanceModelTest
          *        seq s2 F S J L
          *        	  ss H E E C
          */
    -    else {
    -    	
    -    	anns1 = new Annotation[] { ssH, ssE, ssC, ssE};
    -    	anns2 = new Annotation[] { ssH, ssE, ssE, ssC};
    +    else
    +    {
    +
    +      anns1 = new Annotation[] { ssH, ssE, ssC, ssE };
    +      anns2 = new Annotation[] { ssH, ssE, ssE, ssC };
         }
    -    
    -    
    -    AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure",
    -            "Secondary Structure", anns1);
    -    AlignmentAnnotation ann2 = new AlignmentAnnotation("Secondary Structure",
    -            "Secondary Structure", anns2);
    -    
    +
    +    AlignmentAnnotation ann1 = new AlignmentAnnotation(
    +            "Secondary Structure", "Secondary Structure", anns1);
    +    AlignmentAnnotation ann2 = new AlignmentAnnotation(
    +            "Secondary Structure", "Secondary Structure", anns2);
    +
         s1.addAlignmentAnnotation(ann1);
    -    s2.addAlignmentAnnotation(ann2);    
    -    
    +    s2.addAlignmentAnnotation(ann2);
    +
         AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
         AlignFrame af = new AlignFrame(al, 300, 300);
         af.setShowSeqFeatures(true);
         af.getFeatureRenderer().findAllFeatures(true);
         return af;
       }
    -  
     
       /**
        * 
    @@ -320,7 +323,7 @@ public class SecondaryStructureDistanceModelTest
        */
       protected AlignFrame setupAlignmentViewWithGap()
       {
    -    
    +
         SequenceI s1 = new Sequence("s1", "FR S");
         SequenceI s2 = new Sequence("s2", "FSJL");
     
    @@ -334,39 +337,39 @@ public class SecondaryStructureDistanceModelTest
                 new SequenceFeature("metal", null, 1, 4, 0f, null));
         s2.addSequenceFeature(
                 new SequenceFeature("Pfam", null, 1, 4, 0f, null));
    -    
    -    
    -    Annotation ssE = new Annotation("","",'E',0);
    -    Annotation ssH = new Annotation("","",'H',0);
    -    Annotation ssC = new Annotation(".","",' ',0);
    -    
    +
    +    Annotation ssE = new Annotation("", "", 'E', 0);
    +    Annotation ssH = new Annotation("", "", 'H', 0);
    +    Annotation ssC = new Annotation(".", "", ' ', 0);
    +
         Annotation[] anns1;
         Annotation[] anns2;
    -    	
    -    anns1 = new Annotation[] { ssH, ssE, ssC};
    -    anns2 = new Annotation[] { ssH, ssE, ssE, ssC};    
    -    
    -    AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure",
    -            "Secondary Structure", anns1);
    -    AlignmentAnnotation ann2 = new AlignmentAnnotation("Secondary Structure",
    -            "Secondary Structure", anns2);
    -    
    +
    +    anns1 = new Annotation[] { ssH, ssE, ssC };
    +    anns2 = new Annotation[] { ssH, ssE, ssE, ssC };
    +
    +    AlignmentAnnotation ann1 = new AlignmentAnnotation(
    +            "Secondary Structure", "Secondary Structure", anns1);
    +    AlignmentAnnotation ann2 = new AlignmentAnnotation(
    +            "Secondary Structure", "Secondary Structure", anns2);
    +
         s1.addAlignmentAnnotation(ann1);
    -    s2.addAlignmentAnnotation(ann2);    
    -        
    +    s2.addAlignmentAnnotation(ann2);
    +
         AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
         AlignFrame af = new AlignFrame(al, 300, 300);
         af.setShowSeqFeatures(true);
         af.getFeatureRenderer().findAllFeatures(true);
    -    
    +
         return af;
       }
    -  
    -  protected AlignFrame setupAlignmentViewWithoutSS(String type) {
    -    
    +
    +  protected AlignFrame setupAlignmentViewWithoutSS(String type)
    +  {
    +
         SequenceI s1 = new Sequence("s1", "FR S");
         SequenceI s2 = new Sequence("s2", "FSJL");
    -    
    +
         s1.addSequenceFeature(
                 new SequenceFeature("chain", null, 1, 3, 0f, null));
         s1.addSequenceFeature(
    @@ -377,60 +380,61 @@ public class SecondaryStructureDistanceModelTest
                 new SequenceFeature("metal", null, 1, 4, 0f, null));
         s2.addSequenceFeature(
                 new SequenceFeature("Pfam", null, 1, 4, 0f, null));
    -    
    -    if(!type.equals("both")) {    
    -      Annotation ssE = new Annotation("","",'E',0);
    -      Annotation ssH = new Annotation("","",'H',0);
    -      Annotation ssC = new Annotation(".","",' ',0);
    -      
    +
    +    if (!type.equals("both"))
    +    {
    +      Annotation ssE = new Annotation("", "", 'E', 0);
    +      Annotation ssH = new Annotation("", "", 'H', 0);
    +      Annotation ssC = new Annotation(".", "", ' ', 0);
    +
           Annotation[] anns1;
    -        
    -      anns1 = new Annotation[] { ssH, ssE, ssC};
    -          
    -      AlignmentAnnotation ann1 = new AlignmentAnnotation("Secondary Structure",
    -              "Secondary Structure", anns1);    
    -  
    -      s1.addAlignmentAnnotation(ann1);    
    +
    +      anns1 = new Annotation[] { ssH, ssE, ssC };
    +
    +      AlignmentAnnotation ann1 = new AlignmentAnnotation(
    +              "Secondary Structure", "Secondary Structure", anns1);
    +
    +      s1.addAlignmentAnnotation(ann1);
         }
    -    
    +
         AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
         AlignFrame af = new AlignFrame(al, 300, 300);
         af.setShowSeqFeatures(true);
         af.getFeatureRenderer().findAllFeatures(true);
         return af;
       }
    -  
    -  
    +
       @DataProvider(name = "testData")
    -  public Object[][] testData() {
    -      return new Object[][] {
    -              {"All Similar", 1d, 1d, 0d, 0d / 4},
    -              {"Partially Similar", 1d, 1d, 0d, 0d},
    -              {"Not Similar", 1d, 1d, 0d, 0d},
    -              {"With Coil", 1d, 1d, 0d, 0d},
    -      };
    +  public Object[][] testData()
    +  {
    +    return new Object[][] { { "All Similar", 1d, 1d, 0d, 0d / 4 },
    +        { "Partially Similar", 1d, 1d, 0d, 0d },
    +        { "Not Similar", 1d, 1d, 0d, 0d },
    +        { "With Coil", 1d, 1d, 0d, 0d }, };
       }
     
       @Test(dataProvider = "testData")
    -  public void testFindDistances(String scenario, double expectedValue00, double expectedValue11,
    -                                 double expectedValue01, double expectedValue10) {
    -      AlignFrame af = setupAlignmentView(scenario);
    -      AlignViewport viewport = af.getViewport();
    -      AlignmentView view = viewport.getAlignmentView(false);
    -
    -      ScoreModelI sm = new SecondaryStructureDistanceModel();
    -      sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
    -              af.alignPanel);
    -
    -      SimilarityParamsI params = new SimilarityParams(false, true, true, true);
    -      params.setSecondaryStructureSource("3D Structures");
    -      MatrixI distances = sm.findDistances(view, params);
    -
    -      assertEquals(distances.getValue(0, 0), expectedValue00);
    -      assertEquals(distances.getValue(1, 1), expectedValue11);
    -      assertEquals(distances.getValue(0, 1), expectedValue01);
    -      assertEquals(distances.getValue(1, 0), expectedValue10);
    +  public void testFindDistances(String scenario, double expectedValue00,
    +          double expectedValue11, double expectedValue01,
    +          double expectedValue10)
    +  {
    +    AlignFrame af = setupAlignmentView(scenario);
    +    AlignViewport viewport = af.getViewport();
    +    AlignmentView view = viewport.getAlignmentView(false);
    +
    +    ScoreModelI sm = new SecondaryStructureDistanceModel();
    +    sm = ScoreModels.getInstance().getScoreModel(sm.getName(),
    +            af.alignPanel);
    +
    +    SimilarityParamsI params = new SimilarityParams(false, true, true,
    +            true);
    +    params.setSecondaryStructureSource("3D Structures");
    +    MatrixI distances = sm.findDistances(view, params);
    +
    +    assertEquals(distances.getValue(0, 0), expectedValue00);
    +    assertEquals(distances.getValue(1, 1), expectedValue11);
    +    assertEquals(distances.getValue(0, 1), expectedValue01);
    +    assertEquals(distances.getValue(1, 0), expectedValue10);
       }
     
    -  
     }
    diff --git a/test/jalview/commands/EditCommandTest.java b/test/jalview/commands/EditCommandTest.java
    index 1255c58..2e36111 100644
    --- a/test/jalview/commands/EditCommandTest.java
    +++ b/test/jalview/commands/EditCommandTest.java
    @@ -1182,12 +1182,14 @@ public class EditCommandTest
         assertEquals(10, sf.getBegin());
         assertEquals(11, sf.getEnd());
       }
    +
       private SequenceI mkDs(SequenceI as)
       {
         SequenceI ds = as.createDatasetSequence();
         ds.setSequence(ds.getSequenceAsString().toUpperCase(Locale.ROOT));
         return ds;
       }
    +
       /**
        * Test that mimics 'remove all gapped columns' action. This generates a
        * series Delete Gap edits that each act on all sequences that share a gapped
    @@ -1210,35 +1212,38 @@ public class EditCommandTest
          * and check we are preserving data - if the calls below fail, something has broken the Jalview dataset derivation process
          */
         assertEquals("ABCDEF", seq1.getDatasetSequence().getSequenceAsString());
    -    assertEquals(original1,seq1.getSequenceAsString());
    -    SequenceI seq2 = new Sequence("sq2",original2);
    +    assertEquals(original1, seq1.getSequenceAsString());
    +    SequenceI seq2 = new Sequence("sq2", original2);
         SequenceI ds2 = mkDs(seq2);
         SequenceI seq3 = new Sequence("sq3", original3);
         SequenceI ds3 = mkDs(seq3);
    -    List sqs = Arrays.asList( seq1, seq2, seq3 );
    +    List sqs = Arrays.asList(seq1, seq2, seq3);
         Alignment al = new Alignment(sqs.toArray(new SequenceI[0]));
    -    EditCommand lefj = new JustifyLeftOrRightCommand("Left J", true, sqs, 1, 7, al);
    +    EditCommand lefj = new JustifyLeftOrRightCommand("Left J", true, sqs, 1,
    +            7, al);
         String exp = "-ABcD---EF";
         // check without case conservation
    -    assertEquals(exp.toUpperCase(Locale.ROOT),seq1.getSequenceAsString().toUpperCase(Locale.ROOT));
    +    assertEquals(exp.toUpperCase(Locale.ROOT),
    +            seq1.getSequenceAsString().toUpperCase(Locale.ROOT));
         // check case
    -    assertEquals(exp,seq1.getSequenceAsString());
    +    assertEquals(exp, seq1.getSequenceAsString());
         // and other seqs
    -    assertEquals("-GHiJ---",seq2.getSequenceAsString());
    -    assertEquals("-MNoP---Q",seq3.getSequenceAsString());
    -    lefj.undoCommand(new AlignmentI[] { al});
    -    assertEquals(original3,seq3.getSequenceAsString());
    -    assertEquals(original1,seq1.getSequenceAsString());
    -    assertEquals(original2,seq2.getSequenceAsString());
    -    
    -    EditCommand righj = new JustifyLeftOrRightCommand("Right J", false, sqs, 2, 7, al);
    -    assertEquals("----ABcDEF",seq1.getSequenceAsString());
    -    assertEquals("-G---HiJ",seq2.getSequenceAsString());
    -    assertEquals("-M---NoPQ",seq3.getSequenceAsString());
    -    righj.undoCommand(new AlignmentI[] { al});
    -    assertEquals(original3,seq3.getSequenceAsString());
    -    assertEquals(original1,seq1.getSequenceAsString());
    -    assertEquals(original2,seq2.getSequenceAsString());
    -        
    +    assertEquals("-GHiJ---", seq2.getSequenceAsString());
    +    assertEquals("-MNoP---Q", seq3.getSequenceAsString());
    +    lefj.undoCommand(new AlignmentI[] { al });
    +    assertEquals(original3, seq3.getSequenceAsString());
    +    assertEquals(original1, seq1.getSequenceAsString());
    +    assertEquals(original2, seq2.getSequenceAsString());
    +
    +    EditCommand righj = new JustifyLeftOrRightCommand("Right J", false, sqs,
    +            2, 7, al);
    +    assertEquals("----ABcDEF", seq1.getSequenceAsString());
    +    assertEquals("-G---HiJ", seq2.getSequenceAsString());
    +    assertEquals("-M---NoPQ", seq3.getSequenceAsString());
    +    righj.undoCommand(new AlignmentI[] { al });
    +    assertEquals(original3, seq3.getSequenceAsString());
    +    assertEquals(original1, seq1.getSequenceAsString());
    +    assertEquals(original2, seq2.getSequenceAsString());
    +
       }
     }
    diff --git a/test/jalview/ext/ensembl/EnsemblGeneTest.java b/test/jalview/ext/ensembl/EnsemblGeneTest.java
    index 4a6036f..4923c8f 100644
    --- a/test/jalview/ext/ensembl/EnsemblGeneTest.java
    +++ b/test/jalview/ext/ensembl/EnsemblGeneTest.java
    @@ -326,7 +326,10 @@ public class EnsemblGeneTest
         assertTrue(geneIds.contains("ENSRNOG00000010957")); // rat
         assertTrue(geneIds.contains("ENSXETG00000004845")); // xenopus
         assertTrue(geneIds.contains("ENSDARG00000017661")); // zebrafish
    -    assertTrue(geneIds.contains("ENSGALG00000012865")); // chicken
    +    // was ENSGALG00000012865 - which is still the canonical uniprot BRAF cross
    +    // reference via GRCg6a
    +    assertTrue(geneIds.contains("ENSGALG00010013466")); // chicken BRAF
    +                                                        // bGalGal1.mat.broiler.GRCg7b
         assertEquals(8, geneIds.size());
     
       }
    diff --git a/test/jalview/gui/AssociatePDBFileTest.java b/test/jalview/gui/AssociatePDBFileTest.java
    index 0e6791b..c1b5b6e 100644
    --- a/test/jalview/gui/AssociatePDBFileTest.java
    +++ b/test/jalview/gui/AssociatePDBFileTest.java
    @@ -20,7 +20,6 @@
      */
     package jalview.gui;
     
    -
     import java.awt.Color;
     import java.io.File;
     import java.util.Iterator;
    @@ -92,18 +91,14 @@ public class AssociatePDBFileTest
                 + "KVRLYSIASSAIGDFGDSKTVSLCVKRLIYTNDAGEIVKGVCSNFLCDLQPGDNVQITGPVGKEMLMPKDPN\n"
                 + "ATIIMLATGTGIAPFRSFLWKMFFEKHDDYKFNGLGWLFLGVPTSSSLLYKEEFGKMKERAPENFRVDYAVS\n"
                 + "REQTNAAGERMYIQTRMAEYKEELWELLKKDNTYVYMCGLKGMEKGIDDIMVSLAEKDGIDWFDYKKQLKRG\n"
    -            + "DQWNVEVY\n"
    -            + ">1GAQ|B/1-98\n"
    +            + "DQWNVEVY\n" + ">1GAQ|B/1-98\n"
                 + "ATYNVKLITPEGEVELQVPDDVYILDQAEEDGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSYLDDGQIADG\n"
    -            + "WVLTCHAYPTSDVVIETHKEEELTGA\n"
    -            + ">1GAQ|C/19-314\n"
    +            + "WVLTCHAYPTSDVVIETHKEEELTGA\n" + ">1GAQ|C/19-314\n"
                 + "ESKKQEEGVVTNLYKPKEPYVGRCLLNTKITGDDAPGETWHMVFSTEGKIPYREGQSIGVIADGVDKNGKPH\n"
                 + "KVRLYSIASSAIGDFGDSKTVSLCVKRLIYTNDAGEIVKGVCSNFLCDLQPGDNVQITGPVGKEMLMPKDPN\n"
                 + "ATIIMLATGTGIAPFRSFLWKMFFEKHDDYKFNGLGWLFLGVPTSSSLLYKEEFGKMKERAPENFRVDYAVS\n"
                 + "REQTNAAGERMYIQTRMAEYKEELWELLKKDNTYVYMCGLKGMEKGIDDIMVSLAEKDGIDWFDYKKQLKRG\n"
    -            + "DQWNVEVY\n"
    -            ,
    -            DataSourceType.PASTE);
    +            + "DQWNVEVY\n", DataSourceType.PASTE);
     
         /*
          * wait for Consensus thread to complete
    @@ -128,15 +123,15 @@ public class AssociatePDBFileTest
       @Test(groups = "Functional")
       public void testAssociatePDBFile()
       {
    -    String assoc_file="examples/1gaq.txt";
    -    for (SequenceI toassoc:af.getViewport().getAlignment().getSequences())
    +    String assoc_file = "examples/1gaq.txt";
    +    for (SequenceI toassoc : af.getViewport().getAlignment().getSequences())
         {
    -      PDBEntry pe = new AssociatePdbFileWithSeq()
    -              .associatePdbWithSeq(assoc_file,
    -                      DataSourceType.FILE, toassoc, false,
    -                      Desktop.instance);
    +      PDBEntry pe = new AssociatePdbFileWithSeq().associatePdbWithSeq(
    +              assoc_file, DataSourceType.FILE, toassoc, false,
    +              Desktop.instance);
           Assert.assertNotNull(pe);
    -      Assert.assertNotEquals(toassoc.getDatasetSequence().getAnnotation().length,0);
    +      Assert.assertNotEquals(
    +              toassoc.getDatasetSequence().getAnnotation().length, 0);
         }
       }
     }
    diff --git a/test/jalview/gui/CalculationChooserTest.java b/test/jalview/gui/CalculationChooserTest.java
    index ac02c03..e6316f3 100644
    --- a/test/jalview/gui/CalculationChooserTest.java
    +++ b/test/jalview/gui/CalculationChooserTest.java
    @@ -55,29 +55,33 @@ public class CalculationChooserTest
          * peptide models for PCA
          */
         List filtered = CalculationChooser
    -            .getApplicableScoreModels(false, true, true,false);
    +            .getApplicableScoreModels(false, true, true, false);
         assertEquals(filtered.size(), 5);
         assertSame(filtered.get(0), blosum62);
         assertSame(filtered.get(1), pam250);
         assertEquals(filtered.get(2).getName(), "PID");
         assertEquals(filtered.get(3).getName(), "Sequence Feature Similarity");
    -    assertEquals(filtered.get(4).getName(), "Secondary Structure Similarity");
    +    assertEquals(filtered.get(4).getName(),
    +            "Secondary Structure Similarity");
     
         /*
          * peptide models for Tree are the same
          */
    -    filtered = CalculationChooser.getApplicableScoreModels(false, false, true,false);
    +    filtered = CalculationChooser.getApplicableScoreModels(false, false,
    +            true, false);
         assertEquals(filtered.size(), 5);
         assertSame(filtered.get(0), blosum62);
         assertSame(filtered.get(1), pam250);
         assertEquals(filtered.get(2).getName(), "PID");
         assertEquals(filtered.get(3).getName(), "Sequence Feature Similarity");
    -    assertEquals(filtered.get(4).getName(), "Secondary Structure Similarity");
    +    assertEquals(filtered.get(4).getName(),
    +            "Secondary Structure Similarity");
     
         /*
          * nucleotide models for PCA
          */
    -    filtered = CalculationChooser.getApplicableScoreModels(true, true, false,false);
    +    filtered = CalculationChooser.getApplicableScoreModels(true, true,
    +            false, false);
         assertEquals(filtered.size(), 3);
         assertSame(filtered.get(0), dna);
         assertEquals(filtered.get(1).getName(), "PID");
    @@ -86,7 +90,8 @@ public class CalculationChooserTest
         /*
          * nucleotide models for Tree are the same
          */
    -    filtered = CalculationChooser.getApplicableScoreModels(true, false, false,false);
    +    filtered = CalculationChooser.getApplicableScoreModels(true, false,
    +            false, false);
         assertEquals(filtered.size(), 3);
         assertSame(filtered.get(0), dna);
         assertEquals(filtered.get(1).getName(), "PID");
    @@ -101,30 +106,37 @@ public class CalculationChooserTest
         /*
          * nucleotide models for Tree are unchanged
          */
    -    filtered = CalculationChooser.getApplicableScoreModels(true, false, true,false);
    +    filtered = CalculationChooser.getApplicableScoreModels(true, false,
    +            true, false);
         assertEquals(filtered.size(), 4);
         assertSame(filtered.get(0), dna);
         assertEquals(filtered.get(1).getName(), "PID");
         assertEquals(filtered.get(2).getName(), "Sequence Feature Similarity");
    -    assertEquals(filtered.get(3).getName(), "Secondary Structure Similarity");
    +    assertEquals(filtered.get(3).getName(),
    +            "Secondary Structure Similarity");
     
         /*
          * nucleotide models for PCA add BLOSUM62 as last option
          */
    -    filtered = CalculationChooser.getApplicableScoreModels(true, true, false,false);
    +    filtered = CalculationChooser.getApplicableScoreModels(true, true,
    +            false, false);
         assertEquals(filtered.size(), 4);
         assertSame(filtered.get(0), dna);
         assertEquals(filtered.get(1).getName(), "PID");
         assertEquals(filtered.get(2).getName(), "Sequence Feature Similarity");
         assertSame(filtered.get(3), blosum62);
    -    
    -    filtered = CalculationChooser.getApplicableScoreModels(true, true, false,true);
    +
    +    filtered = CalculationChooser.getApplicableScoreModels(true, true,
    +            false, true);
         assertEquals(filtered.size(), 1); // DNA matrix for DNA pasimap
    -    for (int i=0; i<=8;i++)
    +    for (int i = 0; i <= 8; i++)
         {
    -      boolean isDna = (i & 1) != 0,isPca = (i & 2) != 0,isSS = (i & 4) != 0;
    -     
    -      assertEquals(CalculationChooser.getApplicableScoreModels(isDna,isPca,isSS,true).size(), (isDna) ? 1: 2);
    +      boolean isDna = (i & 1) != 0, isPca = (i & 2) != 0,
    +              isSS = (i & 4) != 0;
    +
    +      assertEquals(CalculationChooser
    +              .getApplicableScoreModels(isDna, isPca, isSS, true).size(),
    +              (isDna) ? 1 : 2);
         }
       }
     }
    diff --git a/test/jalview/project/Jalview2xmlTests.java b/test/jalview/project/Jalview2xmlTests.java
    index 8b2fa74..ca90d8a 100644
    --- a/test/jalview/project/Jalview2xmlTests.java
    +++ b/test/jalview/project/Jalview2xmlTests.java
    @@ -250,9 +250,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     
         boolean diffseqcols = false, diffgseqcols = false;
         SequenceI[] sqs = af.getViewport().getAlignment().getSequencesArray();
    -    for (int p = 0,
    -            pSize = af.getViewport().getAlignment().getWidth(); p < pSize
    -                    && (!diffseqcols || !diffgseqcols); p++)
    +    for (int p = 0, pSize = af.getViewport().getAlignment()
    +            .getWidth(); p < pSize && (!diffseqcols || !diffgseqcols); p++)
         {
           if (_rcs.findColour(sqs[0].getCharAt(p), p, sqs[0], null, 0f) != _rcs
                   .findColour(sqs[5].getCharAt(p), p, sqs[5], null, 0f))
    @@ -271,9 +270,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
         assertTrue(__rcs.isSeqAssociated(),
                 "Group Annotation colourscheme wasn't sequence associated");
     
    -    for (int p = 0,
    -            pSize = af.getViewport().getAlignment().getWidth(); p < pSize
    -                    && (!diffseqcols || !diffgseqcols); p++)
    +    for (int p = 0, pSize = af.getViewport().getAlignment()
    +            .getWidth(); p < pSize && (!diffseqcols || !diffgseqcols); p++)
         {
           if (_rgcs.findColour(sqs[1].getCharAt(p), p, sqs[1], null,
                   0f) != _rgcs.findColour(sqs[2].getCharAt(p), p, sqs[2], null,
    diff --git a/test/jalview/renderer/ResidueShaderTest.java b/test/jalview/renderer/ResidueShaderTest.java
    index 9ff93e1..a198d3c 100644
    --- a/test/jalview/renderer/ResidueShaderTest.java
    +++ b/test/jalview/renderer/ResidueShaderTest.java
    @@ -345,7 +345,7 @@ public class ResidueShaderTest
                       SecondaryStructureCount secondaryStructureCount)
               {
                 // TODO Auto-generated method stub
    -            
    +
               }
     
               @Override
    diff --git a/test/jalview/schemes/ClustalxColourSchemeTest.java b/test/jalview/schemes/ClustalxColourSchemeTest.java
    index d476d6e..983f94c 100644
    --- a/test/jalview/schemes/ClustalxColourSchemeTest.java
    +++ b/test/jalview/schemes/ClustalxColourSchemeTest.java
    @@ -151,6 +151,7 @@ public class ClustalxColourSchemeTest
         // viewport
         // assertEquals(cs.findColour('C', 0, al.getSequenceAt(0)), clustalPink);
       }
    +
       @Test
       public void testDocString()
       {
    diff --git a/test/jalview/util/FileUtilsTest.java b/test/jalview/util/FileUtilsTest.java
    index 3cc9ca6..62dc73e 100644
    --- a/test/jalview/util/FileUtilsTest.java
    +++ b/test/jalview/util/FileUtilsTest.java
    @@ -77,6 +77,11 @@ public class FileUtilsTest
                   + d + "' contains '" + notInDirname + "' when it shouldn't");
       }
     
    +  /**
    +   * these need to be maintained as jalview's source base grows
    +   * 
    +   * @return
    +   */
       @DataProvider(name = "patternsAndMinNumFiles")
       public Object[][] patternsAndMinNumFiles()
       {
    @@ -90,7 +95,7 @@ public class FileUtilsTest
             { "test/jalview/**/F*.java", 18, 30 }, // 20 at time of writing
             { "test/jalview/util/F**.java", 1, 5 }, // 2 at time of writing
             { "src/jalview/b*/*.java", 14, 19 }, // 15 at time of writing
    -        { "src/jalview/b**/*.java", 20, 25 }, // 22 at time of writing
    +        { "src/jalview/b**/*.java", 23, 26 }, // 22 at time of writing
         };
       }
     
    diff --git a/utils/channels/default/channel_gradle.properties b/utils/channels/default/channel_gradle.properties
    index cfb5ab0..04acbc3 100644
    --- a/utils/channels/default/channel_gradle.properties
    +++ b/utils/channels/default/channel_gradle.properties
    @@ -36,3 +36,4 @@ install4j_background_image_text_suffix_cmd = font-size 30 text 194,218 '%s'
     install4j_background_image_text_commit_cmd = text 18,170 '%s'
     install4j_background_image_text_date_cmd = text 18,190 '%s'
     
    +install4j_title_icon = jalview_logo-64.png
    diff --git a/utils/channels/default/images/jalview_logo-64.png b/utils/channels/default/images/jalview_logo-64.png
    new file mode 100644
    index 0000000..c5b5a3c
    Binary files /dev/null and b/utils/channels/default/images/jalview_logo-64.png differ
    diff --git a/utils/channels/default/images/jalview_logo-64@2x.png b/utils/channels/default/images/jalview_logo-64@2x.png
    new file mode 100644
    index 0000000..34748ed
    Binary files /dev/null and b/utils/channels/default/images/jalview_logo-64@2x.png differ
    diff --git a/utils/channels/develop-SUFFIX/channel_gradle.properties b/utils/channels/develop-SUFFIX/channel_gradle.properties
    index b39dc99..671a339 100644
    --- a/utils/channels/develop-SUFFIX/channel_gradle.properties
    +++ b/utils/channels/develop-SUFFIX/channel_gradle.properties
    @@ -48,3 +48,4 @@ install4j_background_image_text_suffix_cmd = font-size 30 text 194,218 '%s'
     install4j_background_image_text_commit_cmd = text 18,250 '%s'
     install4j_background_image_text_date_cmd = text 18,270 '%s'
     
    +install4j_title_icon = jalview_develop_logo-64.png
    diff --git a/utils/channels/develop-SUFFIX/images/jalview_develop_logo-64.png b/utils/channels/develop-SUFFIX/images/jalview_develop_logo-64.png
    new file mode 100644
    index 0000000..54d7f89
    Binary files /dev/null and b/utils/channels/develop-SUFFIX/images/jalview_develop_logo-64.png differ
    diff --git a/utils/channels/develop-SUFFIX/images/jalview_develop_logo-64@2x.png b/utils/channels/develop-SUFFIX/images/jalview_develop_logo-64@2x.png
    new file mode 100644
    index 0000000..e7e3928
    Binary files /dev/null and b/utils/channels/develop-SUFFIX/images/jalview_develop_logo-64@2x.png differ
    diff --git a/utils/channels/develop/channel_gradle.properties b/utils/channels/develop/channel_gradle.properties
    index 2c152d0..cd356ab 100644
    --- a/utils/channels/develop/channel_gradle.properties
    +++ b/utils/channels/develop/channel_gradle.properties
    @@ -48,3 +48,4 @@ install4j_background_image_text_suffix_cmd = font-size 30 text 194,218 '%s'
     install4j_background_image_text_commit_cmd = text 18,250 '%s'
     install4j_background_image_text_date_cmd = text 18,270 '%s'
     
    +install4j_title_icon = jalview_develop_logo-64.png
    diff --git a/utils/channels/develop/images/jalview_develop_logo-64.png b/utils/channels/develop/images/jalview_develop_logo-64.png
    new file mode 100644
    index 0000000..54d7f89
    Binary files /dev/null and b/utils/channels/develop/images/jalview_develop_logo-64.png differ
    diff --git a/utils/channels/develop/images/jalview_develop_logo-64@2x.png b/utils/channels/develop/images/jalview_develop_logo-64@2x.png
    new file mode 100644
    index 0000000..e7e3928
    Binary files /dev/null and b/utils/channels/develop/images/jalview_develop_logo-64@2x.png differ
    diff --git a/utils/channels/jalviewjs/channel_gradle.properties b/utils/channels/jalviewjs/channel_gradle.properties
    index 6f3991b..4367f3f 100644
    --- a/utils/channels/jalviewjs/channel_gradle.properties
    +++ b/utils/channels/jalviewjs/channel_gradle.properties
    @@ -32,3 +32,5 @@ install4j_background_image_text_suffix_cmd = font-size 30 text 194,218 '%s'
     install4j_background_image_text_commit_cmd = text 18,170 '%s'
     install4j_background_image_text_date_cmd = text 18,190 '%s'
     
    +install4j_title_icon = jalview_logo-64.png
    +install4j_title_icon = jalview_logo-64.png
    diff --git a/utils/channels/jalviewjs/images/jalview_logo-64.png b/utils/channels/jalviewjs/images/jalview_logo-64.png
    new file mode 100644
    index 0000000..57c7a9e
    Binary files /dev/null and b/utils/channels/jalviewjs/images/jalview_logo-64.png differ
    diff --git a/utils/channels/jalviewjs/images/jalview_logo-64@2x.png b/utils/channels/jalviewjs/images/jalview_logo-64@2x.png
    new file mode 100644
    index 0000000..869701d
    Binary files /dev/null and b/utils/channels/jalviewjs/images/jalview_logo-64@2x.png differ
    diff --git a/utils/channels/release/channel_gradle.properties b/utils/channels/release/channel_gradle.properties
    index 27fc1a4..904edf1 100644
    --- a/utils/channels/release/channel_gradle.properties
    +++ b/utils/channels/release/channel_gradle.properties
    @@ -37,3 +37,4 @@ install4j_background_image_text_suffix_cmd = font-size 30 text 194,218 '%s'
     install4j_background_image_text_commit_cmd = text 18,250 '%s'
     install4j_background_image_text_date_cmd = text 18,270 '%s'
     
    +install4j_title_icon = jalview_logo-64.png
    diff --git a/utils/channels/release/images/jalview_logo-64.png b/utils/channels/release/images/jalview_logo-64.png
    new file mode 100644
    index 0000000..23a9ce2
    Binary files /dev/null and b/utils/channels/release/images/jalview_logo-64.png differ
    diff --git a/utils/channels/release/images/jalview_logo-64@2x.png b/utils/channels/release/images/jalview_logo-64@2x.png
    new file mode 100644
    index 0000000..42727e0
    Binary files /dev/null and b/utils/channels/release/images/jalview_logo-64@2x.png differ
    diff --git a/utils/channels/test-release/channel_gradle.properties b/utils/channels/test-release/channel_gradle.properties
    index f0c8e2a..b774de5 100644
    --- a/utils/channels/test-release/channel_gradle.properties
    +++ b/utils/channels/test-release/channel_gradle.properties
    @@ -37,3 +37,4 @@ install4j_background_image_text_suffix_cmd = font-size 30 text 194,218 '%s'
     install4j_background_image_text_commit_cmd = text 18,250 '%s'
     install4j_background_image_text_date_cmd = text 18,270 '%s'
     
    +install4j_title_icon = jalview_test-release_logo-64.png
    diff --git a/utils/channels/test-release/images/jalview_test-release_logo-64.png b/utils/channels/test-release/images/jalview_test-release_logo-64.png
    new file mode 100644
    index 0000000..5f79cb9
    Binary files /dev/null and b/utils/channels/test-release/images/jalview_test-release_logo-64.png differ
    diff --git a/utils/channels/test-release/images/jalview_test-release_logo-64@2x.png b/utils/channels/test-release/images/jalview_test-release_logo-64@2x.png
    new file mode 100644
    index 0000000..8185b9b
    Binary files /dev/null and b/utils/channels/test-release/images/jalview_test-release_logo-64@2x.png differ
    diff --git a/utils/getdown/bin/jalview.ps1 b/utils/getdown/bin/jalview.ps1
    index 1098010..ade0089 100755
    --- a/utils/getdown/bin/jalview.ps1
    +++ b/utils/getdown/bin/jalview.ps1
    @@ -2,7 +2,6 @@
     
     # save args and first parameter
     $myArgs = $args.Clone()
    -$myArg1 = $args[0]
     
     # setup for powershell version < 6.0
     [bool] $myIsWindows = 0
    @@ -16,35 +15,67 @@ if ( $IsWindows -eq $null ) {
       $myIsMacOS = $IsMacOS
     }
     
    -# parent dir of this actual script (which should be the getdown appdir/bin). Follow all symlinks.  Like GNU readlink -f
    +[bool] $headless = 0
    +[bool] $gui = 0
    +[bool] $help = 0
    +[bool] $debug = 0
    +Switch -Regex ($args) {
    +  "--help|--help-|--version|-h" {
    +    $help = 1
    +    $headless = 1
    +    Continue
    +  }
    +  "--gui" {
    +    $gui = 1
    +    Continue
    +  }
    +  "--headless" {
    +    $headless = 1
    +    Continue
    +  }
    +  "--debug" {
    +    $debug = 1
    +    Continue
    +  }
    +}
    +if ( $help ) {
    +  # --help takes precedence
    +  $gui = 0
    +} elseif ( $gui ) {
    +  # --gui takes precedence over --headless
    +  $headless = 0
    +}
    +
    +# actual path of this script (which should be the getdown appdir/bin). Follow all symlinks.  Like GNU readlink -f
     function Readlink-f {
    -  Param($Link)
    -  $Return = $null
    -  $c = 0
    -  $max = 100 # just in case we end up in a loop
    -  [bool] $found = 0
    -  $file = Get-Item -Path $Link
    -  $prevfile = $null
    -  While ( $c -lt $max -and "${file}" -ne "${prevfile}" -and -not $found ) {
    -    $prevfile = $file
    -    [string] $target = ( $file ).Target
    -    If ( $target -eq $null -or ( $file ).LinkType -ne "SymbolicLink" ) {
    -      $Return = $file
    -      $found = 1
    -    } Else {
    -      If ( $( Split-Path -Path $target -IsAbsolute ) ) {
    -        $file = Get-Item -Path $target
    -      } Else {
    -# symbolic link is relative: combine previous link parent dir with the link target and resolve
    -        $file = Get-Item -Path ( Join-Path -Path ( Split-Path -Path $prevfile -Parent ) -ChildPath $target -Resolve )
    -      }
    +  Param(
    +    [Parameter(mandatory=$true, ValueFromPipeline=$true)]$Link,
    +    [Parameter()]$iteration_count = 1
    +  )
    +  if ( $iteration_count -ge 100 ) {
    +    Write-Error "Readlink-f iterated 100 times"
    +    return $Link
    +  }
    +  if ( $Link -eq "" -or $Link -eq $null ) {
    +    return $null
    +  }
    +  $path_components = @()
    +  $dir = Get-Item $Link
    +  while ( $dir -ne $null ) {
    +    while ( $dir.Target -ne $null ) {
    +      # [System.IO.Path]::Combine caters for a multitude of sins that it's almost impossible to deal with with Join-Path
    +      $dir = Get-Item ([System.IO.Path]::GetFullPath( [System.IO.Path]::Combine( (Split-Path $dir -Parent), $dir.Target )))
         }
    -    $c++
    +    $parent = Split-Path -Path $dir -Parent
    +    $path_components = @( (Split-Path -Path $dir -Leaf) ) + $path_components
    +    $dir = Readlink-f $parent ($iteration_count + 1)
       }
    -  if ( -not $found ) {
    -    throw "Could not determine path to actual file $( Split-Path -Path $Link -Leaf )"
    +  $real = Get-Item "/"
    +  foreach ( $component in $path_components) {
    +    # [System.IO.Path]::Combine caters for a multitude of sins that it's almost impossible to deal with with Join-Path
    +    $real = Get-Item ([System.IO.Path]::GetFullPath( [System.IO.Path]::Combine( $real, $component )))
       }
    -  $Return
    +  $real
     }
     
     # Avert problem with unix version of powershell and tell user the reason (Windows must always have .ps1 extension)
    @@ -52,14 +83,28 @@ if ( $MyInvocation.MyCommand.Path -eq $null ) {
       throw "Script or link to script must have extension .ps1"
     }
     
    +# args for the JVM
    +$JVMARGS = @()
     
     $CMDPATH = ( Get-Item $MyInvocation.MyCommand.Path )
     $SCRIPTPATH = Readlink-f -Link $CMDPATH
    +$SCRIPT = $SCRIPTPATH
     $DIR = Split-Path -Path $SCRIPTPATH -Parent
    -
     $APPDIR = If ( ( Split-Path -Path $DIR -Leaf ) -eq "bin" ) { Split-Path -Path $DIR -Parent } Else { $DIR }
     $JAVAEXE = If ( $myIsWindows ) { "java.exe" } Else { "java" }
     $JAVA = Join-Path -Path $APPDIR -ChildPath ( "jre/" + $( If ( $myIsMacOS ) { "Contents/Home/" } Else { "" } ) + "bin/${JAVAEXE}" )
    +
    +if ( $headless ) {
    +  # not setting java.awt.headless in java invocation of running jalview due to problem with Jmol
    +  if ( $help ) {
    +    $JVMARGS += "-Djava.awt.headless=true"
    +  }
    +  # this suppresses the Java icon appearing in the macOS Dock
    +  if ( $myIsMacOS ) {
    +    $JVMARGS += "-Dapple.awt.UIElement=true"
    +  }
    +}
    +
     $GETDOWNTXT = Join-Path -Path $APPDIR -ChildPath "getdown.txt"
     
     # look for getdown.txt -- needed to create classpath
    @@ -67,22 +112,39 @@ if ( -not ( Test-Path -Path "${GETDOWNTXT}" ) ) {
       throw "Cannot find ${GETDOWNTXT}"
     }
     
    +# launching Jalview with jalview.bin.Launcher instead of getdown-launcher.jar
    +$CLASS = "jalview.bin.Launcher"
    +
    +# get CLASSPATH from the code= entries in getdown.txt
    +$CLASSPATH = ( Select-String -Path "${GETDOWNTXT}" -AllMatches -Pattern "code\s*=\s*(.*)$" | foreach { Join-Path -Path $APPDIR -ChildPath $($_.Matches.Groups[1].Value ) } ) -join $( If ( $myIsWindows ) { ";" } Else { ":" } )
    +
    +# get console width
    +$COLUMNS = $Host.UI.RawUI.WindowSize.Width
    +$JVMARGS += "-DCONSOLEWIDTH=${COLUMNS}"
    +$JVMARGS += "-Dgetdownappdir=${APPDIR}"
    +$JVMARGS += "-Dinstaller.appdir=${APPDIR}"
    +$JVMARGS += "-Dlauncher.script=${SCRIPT}"
    +
     # look for bundled JRE. Might not be there if unix installer used in which case just invoke "java"
     if ( -not ( Test-Path -Path "${JAVA}" ) ) {
    -  Write-Host "Cannot find bundled ${JAVAEXE}. Using system ${JAVAEXE} and hoping for the best!"
    +  Write-Host "Cannot find bundled ${JAVA}. Using system ${JAVAEXE} and hoping for the best!"
       $JAVA = $JAVAEXE
     }
     
    -$CLASSPATH = ( Select-String -Path "${GETDOWNTXT}" -AllMatches -Pattern "code\s*=\s*(.*)$" | foreach { Join-Path -Path $APPDIR -ChildPath $($_.Matches.Groups[1].Value ) } ) -join $( If ( $myIsWindows ) { ";" } Else { ":" } )
    -
    -# get console width
    -$CONSOLEWIDTH = $Host.UI.RawUI.WindowSize.Width
    +# we should always have at least one JVMARGS so this is okay
    +$myJvmArgsString = '"' + $($JVMARGS -join '" "') + '"'
     
    -# quote the args and the command (in case of spaces) with escape chars (`) and precede with & to indicate command not string
    +# quote the args and the command (in case of spaces) with escape chars (`) and precede with & to indicate a command not string
     if ( $myArgs.count -eq 0 ) {
    -  Invoke-Expression -Command "& `"${JAVA}`" `"-DCONSOLEWIDTH=${CONSOLEWIDTH}`" `"-Dgetdownappdir=${APPDIR}`" -cp `"${CLASSPATH}`" jalview.bin.Launcher"
    +  $COMMAND = "& `"${JAVA}`" ${myJvmArgsString} -cp `"${CLASSPATH}`" $CLASS"
     } else {
       $myArgsString = '"' + $($myArgs -join '" "') + '"'
    -  Invoke-Expression -Command "& `"${JAVA}`" `"-DCONSOLEWIDTH=${CONSOLEWIDTH}`" `"-Dgetdownappdir=${APPDIR}`" -cp `"${CLASSPATH}`" jalview.bin.Launcher ${myArgsString}"
    +  $COMMAND = "& `"${JAVA}`" ${myJvmArgsString} -cp `"${CLASSPATH}`" $CLASS ${myArgsString}"
     }
     
    +if ( $debug -or $help ) {
    +  Write-Error -Message "Shell running: ${COMMAND}"
    +}
    +
    +Invoke-Expression -Command ${COMMAND}
    +
    diff --git a/utils/getdown/bin/jalview.sh b/utils/getdown/bin/jalview.sh
    index 90d1558..3880faf 100755
    --- a/utils/getdown/bin/jalview.sh
    +++ b/utils/getdown/bin/jalview.sh
    @@ -2,34 +2,6 @@
     
     declare -a ARGS=("${@}")
     
    -# this whole next part is because there's no readlink -f in Darwin
    -function readlinkf() {
    -  FINDFILE="$1"
    -  FILE="${FINDFILE}"
    -  PREVFILE=""
    -  C=0
    -  MAX=100 # just in case we end up in a loop
    -  FOUND=0
    -  while [ "${C}" -lt "${MAX}" -a "${FILE}" != "${PREVFILE}" -a "${FOUND}" -ne 1 ]; do
    -    PREVFILE="${FILE}"
    -    FILE="$(readlink "${FILE}")"
    -    if [ -z "${FILE}" ]; then
    -      # the readlink is empty means we've arrived at the script, let's canonicalize with pwd
    -      FILE="$(cd "$(dirname "${PREVFILE}")" &> /dev/null && pwd -P)"/"$(basename "${PREVFILE}")"
    -      FOUND=1
    -    elif [ "${FILE#/}" = "${FILE}" ]; then
    -      # FILE is not an absolute path link, we need to add the relative path to the previous dir
    -      FILE="$(dirname "${PREVFILE}")/${FILE}"
    -    fi
    -    C=$((C+1))
    -  done
    -  if [ "${FOUND}" -ne 1 ]; then
    -    echo "Could not determine path to actual file '$(basename "${FINDFILE}")'" >&2
    -    exit 1
    -  fi
    -  echo "${FILE}"
    -}
    -
     ISMACOS=0
     if [ "$( uname -s )" = "Darwin" ]; then
       ISMACOS=1
    @@ -48,6 +20,7 @@ for RAWARG in "${@}"; do
           ;;
         --help|--help-*|--version|-h)
           HELP=1
    +      HEADLESS=1
           ;;
         --gui)
           GUI=1
    @@ -56,33 +29,85 @@ for RAWARG in "${@}"; do
           DEBUG=1
           ;;
       esac
    -  
    -  if [ "${HELP}" = 1 ]; then
    -    # --help takes precedence
    -    HEADLESS=1
    -    GUI=0
    -  elif [ "${GUI}" = 1 ]; then
    -    # --gui takes precedence over --headless
    -    HEADLESS=0
    -  fi
     done
    +if [ "${HELP}" = 1 ]; then
    +  # --help takes precedence
    +  GUI=0
    +elif [ "${GUI}" = 1 ]; then
    +  # --gui takes precedence over --headless
    +  HEADLESS=0
    +fi
    +
    +# this whole next part is because there's no readlink -f in Darwin
    +function readlinkf() {
    +  FINDFILE="$1"
    +  FILE="${FINDFILE}"
    +  PREVFILE=""
    +  C=0
    +  MAX=100 # just in case we end up in a loop
    +  FOUND=0
    +  while [ "${C}" -lt "${MAX}" -a "${FILE}" != "${PREVFILE}" -a "${FOUND}" -ne 1 ]; do
    +    PREVFILE="${FILE}"
    +    FILE="$(readlink "${FILE}")"
    +    if [ -z "${FILE}" ]; then
    +      # the readlink is empty means we've arrived at the script, let's canonicalize with pwd
    +      FILE="$(cd "$(dirname "${PREVFILE}")" &> /dev/null && pwd -P)"/"$(basename "${PREVFILE}")"
    +      FOUND=1
    +    elif [ "${FILE#/}" = "${FILE}" ]; then
    +      # FILE is not an absolute path link, we need to add the relative path to the previous dir
    +      FILE="$(dirname "${PREVFILE}")/${FILE}"
    +    fi
    +    C=$((C+1))
    +  done
    +  if [ "${FOUND}" -ne 1 ]; then
    +    echo "Could not determine path to actual file '$(basename "${FINDFILE}")'" >&2
    +    exit 1
    +  fi
    +  echo "${FILE}"
    +}
     
    +# args for the JVM
     declare -a JVMARGS=()
     
    +JAVABIN=""
     # set vars for being inside the macos App Bundle
     if [ "${ISMACOS}" = 1 ]; then
     # MACOS ONLY
    -  DIR="$(dirname "$(readlinkf "$0")")"
    +  SCRIPT="$(readlinkf "$0")"
    +  DIR="$(dirname "${SCRIPT}")"
       APPDIR="${DIR%/bin}"
    -  JAVA="${APPDIR}/jre/Contents/Home/bin/java"
    -  JVMARGS=( "${JVMARGS[@]}" "-Xdock:icon=${APPDIR}/resource/jalview_logo.png" )
    +
    +  if [ -d "${APPDIR}/jre" ]; then
    +    JREDIR="${APPDIR}/jre"
    +  elif [ -e "${APPDIR}/installer.properties" ]; then
    +    INSTALLERAPPDIR="$( grep -E "^installer.appdir[[:space:]]*=[[:space:]]*" "${APPDIR}/installer.properties" | sed -E 's/^installer.appdir[[:space:]]*=[[:space:]]*//' )"
    +    if [ -d "${INSTALLERAPPDIR}/jre" ]; then
    +      JREDIR="${INSTALLERAPPDIR}/jre"
    +    fi
    +  fi
    +  if [ ! -z "$JREDIR" ]; then
    +    JAVABIN="${JREDIR}/Contents/Home/bin"
    +  fi
    +  if [ "${HEADLESS}" != 1 ]; then
    +    JVMARGS=( "${JVMARGS[@]}" "-Xdock:icon=${APPDIR}/resource/jalview_logo.png" )
    +  fi
     else
     # NOT MACOS
    -  DIR="$(dirname "$(readlink -f "$0")")"
    +  SCRIPT="$(readlink -f "$0")"
    +  DIR="$(dirname "${SCRIPT}")"
       APPDIR="${DIR%/bin}"
    -  JAVA="${APPDIR}/jre/bin/java"
    +  if [ -d "${APPDIR}/jre" ]; then
    +    JAVABIN="${APPDIR}/jre/bin"
    +  elif [ -e "${APPDIR}/installer.properties" ]; then
    +    INSTALLERAPPDIR="$( grep -E "^installer.appdir[[:space:]]*=[[:space:]]*" "${APPDIR}/installer.properties" | sed -E 's/^installer.appdir[[:space:]]*=[[:space:]]*//' )"
    +    if [ ! -z "$INSTALLERAPPDIR" -a -d "${INSTALLERAPPDIR}/jre" ]; then
    +      JAVABIN="${INSTALLERAPPDIR}/jre/bin"
    +    fi
    +  fi
     fi
    +JAVA="${JAVABIN}/java"
     
    +# headless java arguments
     if [ "${HEADLESS}" = 1 ]; then
       # not setting java.awt.headless in java invocation of running jalview due to problem with Jmol
       if [ "${HELP}" = 1 ]; then
    @@ -96,27 +121,50 @@ fi
     
     SYSJAVA=java
     GETDOWNTXT="${APPDIR}/getdown.txt"
    +CHANNELPROPS="${APPDIR}/channel.props"
    +NAME="$( grep app_name= "${CHANNELPROPS}" | cut -d= -f2 )"
     
     CLASSPATH=""
     # save an array of JAR paths in case we're in WSL (see later)
     declare -a JARPATHS=()
    -if [ -e "${GETDOWNTXT}" ]; then
    -  # always check grep and sed regexes on macos -- they're not the same
    -for JAR in $(grep -e '^code[[:space:]]*=[[:space:]]*' "${GETDOWNTXT}" | while read -r line; do echo $line | sed -E -e 's/code[[:space:]]*=[[:space:]]*//;'; done);
    -  do
    -    [ -n "${CLASSPATH}" ] && CLASSPATH="${CLASSPATH}:"
    -    CLASSPATH="${CLASSPATH}${APPDIR}/${JAR}"
    -    JARPATHS=( "${JARPATHS[@]}" "${APPDIR}/${JAR}" )
    -  done
    -else
    -  echo "Cannot find getdown.txt" >&2
    +
    +# look for getdown.txt -- needed to create classpath
    +if [ ! -e "${GETDOWNTXT}" ]; then
    +  echo "Cannot find ${GETDOWNTXT}" >&2
       exit 3
     fi
     
    -# WINDOWS ONLY (Cygwin or WSL)
    -# change paths for Cygwin or Windows Subsystem for Linux (WSL)
    +# launching Jalview with jalview.bin.Launcher instead of getdown-launcher.jar
    +CLASS="jalview.bin.Launcher"
    +
    +# get classpath from the code= entries in getdown.txt
    +# always check grep and sed regexes on macos -- they're not the same
    +for JAR in $(grep -e '^code[[:space:]]*=[[:space:]]*' "${GETDOWNTXT}" | while read -r line; do echo $line | sed -E -e 's/code[[:space:]]*=[[:space:]]*//;'; done);
    +do
    +  [ -n "${CLASSPATH}" ] && CLASSPATH="${CLASSPATH}:"
    +  CLASSPATH="${CLASSPATH}${APPDIR}/${JAR}"
    +  JARPATHS=( "${JARPATHS[@]}" "${APPDIR}/${JAR}" )
    +done
    +
    +COLUMNS=80
    +# get console width -- three ways to try, just in case (not needed for update)
    +if command -v tput 2>&1 >/dev/null; then
    +  COLUMNS=$(tput cols) 2>/dev/null
    +elif command -v stty 2>&1 >/dev/null; then
    +  COLUMNS=$(stty size | cut -d" " -f2) 2>/dev/null
    +elif command -v resize 2>&1 >/dev/null; then
    +  COLUMNS=$(resize -u | grep COLUMNS= | sed -e 's/.*=//;s/;//') 2>/dev/null
    +fi
    +JVMARGS=( "${JVMARGS[@]}" "-DCONSOLEWIDTH=${COLUMNS}" )
    +JVMARGS=( "${JVMARGS[@]}" "-Dgetdownappdir=${APPDIR}" )
    +JVMARGS=( "${JVMARGS[@]}" "-Dlauncher.script=${SCRIPT}" )
    +JVMARGS=( "${JVMARGS[@]}" "-Dinstaller.appdir=${APPDIR}" )
    +
    +JAVAEXT=""
    +# WINDOWS ONLY in Cygwin or Windows Subsystem for Linux (WSL)
    +# change paths for Cygwin or WSL
     if [ "${ISMACOS}" != 1 ]; then # older macos doesn't like uname -o, best to avoid
    -  if [ "$(uname -o)" = "Cygwin" ]; then
    +  if [ "$(uname -o)" = "Cygwin" ]; then # Cygwin
       # CYGWIN
         CLASSPATH=$(cygpath -pw "${CLASSPATH}")
         # now for some arg paths fun. only translating paths starting with './', '../', '/' or '~'
    @@ -128,7 +176,7 @@ if [ "${ISMACOS}" != 1 ]; then # older macos doesn't like uname -o, best to avoi
             ARGS=( "${ARGS[@]}" "${ARG}" )
           fi
         done
    -  elif uname -r | grep -i microsoft | grep -i wsl >/dev/null; then
    +  elif uname -r | grep -i microsoft | grep -i wsl >/dev/null; then # WSL
       # WSL
         CLASSPATH=""
         for JARPATH in "${JARPATHS[@]}"; do
    @@ -146,32 +194,27 @@ if [ "${ISMACOS}" != 1 ]; then # older macos doesn't like uname -o, best to avoi
             ARGS=( "${ARGS[@]}" "${ARG}" )
           fi
         done
    -    JAVA="${JAVA}.exe"
    -    SYSJAVA="java.exe"
    +    JAVAEXT=".exe"
    +    JAVA="${JAVA}${JAVAEXT}"
    +    SYSJAVA="java${JAVAEXT}"
       fi
     fi
     
    -# get console width -- three ways to try, just in case
    -if command -v tput 2>&1 >/dev/null; then
    -  COLUMNS=$(tput cols) 2>/dev/null
    -elif command -v stty 2>&1 >/dev/null; then
    -  COLUMNS=$(stty size | cut -d" " -f2) 2>/dev/null
    -elif command -v resize 2>&1 >/dev/null; then
    -  COLUMNS=$(resize -u | grep COLUMNS= | sed -e 's/.*=//;s/;//') 2>/dev/null
    +# look for bundled JRE. Might not be there if unix installer used in which case just invoke "java"
    +if [ ! -z "${JAVABIN}" -a -e "${JAVABIN}/${NAME}${JAVAEXT}" ]; then
    +  JAVA="${JAVABIN}/${NAME}${JAVAEXT}"
     fi
    -JVMARGS=( "${JVMARGS[@]}" "-DCONSOLEWIDTH=${COLUMNS}" )
    -JVMARGS=( "${JVMARGS[@]}" "-Dgetdownappdir=${APPDIR}" )
    -
    -# Is there a bundled Java?  If not just try one in the PATH (do need .exe in WSL)
    -if [ \! -e "${JAVA}" ]; then
    -  JAVA=$SYSJAVA
    -  echo "Cannot find bundled java, using system ${JAVA} and hoping for the best!" >&2
    +# If not just try one in the PATH (we need .exe in WSL, added above)
    +if [ -z "${JAVABIN}" -o ! -e "${JAVA}" ]; then
    +  JAVA="${SYSJAVA}"
    +  echo "Cannot find bundled ${JAVA}, using system ${SYSJAVA} and hoping for the best!" >&2
     fi
     
    +# This is just needed for display purposes
     function quotearray() {
       QUOTEDVALS=""
       for VAL in "${@}"; do
    -    if [ \! "$QUOTEDVALS" = "" ]; then
    +    if [ ! "$QUOTEDVALS" = "" ]; then
           QUOTEDVALS="${QUOTEDVALS} "
         fi
         QUOTEDVALS="${QUOTEDVALS}\"${VAL}\""
    @@ -179,11 +222,12 @@ function quotearray() {
       echo $QUOTEDVALS
     }
     
    +# for the debug command display
     JVMARGSSTR=$(quotearray "${JVMARGS[@]}")
     ARGSSTR=$(quotearray "${ARGS[@]}")
     
     if [ "${DEBUG}" = 1 ]; then
    - echo Shell running: \""${JAVA}"\" ${JVMARGSSTR} -cp \""${CLASSPATH}"\" jalview.bin.Launcher ${ARGSSTR}
    + echo Shell running: \""${JAVA}"\" ${JVMARGSSTR} -cp \""${CLASSPATH}"\" \""${CLASS}"\" ${ARGSSTR} >&2
     fi
     
    -"${JAVA}" "${JVMARGS[@]}" -cp "${CLASSPATH}" jalview.bin.Launcher "${ARGS[@]}"
    +"${JAVA}" "${JVMARGS[@]}" -cp "${CLASSPATH}" "${CLASS}" "${ARGS[@]}"
    diff --git a/utils/getdown/bin/run_other_script.ps1 b/utils/getdown/bin/run_other_script.ps1
    new file mode 100755
    index 0000000..1c00beb
    --- /dev/null
    +++ b/utils/getdown/bin/run_other_script.ps1
    @@ -0,0 +1,49 @@
    +#!/usr/bin/env pwsh
    +
    +$OTHERSCRIPT = "__OTHERSCRIPT__"
    +
    +# actual path of this script (which should be the getdown appdir/bin). Follow all symlinks.  Like GNU readlink -f
    +function Readlink-f {
    +  Param(
    +    [Parameter(mandatory=$true, ValueFromPipeline=$true)]$Link,
    +    [Parameter()]$iteration_count = 1
    +  )
    +  if ( $iteration_count -ge 100 ) {
    +    Write-Error "Readlink-f iterated 100 times"
    +    return $Link
    +  }
    +  if ( $Link -eq "" -or $Link -eq $null ) {
    +    return $null
    +  }
    +  $path_components = @()
    +  $dir = Get-Item $Link
    +  while ( $dir -ne $null ) {
    +    while ( $dir.Target -ne $null ) {
    +      # [System.IO.Path]::Combine caters for a multitude of sins that it's almost impossible to deal with with Join-Path
    +      $dir = Get-Item ([System.IO.Path]::GetFullPath( [System.IO.Path]::Combine( (Split-Path $dir -Parent), $dir.Target )))
    +    }
    +    $parent = Split-Path -Path $dir -Parent
    +    $path_components = @( (Split-Path -Path $dir -Leaf) ) + $path_components
    +    $dir = Readlink-f $parent ($iteration_count + 1)
    +  }
    +  $real = Get-Item "/"
    +  foreach ( $component in $path_components) {
    +    # [System.IO.Path]::Combine caters for a multitude of sins that it's almost impossible to deal with with Join-Path
    +    $real = Get-Item ([System.IO.Path]::GetFullPath( [System.IO.Path]::Combine( $real, $component )))
    +  }
    +  $real
    +}
    +
    +$CMDPATH = ( Get-Item $MyInvocation.MyCommand.Path )
    +$SCRIPTPATH = Readlink-f -Link $CMDPATH
    +$SCRIPTBIN = Split-Path -Path $SCRIPTPATH -Parent
    +$SCRIPT = Join-Path $SCRIPTBIN -ChildPath $OTHERSCRIPT
    +
    +if ( $args.Count -eq 0 ) {
    +  & $SCRIPT
    +} else {
    +  if ($args.Contains("--debug")) {
    +    Write-Host "Running: $SCRIPT $args"
    +  }
    +  & $SCRIPT @args
    +}
    diff --git a/utils/getdown/bin/jalview.bat b/utils/getdown/bin/run_powershell.bat
    similarity index 100%
    rename from utils/getdown/bin/jalview.bat
    rename to utils/getdown/bin/run_powershell.bat
    diff --git a/utils/getdown/bin/update.ps1 b/utils/getdown/bin/update.ps1
    new file mode 100755
    index 0000000..82b74d4
    --- /dev/null
    +++ b/utils/getdown/bin/update.ps1
    @@ -0,0 +1,204 @@
    +#!/usr/bin/env pwsh
    +
    +# setup for powershell version < 6.0
    +[bool] $myIsWindows = 0
    +[bool] $myIsMacOS = 0
    +if ( $IsWindows -eq $null ) {
    +  # for powershell version < 6.0 let's assume Windows
    +  $myIsWindows = 1
    +  $myIsMacOS = 0
    +} else {
    +  $myIsWindows = $IsWindows
    +  $myIsMacOS = $IsMacOS
    +}
    +
    +$USAGE = "Please use either --installation or --userspace."
    +
    +[bool] $debug = 0
    +[bool] $userspace = 0
    +[bool] $installation = 0
    +Switch ($args) {
    +  "--debug" {
    +    $debug = 1
    +    Continue
    +  }
    +  "--installation" {
    +    $installation = 1
    +    Continue
    +  }
    +  "--userspace" {
    +    $userspace = 1
    +    Continue
    +  }
    +  Default {
    +    throw "Unknown option '$_'.  ${USAGE}."
    +  }
    +}
    +
    +if ( -not ( $userspace -or -$installation ) ) {
    +  Write-Output "${USAGE}."
    +  Exit
    +}
    +
    +# actual path of this script (which should be the getdown appdir/bin). Follow all symlinks.  Like GNU readlink -f
    +function Readlink-f {
    +  Param(
    +    [Parameter(mandatory=$true, ValueFromPipeline=$true)]$Link,
    +    [Parameter()]$iteration_count = 1
    +  )
    +  if ( $iteration_count -ge 100 ) {
    +    Write-Error "Readlink-f iterated 100 times"
    +    return $Link
    +  }
    +  if ( $Link -eq "" -or $Link -eq $null ) {
    +    return $null
    +  }
    +  $path_components = @()
    +  $dir = Get-Item $Link
    +  while ( $dir -ne $null ) {
    +    while ( $dir.Target -ne $null ) {
    +      # [System.IO.Path]::Combine caters for a multitude of sins that it's almost impossible to deal with with Join-Path
    +      $dir = Get-Item ([System.IO.Path]::GetFullPath( [System.IO.Path]::Combine( (Split-Path $dir -Parent), $dir.Target )))
    +    }
    +    $parent = Split-Path -Path $dir -Parent
    +    $path_components = @( (Split-Path -Path $dir -Leaf) ) + $path_components
    +    $dir = Readlink-f $parent ($iteration_count + 1)
    +  }
    +  $real = Get-Item "/"
    +  foreach ( $component in $path_components) {
    +    # [System.IO.Path]::Combine caters for a multitude of sins that it's almost impossible to deal with with Join-Path
    +    $real = Get-Item ([System.IO.Path]::GetFullPath( [System.IO.Path]::Combine( $real, $component )))
    +  }
    +  $real
    +}
    +
    +# Avert problem with unix version of powershell and tell user the reason (Windows must always have .ps1 extension)
    +if ( $MyInvocation.MyCommand.Path -eq $null ) {
    +  throw "Script or link to script must have extension .ps1"
    +}
    +
    +# args for the JVM
    +$JVMARGS = @()
    +
    +$CMDPATH = ( Get-Item $MyInvocation.MyCommand.Path )
    +$SCRIPTPATH = Readlink-f -Link $CMDPATH
    +$SCRIPT = $SCRIPTPATH
    +$DIR = Split-Path -Path $SCRIPTPATH -Parent
    +$APPDIR = If ( ( Split-Path -Path $DIR -Leaf ) -eq "bin" ) { Split-Path -Path $DIR -Parent } Else { $DIR }
    +$JAVAEXE = If ( $myIsWindows ) { "java.exe" } Else { "java" }
    +if ( $myIsMacOS ) {
    +  $JAVABIN = Join-Path -Path $APPDIR -ChildPath "jre/Contents/Home/bin"
    +  $APPFOLDER = ( $APPDIR -Replace "\.app.*", "" ) + ".app"
    +  $VMOPTIONS = Join-Path -Path $APPFOLDER -ChildPath "Contents/vmoptions.txt"
    +} else {
    +  $JAVABIN = Join-Path -Path $APPDIR -ChildPath "jre" | Join-Path -ChildPath "bin"
    +  $APPFOLDER = $APPDIR
    +  $VMOPTIONS = Join-Path -Path $APPDIR -ChildPath "jalviewg.vmoptions"
    +}
    +$JAVA = Join-Path -Path $JAVABIN -ChildPath $JAVAEXE
    +
    +$JVMARGS += "-Djava.awt.headless=true"
    +if ( $myIsMacOS ) {
    +  $JVMARGS += "-Dapple.awt.UIElement=true"
    +}
    +
    +$GETDOWNLAUNCHERJAR = Join-Path -Path $APPDIR -ChildPath "getdown-launcher.jar"
    +$GETDOWNCOREJAR = Join-Path -Path $APPDIR -ChildPath "resource" | Join-Path -ChildPath "getdown-core.jar"
    +$CHANNELPROPS = Join-Path -Path $APPDIR -ChildPath "channel.props"
    +$NAME = ( Select-String -Path "${CHANNELPROPS}" -Pattern "^app_name=(.*)$" ).Matches.Groups[1].Value
    +$US_NAME = $NAME -Replace " ", "_"
    +
    +# getdown-launcher classpath
    +if ( Test-Path -Path $GETDOWNLAUNCHERJAR ) {
    +  $GDL_CLASSPATH = "${GETDOWNLAUNCHERJAR}"
    +} else {
    +  throw "Cannot find ${GETDOWNLAUNCHERJAR} to run update"
    +}
    +
    +# getdown-core classpath
    +if ( Test-Path -Path $GETDOWNCOREJAR ) {
    +  $GDC_CLASSPATH = "${GETDOWNCOREJAR}"
    +} else {
    +  throw "Cannot find ${GETDOWNCOREJAR} to run update"
    +}
    +
    +# USER space update
    +if ( $userspace ) {
    +  if ( Test-Path -Path $VMOPTIONS ) {
    +    $LINENUM = 0
    +    $lines = Get-Content -Path $VMOPTIONS
    +    foreach ( $line in $lines ) {
    +      # remove comments
    +      $line -Replace "#.*", "" | Out-Null
    +      # remove leading and trailing whitespace
    +      $line -Replace "(^\s+|\s+$)", "" | Out-Null
    +      $LINENUM++
    +
    +      if ( $line -Match "^-Dsetuserappdirpath=" ) {
    +        $JVMARGS += $line
    +      }
    +      if ( $line -Match "^-Dnouserdefaultappdir=" ) {
    +        $NOUSERUPDATEVALUE = ( $line -Replace ".*=", "" ).ToLower()
    +        if ( $NOUSERUPDATEVALUE -eq "true" ) {
    +          throw "Cannot perform manual user-space update when user-space updates are disabled.`nSee line ${LINENUM} (${line}) in file '${VMOPTIONS}'."
    +        }
    +        $JVMARGS += $line
    +      }
    +    }
    +  } else {
    +    echo "Could not find VMOPTIONS file '${VMOPTIONS}'"
    +  }
    +  $JVMARGS += "-Duserdefaultappdir=true"
    +  $JVMARGS += "-Dnouserdefaultappdir=false"
    +}
    +
    +# INSTALLATION update
    +if ( $installation ) {
    +  $JVMARGS += "-Duserdefaultappdir=false"
    +  $JVMARGS += "-Dnouserdefaultappdir=true"
    +  $JVMARGS += "-Dlauncher.appdir=${APPDIR}"
    +  $JVMARGS += "-Dappdir=${APPDIR}"
    +}
    +
    +# setting the appdir arg[0] and appid arg[1] to blank values
    +# so appDir is determined by EnvConfig.getUserAppdir() or appdir property
    +# and appId is passed as system property appid
    +$GDL_ARGS = @( "", "" )
    +
    +# both USER and INSTALLATION updates
    +$JVMARGS += "-Dinstaller.appdir=${APPDIR}"
    +$JVMARGS += "-Dinstaller.application_folder=${US_NAME}"
    +$JVMARGS += "-Dlauncher.script=${SCRIPT}"
    +$JVMARGS += "-Dlauncher.update=true"
    +$JVMARGS += "-Dchannel.app_name=${NAME}"
    +$JVMARGS += "-Dappid=jalview"
    +
    +# IMPORTANT! tell getdown to update jalview withouth launching
    +$JVMARGS += "-Dsilent=true"
    +
    +# add these Just In Case although jalview shouldn't be launched due to -Dsilent=true
    +$GDL_ARGS += ( "--headless", "--quit", "--nojavaconsole", "--nosplash", "--nonews" )
    +
    +# look for bundled JRE. Might not be there if unix installer used in which case just invoke "java"
    +if ( -not ( Test-Path -Path $JAVA ) ) {
    +  Write-Host "Cannot find bundled ${JAVA}. Using system ${JAVAEXE} and hoping for the best!"
    +  $JAVA = $JAVAEXE
    +}
    +
    +# we should always have at least one JVMARGS and GDL_ARGS so this is okay
    +$myJvmArgsString = '"' + $($JVMARGS -join '" "') + '"'
    +$myGdlArgsString = '"' + $($GDL_ARGS -join '" "') + '"'
    +
    +# quote the args and the command (in case of spaces) with escape chars (`) and precede with & to indicate a command not string
    +$COMMAND = "& `"${JAVA}`" ${myJvmArgsString} -cp `"${GDL_CLASSPATH}`" com.threerings.getdown.launcher.GetdownApp ${myGdlArgsString}"
    +if ( $debug ) {
    +  Write-Output "Shell running: ${COMMAND}"
    +}
    +Invoke-Expression -Command $COMMAND
    +
    +# move updated getdown-launcher.jar into place
    +$COMMAND = "& `"${JAVA}`" ${myJvmArgsString} -cp `"${GDC_CLASSPATH}`" jalview.bin.GetdownLauncherUpdate"
    +if ( $debug ) {
    +  Write-Output "Shell running: ${COMMAND}"
    +}
    +Invoke-Expression -Command $COMMAND
    diff --git a/utils/getdown/bin/update.sh b/utils/getdown/bin/update.sh
    new file mode 100755
    index 0000000..03f369e
    --- /dev/null
    +++ b/utils/getdown/bin/update.sh
    @@ -0,0 +1,253 @@
    +#!/usr/bin/env bash
    +
    +declare -a ARGS=("${@}")
    +
    +ISMACOS=0
    +if [ "$( uname -s )" = "Darwin" ]; then
    +  ISMACOS=1
    +fi
    +
    +USAGE="Please use either --installation or --userspace"
    +
    +DEBUG=0
    +USERSPACE=0
    +INSTALLATION=0
    +DISABLEROOTCHECK=0
    +for RAWARG in "${@}"; do
    +  ARG="${RAWARG%%=*}"
    +  case "${ARG}" in
    +    --debug)
    +      DEBUG=1
    +      ;;
    +    --installation)
    +      INSTALLATION=1
    +      ;;
    +    --userspace)
    +      USERSPACE=1
    +      ;;
    +    --norootcheck)
    +      DISABLEROOTCHECK=1
    +      ;;
    +    *)
    +      echo "Unknown option '${ARG}'.  ${USAGE}." >&2
    +      exit 2
    +  esac
    +done
    +
    +if [ "${USERSPACE}${INSTALLATION}" = "00" ]; then
    +  echo "${USAGE}."
    +  exit
    +fi
    +
    +# this whole next part is because there's no readlink -f in Darwin
    +function readlinkf() {
    +  FINDFILE="$1"
    +  FILE="${FINDFILE}"
    +  PREVFILE=""
    +  C=0
    +  MAX=100 # just in case we end up in a loop
    +  FOUND=0
    +  while [ "${C}" -lt "${MAX}" -a "${FILE}" != "${PREVFILE}" -a "${FOUND}" -ne 1 ]; do
    +    PREVFILE="${FILE}"
    +    FILE="$(readlink "${FILE}")"
    +    if [ -z "${FILE}" ]; then
    +      # the readlink is empty means we've arrived at the script, let's canonicalize with pwd
    +      FILE="$(cd "$(dirname "${PREVFILE}")" &> /dev/null && pwd -P)"/"$(basename "${PREVFILE}")"
    +      FOUND=1
    +    elif [ "${FILE#/}" = "${FILE}" ]; then
    +      # FILE is not an absolute path link, we need to add the relative path to the previous dir
    +      FILE="$(dirname "${PREVFILE}")/${FILE}"
    +    fi
    +    C=$((C+1))
    +  done
    +  if [ "${FOUND}" -ne 1 ]; then
    +    echo "Could not determine path to actual file '$(basename "${FINDFILE}")'" >&2
    +    exit 1
    +  fi
    +  echo "${FILE}"
    +}
    +
    +# args for the JVM
    +declare -a JVMARGS=()
    +
    +# set vars for being inside the macos App Bundle
    +if [ "${ISMACOS}" = 1 ]; then
    +# MACOS ONLY
    +  SCRIPT="$(readlinkf "$0")"
    +  DIR="$(dirname "${SCRIPT}")"
    +  APPDIR="${DIR%/bin}"
    +  JAVABIN="${APPDIR}/jre/Contents/Home/bin"
    +  # e.g. APPFOLDER=/Applications/Jalview.app
    +  APPFOLDER="${APPDIR%%.app/*}.app"
    +  VMOPTIONS="${APPFOLDER}/Contents/vmoptions.txt"
    +else
    +# NOT MACOS
    +  SCRIPT="$(readlink -f "$0")"
    +  DIR="$(dirname "${SCRIPT}")"
    +  APPDIR="${DIR%/bin}"
    +  JAVABIN="${APPDIR}/jre/bin"
    +  # e.g. APPFOLDER=/opt/jalview
    +  APPFOLDER="${APPDIR}"
    +  VMOPTIONS="${APPDIR}/jalviewg.vmoptions"
    +fi
    +JAVA="${JAVABIN}/java"
    +
    +# headless java arguments
    +JVMARGS=( "${JVMARGS[@]}" "-Djava.awt.headless=true" )
    +if [ "${ISMACOS}" = 1 ]; then
    +  JVMARGS=( "${JVMARGS[@]}" "-Dapple.awt.UIElement=true" )
    +fi
    +
    +SYSJAVA=java
    +GETDOWNLAUNCHERJAR="${APPDIR}/getdown-launcher.jar"
    +GETDOWNCOREJAR="${APPDIR}/resource/getdown-core.jar"
    +CHANNELPROPS="${APPDIR}/channel.props"
    +NAME="$( grep app_name= "${CHANNELPROPS}" | cut -d= -f2 )"
    +US_NAME="${NAME// /_}"
    +
    +GDL_CLASSPATH=""
    +GDC_CLASSPATH=""
    +# save an array of JAR paths in case we're in WSL (see later)
    +declare -a GDL_JARPATHS=()
    +declare -a GDC_JARPATHS=()
    +declare -a GDL_ARGS=()
    +
    +# getdown-launcher classpath
    +if [ -e "${GETDOWNLAUNCHERJAR}" ]; then
    +  GDL_CLASSPATH="${GETDOWNLAUNCHERJAR}"
    +  GDL_JARPATHS=( "${GDL_JARPATHS[@]}" "${GETDOWNLAUNCHERJAR}" )
    +else
    +  echo "Cannot find ${GETDOWNLAUNCHERJAR} to run update" >&2
    +  exit 3
    +fi
    +
    +# getdown-core classpath
    +if [ -e "${GETDOWNCOREJAR}" ]; then
    +  GDC_CLASSPATH="${GETDOWNCOREJAR}"
    +  GDC_JARPATHS=( "${GDC_JARPATHS[@]}" "${GETDOWNCOREJAR}" )
    +else
    +  echo "Cannot find $( basename "${GETDOWNCOREJAR}" ) to run update" >&2
    +  exit 4
    +fi
    +
    +# USER space update
    +if [ "${USERSPACE}" = 1 ]; then
    +  if [ -e "${VMOPTIONS}" ]; then
    +    LINENUM=0
    +    while IFS= read -r line; do
    +      # remove comments
    +      line=${line%%#*}
    +      # remove leading and trailing whitespace
    +      line="${line%"${line##*[![:space:]]}"}"
    +      line="${line#"${line%%[![:space:]]*}"}"
    +      LINENUM=$((LINENUM+1))
    +
    +      # add settings for user appdir
    +      if [ "${line}" != "${line#-Dsetuserappdirpath=}" ]; then # starts with -Dsetuserappdirpath=
    +        JVMARGS=( "${JVMARGS[@]}" "${line}" )
    +      fi
    +      if [ "${line}" != "${line#-Dnouserdefaultappdir=}" ]; then # starts with -Dnouserdefaultappdir=
    +        # don't perform user update if user updates are disabled
    +        NOUSERUPDATEVALUE="$(echo "${line#-Dnouserdefaultappdir=}" | tr '[:upper:]' '[:lower:]')"
    +        if [ "${NOUSERUPDATEVALUE}" = "true" ]; then
    +          echo "Cannot perform manual user-space update when user-space updates are disabled." >&2
    +          echo "See line ${LINENUM} (${line}) in file '${VMOPTIONS}'." >&2
    +          exit 5
    +        fi
    +        JVMARGS=( "${JVMARGS[@]}" "${line}" )
    +      fi
    +    done < "${VMOPTIONS}"
    +  fi
    +  JVMARGS=( "${JVMARGS[@]}" "-Duserdefaultappdir=true" )
    +  JVMARGS=( "${JVMARGS[@]}" "-Dnouserdefaultappdir=false" )
    +fi
    +
    +# INSTALLATION update
    +if [ "${INSTALLATION}" = 1 ]; then
    +  # root permissions check
    +  if [ "${DISABLEROOTCHECK}" != 1 -a "${EUID}" != 0 ]; then
    +    echo "--installation updates should be run with root permissions, or disable this root check with --norootcheck" >&2
    +    exit 6
    +  fi
    +  JVMARGS=( "${JVMARGS[@]}" "-Duserdefaultappdir=false" )
    +  JVMARGS=( "${JVMARGS[@]}" "-Dnouserdefaultappdir=true" )
    +  JVMARGS=( "${JVMARGS[@]}" "-Dlauncher.appdir=${APPDIR}" )
    +  JVMARGS=( "${JVMARGS[@]}" "-Dappdir=${APPDIR}" )
    +fi
    +
    +# setting the appdir arg[0] and appid arg[1] to blank values
    +# so appDir is determined by EnvConfig.getUserAppdir() or appdir property
    +# and appId is passed as system property appid
    +GDL_ARGS=( "" "" )
    +
    +# both USER and INSTALLATION updates
    +JVMARGS=( "${JVMARGS[@]}" "-Dinstaller.appdir=${APPDIR}" )
    +JVMARGS=( "${JVMARGS[@]}" "-Dinstaller.application_folder=${US_NAME}" )
    +JVMARGS=( "${JVMARGS[@]}" "-Dlauncher.script=${SCRIPT}" )
    +JVMARGS=( "${JVMARGS[@]}" "-Dlauncher.update=true" )
    +JVMARGS=( "${JVMARGS[@]}" "-Dchannel.app_name=${NAME}" )
    +JVMARGS=( "${JVMARGS[@]}" "-Dappid=jalview" )
    +
    +# IMPORTANT! tell getdown to update jalview withouth launching
    +JVMARGS=( "${JVMARGS[@]}" "-Dsilent=true" )
    +
    +# add these Just In Case although jalview shouldn't be launched due to -Dsilent=true
    +GDL_ARGS=( "${GDL_ARGS[@]}" "--headless" "--quit" "--nojavaconsole" "--nosplash" "--nonews" )
    +
    +# WINDOWS ONLY in Cygwin or Windows Subsystem for Linux (WSL)
    +# change paths for Cygwin or WSL
    +if [ "${ISMACOS}" != 1 ]; then # older macos doesn't like uname -o, best to avoid
    +  if [ "$(uname -o)" = "Cygwin" ]; then
    +    # CYGWIN
    +    GDL_CLASSPATH=$(cygpath -pw "${GDL_CLASSPATH}")
    +    GDC_CLASSPATH=$(cygpath -pw "${GDC_CLASSPATH}")
    +  elif uname -r | grep -i microsoft | grep -i wsl >/dev/null; then
    +    # WSL
    +    GDL_CLASSPATH=""
    +    for JARPATH in "${GDL_JARPATHS[@]}"; do
    +      [ -n "${GDL_CLASSPATH}" ] && GDL_CLASSPATH="${GDL_CLASSPATH};"
    +      GDL_CLASSPATH="${GDL_CLASSPATH}$(wslpath -aw "${JARPATH}")"
    +    done
    +    GDC_CLASSPATH=""
    +    for JARPATH in "${GDC_JARPATHS[@]}"; do
    +      [ -n "${GDC_CLASSPATH}" ] && GDC_CLASSPATH="${GDC_CLASSPATH};"
    +      GDC_CLASSPATH="${GDC_CLASSPATH}$(wslpath -aw "${JARPATH}")"
    +    done
    +    JAVA="${JAVA}.exe"
    +    SYSJAVA="java.exe"
    +  fi
    +fi
    +
    +# Is there a bundled Java?  If not just try one in the PATH (we need .exe in WSL, added above)
    +if [ \! -e "${JAVA}" ]; then
    +  JAVA=$SYSJAVA
    +  echo "Cannot find bundled ${JAVA}, using system ${SYSJAVA} and hoping for the best!" >&2
    +fi
    +
    +# This is just needed for display purposes
    +function quotearray() {
    +  QUOTEDVALS=""
    +  for VAL in "${@}"; do
    +    if [ \! "$QUOTEDVALS" = "" ]; then
    +      QUOTEDVALS="${QUOTEDVALS} "
    +    fi
    +    QUOTEDVALS="${QUOTEDVALS}\"${VAL}\""
    +  done
    +  echo $QUOTEDVALS
    +}
    +
    +JVMARGSSTR=$(quotearray "${JVMARGS[@]}")
    +ARGSSTR=$(quotearray "${GDL_ARGS[@]}")
    +
    +if [ "${DEBUG}" = 1 ]; then
    + echo Shell running: \""${JAVA}"\" ${JVMARGSSTR} -cp \""${GDL_CLASSPATH}"\" com.threerings.getdown.launcher.GetdownApp ${ARGSSTR} >&2
    +fi
    +
    +"${JAVA}" "${JVMARGS[@]}" -cp "${GDL_CLASSPATH}" com.threerings.getdown.launcher.GetdownApp "${GDL_ARGS[@]}"
    +
    +# move updated getdown-launcher.jar into place
    +if [ "${DEBUG}" = 1 ]; then
    +  echo Shell running: \""${JAVA}"\" ${JVMARGSSTR} -cp \""${GDC_CLASSPATH}"\" jalview.bin.GetdownLauncherUpdate >&2
    +fi
    +
    +"${JAVA}" "${JVMARGS[@]}" -cp "${GDC_CLASSPATH}" jalview.bin.GetdownLauncherUpdate
    diff --git a/utils/install4j/default.vmoptions b/utils/install4j/default.vmoptions
    new file mode 100644
    index 0000000..9989aa7
    --- /dev/null
    +++ b/utils/install4j/default.vmoptions
    @@ -0,0 +1,21 @@
    +# Enter one VM parameter per line
    +# For example, to adjust the maximum memory usage to 512 MB, uncomment the following line:
    +# -Xmx512m
    +# To include another file, uncomment the following line:
    +# -include-options [path to other .vmoption file]
    +
    +# Jalview specific options below
    +
    +# Jalview options added by __INSTALLERFILENAME__ at __INSTALLDATETIME__
    +# 
    +# Uncomment the following line to disable user-space updates
    +#-Dnouserdefaultappdir=true
    +# 
    +# Uncomment the below line to set a custom path for user-space updates -- use with caution.
    +# A leading ~/ or %h anywhere will be substituted with the user's home path, and %u by the username.
    +# If not set, the default is ${installer:userDefaultAppdirBase} for ${installer:osName}
    +#-Dsetuserappdirpath=/tmp/jalview/%u
    +# 
    +# Uncomment the following line to also disable all updates
    +#-Dsilent=noupdate 
    +
    diff --git a/utils/install4j/file_associations_auto-install4j10.xml b/utils/install4j/file_associations_auto-install4j10.xml
    index 4a87364..7364320 100644
    --- a/utils/install4j/file_associations_auto-install4j10.xml
    +++ b/utils/install4j/file_associations_auto-install4j10.xml
    @@ -1,5 +1,5 @@
     
    -                  
    +                  
                         
                           Jalview (.jvp)
                           Creating file associations...
    @@ -8,13 +8,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Jalview File
                           jvp
    @@ -44,7 +44,7 @@
     
     
     
    -                  
    +                  
                         
                           Jalview Launch (.jvl)
                           Creating file associations...
    @@ -53,13 +53,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Jalview Launch File
                           jvl
    @@ -89,7 +89,7 @@
     
     
     
    -                  
    +                  
                         
                           CIF (.cif)
                           Creating file associations...
    @@ -98,13 +98,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           CIF File
                           cif
    @@ -134,7 +134,7 @@
     
     
     
    -                  
    +                  
                         
                           mmCIF (.mcif, .mmcif)
                           Creating file associations...
    @@ -143,13 +143,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           mmCIF File
                           mcif,mmcif
    @@ -179,7 +179,7 @@
     
     
     
    -                  
    +                  
                         
                           PDB (.ent, .pdb)
                           Creating file associations...
    @@ -188,13 +188,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           PDB File
                           ent,pdb
    @@ -224,7 +224,7 @@
     
     
     
    -                  
    +                  
                         
                           AMSA (.amsa)
                           Creating file associations...
    @@ -233,13 +233,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           AMSA File
                           amsa
    @@ -269,7 +269,7 @@
     
     
     
    -                  
    +                  
                         
                           Jalview Annotations (.annotations, .jvannotations)
                           Creating file associations...
    @@ -278,13 +278,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Jalview Annotations File
                           annotations,jvannotations
    @@ -314,7 +314,7 @@
     
     
     
    -                  
    +                  
                         
                           BioJSON (.biojson)
                           Creating file associations...
    @@ -323,13 +323,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           BioJSON File
                           biojson
    @@ -359,7 +359,7 @@
     
     
     
    -                  
    +                  
                         
                           BLC (.blc)
                           Creating file associations...
    @@ -368,13 +368,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           BLC File
                           blc
    @@ -404,7 +404,7 @@
     
     
     
    -                  
    +                  
                         
                           Clustal (.aln)
                           Creating file associations...
    @@ -413,13 +413,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Clustal File
                           aln
    @@ -449,7 +449,7 @@
     
     
     
    -                  
    +                  
                         
                           Fasta (.fa, .fasta)
                           Creating file associations...
    @@ -458,13 +458,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Fasta File
                           fa,fasta
    @@ -494,7 +494,7 @@
     
     
     
    -                  
    +                  
                         
                           Jalview Features (.features, .jvfeatures)
                           Creating file associations...
    @@ -503,13 +503,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Jalview Features File
                           features,jvfeatures
    @@ -539,7 +539,7 @@
     
     
     
    -                  
    +                  
                         
                           Jalview Feature Settings File (.fc)
                           Creating file associations...
    @@ -548,13 +548,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Jalview Feature Settings File File
                           fc
    @@ -584,7 +584,7 @@
     
     
     
    -                  
    +                  
                         
                           GenBank Flatfile (.gb, .gbk)
                           Creating file associations...
    @@ -593,13 +593,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           GenBank Flatfile File
                           gb,gbk
    @@ -629,7 +629,7 @@
     
     
     
    -                  
    +                  
                         
                           Generic Features Format v2 (.gff2)
                           Creating file associations...
    @@ -638,13 +638,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Generic Features Format v2 File
                           gff2
    @@ -674,7 +674,7 @@
     
     
     
    -                  
    +                  
                         
                           Generic Features Format v3 (.gff3)
                           Creating file associations...
    @@ -683,13 +683,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Generic Features Format v3 File
                           gff3
    @@ -719,7 +719,7 @@
     
     
     
    -                  
    +                  
                         
                           JnetFile (.concise, .jnet)
                           Creating file associations...
    @@ -728,13 +728,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           JnetFile File
                           concise,jnet
    @@ -764,7 +764,7 @@
     
     
     
    -                  
    +                  
                         
                           MSF (.msf)
                           Creating file associations...
    @@ -773,13 +773,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           MSF File
                           msf
    @@ -809,7 +809,7 @@
     
     
     
    -                  
    +                  
                         
                           PFAM (.pfam)
                           Creating file associations...
    @@ -818,13 +818,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           PFAM File
                           pfam
    @@ -854,7 +854,7 @@
     
     
     
    -                  
    +                  
                         
                           PHYLIP (.phy)
                           Creating file associations...
    @@ -863,13 +863,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           PHYLIP File
                           phy
    @@ -899,7 +899,7 @@
     
     
     
    -                  
    +                  
                         
                           PileUp (.pileup)
                           Creating file associations...
    @@ -908,13 +908,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           PileUp File
                           pileup
    @@ -944,7 +944,7 @@
     
     
     
    -                  
    +                  
                         
                           PIR (.pir)
                           Creating file associations...
    @@ -953,13 +953,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           PIR File
                           pir
    @@ -989,7 +989,7 @@
     
     
     
    -                  
    +                  
                         
                           RNAML (.rnaml)
                           Creating file associations...
    @@ -998,13 +998,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           RNAML File
                           rnaml
    @@ -1034,7 +1034,7 @@
     
     
     
    -                  
    +                  
                         
                           Substitution Matrix (.mat)
                           Creating file associations...
    @@ -1043,13 +1043,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Substitution Matrix File
                           mat
    @@ -1079,7 +1079,7 @@
     
     
     
    -                  
    +                  
                         
                           Stockholm (.stk, .sto)
                           Creating file associations...
    @@ -1088,13 +1088,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           Stockholm File
                           stk,sto
    diff --git a/utils/install4j/file_associations_template-install4j10.xml b/utils/install4j/file_associations_template-install4j10.xml
    index 8663ed9..078076f 100644
    --- a/utils/install4j/file_associations_template-install4j10.xml
    +++ b/utils/install4j/file_associations_template-install4j10.xml
    @@ -1,5 +1,5 @@
     
    -                  
    +                  
                         
                           $$NAME$$ ($$DISPLAYEXTENSION$$)
                           Creating file associations...
    @@ -8,13 +8,13 @@
                         
                       
     
    -                  
    +                  
                         
                           
                         
                       
     
    -                  
    +                  
                         
                           $$NAME$$ File
                           $$EXTENSION$$
    diff --git a/utils/install4j/install4j10_template.install4j b/utils/install4j/install4j10_template.install4j
    index 6172279..9531fc6 100644
    --- a/utils/install4j/install4j10_template.install4j
    +++ b/utils/install4j/install4j10_template.install4j
    @@ -1,7 +1,7 @@
     
     
    -  
    -  
    +  
    +  
         
           
           
    @@ -45,6 +45,9 @@
           
           
           
    +      
    +      
    +      
           
           
           
    @@ -66,15 +69,14 @@
           
           
           
    -      
    -      
    -      
    -      
    +      
    +      
           
           
    -      
    -      
    -      
    +      
    +      
    +      
    +      
           
         
         
    @@ -131,7 +133,7 @@
           
         
         
    -      
    +      
                   
                     
    +                  
                       
                         
                           ArrayList<String> tryPaths = new ArrayList<> ();
    @@ -375,27 +719,216 @@ return null;
                       
                       unixBinDir
                     
    -                context.getBooleanVariable("makeSymbolicLink")
    +                if (!context.getBooleanVariable("makeSymbolicLink")) {
    +    return false;
    +}
    +String unixBinDir = (String) context.getVariable("unixBinDir");
    +if (unixBinDir != null && unixBinDir.length() > 0) {
    +    if (unixBinDir.startsWith("~/")) {
    +        unixBinDir = (String)context.getVariable("sys.userHome") + unixBinDir.substring(1);
    +        context.setVariable("unixBinDir", unixBinDir);
    +    }
    +    return false;
    +}
    +return true;
                   
    -              
    +              
                     
                       
                         
                           String javaHome = System.getProperty("java.home");
     String appName = ((String)context.getCompilerVariable("JALVIEW_APPLICATION_NAME")) + ".app";
     int i = javaHome.indexOf(appName);
    -String wrapperLink = null;
    +String MacOSDir = null;
     if (i > -1) {
    -    wrapperLink = javaHome.substring(0, i) + appName + File.separator + "Contents" + File.separator + "MacOS" + File.separator + ((String)context.getCompilerVariable("WRAPPER_LINK"));
    +    MacOSDir = javaHome.substring(0, i) + appName + File.separator + "Contents" + File.separator + "MacOS";
     }
    -return wrapperLink;
    +return MacOSDir;
     
                         
                       
    -                  macWrapperLinkLocation
    +                  MacOSDir
                     
                     Util.isMacOS() && !context.getBooleanVariable("isAdmin") // Admin on macOS will add path to /etc/paths.d in Create File action
                   
    +              
    +                
    +                  
    +                  
    +                  
    +                    
    +                      Boolean.FALSE
    +                    
    +                  
    +                  advancedOptions
    +                
    +              
    +              
    +                
    +                  
    +                  
    +                  
    +                    
    +                      Boolean.TRUE
    +                    
    +                  
    +                  allowUserDefaultAppdirUpdates
    +                
    +              
    +              
    +                
    +                  
    +                  
    +                  
    +                    
    +                      Boolean.FALSE
    +                    
    +                  
    +                  allowSetUserAppdirPath
    +                
    +              
    +              
    +                
    +                  
    +                  
    +                  
    +                    
    +                      ""
    +                    
    +                  
    +                  userAppdirPath
    +                
    +              
    +              
    +                
    +                  
    +                  
    +                  
    +                    
    +                      Boolean.FALSE
    +                    
    +                  
    +                  allowInstallerAppdirUpdates
    +                
    +              
    +              
    +                
    +                  
    +                    
    +                      getOsAppDataPath(context)
    +                    
    +                  
    +                  userDefaultAppdirBase
    +                
    +              
    +              
    +                
    +                  
    +                    
    +                      if (Util.isWindows()) {
    +    return "Windows";
    +} else if (Util.isMacOS()) {
    +    return "macOS";
    +} else if (Util.isLinux()) {
    +    return "Linux";
    +}
    +return context.getCompilerVariable("sys.platform");
    +                    
    +                  
    +                  osName
    +                
    +              
    +              
    +                
    +                  
    +                    
    +                      Boolean.FALSE
    +                    
    +                  
    +                  consoleDisableUserAppdir
    +                
    +              
    +              
    +                
    +                  
    +                    
    +                      Boolean.FALSE
    +                    
    +                  
    +                  consoleDisableAllUpdates
    +                
    +              
    +              
    +                
    +                  
    +                    
    +                      Boolean.FALSE
    +                    
    +                  
    +                  consoleAllowUserAppdirPath
    +                
    +              
    +              
    +                
    +                  
    +                    
    +                      String[] args = context.getExtraCommandLineArguments();
    +
    +for (int i = 0; i < args.length; i++) {
    +    String arg = args[i];
    +    switch(arg) {
    +        case "-a":
    +            if (args.length - 1 < i + 1) {
    +                System.out.println("Option " + arg + " requires a value.  Ignoring.");
    +            }
    +            context.setInstallationDirectory(new File(args[i + 1]));
    +            i++;
    +            break;
    +        case "-u":
    +            if (args.length - 1 < i + 1) {
    +                System.out.println("Option " + arg + " requires a value.  Ignoring.");
    +            }
    +            context.setVariable("userAppdirPath", args[i + 1]);
    +            context.setVariable("consoleAllowUserAppdirPath", true);
    +            i++;        
    +            break;
    +        case "-U":
    +            context.setVariable("consoleDisableUserAppdir", true);
    +            break;
    +        case "-S":
    +            context.setVariable("consoleDisableAllUpdates", true);
    +            break;
    +        default:
    +            System.out.println("Option " + arg + " not recognised.  Ignoring.");
    +            break;
    +    }
    +}
    +
    +return true;
    +                    
    +                  
    +                
    +                context.isConsole() || context.isUnattended()
    +              
    +              
    +                
    +                  
    +                    
    +                      String[] extensions = (String[]) context.getVariable("sys.fileAssociation.extensions");
    +if (extensions == null) {
    +    return false;
    +}
    +int num = extensions.length;
    +String[] launchers = new String[num];
    +for (int i = 0; i < num; i++) {
    +    launchers[i] = "JALVIEW";
    +}
    +context.setVariable("sys.fileAssociation.launchers", launchers);
    +return true;
    +                    
    +                  
    +                
    +              
                 
               
             
    @@ -468,14 +1001,24 @@ return wrapperLink;
                 
                   
                     
    -                  
    +                  
                         sys.installationDir
    +                    sys.adminRights$Boolean
    +                    sys.adminRightsUiRootUnix$Boolean
    +                    sys.component.1031$Boolean
    +                    sys.fileAssociation.launchers$StringArray
                       
                     
                     context.getBooleanVariable("sys.confirmedUpdateInstallation")
                   
                 
                 
    +              
    +                
    +                  <strong>Administrator mode</strong>
    +                
    +                context.getBooleanVariable("isAdmin")
    +              
                   
                     
                       ${form:welcomeMessage}
    @@ -505,19 +1048,29 @@ return console.askOkCancel(message, true);
                   
                 
               
    -          
    +          
                 !context.getBooleanVariable("sys.confirmedUpdateInstallation")
                 
                   
                     
    -                  
    +                  
                         sys.installationDir
    +                    sys.adminRights$Boolean
    +                    sys.adminRightsUiRootUnix$Boolean
    +                    sys.component.1031$Boolean
    +                    sys.fileAssociation.launchers$StringArray
                       
                     
                     context.getVariable("sys.responseFile") == null
                   
                 
                 
    +              
    +                
    +                  <strong>Administrator mode</strong>
    +                
    +                context.getBooleanVariable("isAdmin")
    +              
                   
                     
                       ${i18n:SelectDirLabel(${compiler:sys.fullName})}
    @@ -545,27 +1098,61 @@ return console.askOkCancel(message, true);
               
               
                 
    +              
    +                
    +                  <strong>Administrator mode</strong>
    +                
    +                context.getBooleanVariable("isAdmin")
    +              
                   
                     
                       ${i18n:SelectAssociationsLabel}
                     
                   
    -              
    +              
    +                
    +                  
    +                    
    +                      Screen s = formEnvironment.getScreen();
    +
    +FormComponent fc = formEnvironment.getFormComponentById("FILE_ASSOCIATIONS_SELECTOR");
    +com.install4j.api.actions.Action a0 = context.getActionById("FA_FILEASSOCIATION-CIF-false");
    +Screen s2 = context.getScreenById("EXTENSIONS_REPLACED_BY_GRADLE_PARENT_GROUP");
    +
    +for (com.install4j.api.actions.Action a : context.getActions(s2)) {
    +    String aid = context.getId(a);
    +    if (aid.startsWith("FA_FILEASSOCIATION-")) {
    +        com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction aa = (com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction) a;
    +        boolean set = aid.endsWith("-true");
    +        boolean got = aa.isSelected();
    +        aa.setSelected(set);
    +        System.err.println("Setting '"+aid+"' from "+got+" to "+set);
    +    }
    +}
    +
    +context.gotoScreen(s);
    +//formEnvironment.reinitializeFormComponents();
    +                    
    +                  
    +                  Reset
    +                
    +              
    +              
                     
                       
                       
                       
                     
                     
    -                  showSelectionButtons
                       selectionButtonPosition
    +                  showSelectionButtons
                     
                   
                 
               
               
                 
    -              User account
    +              Additional tasks for user installation (${installer:sys.userName})
                   ${i18n:WizardSelectTasks}
                 
                 !context.getBooleanVariable("isAdmin")
    @@ -610,19 +1197,144 @@ return console.askOkCancel(message, true);
          || Util.isUnixInstaller()
          || (
               ( Util.isMacOS() && !Util.hasFullAdminRights() ) // Admin on macOS will add path to /etc/paths.d
    -          && context.getVariable("macWrapperLinkLocation") != null
    +          && context.getVariable("MacOSDir") != null
             )
         )
                   
    +              
    +              
    +                
    +                  Enable advanced options for user installation
    +                  
    +                    2980
    +                    3014
    +                    2975
    +                    2989
    +                  
    +                  
    +                    
    +                      validateUserSpaceAdvancedOptionsForm(formEnvironment)
    +                    
    +                  
    +                  advancedOptions
    +                
    +              
    +              
    +                
    +                  
    +                    
    +                      128
    +                      128
    +                      128
    +                      255
    +                    
    +                  
    +                  
    +                  
    +                  Advanced options will not be used
    +                
    +                !context.getBooleanVariable("advancedOptions")
    +
    +              
    +              
    +                
    +                  
    +                    
    +                      FormComponent fc_advancedOptions = formEnvironment.getFormComponentById("US_ADVANCED_OPTIONS");
    +
    +JCheckBox jcb_advancedOptions = (JCheckBox) fc_advancedOptions.getConfigurationObject();
    +boolean advancedOptions = jcb_advancedOptions.isSelected();
    +
    +return advancedOptions;
    +                    
    +                  
    +                
    +                
    +                  
    +                    
    +                      
    +                        
    +                          
    +                          
    +                          
    +                          
    +                        
    +                      
    +                      
    +                        
    +                          4
    +                          4
    +                          4
    +                          4
    +                        
    +                      
    +                    
    +                    
    +                      
    +                        
    +                          <html>The following option is <strong>strongly recommended</strong>
    +to be left as default unless there is a particular
    +reason to change it.</html>
    +                        
    +                      
    +                      
    +                      
    +                        
    +                          Allow user-space updates for ${compiler:JALVIEW_APPLICATION_NAME} components
    +                          <html>This option allows updates to ${compiler:JALVIEW_APPLICATION_NAME}
    +<br>
    +components to be automatically downloaded
    +<br>
    +under the user's home space, separately from
    +<br>
    +the installation location.
    +<br>
    +<strong>This option is strongly recommended.</strong>
    +<br>
    +<br>
    +On ${installer:osName}, user updates will be installed under
    +<br>
    +<pre>${installer:userDefaultAppdirBase}</pre>
    +</html>
    +                          
    +                          
    +                            
    +                              validateUserSpaceAdvancedOptionsForm(formEnvironment)
    +                            
    +                          
    +                          allowUserDefaultAppdirUpdates
    +                        
    +                      
    +                      
    +                        
    +                          
    +                            
    +                              ${compiler:JALVIEW_DIR}/${compiler:INSTALL4J_UTILS_DIR}/warning.png
    +                            
    +                          
    +                          No automatic updates will occur when Jalview is launched
    +                        
    +                        !( context.getBooleanVariable("allowUserDefaultAppdirUpdates") || context.getBooleanVariable("allowInstallerAppdirUpdates") )
    +                      
    +                    
    +                  
    +                
    +              
                 
               
               
                 
    -              System
    +              Additional tasks for administrator installation
                   ${i18n:WizardSelectTasks}
                 
                 context.getBooleanVariable("isAdmin")
                 
    +              
    +                
    +                  <strong>Administrator mode</strong>
    +                
    +                context.getBooleanVariable("isAdmin")
    +              
                   
                     
                       ${i18n:SelectTasksLabel2(${compiler:JALVIEW_APPLICATION_NAME})}
    @@ -649,14 +1361,313 @@ return console.askOkCancel(message, true);
          || Util.isUnixInstaller()
          || (
               ( Util.isMacOS() && !Util.hasFullAdminRights() ) // Admin on macOS will add path to /etc/paths.d
    -          && context.getVariable("macWrapperLinkLocation") != null
    +          && context.getVariable("MacOSDir") != null
             )
         )
     
                   
    +              
    +              
    +                
    +                  Enable advanced options for system installation
    +                  
    +                    3030
    +                    2985
    +                    3013
    +                    2986
    +                    2974
    +                    2988
    +                  
    +                  
    +                    
    +                      validateSystemSpaceAdvancedOptionsForm(context, formEnvironment)
    +                    
    +                  
    +                  advancedOptions
    +                
    +              
    +              
    +                
    +                  
    +                    
    +                      128
    +                      128
    +                      128
    +                      255
    +                    
    +                  
    +                  
    +                  
    +                  Advanced options will not be used
    +                
    +                !context.getBooleanVariable("advancedOptions")
    +
    +              
    +              
    +                
    +                  
    +                    
    +                      context.getBooleanVariable("advancedOptions")
    +
    +                    
    +                  
    +                
    +                
    +                  
    +                    
    +                      
    +                        
    +                          
    +                          
    +                          
    +                          
    +                        
    +                      
    +                      
    +                        
    +                          4
    +                          4
    +                          4
    +                          4
    +                        
    +                      
    +                      
    +                        
    +                          
    +                        
    +                      
    +                    
    +                    
    +                      
    +                        
    +                          <html>The following options are <strong>strongly recommended</strong> to be left as default unless there is a particular reason to change them.</html>
    +                        
    +                      
    +                      
    +                      
    +                        
    +                          Allow user-space updates for ${compiler:JALVIEW_APPLICATION_NAME} components
    +                          
    +                            3021
    +                          
    +                          <html>This option allows updates to ${compiler:JALVIEW_APPLICATION_NAME}
    +<br>
    +components to be automatically downloaded
    +<br>
    +under the user's home space, separately from
    +<br>
    +the installation location.
    +<br>
    +<strong>This option is strongly recommended.</strong>
    +<br>
    +<br>
    +On ${installer:osName}, user updates will be installed under
    +<pre>${installer:userDefaultAppdirBase}</pre>
    +unless customised below.
    +</html>
    +                          
    +                            
    +                              validateSystemSpaceAdvancedOptionsForm(context, formEnvironment)
    +                            
    +                          
    +                          allowUserDefaultAppdirUpdates
    +                        
    +                      
    +                      
    +                        
    +                          
    +                            
    +                              0
    +                              32
    +                              0
    +                              0
    +                            
    +                          
    +                          
    +                            
    +                              
    +                            
    +                          
    +                        
    +                        
    +                          
    +                            
    +                              Customise the user-space path
    +                              
    +                                
    +                                  validateSystemSpaceAdvancedOptionsForm(context, formEnvironment)
    +                                
    +                              
    +                              allowSetUserAppdirPath
    +                            
    +                            component.setEnabled( context.getBooleanVariable("allowUserDefaultAppdirUpdates") )
    +                          
    +                          
    +                            
    +                              <html>The base path where individual users' updates
    +<br>
    +will be stored.
    +<br>
    +<strong>Only change this option if you need to!</strong>
    +<br>
    +The following substitutions will be made:
    +<table>
    +<tr><td>%u</td><td>The user's username</td></tr>
    +<tr><td>%h</td><td>The user's home directory path</td></tr>
    +<tr><td>~${installer:sys.fileSeparator}</td><td>(at start) The user's home directory path${installer:sys.fileSeparator}</td></tr>
    +</table>
    +At least one of the above substitutions should be
    +<br>
    +used, e.g. <tt>/tmp/${compiler:UNIX_APPLICATION_FOLDER}/%u/app</tt>
    +<br>
    +The default value on ${installer:osName} is
    +<br>
    +<pre>${installer:userDefaultAppdirBase}</pre>
    +</html>
    +                              
    +                                
    +                                  validateSystemSpaceAdvancedOptionsForm(context, formEnvironment, true)
    +                                
    +                              
    +                              
    +                                
    +                                  showInvalidUserAppdirPathWarning(context, formEnvironment)
    +
    +                                
    +                              
    +                              
    +                                
    +                                  
    +                                
    +                              
    +                              userAppdirPath
    +                            
    +                            component.setEnabled( context.getBooleanVariable("allowUserDefaultAppdirUpdates") && context.getBooleanVariable("allowSetUserAppdirPath") );
    +
    +                          
    +                        
    +                      
    +                      
    +                        
    +                          Allow installation updates for ${compiler:JALVIEW_APPLICATION_NAME} components
    +                          <html>This option allows updates to ${compiler:JALVIEW_APPLICATION_NAME}
    +<br>
    +components to be automatically downloaded
    +<br>
    +into the installation location.
    +<br>
    +If you are installing into a system location,
    +<br>
    +a non-administrator user may have problems
    +<br>
    +launching ${compiler:JALVIEW_APPLICATION_NAME}.
    +<br>
    +<strong>
    +It is strongly recommended to use the
    +<br>
    +user-space updates option above.
    +</strong>
    +<br>
    +<br>
    +Installation updates will be installed into
    +<br>
    +<pre>${installer:sys.contentDir}</pre>
    +</html>
    +                          
    +                            
    +                              validateSystemSpaceAdvancedOptionsForm(context, formEnvironment)
    +                            
    +                          
    +                          allowInstallerAppdirUpdates
    +                        
    +                        component.setEnabled( !context.getBooleanVariable("allowUserDefaultAppdirUpdates") )
    +                      
    +                      
    +                        
    +                          
    +                            
    +                              FormComponent fc_userUpdates = formEnvironment.getFormComponentById("SS_ALLOW_USER_APPDIR_UPDATES");
    +FormComponent fc_installerUpdates = formEnvironment.getFormComponentById("SS_ALLOW_INSTALLER_APPDIR_UPDATES");
    +FormComponent fc_allowUserAppdirPath = formEnvironment.getFormComponentById("SS_ALLOW_USER_APPDIR_PATH");
    +FormComponent fc_userAppdirPath = formEnvironment.getFormComponentById("SS_USER_APPDIR_PATH");
    +
    +// set defaults
    +((JCheckBox) fc_userUpdates.getConfigurationObject()).setSelected(true);
    +((JCheckBox) fc_allowUserAppdirPath.getConfigurationObject()).setSelected(false);
    +((JTextField) fc_userAppdirPath.getConfigurationObject()).setText("");
    +((JCheckBox) fc_installerUpdates.getConfigurationObject()).setSelected(false);
    +
    +// revalidate
    +validateSystemSpaceAdvancedOptionsForm(context, formEnvironment);
    +
    +                            
    +                          
    +                          Reset advanced options to defaults
    +                        
    +                        FormComponent fc_advancedOptions = formEnvironment.getFormComponentById("SS_ADVANCED_OPTIONS");
    +FormComponent fc_userUpdates = formEnvironment.getFormComponentById("SS_ALLOW_USER_APPDIR_UPDATES");
    +FormComponent fc_userAppdirPath = formEnvironment.getFormComponentById("SS_USER_APPDIR_PATH");
    +FormComponent fc_installerUpdates = formEnvironment.getFormComponentById("SS_ALLOW_INSTALLER_APPDIR_UPDATES");
    +FormComponent fc_allowUserAppdirPath = formEnvironment.getFormComponentById("SS_ALLOW_USER_APPDIR_PATH");
    +
    +JCheckBox jcb_user = (JCheckBox) fc_userUpdates.getConfigurationObject();
    +boolean userUpdates = jcb_user.isSelected();
    +
    +JCheckBox jcb_allowUserAppdirPath = (JCheckBox) fc_allowUserAppdirPath.getConfigurationObject();
    +boolean allowUserAppdirPath = jcb_allowUserAppdirPath.isSelected();
    +
    +JTextField jtf_userAppdirPath = (JTextField) fc_userAppdirPath.getConfigurationObject();
    +String userAppdirPath = jtf_userAppdirPath.getText();
    +
    +JCheckBox jcb_installer = (JCheckBox) fc_installerUpdates.getConfigurationObject();
    +boolean installerUpdates = jcb_installer.isSelected();
    +
    +
    +// set whether "Set defaults" button should be enabled
    +boolean enableSetDefaults = !( userUpdates && !allowUserAppdirPath && userAppdirPath.length() == 0 && !installerUpdates );
    +component.setEnabled(enableSetDefaults);
    +                      
    +                      
    +                        
    +                          
    +                            
    +                              ${compiler:JALVIEW_DIR}/${compiler:INSTALL4J_UTILS_DIR}/warning.png
    +                            
    +                          
    +                          No automatic updates will occur when ${compiler:JALVIEW_APPLICATION_NAME} is launched
    +                        
    +                        !( context.getBooleanVariable("allowUserDefaultAppdirUpdates") || context.getBooleanVariable("allowInstallerAppdirUpdates") )
    +                      
    +                      
    +                        
    +                          
    +                            
    +                              ${compiler:JALVIEW_DIR}/${compiler:INSTALL4J_UTILS_DIR}/warning.png
    +                            
    +                          
    +                          The user-space path should contain one of "~${installer:sys.fileSeparator}" (at the start), "%u" or "%h"
    +                        
    +                        String userAppdirPath = (String) context.getVariable("userAppdirPath");
    +
    +if (userAppdirPath == null) {
    +  return false;
    +}
    +
    +boolean u = userAppdirPath.contains("%u");
    +boolean h = userAppdirPath.contains("%h");
    +boolean t = userAppdirPath.startsWith("~" + (String)context.getVariable("sys.fileSeparator"));
    +
    +boolean showInvalidPathWarning = !( userAppdirPath.length() == 0 || u || h || t );
    +
    +return context.getBooleanVariable("allowUserDefaultAppdirUpdates") && context.getBooleanVariable("allowSetUserAppdirPath") && showInvalidPathWarning;
    +                      
    +                    
    +                  
    +                
    +              
                 
               
    -          
    +          
                 
                   
                   
    @@ -694,7 +1705,7 @@ return console.askOkCancel(message, true);
                       ${compiler:sys.fullName} ${compiler:sys.version}
                     
                   
    -              
    +              
                     
                       
                         
    @@ -728,11 +1739,23 @@ return console.askOkCancel(message, true);
                       
                       
                         
    -                      
    +                      
                         
                       
                     
                   
    +              
    +                
    +                  ${i18n:FinishedHeadingLabel(${compiler:JALVIEW_APPLICATION_NAME})}
    +                  
    +                  
    +                
    +              
    +              
    +                
    +                  
    +                
    +              
                   
                     
                       
    @@ -776,7 +1799,7 @@ return console.askOkCancel(message, true);
                       
                     
                     
    -                  
    +                  
                         
                           
                           ${compiler:APPLICATION_CATEGORIES}
    @@ -798,7 +1821,7 @@ return console.askOkCancel(message, true);
                             
                           
                         
    -                    !Util.hasFullAdminRights() && !context.getBooleanVariable("sys.programGroupDisabled")
    +                    !context.getBooleanVariable("sys.programGroupDisabled")
                       
                       
                         
    @@ -821,7 +1844,7 @@ return console.askOkCancel(message, true);
                             
    - !Util.hasFullAdminRights() && context.getBooleanVariable("createDesktopLinkAction") + context.getBooleanVariable("createDesktopLinkAction") @@ -831,9 +1854,7 @@ return console.askOkCancel(message, true);
    - !Util.hasFullAdminRights() -&& -context.getBooleanVariable("addToDockAction") + context.getBooleanVariable("addToDockAction") @@ -841,13 +1862,53 @@ context.getBooleanVariable("addToDockAction") ${installer:sys.contentDir}\${compiler:WRAPPER_SCRIPT_BIN_DIR} Path - !Util.hasFullAdminRights() && context.getBooleanVariable("appendToPathAction") + context.getBooleanVariable("appendToPathAction") - + - ${installer:macWrapperLinkLocation} + ../Resources/app/${compiler:WRAPPER_SCRIPT_BIN_DIR}/${compiler:BASH_WRAPPER_SCRIPT} + + + + + ${installer:MacOSDir}/${compiler:WRAPPER_LINK} + + + + Util.isMacOS() && +( + context.getBooleanVariable("makeSymbolicLinkAction") + && context.getVariable("unixBinDir") != null + && context.getVariable("MacOSDir") != null +) + + + + + + ../Resources/app/${compiler:WRAPPER_SCRIPT_BIN_DIR}/${compiler:BASH_UPDATE_SCRIPT} + + + + + ${installer:MacOSDir}/update_${compiler:WRAPPER_LINK} + + + + Util.isMacOS() && +( + context.getBooleanVariable("makeSymbolicLinkAction") + && context.getVariable("unixBinDir") != null + && context.getVariable("MacOSDir") != null +) + + + + + + ${installer:MacOSDir}/${compiler:WRAPPER_LINK} @@ -856,12 +1917,31 @@ context.getBooleanVariable("addToDockAction")
    - Util.isMacOS() && !Util.hasFullAdminRights() // Admin on macOS will add path to /etc/paths.d -&& + Util.isMacOS() && ( context.getBooleanVariable("makeSymbolicLinkAction") && context.getVariable("unixBinDir") != null - && context.getVariable("macWrapperLinkLocation") != null + && context.getVariable("MacOSDir") != null +) + + + + + + ${installer:MacOSDir}/update_${compiler:WRAPPER_LINK} + + + + + ${installer:unixBinDir}/update_${compiler:WRAPPER_LINK} + + + + Util.isMacOS() && +( + context.getBooleanVariable("makeSymbolicLinkAction") + && context.getVariable("unixBinDir") != null + && context.getVariable("MacOSDir") != null ) @@ -875,7 +1955,7 @@ context.getBooleanVariable("addToDockAction") - + ${compiler:APPLICATION_CATEGORIES} ${compiler:JALVIEW_APPLICATION_NAME} @@ -922,7 +2002,7 @@ context.getBooleanVariable("addToDockAction") context.getBooleanVariable("createDesktopLinkAction") - + @@ -931,14 +2011,27 @@ context.getBooleanVariable("addToDockAction") context.getBooleanVariable("appendToPathAction") + + + + + String dir = (String)context.getVariable("sys.installationDir"); +String hash = getCanonicalFullPathToDirectoryHash(dir); +return (Object) hash; + + + + installationAppdirHash + + - /etc/paths.d/${compiler:APPLICATION_FOLDER} + /etc/paths.d/${compiler:APPLICATION_FOLDER}-${installer:installationAppdirHash} - /Applications/${compiler:JALVIEW_APPLICATION_NAME}.app/Contents/MacOS + ${installer:sys.installationDir}/${installer:sys.contentDir}/${compiler:JALVIEW_APPLICATION_NAME}.app/Contents/MacOS Util.isMacOS() @@ -946,7 +2039,7 @@ context.getBooleanVariable("addToDockAction") - + @@ -965,6 +2058,177 @@ context.getBooleanVariable("addToDockAction") + + + + + + + boolean advanced = context.getBooleanVariable("advancedOptions"); +boolean allowUser = context.getBooleanVariable("allowUserDefaultAppdirUpdates"); +boolean consoleDisableUserAppdir = context.getBooleanVariable("consoleDisableUserAppdir"); +if (consoleDisableUserAppdir) { + return true; +} +return advanced ? !allowUser : false; + + + disableUserDefaultAppdirUpdates + + + + + + + boolean advanced = context.getBooleanVariable("advancedOptions"); +boolean allowUser = context.getBooleanVariable("allowUserDefaultAppdirUpdates"); +boolean allowSetUserAppdirPath = context.getBooleanVariable("allowSetUserAppdirPath"); +String userAppdirPath = (String)context.getVariable("userAppdirPath"); +boolean saneValue = userAppdirPath != null && userAppdirPath.length() > 0; +boolean consoleAllowUserAppdirPath = context.getBooleanVariable("consoleAllowUserAppdirPath"); +if (consoleAllowUserAppdirPath && saneValue) { + return userAppdirPath; +} +return advanced && allowUser && allowSetUserAppdirPath && saneValue ? userAppdirPath : null; + + + setUserAppdirPath + + + + + + + boolean advanced = context.getBooleanVariable("advancedOptions"); +boolean allowUser = context.getBooleanVariable("allowUserDefaultAppdirUpdates"); +boolean allowInstaller = context.getBooleanVariable("allowInstallerAppdirUpdates"); +boolean consoleDisableAllUpdates = context.getBooleanVariable("consoleDisableAllUpdates"); +if (consoleDisableAllUpdates) { + return true; +} +return advanced ? !( allowUser || allowInstaller ) : false; + + + disableUpdates + + + + + + + String file = (String)context.getVariable("sys.mediaFile"); +int i = file.lastIndexOf(File.separator); +return file.substring(i+1); + + + installerFilename + + + + + + + String date = (String)context.getVariable("sys.date"); +String time = (String)context.getVariable("sys.time"); +StringBuilder sb = new StringBuilder(); +sb.append(date.substring(0,4)); +sb.append("-"); +sb.append(date.substring(4,6)); +sb.append("-"); +sb.append(date.substring(6,8)); +sb.append(" "); +sb.append(time.substring(0,2)); +sb.append(":"); +sb.append(time.substring(2,4)); +sb.append(":"); +sb.append(time.substring(4,6)); +return sb.toString(); + + + + installDateTime + + + + + 2823 + + # Jalview options added by ${installer:installerFilename} at ${installer:installDateTime} + + + + + + 2823 + + # + # Uncomment the following line to disable user-space updates + #-Dnouserdefaultappdir=true + + + !context.getBooleanVariable("disableUserDefaultAppdirUpdates") + + + + 2823 + + # + # Comment out the following line to allow user-space updates + -Dnouserdefaultappdir=true + + + context.getBooleanVariable("disableUserDefaultAppdirUpdates") + + + + 2823 + + # + # The below line sets a custom path for user-space updates -- use with caution. + # A leading ~/ or %h anywhere will be substituted with the user's home path, and %u by the username. + # If unset, the default is ${installer:userDefaultAppdirBase} for ${installer:osName} + -Dsetuserappdirpath=${installer:setUserAppdirPath} + + + (String)context.getVariable("setUserAppdirPath") != null + + + + 2823 + + # + # Uncomment the below line to set a custom path for user-space updates -- use with caution. + # A leading ~/ or %h anywhere will be substituted with the user's home path, and %u by the username. + # If not set, the default is ${installer:userDefaultAppdirBase} for ${installer:osName} + #-Dsetuserappdirpath=/tmp/jalview/%u + + + (String)context.getVariable("setUserAppdirPath") == null + + + + 2823 + + # + # Uncomment the following line to also disable all updates + #-Dsilent=noupdate + + + !context.getBooleanVariable("disableUpdates") + + + + 2823 + + # + # Comment out the following line to enable updates + -Dsilent=noupdate + + + context.getBooleanVariable("disableUpdates") + + + @@ -981,7 +2245,7 @@ context.getBooleanVariable("addToDockAction") - Util.isLinux() || Util.isMacOS() + Util.isLinux() || ( Util.isMacOS() && !Util.isUnixInstaller() ) @@ -997,14 +2261,14 @@ context.getBooleanVariable("addToDockAction") - (Util.isLinux() || Util.isMacOS()) + ( Util.isLinux() || ( Util.isMacOS() && !Util.isUnixInstaller() ) ) && !((String)context.getCompilerVariable("JALVIEW_APPLICATION_NAME")).equals((String)context.getCompilerVariable("JALVIEW_NAME")) - + @@ -1019,48 +2283,41 @@ context.getBooleanVariable("addToDockAction") Util.isLinux() || Util.isUnixInstaller() || Util.isMacOS() - - - - - + - + - ${compiler:WRAPPER_SCRIPT_BIN_DIR}/${compiler:WRAPPER_LINK}.bat + ${compiler:WRAPPER_SCRIPT_BIN_DIR}/${compiler:BASH_UPDATE_SCRIPT} - - - - ${compiler:WRAPPER_SCRIPT_BIN_DIR}/${compiler:BATCH_WRAPPER_SCRIPT} - - - - - Util.isWindows() && !(((String)context.getCompilerVariable("WRAPPER_LINK")+".bat").equals((String)context.getCompilerVariable("BATCH_WRAPPER_SCRIPT"))) - - - - + - ${compiler:WRAPPER_SCRIPT_BIN_DIR}/${compiler:WRAPPER_LINK}.ps1 + ${compiler:WRAPPER_SCRIPT_BIN_DIR}/${compiler:WRAPPER_LINK}_update - - - - ${compiler:WRAPPER_SCRIPT_BIN_DIR}/${compiler:POWERSHELL_WRAPPER_SCRIPT} - - - - Util.isWindows() && !(((String)context.getCompilerVariable("WRAPPER_LINK")+".ps1").equals((String)context.getCompilerVariable("POWERSHELL_WRAPPER_SCRIPT"))) + Util.isLinux() || Util.isUnixInstaller() || Util.isMacOS() + + + + + + + + + + + + + <strong>Administrator mode</strong> + + context.getBooleanVariable("isAdmin") + ${i18n:WizardPreparing} @@ -1070,6 +2327,12 @@ context.getBooleanVariable("addToDockAction") + + + <strong>Administrator mode</strong> + + context.getBooleanVariable("isAdmin") + ${form:finishedMessage} @@ -1468,7 +2731,7 @@ return console.askYesNo(message, true); ( Util.isLinux() || Util.isUnixInstaller() || ( Util.isMacOS() - && context.getVariable("macWrapperLinkLocation") != null + && context.getVariable("MacOSDir") != null ) ) && context.getVariable("unixBinDir") != null @@ -1514,7 +2777,7 @@ ${compiler:JALVIEW_APPLICATION_NAME} will now launch. - + @@ -1765,9 +3028,13 @@ ${compiler:JALVIEW_APPLICATION_NAME} will now launch. + + + + @@ -1786,9 +3053,13 @@ ${compiler:JALVIEW_APPLICATION_NAME} will now launch. + + + + @@ -1802,7 +3073,7 @@ ${compiler:JALVIEW_APPLICATION_NAME} will now launch. - + @@ -1817,7 +3088,7 @@ ${compiler:JALVIEW_APPLICATION_NAME} will now launch. - + @@ -1844,13 +3115,7 @@ ${compiler:JALVIEW_APPLICATION_NAME} will now launch. - - - - - - - - + + diff --git a/utils/install4j/macos-install-jalview.sh b/utils/install4j/macos-install-jalview.sh new file mode 100755 index 0000000..60dc70c --- /dev/null +++ b/utils/install4j/macos-install-jalview.sh @@ -0,0 +1,414 @@ +#!/usr/bin/env bash + +usage() { + echo "Usage: $( basename $0 ) [-h] [ [-d] [-m arch] [-c channel] | [-i filename] ] [-a folder] [-u] [-U] [-S] [-P] [-R]" + echo "" + echo " This script downloads and installs Jalview in macOS, or installs from a previously downloaded Jalview DMG file." + echo " One of -d or -i should be specified, whichever comes last is used." + echo " Default behaviour with -d is to download the latest release version of Jalview for your architecture and install" + echo " the .app in /Applications with user-space updates enabled." + echo " These can be adjusted with the following options." + echo "" + echo " -h Show help" + echo " -d Download the latest DMG for the channel" + echo " -m arch (with -d) Download specific JVM architecture. Should be one of 'arm64' or 'x86_64' (defaults to \`uname -m\`)" + echo " -c channel (with -d) Download from channel. Should be one of 'release', 'test-release', 'develop' (defaults to 'release')." + echo " -i filename Use filename as DMG image file instead of downloading." + echo " -a folder Install the application .app bundle in folder (default '/Applications')." + echo " -v Verbose output." + echo " -y Assume 'yes' to confirmation." + echo " -q No output other than errors. Assumes -y." + echo "" + echo " Advanced options:" + echo "" + echo " -u template Use template for user-space updates path (defaults to '~/Library/Application Support/Jalview-Desktop')." + echo " template should contain one of: a leading '~/', '%u' (user's username) or '%h' (user's home path)." + echo " -U Disable user-space updates (updates will be attempted in the installation folder)." + echo " -S Disable all user-space and installation updates." + echo " -P Do not add the jalview command-line path to /etc/paths.d." + echo " -R Do not perform the check for root privileges." + echo " -t tmpdir Use tmpdir for installation files (defaults to /tmp)" +} + +# check OS +UOS="$(uname -s)" +if [ "$UOS" != "Darwin" ]; then + echo "This install script is for macOS." + echo "Jalview can be installed on other OSes using the installers found at" + echo "https://www.jalview.org/download/" + exit 1 +fi + +# set defaults +DOWNLOAD=0 +UARCH=$(uname -m) +CHANNEL="release" +DMGFILE="" +INSTALLERNAME="$(basename $0)" +APPLICATIONFOLDER="/Applications" +VERBOSE=0 +YES=0 +QUIET=0 +USERAPPDIRTEMPLATE="" +DISABLEUSERAPPDIR=0 +DISABLEALLUPDATES=0 +DISABLEGLOBALPATH=0 +DISABLEROOTCHECK=0 +USETEMPDIR="" +TMP="/tmp" + +CURLOPT="" +RSYNCOPT="" +DITTOOPT="" +HDIUTILOPT="-quiet" + +# set options +while getopts "hdi:a:vyqu:c:USPR" opt; do + case ${opt} in + h) + usage + exit 0 + ;; + d) + DOWNLOAD=1 + ;; + m) + UARCH="${OPTARG}" + ;; + c) + CHANNEL="${OPTARG}" + ;; + i) + DMGFILE="${OPTARG}" + DOWNLOAD=0 + ;; + a) + APPLICATIONFOLDER="${OPTARG}" + ;; + v) + VERBOSE=1 + CURLOPT="-v" + RSYNCOPT="-v" + DITTOOPT="-V" + HDIUTILOPT="-verbose" + ;; + y) + YES=1 + ;; + q) + QUIET=1 + CURLOPT="-s" + RSYNCOPT="-q" + HDIUTILOPT="-quiet" + YES=1 + ;; + u) + USERAPPDIRTEMPLATE="${OPTARG}" + ;; + U) + DISABLEUSERAPPDIR=1 + ;; + S) + DISABLEALLUPDATES=1 + ;; + P) + DISABLEGLOBALPATH=1 + ;; + R) + DISABLEROOTCHECK=1 + ;; + t) + TMP="${OPTARG}" + ;; + *) + echo "Unrecognised option. Run with -h for help." + exit 2 + ;; + esac +done + +myecho() { + if [ "${QUIET}" != 1 ]; then + echo "* $1" + fi +} + +# no -d or -i arguments +if [ "${DOWNLOAD}" = 0 -a -z "${DMGFILE}" ]; then + echo "Please use one of -d or -i options" + echo "" + usage + exit 0 +fi + +# root permissions check +if [ "${DISABLEROOTCHECK}" != 1 -a "${EUID}" != 0 ]; then + echo "This script should be run with root permissions, or disable this root check with -R." + exit 5 +fi + +# check channel +if [ ! -z "$DMGFILE" -a -e "$DMGFILE" ]; then + myecho "Using DMG file '${DMGFILE}'" + CHANNEL="dmg" +else + case "$CHANNEL" in + release|test-release|develop) + myecho "Using channel ${CHANNEL}" + ;; + *) + echo "-c channel must be one of 'release', 'test-release' or 'develop'" + exit 3 + ;; + esac +fi + +# convert uarch to jarch +case $UARCH in + x86_64) + JARCH=x64 + ;; + arm64) + JARCH=aarch64 + ;; + *) + echo "Unknown architecture '$UARCH'. Exiting." + exit 4; + ;; +esac + +# dir for downloads and volume mount +TEMPDIR=$(mktemp -d -p "${TMP}" -t "${INSTALLERNAME%.sh}_${CHANNEL}") +if [ "${DOWNLOAD}" = 1 ]; then + myecho "Using directory '${TEMPDIR}' to download and mount disk image" +else + myecho "Using directory '${TEMPDIR}' to mount disk image" +fi +FILEBASE="${TEMPDIR}/jalview-${CHANNEL}-latest-macos-${JARCH}" +VOLUMEDIR="${FILEBASE}.vol" + +# Confirmation of what's about to happen +if [ "${YES}" != 1 ]; then + if [ "${DOWNLOAD}" = 1 ]; then + myecho "This script will download Jalview from the '${CHANNEL}' channel and install it into the '${APPLICATIONFOLDER}' folder." + else + myecho "This script will install Jalview from the '${DMGFILE}' disk image file into the '${APPLICATIONFOLDER}' folder." + fi + + read -r -p "Continue? [y/N] " response + case $(echo "${response}" | tr '[:upper:]' '[:lower:]') in + yes|y) + myecho "Excellent! Continuing." + ;; + *) + echo "Aborting due to negative confirmation." && exit + ;; + esac +fi + +if [ "${DOWNLOAD}" = 1 ]; then + DMGFILE="${FILEBASE}.dmg" + SHA256="" + + URL="https://www.jalview.org/downloads/${CHANNEL}/installer/macos-${JARCH}" + + myecho "Downloading '${URL}' to '${DMGFILE}'" + curl ${CURLOPT} -f -L -o "${DMGFILE}" "${URL}" + [ $? != 0 ] && echo "Could not download '$URL' to '$DMGFILE'" && exit 6 + SHA256=$( curl ${CURLOPT} -f -s -L "${URL}.sha256" ) + [ $? != 0 ] && echo "Could not download '$URL.sha256'" && exit 7 + + CHECK=$( shasum -a 256 "${DMGFILE}" | cut -d" " -f1 ) + if [ "${CHECK}" = "${SHA256}" ]; then + myecho "Downloaded file '$DMGFILE' checksum matches downloaded checksum '$SHA256'" + else + echo "Downloaded file '$DMGFILE' checksum does not match downloaded checksum '$SHA256'" + exit 8 + fi +fi + +# mount the DMG image +myecho "Mounting disk image '${DMGFILE}' on '${VOLUMEDIR}'" +hdiutil attach ${HDIUTILOPT} -mountpoint "${VOLUMEDIR}" "${DMGFILE}" +[ $? != 0 ] && echo "Could not mount '${DMGFILE}' on mount point '${VOLUMEDIR}'" && exit 9 + +myecho "MOUNTED" + +# difficult to use a wildcard for a non-user-readable folder without inserting sudo directly into the command +# i.e. what I really want to do here is +# APP=$( sudo sh -c "ls -1d ${VOLUMEDIR}/Jalview*.app" | head -1 ) +# but don't want to put sudo in the script because of the -R option. We'll loop through instead. +VOLUMEFILES=$( ls -1 ${VOLUMEDIR} ) +while IFS= read -r VOLUMEFILE; do + FILE=$( basename "${VOLUMEFILE}" ) + if [ "$FILE" != "${FILE#Jalview}" -a "$FILE" != "${FILE%.app}" ]; then + APP="$FILE" + break + fi +done <<< "$VOLUMEFILES" +[ -z "$APP" ] && echo "Could not find Jalview\*.app in the volume '${VOLUMEDIR}'" && exit 10 + +APPNAME=$( basename "$APP" ) +myecho "Found application '${APP}'" + +# ensure no trailing slash on APPNAME or APPLICATIONFOLDER (important for rsync) +while [ "${APPLICATIONFOLDER}" != "${APPLICATIONFOLDER%/}" -a "${APPLICATIONFOLDER}" != "/" ]; do + myecho "Removing trailing slash from APPLICATIONFOLDER='${APPLICATIONFOLDER}'" + APPLICATIONFOLDER="${APPLICATIONFOLDER%/}" +done +while [ "${APPNAME}" != "${APPNAME%/}" ]; do + myecho "Removing trailing slash from APPNAME='${APPNAME}'" + APPNAME=${APPNAME%/} +done +[ -z "$APPNAME" -o "${APPNAME%.app}" = "$APPNAME" ] && echo "Could not find suitable Jalview\*.app in the volume '${VOLUMEDIR}'" && exit 11 + +## rsync .app from mounted volume to application folder +#myecho "Rsyncing '${VOLUMEDIR}/${APPNAME}' to '${APPLICATIONFOLDER}/${APPNAME}'" +#rsync ${RSYNCOPT} -ah --delete "${VOLUMEDIR}/${APPNAME}" "${APPLICATIONFOLDER}/" +#[ $? != 0 ] && echo "Possible problem when rsyncing '${APP}' to '${APPLICATIONFOLDER}'" && exit 12 +#myecho "Finished rsync" + +# using ditto +APPPATH="${APPLICATIONFOLDER}/${APPNAME}" +OLDAPPPATH="${APPPATH}.old" +myecho "Copying '${VOLUMEDIR}/${APPNAME}' to '${APPPATH}'" +if [ -e "$APPPATH" ]; then + if [ -e "$OLDAPPPATH" ]; then + rm -Rf "$OLDAPPPATH" + fi + mv "$APPPATH" "$OLDAPPPATH" +fi +ditto ${DITTOOPT} "${VOLUMEDIR}/${APPNAME}" "$APPPATH" && [ -e "$OLDAPPPATH" ] && rm -Rf "$OLDAPPPATH" +myecho "Finished copying '${APPNAME}'" + +EXIT=0 +declare -a WARNINGS=() +addwarning() { + local W=$1 + local N=$2 + myecho "${W}" + WARNINGS=( "${WARNINGS[@]}" "${W}" ) + # exit with the first warning value + [ "${EXIT}" = 0 ] && EXIT=$N +} + +# unmount the DMG image +myecho "Unmounting '${VOLUMEDIR}'" +hdiutil detach ${HDIUTILOPT} "${VOLUMEDIR}" || addwarning "Possible problem when unmounting/deleting '${VOLUMEDIR}'. I'm continuing the install but you should look at it later." 13 + +# delete the image file and temp dir +if [ "${DOWNLOAD}" = 1 ]; then + myecho "Deleting downloaded disk image file '${DMGFILE}'" + rm "${DMGFILE}" +fi +myecho "Removing temporary directory '${TEMPDIR}'" +rmdir "${TEMPDIR}" + +VMOPTIONS="${APPLICATIONFOLDER}/${APPNAME}/Contents/vmoptions.txt" + +VMOPTIONS_START="" +if [ -e "${VMOPTIONS}" ]; then + while IFS= read -r line; do + VMOPTIONS_START="${VMOPTIONS_START}${line}"$'\n' + if [ "${line}" != "${line/Jalview/}" ]; then # i.e. $line contains "Jalview" + break + fi + done < "${VMOPTIONS}" +fi + +LONGHASH=$( printf %s "${APPLICATIONFOLDER}/${APPNAME}/Contents/Resources/app" | shasum -a 256 -b ) +HASH=${LONGHASH:0:8} +NAME=${APPNAME%.app} + +myecho "Writing vmoptions files '${VMOPTIONS}'" +VMOPTIONS_COMMENT=$( cat << EOM +# Jalview options added by $( basename $0 ) at $( date +"%F %T") +EOM +) + +# -Dnouserdefaultappdir=false +if [ "${DISABLEUSERAPPDIR}" = 1 ]; then + myecho "- User-space updates DISABLED" + VMOPTIONS_USERAPPDIR=$( cat << EOM +# +# Comment out the following line to allow user-space updates +-Dnouserdefaultappdir=true +EOM +) +else + myecho "- User-space updates enabled" + VMOPTIONS_USERAPPDIR=$( cat << EOM +# +# Uncomment the following line to disable user-space updates +#-Dnouserdefaultappdir=true +EOM +) +fi + +# -Dsetuserappdirpath +if [ -z "${USERAPPDIRTEMPLATE}" ]; then + myecho "- Default user-space updates path (~/Library/Application Support/Jalview-Desktop/${NAME}/${HASH})" + VMOPTIONS_USERAPPDIRPATH=$( cat << EOM +# +# Uncomment the below line to set a custom path for user-space updates -- use with caution. +# A leading ~/ or %h anywhere will be substituted with the user's home path, and %u by the username. +# If not set, the default is ~/Library/Application Support/Jalview-Desktop for macOS +#-Dsetuserappdirpath=/tmp/jalview/%u +EOM +) +else + myecho "- CUSTOMISED user-space updates path (${USERAPPDIRTEMPLATE})" + VMOPTIONS_USERAPPDIRPATH=$( cat << EOM +# +# The below line sets a custom path for user-space updates -- use with caution. +# A leading ~/ or %h anywhere will be substituted with the user's home path, and %u by the username. +# If unset, the default is ~/Library/Application Support/Jalview-Desktop for macOS +-Dsetuserappdirpath=${USERAPPDIRTEMPLATE} +EOM +) +fi + +# -Dsilent=noupdate +if [ "${DISABLEALLUPDATES}" = 1 ]; then + myecho "- All automatic updates DISABLED" + VMOPTIONS_UPDATES=$( cat << EOM +# +# Comment out the following line to enable updates +-Dsilent=noupdate +EOM +) +else + if [ "${DISABLEUSERAPPDIR}" = 1 ]; then + myecho "- Automatic updates enabled IN INSTALLATION" + else + myecho "- Automatic updates enabled in user-space" + fi + VMOPTIONS_UPDATES=$( cat << EOM +# +# Uncomment the following line to also disable all updates +#-Dsilent=noupdate +EOM +) +fi + +printf "%s\n%s\n%s\n%s\n%s\n" "${VMOPTIONS_START}" "${VMOPTIONS_COMMENT}" "${VMOPTIONS_USERAPPDIR}" "${VMOPTIONS_USERAPPDIRPATH}" "${VMOPTIONS_UPDATES}" > "${VMOPTIONS}" || addwarning "Possible problem adding options to '${VMOPTIONS}'" 14 + +# set a global path in /etc/paths.d +if [ "${DISABLEGLOBALPATH}" != 1 ]; then + US_NAME="${NAME// /_}" + PATHFILE="/etc/paths.d/${US_NAME}-${HASH}" + myecho "Writing global PATH to '${PATHFILE}'" + echo "${APPLICATIONFOLDER}/${APPNAME}/Contents/MacOS" > "${PATHFILE}" || addwarning "Possible problem writing path file '${PATHFILE}'" 15 +fi + +# show accumulated warnings +if [ "${#WARNINGS[@]}" != 0 ]; then + myecho "-----------------" + myecho "Installation complete." + myecho "Warnings summary:" + myecho "$( printf -- '- %s\n' "${WARNINGS[@]}" )" +else + myecho "Successful installation!" +fi + +exit $EXIT diff --git a/utils/install4j/warning.png b/utils/install4j/warning.png new file mode 100644 index 0000000..2063df2 Binary files /dev/null and b/utils/install4j/warning.png differ diff --git a/utils/osx_signing/sign_dmg.sh b/utils/osx_signing/sign_dmg.sh new file mode 100755 index 0000000..1b3973c --- /dev/null +++ b/utils/osx_signing/sign_dmg.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +if [[ "$GITDIR" == "" ]]; then + GITDIR=~/uod-development/jalview-builds/git/jalview +fi; + +if [[ "$DEVELOPERID" == "" ]]; then + DEVELOPERID="Developer ID" +fi; + +if [[ "$TMPDMG" == "" ]]; then + TMPDMG="signingDMG" +fi; + +echo APPNAME $APPNAME like Jalview Test +echo doing ARCH $ARCH +echo using entitlements from $GITDIR +echo using key $DEVELOPERID + +FAPPNAME="${APPNAME/ /\\ }" +FAPPNAMEESC="${APPNAME/ /\\\\\\ }" +FWAPP="${APPNAME/ [A-Za-z]*/}" +ARCHNAME="${APPNAME// /_}-${APPVER//\./_}-macos-$ARCH-java_$JVER" +DMGNAME="${APPNAME/ /_}-${APPVER//\./_}-macos-$ARCH-java_$JVER.dmg" +VOLNAME="${APPNAME// /_}\\ Installer\\ \\(${APPVER//\./_}\\ $ARCH\\ $JVER\\)" +VLNAME="${APPNAME// /_} Installer (${APPVER//\./_} $ARCH $JVER)" +BORINGVLNAME="${APPNAME} Installer" + + + +echo "will mount $DMGNAME as $VOLNAME" +if [[ -d $TMPDMG ]]; then + echo "'$TMPDMG' is in the way. Please delete it or set TMPDMG" + exit 1; +fi + +if [[ -f $DMGNAME ]]; then + hdiutil attach $DMGNAME + ditto /Volumes/${FWAPP}* $TMPDMG + hdiutil eject /Volumes/${FWAPP}* + mkdir -p unsigned + mv -v $DMGNAME unsigned/ + echo Moved $DMGNAME to unsigned/$DMGNAME + codesign --remove-signature --force --deep -vvvv -s "Developer ID" --options runtime --entitlements $GITDIR/utils/osx_signing/entitlements.txt $TMPDMG/${FWAPP}*.app/Contents/Resources/app/jre/Contents/MacOS/libjli.dylib + + codesign --verify --deep -v ./$TMPDMG/${FWAPP}*.app/Contents/Resources/app/jre/Contents/MacOS/libjli.dylib + + codesign --remove-signature --force --deep -vvvv -s "Developer ID" --options runtime --entitlements $GITDIR/utils/osx_signing/entitlements.txt $TMPDMG/${FWAPP}*.app/Contents/MacOS/JavaApplicationStub + + hdiutil create -megabytes 260 -srcfolder ./$TMPDMG -volname "$BORINGVLNAME" $ARCHNAME.dmg + + codesign --force --deep -vvvv -s "Developer ID" --options runtime --entitlements $GITDIR/utils/osx_signing/entitlements.txt $ARCHNAME.dmg + + codesign --deep -vvvv $ARCHNAME.dmg + + rm -Rf $TMPDMG +else + echo Can\'t find $DMGNAME - dit you set APPNAME APPVER ARCH and JVER correctly ? +fi + diff --git a/utils/osx_signing/staple_dmg.sh b/utils/osx_signing/staple_dmg.sh new file mode 100755 index 0000000..0eb24dc --- /dev/null +++ b/utils/osx_signing/staple_dmg.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +if [[ "$GITDIR" == "" ]]; then + GITDIR=~/uod-development/jalview-builds/git/jalview +fi; + + +if [[ "$DEVELOPERID" == "" ]]; then + DEVELOPERID="Developer ID" +fi; + +if [[ "$TMPDMG" == "" ]]; then + TMPDMG="staplingDMG" +fi; + + +echo APPNAME $APPNAME like Jalview Test +echo doing ARCH $ARCH +echo using entitlements from $GITDIR + +FAPPNAME="${APPNAME/ /\\ }" +FAPPNAMEESC="${APPNAME/ /\\\\\\ }" +FWAPP="${APPNAME/ [A-Za-z]*/}" +ARCHNAME="${APPNAME// /_}-${APPVER//\./_}-macos-$ARCH-java_$JVER" +DMGNAME="${APPNAME/ /_}-${APPVER//\./_}-macos-$ARCH-java_$JVER.dmg" +VOLNAME="${APPNAME// /_}\\ Installer\\ \\(${APPVER//\./_}\\ $ARCH\\ $JVER\\)" +VLNAME="${APPNAME// /_} Installer (${APPVER//\./_} $ARCH $JVER)" +BORINGVLNAME="${APPNAME} Installer" +echo "will mount $DMGNAME as $VOLNAME" + +if [[ -d $TMPDMG ]]; then + echo "'$TMPDMG' is in the way. Please delete it or set TMPDMG" + exit 1; +fi + +if [[ -f $DMGNAME ]]; then + hdiutil attach $DMGNAME + ditto /Volumes/${FWAPP}* $TMPDMG + hdiutil eject /Volumes/${FWAPP}* + xcrun stapler staple $TMPDMG/${FWAPP}*.app + mkdir -p stapled + hdiutil create -megabytes 240 -srcfolder $TMPDMG -volname "$BORINGVLNAME" stapled/$DMGNAME + codesign --force --deep -vvvv -s "$DEVELOPERID" --options runtime --entitlements ${GITDIR}/utils/osx_signing/entitlements.txt stapled/$DMGNAME + codesign --deep -vvvv stapled/$DMGNAME + echo "Stapled DMG is in stapled/$DMGNAME" + rm -Rf $TMPDMG +else + echo Can\'t find $DMGNAME - dit you set APPNAME APPVER ARCH and JVER correctly ? +fi +