jetty-io-9.2.10.v20150310.jar
jetty-server-9.2.10.v20150310.jar
jetty-util-9.2.10.v20150310.jar
-jfreesvg-2.1.jar GPL v3 licensed library from the JFree suite - http://www.jfree.org/jfreesvg/
+jfreesvg-3.4.3.jar GPL v3 licensed library from the JFree suite - last release with Java 1.8 compatibility http://www.jfree.org/jfreesvg/
JGoogleAnalytics_0.3.jar APL 2.0 License - http://code.google.com/p/jgoogleanalytics/
jhall.jar
Jmol-NO_LOG4J-14.31.53.jar GPL/LGPLv2 built manually from commit https://github.com/BobHanson/Jmol-SwingJS/commit/a6a2fb767e3fc2a73e72d926a11fd93a0e4c9f23 (excluded jspecview/application to compile)
import org.gradle.plugins.ide.eclipse.model.Library
import java.security.MessageDigest
import java.util.regex.Matcher
+import java.util.concurrent.Executors
+import java.util.concurrent.Future
+import java.util.concurrent.ScheduledExecutorService
+import java.util.concurrent.TimeUnit
import groovy.transform.ExternalizeMethods
import groovy.util.XmlParser
import groovy.xml.XmlUtil
jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
jalviewjsJ2sProps = null
jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
+ jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
eclipseWorkspace = null
eclipseBinary = string("")
eclipseVersion = string("")
eclipseDebug = false
+
+ jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
+ jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
+
// ENDEXT
}
}
+task jalviewjsCopyStderrLaunchFile(type: Copy) {
+ from file(jalviewjs_stderr_launch)
+ into jalviewjsSiteDir
+
+ inputs.file jalviewjs_stderr_launch
+ outputs.file jalviewjsStderrLaunchFilename
+}
+
+task cleanJalviewjsChromiumUserDir {
+ doFirst {
+ delete jalviewjsChromiumUserDir
+ }
+ outputs.dir jalviewjsChromiumUserDir
+ // always run when depended on
+ outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
+}
+
+task jalviewjsChromiumProfile {
+ dependsOn cleanJalviewjsChromiumUserDir
+ mustRunAfter cleanJalviewjsChromiumUserDir
+
+ def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
+
+ doFirst {
+ mkdir jalviewjsChromiumProfileDir
+ firstRun.text = ""
+ }
+ outputs.file firstRun
+}
+
+task jalviewjsLaunchTest {
+ group "Test"
+ description "Check JalviewJS opens in a browser"
+ dependsOn jalviewjsBuildSite
+ dependsOn jalviewjsCopyStderrLaunchFile
+ dependsOn jalviewjsChromiumProfile
+
+ def macOS = OperatingSystem.current().isMacOsX()
+ def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
+ if (chromiumBinary.startsWith("~/")) {
+ chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
+ }
+
+ def stdout
+ def stderr
+ doFirst {
+ def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
+
+ def binary = file(chromiumBinary)
+ if (!binary.exists()) {
+ throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
+ }
+ stdout = new ByteArrayOutputStream()
+ stderr = new ByteArrayOutputStream()
+ def execStdout
+ def execStderr
+ if (jalviewjs_j2s_to_console.equals("true")) {
+ execStdout = new org.apache.tools.ant.util.TeeOutputStream(
+ stdout,
+ System.out)
+ execStderr = new org.apache.tools.ant.util.TeeOutputStream(
+ stderr,
+ System.err)
+ } else {
+ execStdout = stdout
+ execStderr = stderr
+ }
+ def execArgs = [
+ "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
+ "--headless=new",
+ "--disable-gpu",
+ "--timeout=${timeoutms}",
+ "--virtual-time-budget=${timeoutms}",
+ "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
+ "--profile-directory=${jalviewjs_chromium_profile_name}",
+ "--allow-file-access-from-files",
+ "--enable-logging=stderr",
+ "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
+ ]
+
+ if (true || macOS) {
+ ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
+ Future f1 = executor.submit(
+ () -> {
+ exec {
+ standardOutput = execStdout
+ errorOutput = execStderr
+ executable(chromiumBinary)
+ args(execArgs)
+ println "COMMAND: '"+commandLine.join(" ")+"'"
+ }
+ executor.shutdownNow()
+ }
+ )
+
+ def noChangeBytes = 0
+ def noChangeIterations = 0
+ executor.scheduleAtFixedRate(
+ () -> {
+ String stderrString = stderr.toString()
+ // shutdown the task if we have a success string
+ if (stderrString.contains(jalviewjs_desktop_init_string)) {
+ f1.cancel()
+ Thread.sleep(1000)
+ executor.shutdownNow()
+ }
+ // if no change in stderr for 10s then also end
+ if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
+ executor.shutdownNow()
+ }
+ if (stderrString.length() == noChangeBytes) {
+ noChangeIterations++
+ } else {
+ noChangeBytes = stderrString.length()
+ noChangeIterations = 0
+ }
+ },
+ 1, 1, TimeUnit.SECONDS)
+
+ executor.schedule(new Runnable(){
+ public void run(){
+ f1.cancel()
+ executor.shutdownNow()
+ }
+ }, timeoutms, TimeUnit.MILLISECONDS)
+
+ executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
+ executor.shutdownNow()
+ }
+
+ }
+
+ doLast {
+ def found = false
+ stderr.toString().eachLine { line ->
+ if (line.contains(jalviewjs_desktop_init_string)) {
+ println("Found line '"+line+"'")
+ found = true
+ return
+ }
+ }
+ if (!found) {
+ throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
+ }
+ }
+}
+
+
task jalviewjs {
group "JalviewJS"
- description "Build the site"
+ description "Build the JalviewJS site and run the launch test"
dependsOn jalviewjsBuildSite
+ dependsOn jalviewjsLaunchTest
}
-
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE rnaml SYSTEM "rnaml.dtd">
+
+<rnaml version="1.0">
+
+ <molecule id="1">
+ <sequence>
+ <numbering-system id="1" used-in-file="false">
+ <numbering-range>
+ <start>1</start>
+ <end>20</end>
+ </numbering-range>
+ </numbering-system>
+ <numbering-table length="20" comment="sequence number in pdb file">
+ 1 2 3 4 5 6 7 8 9 10
+ 11 12 13 14 15 16 17 18 19 20
+
+ </numbering-table>
+ <seq-data>
+ GUUAGCAGCC GCAUAGGCUG
+ </seq-data>
+ <seq-annotation comment="?">
+ <segment>
+ <seg-name>LOOP1</seg-name>
+ <base-id-5p><base-id><position>12</position></base-id></base-id-5p>
+ <base-id-3p><base-id><position>14</position></base-id></base-id-3p>
+ </segment>
+ </seq-annotation>
+ </sequence>
+ <structure>
+ <model id="?">
+ <model-info>
+ <method>Crystallography ?</method>
+ <resolution>? Angstroms</resolution>
+ </model-info>
+ <base>
+ <position>1</position>
+ <base-type>G</base-type>
+ <atom serial="1">
+ <atom-type> P </atom-type>
+ <coordinates>7.232 28.529 -12.305</coordinates>
+ </atom>
+ <atom serial="9">
+ <atom-type> O3'</atom-type>
+ <coordinates>4.752 23.963 -11.820</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>2</position>
+ <base-type>U</base-type>
+ <atom serial="24">
+ <atom-type> P </atom-type>
+ <coordinates>3.868 23.252 -12.962</coordinates>
+ </atom>
+ <atom serial="32">
+ <atom-type> O3'</atom-type>
+ <coordinates>0.983 18.432 -13.409</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>3</position>
+ <base-type>U</base-type>
+ <atom serial="44">
+ <atom-type> P </atom-type>
+ <coordinates>1.438 17.540 -14.670</coordinates>
+ </atom>
+ <atom serial="52">
+ <atom-type> O3'</atom-type>
+ <coordinates>-1.417 16.962 -19.633</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>4</position>
+ <base-type>A</base-type>
+ <atom serial="64">
+ <atom-type> P </atom-type>
+ <coordinates>-2.710 16.020 -19.430</coordinates>
+ </atom>
+ <atom serial="72">
+ <atom-type> O3'</atom-type>
+ <coordinates>-7.138 19.555 -19.112</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>5</position>
+ <base-type>G</base-type>
+ <atom serial="86">
+ <atom-type> P </atom-type>
+ <coordinates>-7.829 20.393 -20.298</coordinates>
+ </atom>
+ <atom serial="94">
+ <atom-type> O3'</atom-type>
+ <coordinates>-11.316 24.166 -18.659</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>6</position>
+ <base-type>C</base-type>
+ <atom serial="109">
+ <atom-type> P </atom-type>
+ <coordinates>-12.021 24.790 -19.958</coordinates>
+ </atom>
+ <atom serial="117">
+ <atom-type> O3'</atom-type>
+ <coordinates>-14.686 21.023 -22.223</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>7</position>
+ <base-type>A</base-type>
+ <atom serial="129">
+ <atom-type> P </atom-type>
+ <coordinates>-16.102 21.690 -22.577</coordinates>
+ </atom>
+ <atom serial="137">
+ <atom-type> O3'</atom-type>
+ <coordinates>-20.284 18.901 -22.582</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>8</position>
+ <base-type>G</base-type>
+ <atom serial="151">
+ <atom-type> P </atom-type>
+ <coordinates>-21.555 19.844 -22.854</coordinates>
+ </atom>
+ <atom serial="159">
+ <atom-type> O3'</atom-type>
+ <coordinates>-26.285 20.028 -19.599</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>9</position>
+ <base-type>C</base-type>
+ <atom serial="174">
+ <atom-type> P </atom-type>
+ <coordinates>-27.355 21.190 -19.880</coordinates>
+ </atom>
+ <atom serial="182">
+ <atom-type> O3'</atom-type>
+ <coordinates>-30.900 21.877 -16.104</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>10</position>
+ <base-type>C</base-type>
+ <atom serial="194">
+ <atom-type> P </atom-type>
+ <coordinates>-31.737 23.147 -16.621</coordinates>
+ </atom>
+ <atom serial="202">
+ <atom-type> O3'</atom-type>
+ <coordinates>-33.685 26.755 -13.690</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>11</position>
+ <base-type>G</base-type>
+ <atom serial="214">
+ <atom-type> P </atom-type>
+ <coordinates>-34.360 27.602 -14.877</coordinates>
+ </atom>
+ <atom serial="222">
+ <atom-type> O3'</atom-type>
+ <coordinates>-34.025 32.801 -15.050</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>12</position>
+ <base-type>C</base-type>
+ <atom serial="237">
+ <atom-type> P </atom-type>
+ <coordinates>-35.037 32.875 -16.296</coordinates>
+ </atom>
+ <atom serial="245">
+ <atom-type> O3'</atom-type>
+ <coordinates>-31.850 33.486 -20.341</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>13</position>
+ <base-type>A</base-type>
+ <atom serial="257">
+ <atom-type> P </atom-type>
+ <coordinates>-30.767 32.411 -19.837</coordinates>
+ </atom>
+ <atom serial="265">
+ <atom-type> O3'</atom-type>
+ <coordinates>-25.756 33.919 -20.714</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>14</position>
+ <base-type>U</base-type>
+ <atom serial="279">
+ <atom-type> P </atom-type>
+ <coordinates>-24.465 33.135 -20.171</coordinates>
+ </atom>
+ <atom serial="287">
+ <atom-type> O3'</atom-type>
+ <coordinates>-21.219 37.107 -19.013</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>15</position>
+ <base-type>A</base-type>
+ <atom serial="299">
+ <atom-type> P </atom-type>
+ <coordinates>-22.129 38.268 -18.376</coordinates>
+ </atom>
+ <atom serial="307">
+ <atom-type> O3'</atom-type>
+ <coordinates>-20.542 37.656 -12.798</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>16</position>
+ <base-type>G</base-type>
+ <atom serial="321">
+ <atom-type> P </atom-type>
+ <coordinates>-19.666 36.373 -12.391</coordinates>
+ </atom>
+ <atom serial="329">
+ <atom-type> O3'</atom-type>
+ <coordinates>-21.101 34.091 -7.803</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>17</position>
+ <base-type>G</base-type>
+ <atom serial="344">
+ <atom-type> P </atom-type>
+ <coordinates>-20.251 32.728 -7.687</coordinates>
+ </atom>
+ <atom serial="352">
+ <atom-type> O3'</atom-type>
+ <coordinates>-22.951 28.722 -5.266</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>18</position>
+ <base-type>C</base-type>
+ <atom serial="367">
+ <atom-type> P </atom-type>
+ <coordinates>-21.797 27.634 -5.014</coordinates>
+ </atom>
+ <atom serial="375">
+ <atom-type> O3'</atom-type>
+ <coordinates>-23.692 22.611 -5.084</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>19</position>
+ <base-type>U</base-type>
+ <atom serial="387">
+ <atom-type> P </atom-type>
+ <coordinates>-22.583 21.449 -4.989</coordinates>
+ </atom>
+ <atom serial="395">
+ <atom-type> O3'</atom-type>
+ <coordinates>-22.919 16.822 -7.040</coordinates>
+ </atom>
+ </base>
+ <base>
+ <position>20</position>
+ <base-type>G</base-type>
+ <atom serial="407">
+ <atom-type> P </atom-type>
+ <coordinates>-21.585 16.199 -6.397</coordinates>
+ </atom>
+ <atom serial="415">
+ <atom-type> O3'</atom-type>
+ <coordinates>-18.522 13.024 -10.277</coordinates>
+ </atom>
+ </base>
+ <str-annotation>
+ <base-pair comment="?">
+ <base-id-5p>
+ <base-id><position>1</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>2</position></base-id>
+ </base-id-3p>
+ <edge-5p>S</edge-5p>
+ <edge-3p>H</edge-3p>
+ <bond-orientation>c</bond-orientation>
+ </base-pair>
+ <base-pair comment="?">
+ <base-id-5p>
+ <base-id><position>6</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>20</position></base-id>
+ </base-id-3p>
+ <edge-5p>+</edge-5p>
+ <edge-3p>+</edge-3p>
+ <bond-orientation>c</bond-orientation>
+ </base-pair>
+ <base-pair comment="?">
+ <base-id-5p>
+ <base-id><position>7</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>19</position></base-id>
+ </base-id-3p>
+ <edge-5p>-</edge-5p>
+ <edge-3p>-</edge-3p>
+ <bond-orientation>c</bond-orientation>
+ </base-pair>
+ <base-pair comment="?">
+ <base-id-5p>
+ <base-id><position>8</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>18</position></base-id>
+ </base-id-3p>
+ <edge-5p>+</edge-5p>
+ <edge-3p>+</edge-3p>
+ <bond-orientation>c</bond-orientation>
+ </base-pair>
+ <base-pair comment="?">
+ <base-id-5p>
+ <base-id><position>9</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>17</position></base-id>
+ </base-id-3p>
+ <edge-5p>+</edge-5p>
+ <edge-3p>+</edge-3p>
+ <bond-orientation>c</bond-orientation>
+ </base-pair>
+ <base-pair comment="?">
+ <base-id-5p>
+ <base-id><position>10</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>16</position></base-id>
+ </base-id-3p>
+ <edge-5p>+</edge-5p>
+ <edge-3p>+</edge-3p>
+ <bond-orientation>c</bond-orientation>
+ </base-pair>
+ <base-pair comment="?">
+ <base-id-5p>
+ <base-id><position>11</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>15</position></base-id>
+ </base-id-3p>
+ <edge-5p>S</edge-5p>
+ <edge-3p>H</edge-3p>
+ <bond-orientation>t</bond-orientation>
+ </base-pair>
+ <base-pair comment="?">
+ <base-id-5p>
+ <base-id><position>3</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>4</position></base-id>
+ </base-id-3p>
+ <edge-5p>!</edge-5p>
+ <edge-3p>!</edge-3p>
+ <bond-orientation>!</bond-orientation>
+ </base-pair>
+ <base-pair comment="?">
+ <base-id-5p>
+ <base-id><position>14</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>15</position></base-id>
+ </base-id-3p>
+ <edge-5p>!</edge-5p>
+ <edge-3p>!</edge-3p>
+ <bond-orientation>!</bond-orientation>
+ </base-pair>
+ <helix id="H1">
+ <base-id-5p>
+ <base-id><position>6</position></base-id>
+ </base-id-5p>
+ <base-id-3p>
+ <base-id><position>20</position></base-id>
+ </base-id-3p>
+ <length>6</length>
+ </helix>
+ <single-strand>
+ <segment>
+ <seg-name>SG1</seg-name>
+ <base-id-5p><base-id><position>1</position></base-id></base-id-5p>
+ <base-id-3p><base-id><position>5</position></base-id></base-id-3p>
+ </segment>
+ </single-strand>
+ <single-strand>
+ <segment>
+ <seg-name>SG2</seg-name>
+ <base-id-5p><base-id><position>12</position></base-id></base-id-5p>
+ <base-id-3p><base-id><position>14</position></base-id></base-id-3p>
+ </segment>
+ </single-strand>
+ </str-annotation>
+ <secondary-structure-display comment="x,y coodinates">
+ <ss-base-coord>
+ <base-id><position>1</position></base-id>
+ <coordinates>133.930 0.000</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>2</position></base-id>
+ <coordinates>133.930 33.482</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>3</position></base-id>
+ <coordinates>133.930 66.965</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>4</position></base-id>
+ <coordinates>133.930 100.447</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>5</position></base-id>
+ <coordinates>133.930 133.930</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>6</position></base-id>
+ <coordinates>133.930 167.412</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>7</position></base-id>
+ <coordinates>133.930 223.216</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>8</position></base-id>
+ <coordinates>133.930 279.021</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>9</position></base-id>
+ <coordinates>133.930 334.825</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>10</position></base-id>
+ <coordinates>133.930 390.629</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>11</position></base-id>
+ <coordinates>133.930 446.433</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>12</position></base-id>
+ <coordinates>128.630 516.439</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>13</position></base-id>
+ <coordinates>66.965 550.000</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>14</position></base-id>
+ <coordinates>5.300 516.439</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>15</position></base-id>
+ <coordinates>0.000 446.433</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>16</position></base-id>
+ <coordinates>0.000 390.629</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>17</position></base-id>
+ <coordinates>0.000 334.825</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>18</position></base-id>
+ <coordinates>0.000 279.021</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>19</position></base-id>
+ <coordinates>0.000 223.216</coordinates>
+ </ss-base-coord>
+ <ss-base-coord>
+ <base-id><position>20</position></base-id>
+ <coordinates>0.000 167.412</coordinates>
+ </ss-base-coord>
+ </secondary-structure-display>
+ </model>
+ </structure>
+ </molecule>
+
+
+ <interactions>
+ <str-annotation>
+ </str-annotation>
+ </interactions>
+</rnaml>
# for developing in Eclipse as IDE, set this to automatically copy current swingjs/net.sf.j2s.core.jar to your dropins dir
jalviewjs_eclipseIDE_auto_copy_j2s_plugin = false
# Override this in a local.properties file
-jalviewjs_eclipse_root = ~/buildtools/eclipse/jee-2019-09
+jalviewjs_eclipse_root = ~/buildtools/eclipse/latest
jalviewjs_eclipse_dropins_dir = utils/jalviewjs/eclipse/dropins
jalviewjs_swingjs_zip = swingjs/SwingJS-site.zip
jalviewjs_closure_compiler = tools/closure_compiler.jar
jalviewjs_j2s_closure_stdout = j2s-closure.out
+# for checking jalviewjs launches okay
+jalviewjs_chromium_binary = ~/buildtools/chromium/chrome
+jalviewjs_macos_chromium_binary = /Applications/Chromium.app/Contents/MacOS/Chromium
+jalviewjs_chromium_user_dir = chromium
+jalviewjs_chromium_idle_timeout = 10
+jalviewjs_chromium_overall_timeout = 40
+jalviewjs_chromium_profile_name = BUILD
+jalviewjs_stderr_launch = utils/jalviewjs/chromium_test/jalview_bin_Jalview-stderr.html
+jalviewjs_desktop_init_string = JALVIEWJS: CREATED DESKTOP
testp=gradle.properties
</tr>
<tr valign="top">
+ <td><code>‑‑nostartupfile</code></td>
+ <td>Don't show the default startup file.</td>
+ </tr>
+
+ <tr valign="top">
<td><code>‑‑webservicediscovery / ‑‑nowebservicediscovery</code></td>
<td>Attempt (/ or don't attempt) to connect to JABAWS web services.</td>
</tr>
<!--
<tr valign="top">
+ <td><code>‑‑P<em>PREFERENCE=VALUE</em></code></td>
+ <td>Set a Jalview preference for this session only. Experimental.</td>
+ </tr>
+-->
+
+<!--
+ <tr valign="top">
<td><code>‑‑initsubstitutions / ‑‑noinitsubstitutions</code></td>
<td>Set <code>‑‑substitutions</code> to be initially enabled (or initially disabled).</td>
</tr>
</tr>
<tr valign="top">
- <td><code>‑‑title <em>"string""</em></code></td>
+ <td><code>‑‑title <em>"string"</em></code></td>
<td>Specifies the title for the open alignment window as <em>string</em>.</td>
<td></td>
<td align="center">✓</td>
<tr valign="top">
<td><code>‑‑colour <em>name</em></code></td>
- <td>Applies the colour scheme <em>name</em> to the open alignment window. Valid values for <em>name</em> are:
+ <td>Applies the colour scheme <em>name</em> to the open alignment window. Valid values for <em>name</em> include:
<br/>
<code>clustal</code>,
<br/>
<code>t-coffee-scores</code>,
<br/>
<code>sequence-id</code>.
+ <br/>
+ <br/>
+ Names of user defined schemes will also work, and jalview colour scheme specifications like:
+ <br/>
+ <code>‑‑colour "D,E=red; K,R,H=0022FF; C,c=yellow"</code>
<td></td>
<td align="center">✓</td>
</tr>
<p>Usage data is collected from the logs of various web services
that the Jalview Desktop contacts through its normal operation.
These are described below:</p>
- <ul>
- <li><em>HTTP logs on the Jalview website</em><br> We
- record IP addresses of machines which access the web site, either
- via the browser when downloading the application, or when the
- Jalview Desktop user interface is launched.<br> <br>
- <ul>
- <li><i>The Jalview Getdown Launcher</i> (Since 2.11.0) examines release
- channels every time Jalview launches to determine if a new
- release is available.</li>
- <li><i>The questionnaire web service at
- www.jalview.org/cgi-bin/questionnaire.pl is checked and a
- unique cookie for the current questionnaire is stored in the
- Jalview properties file.</i></li>
- <li><i>The Jalview web services stack is contacted to
- retrieve the currently available web services. All
- interactions with the public Jalview web services are
- logged, but we delete all job data (input data and results)
- after about two weeks.</i></li>
- </ul> <br></li>
- <li><em>Google Analytics</em><br> Since Jalview 2.4.0b2,
- the Jalview Desktop records usage data with Google Analytics via
- the <a href="http://code.google.com/p/jgoogleanalytics/">JGoogleAnalytics</a>
- class.<br> The Google Analytics logs for Jalview version 2.4
- only record the fact that the application was started, but in the
- future, we will use this mechanism to improve the Desktop user
- interface, by tracking which parts of the user interface are being
- used most often.</li>
- </ul>
- </p>
+ <ul>
+ <li><em>HTTP logs on the Jalview website</em><br> We record
+ IP addresses of machines which access the web site, either via the
+ browser when downloading the application, or when the Jalview Desktop
+ user interface is launched.<br> <br>
+ <ul>
+ <li><i>The Jalview Getdown Launcher</i> (Since 2.11.0) examines
+ release channels every time Jalview launches to determine if a new
+ release is available.</li>
+ <li><i>The questionnaire web service at
+ www.jalview.org/cgi-bin/questionnaire.pl is checked and a unique
+ cookie for the current questionnaire is stored in the Jalview
+ properties file.</i></li>
+ <li><i>The Jalview web services stack is contacted to
+ retrieve the currently available web services. All interactions
+ with the public Jalview web services are logged, but we delete all
+ job data (input data and results) after about two weeks.</i></li>
+ </ul> <br></li>
+ <li><em>Usage Analytics</em><br> Since Jalview 2.11.2.7, the
+ Jalview Desktop records usage data with a self-hosted instance of the
+ analytics stack <a href="https://plausible.io">Plausible.io</a> via a
+ custom GPLv3 client developed by Ben Soares. Prior to this, Jalview
+ versions as far back as 2.4 recorded application launches via <a
+ href="http://code.google.com/p/jgoogleanalytics/">JGoogleAnalytics</a>
+ .<br> Usage logs for Jalview record the fact that the
+ application was started, and details about the OS, installed Jalview
+ launcher (if any) and java version used. In the future, we will use
+ this mechanism to improve the Desktop user interface, by tracking
+ which parts of the user interface are being used most often.</li>
+ </ul>
<p>
<strong>Stopping Jalview from calling home</strong><br> If you
run Jalview in 'headless mode' via the command line, then the
--- /dev/null
+---
+version: 2.11.2.7
+date: 2023-06-30
+channel: "release"
+---
+
+## New Features
+- <!-- JAL-4001 --> Jalview now reports usage statistics via Plausible.io
+
+## Issues Resolved
+- <!-- JAL-4116 --> PDB structures slow to view when Jalview Java console is open
+- <!-- JAL-4216 --> chains in PDB or mmCIF files with negative RESNUMs not correctly parsed
---
version: 2.11.3.0
-date: 2023-03-07
+date: 2023-07-19
channel: "release"
---
- <!-- JAL-4019 --> Ambiguous Base Colourscheme
- <!-- JAL-4061 --> Find can search sequence features' type and description
- <!-- JAL-4062 --> Hold down Shift + CMD/CTRL C to copy highlighted regions as new sequences
+- <!-- JAL-1556 --> Quickly enable select and/or colour by for displayed annotation row via its popup menu
+- <!-- JAL-4094 --> Shift+Click+Drag to adjust height of all annotation tracks of same type
+- <!-- JAL-4190 --> Pressing escape in tree panel clears any current selection
+
- <!-- JAL-4089 --> Use selected columns for superposition
- <!-- JAL-4086 --> Highlight aligned positions on all associated structures when mousing over a column
+- <!-- JAL-4221 --> sequence descriptions are updated from database reference sources if not already defined
+
+
+### Improved support for working with computationally determined models
+
- <!-- JAL-3895 --> Alphafold red/orange/yellow/green colourscheme for structures
- <!-- JAL-4095 --> Interactive picking of low pAE score regions
- <!-- JAL-4027 --> contact matrix datatype in Jalview
- <!-- JAL-4033 --> Selections with visual feedback via contact matrix annotation
-- <!-- JAL-4075 --> Don't add string label version of DSSP secondary structure codes in secondary structure annotation rows
- <!-- JAL-3855 --> Discover and import alphafold2 models and metadata from https://alphafold.ebi.ac.uk/
-- <!-- JAL-2961 --> Jmol view not always centred on structures when multiple structures are viewed
+- <!-- JAL-4091 --> Visual indication of relationship with associated sequence to distinguish different sequence associated annotation rows
+- <!-- JAL-4123 --> GUI and command line allows configuration of how temperature factor in imported 3D structure data should be interpreted
+- <!-- JAL-3914 --> Import model reliability scores encoded as temperature factor annotation with their correct name and semantics
+- <!-- JAL-3858 --> Import and display alphafold alignment uncertainty matrices from JSON
+- <!-- JAL-4134,JAL-4158 --> Column-wise alignment groups and selections and interactive tree viewer for PAE matrices
+- <!-- JAL-4124 --> Store/Restore PAE data and visualisation settings from Jalview Project
+- <!-- JAL-4083 --> Multiple residue sidechain highlighting in structure viewers from PAE mouseovers
-- <!-- JAL-2528, JAL-1713 --> Overview window is saved in project file, and state of 'show hidden regions' is preserved.
+### Jalview on the command line
+
+- <!-- JAL-4160,JAL-629 --> New command line argument framework allowing flexible batch processing, figure generation, and import of structures, pae matrices and other sequence associated data
+- <!-- JAL-4121 --> Assume --headless when jalview is run with a command line argument that generates output
+
+### Other improvements
+
+
+- <!-- JAL-4250 --> Secondary structure annotation glyphs are rendered anti-aliasing when enabled
+- <!-- JAL-325 --> Helix and Sheet glyphs vertically centered with respect to grey coil secondary structure annotation track
+- <!-- JAL-4253 --> Lower line of the sequence group border does not align with vertical and background residue box
+- <!-- JAL-4250 --> Updated JFreeSVG (https://www.jfree.org/jfreesvg) from 2.1 to 3.4.3
- <!-- JAL-3119 --> Name of alignment and view included in overview window's title
+- <!-- JAL-4213 --> "add reference annotation" add all positions in reference annotation tracks, not just positions in the currently highlighted columns/selection range
+- <!-- JAL-4119 --> EMBL-EBI SIFTS file downloads now use split directories
-- <!-- JAL-4091 --> Visual indication of relationship with associated sequence to distinguish different sequence associated annotation rows
-- <!-- JAL-4094 --> Shift+Click+Drag to adjust height of all annotation tracks of same type
+- <!-- JAL-4195,JAL-4194,JAL-4193 --> sensible responses from the CLI when things go wrong during image export
+Add a command line option to set Jalview properties for this session only
+Add a command line option to suppress opening the startup file for this session
+
+
+JAL-4187 Powershell launcher script fails when given no arguments with the old ArgsParser
+
+known issue ? <!-- JAL-4127 --> 'Reload' for a jalview project results in all windows being duplicated
+- <!-- JAL-3830 --> Command-line wrapper script for macOS bundle, linux and Windows installations (bash, powershell and .bat wrappers)
+- <!-- JAL-3820 --> In Linux desktops' task-managers, the grouped Jalview windows get a generic name
+
## Still in progress (delete on release)
- <!-- JAL-2382 --> Import and display sequence-associated contact predictions in CASP-RR format
- <!-- JAL-2349 --> Contact prediction visualisation
- <!-- JAL-2348 --> modularise annotation renderer
+### Development and Deployment
+- <!-- JAL-4167 --> Create separate gradle test task for some tests
+- <!-- JAL-4111 --> Allow gradle build to create suffixed DEVELOP-... builds with channel appbase
+- <!-- JAL-4243 --> Jalview bio.tools description maintained under jalview's git repo and bundled with source release
## Issues Resolved
+- <!-- JAL-2961 --> Jmol view not always centred on structures when multiple structures are viewed
- <!-- JAL-3776 --> Cancelling interactive calculation leaves empty progress bar.
- <!-- JAL-3772 --> Unsaved Alignment windows close without prompting to save, individually or at application quit.
- <!-- JAL-1988 --> Can quit Jalview while 'save project' is in progress
- <!-- JAL-3785 --> Overview windows opened automatically (due to preferences settings) lack title
- <!-- JAL-2353 --> Show Crossrefs fails to retrieve CDS from ENA or Ensembl for sequences retrieved from Uniprot due to version numbers in cross-reference accession
- <!-- JAL-4184 --> Stockholm export does not include sequence descriptions
+- <!-- JAL-4075 --> Don't add string label version of DSSP secondary structure codes in secondary structure annotation rows
+- <!-- JAL-4182 --> reference annotation not correctly transferred to alignment containing a sub-sequence when a selection is active
+- <!-- JAL-4177 --> Can press 'Add' or 'New View' multiple times when manually adding and viewing a 3D structure via structure chooser
+- <!-- JAL-4133 --> Jalview project does not preserve font aspect ratio when Viewport is zoomed with mouse
+- <!-- JAL-4128 --> Resizing overview quickly with solid-drags enabled causes exception
+- <!-- JAL-4150 --> Sequences copied to clipboard from within Jalview cannot be pasted via the desktop's popup menu to a new alignment window
+- <!-- JAL-2528, JAL-1713 --> Overview window is saved in project file, and state of 'show hidden regions' is preserved.
+- <!-- JAL-4153 --> JvCacheableInputBoxTest flaky on build server
+
+## New Known defects
+- <!-- JAL-4178 --> Cannot cancel structure view open action once it has been started via the structure chooser dialog
+- <!-- JAL-4142 --> Example project's multiple views do not open in distinct locations when eXpand views is used to show them all separately
+- <!-- JAL-4165 --> Missing last letter when copying consensus sequence from alignment if first column is hidden
+
+
+
+
--- /dev/null
+Jalview 2.11.2.7 is a minor patch release - it includes patches affecting efficiency when importing structures and a small revision to the import processing of structures with negative residue numbering.
+
+With this release, Jalview usage statistics are now collected by a jalview.org hosted instance of the open source privacy-preserving analytics stack, Plausible.io.
+
+
The 2.11.3 series includes support for in-depth exploration of predicted alignment error matrices from AlphaFold in the context of multiple alignments, along with support for standard colourschemes for shading models according to their pLDDT.
+We're launching this release at ISMB 2023 - come find us !
+
It also introduces new support for native ARM-based OSX architectures, and a few other goodies!
label.interpret_tempfac_as = Interpret Temperature Factor as
label.add_pae_matrix_file = Add PAE matrix file
label.nothing_selected = Nothing selected
+prompt.analytics_title = Jalview Usage Statistics
+prompt.analytics = Do you want to help make Jalview better by enabling the collection of usage statistics with Plausible analytics?\nYou can enable or disable usage tracking in the preferences.
label.working_ellipsis = Working ...
action.show_groups_on_matrix = Show groups on matrix
action.show_groups_on_matrix_tooltip = When enabled, clusters defined on the matrix's associated tree or below the assigned threshold are shown as different colours on the matrix annotation row
label.tftype_plddt = pLDDT
label.add_pae_matrix_file = Añadir un fichero de matriz PAE
label.nothing_selected = Nada seleccionado
+prompt.analytics_title = Jalview Estadísticas de Uso
+prompt.analytics = ¿Quiere ayudar a mejorar Jalview habilitando la recopilación de estadísticas de uso con análisis Plausible?\nPuede habilitar o deshabilitar el seguimiento de uso en las preferencias.
pdbpos++;
}
- if (allowmismatch || c1 == c2)
+ // ignore case differences
+ if (allowmismatch || (c1 == c2) || (Math.abs(c2-c1)==('a'-'A')))
{
// extend mapping interval
if (lp1 + 1 != alignpos || lp2 + 1 != pdbpos)
* @param alignment
* the alignment to add them to
* @param selectionGroup
- * current selection group (or null if none)
+ * current selection group - may be null, if provided then any added annotation will be trimmed to just those columns in the selection group
*/
public static void addReferenceAnnotations(
Map<SequenceI, List<AlignmentAnnotation>> annotations,
* @param seq
* @param ann
* @param selectionGroup
- * - may be null
+ * current selection group - may be null, if provided then any added annotation will be trimmed to just those columns in the selection group
* @return annotation added to {@code seq and {@code alignment}
*/
public static AlignmentAnnotation addReferenceAnnotationTo(
AlignmentAnnotation aa;
+ // 0 - normalised dot product
+ // 1 - L1 - ie (abs(v_1-v_2)/dim(v))
+ // L1 is more rational - since can reason about value of difference,
+ // normalised dot product might give cleaner clusters, but more difficult to
+ // understand.
+
+ int mode = 1;
+
/**
* compute cosine distance matrix for a given contact matrix and create a
* UPGMA tree
- *
* @param cm
+ * @param cosineOrDifference false - dot product : true - L1
*/
public AverageDistanceEngine(AlignmentViewport av, AlignmentAnnotation aa,
- ContactMatrixI cm)
+ ContactMatrixI cm, boolean cosineOrDifference)
{
this.av = av;
this.aa = aa;
this.cm = cm;
+ mode = (cosineOrDifference) ? 1 :0;
calculate(cm);
}
- // 0 - normalised dot product
- // 1 - L1 - ie (abs(v_1-v_2)/dim(v))
- // L1 is more rational - since can reason about value of difference,
- // normalised dot product might give cleaner clusters, but more difficult to
- // understand.
-
- int mode = 1;
public void calculate(ContactMatrixI cm)
{
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.analytics;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.invoke.MethodHandles;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.util.ChannelProperties;
+import jalview.util.HttpUtils;
+
+public class Plausible
+{
+ private static final String USER_AGENT;
+
+ private static final String JALVIEW_ID = "Jalview Desktop";
+
+ private static final String DOMAIN = "jalview.org";
+
+ private static final String CONFIG_API_BASE_URL = "https://www.jalview.org/services/config/analytics/url";
+
+ private static final String DEFAULT_API_BASE_URL = "https://analytics.jalview.org/api/event";
+
+ private static final String API_BASE_URL;
+
+ private static final String clientId;
+
+ public static final String APPLICATION_BASE_URL = "desktop://localhost";
+
+ private List<Map.Entry<String, String>> queryStringValues;
+
+ private List<Map.Entry<String, Object>> jsonObject;
+
+ private List<Map.Entry<String, String>> cookieValues;
+
+ private static boolean ENABLED = false;
+
+ private static boolean DEBUG = true;
+
+ private static Plausible instance = null;
+
+ private static final Map<String, String> defaultProps;
+
+ static
+ {
+ defaultProps = new HashMap<>();
+ defaultProps.put("app_name",
+ ChannelProperties.getProperty("app_name") + " Desktop");
+ defaultProps.put("version", Cache.getProperty("VERSION"));
+ defaultProps.put("build_date",
+ Cache.getDefault("BUILD_DATE", "unknown"));
+ defaultProps.put("java_version", System.getProperty("java.version"));
+ String val = System.getProperty("sys.install4jVersion");
+ if (val != null)
+ {
+ defaultProps.put("install4j_version", val);
+ }
+ val = System.getProperty("installer_template_version");
+ if (val != null)
+ {
+ defaultProps.put("install4j_template_version", val);
+ }
+ val = System.getProperty("launcher_version");
+ if (val != null)
+ {
+ defaultProps.put("launcher_version", val);
+ }
+ defaultProps.put("java_arch",
+ System.getProperty("os.arch") + " "
+ + System.getProperty("os.name") + " "
+ + System.getProperty("os.version"));
+ defaultProps.put("os", System.getProperty("os.name"));
+ defaultProps.put("os_version", System.getProperty("os.version"));
+ defaultProps.put("os_arch", System.getProperty("os.arch"));
+ String installation = Cache.applicationProperties
+ .getProperty("INSTALLATION");
+ if (installation != null)
+ {
+ defaultProps.put("installation", installation);
+ }
+
+ // ascertain the API_BASE_URL
+ API_BASE_URL = getAPIBaseURL();
+
+ // random clientId to make User-Agent unique (to register analytic)
+ clientId = String.format("%08x", new Random().nextInt());
+
+ USER_AGENT = HttpUtils.getUserAgent(
+ MethodHandles.lookup().lookupClass().getCanonicalName() + " "
+ + clientId);
+ }
+
+ private Plausible()
+ {
+ this.resetLists();
+ }
+
+ public static void setEnabled(boolean b)
+ {
+ ENABLED = b;
+ }
+
+ public void sendEvent(String eventName, String urlString,
+ String... propsStrings)
+ {
+ sendEvent(eventName, urlString, false, propsStrings);
+ }
+
+ /**
+ * The simplest way to send an analytic event.
+ *
+ * @param eventName
+ * The event name. To emulate a webpage view use "pageview" and set a
+ * "url" key/value. See https://plausible.io/docs/events-api
+ * @param sendDefaultProps
+ * Flag whether to add the default props about the application.
+ * @param propsStrings
+ * Optional multiple Strings in key, value pairs (there should be an
+ * even number of propsStrings) to be set as property of the event.
+ * To emulate a webpage view set "url" as the URL in a "pageview"
+ * event.
+ */
+ public void sendEvent(String eventName, String urlString,
+ boolean sendDefaultProps, String... propsStrings)
+ {
+ // clear out old lists
+ this.resetLists();
+
+ if (!ENABLED)
+ {
+ Console.debug("Plausible not enabled.");
+ return;
+ }
+ Map<String, String> props = new HashMap<>();
+
+ // add these to all events from this application instance
+ if (sendDefaultProps)
+ {
+ props.putAll(defaultProps);
+ }
+
+ // add (and overwrite with) the passed in props
+ if (propsStrings != null && propsStrings.length > 0)
+ {
+ if (propsStrings.length % 2 != 0)
+ {
+ Console.warn(
+ "Cannot addEvent with odd number of propsStrings. Ignoring the last one.");
+ }
+ for (int i = 0; i < propsStrings.length - 1; i += 2)
+ {
+ String key = propsStrings[i];
+ String value = propsStrings[i + 1];
+ props.put(key, value);
+ }
+ }
+
+ addJsonValue("domain", DOMAIN);
+ addJsonValue("name", eventName);
+ StringBuilder eventUrlSb = new StringBuilder(APPLICATION_BASE_URL);
+ if (!APPLICATION_BASE_URL.endsWith("/") && !urlString.startsWith("/"))
+ {
+ eventUrlSb.append("/");
+ }
+ eventUrlSb.append(urlString);
+ addJsonValue("url", eventUrlSb.toString());
+ addJsonObject("props", props);
+ StringBuilder urlSb = new StringBuilder();
+ urlSb.append(API_BASE_URL);
+ String qs = buildQueryString();
+ if (qs != null && qs.length() > 0)
+ {
+ urlSb.append('?');
+ urlSb.append(qs);
+ }
+ try
+ {
+ URL url = new URL(urlSb.toString());
+ URLConnection urlConnection = url.openConnection();
+ HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
+ httpURLConnection.setRequestMethod("POST");
+ httpURLConnection.setDoOutput(true);
+
+ String jsonString = buildJson();
+
+ Console.debug(
+ "Plausible: HTTP Request is: '" + urlSb.toString() + "'");
+ if (DEBUG)
+ {
+ Console.debug("Plausible: User-Agent is: '" + USER_AGENT + "'");
+ }
+ Console.debug("Plausible: POSTed JSON is:\n" + jsonString);
+
+ byte[] jsonBytes = jsonString.getBytes(StandardCharsets.UTF_8);
+ int jsonLength = jsonBytes.length;
+
+ httpURLConnection.setFixedLengthStreamingMode(jsonLength);
+ httpURLConnection.setRequestProperty("Content-Type",
+ "application/json");
+ httpURLConnection.setRequestProperty("User-Agent", USER_AGENT);
+ httpURLConnection.connect();
+ try (OutputStream os = httpURLConnection.getOutputStream())
+ {
+ os.write(jsonBytes);
+ }
+ int responseCode = httpURLConnection.getResponseCode();
+ String responseMessage = httpURLConnection.getResponseMessage();
+
+ if (responseCode < 200 || responseCode > 299)
+ {
+ Console.warn("Plausible connection failed: '" + responseCode + " "
+ + responseMessage + "'");
+ }
+ else
+ {
+ Console.debug("Plausible connection succeeded: '" + responseCode
+ + " " + responseMessage + "'");
+ }
+
+ if (DEBUG)
+ {
+ BufferedReader br = new BufferedReader(new InputStreamReader(
+ (httpURLConnection.getInputStream())));
+ StringBuilder sb = new StringBuilder();
+ String response;
+ while ((response = br.readLine()) != null)
+ {
+ sb.append(response);
+ }
+ String body = sb.toString();
+ Console.debug("Plausible response content:\n" + body);
+ }
+ } catch (MalformedURLException e)
+ {
+ Console.debug(
+ "Somehow the Plausible BASE_URL and queryString is malformed: '"
+ + urlSb.toString() + "'",
+ e);
+ return;
+ } catch (IOException e)
+ {
+ Console.debug("Connection to Plausible BASE_URL '" + API_BASE_URL
+ + "' failed.", e);
+ } catch (ClassCastException e)
+ {
+ Console.debug(
+ "Couldn't cast URLConnection to HttpURLConnection in Plausible.",
+ e);
+ }
+ }
+
+ private void addJsonObject(String key, Map<String, String> map)
+ {
+ List<Map.Entry<String, ? extends Object>> list = new ArrayList<>();
+ for (String k : map.keySet())
+ {
+ list.add(stringEntry(k, map.get(k)));
+ }
+ addJsonObject(key, list);
+
+ }
+
+ private void addJsonObject(String key,
+ List<Map.Entry<String, ? extends Object>> object)
+ {
+ jsonObject.add(objectEntry(key, object));
+ }
+
+ private void addJsonValues(String key, List<Object> values)
+ {
+ jsonObject.add(objectEntry(key, values));
+ }
+
+ private void addJsonValue(String key, String value)
+ {
+ jsonObject.add(objectEntry(key, value));
+ }
+
+ private void addJsonValue(String key, int value)
+ {
+ jsonObject.add(objectEntry(key, Integer.valueOf(value)));
+ }
+
+ private void addJsonValue(String key, boolean value)
+ {
+ jsonObject.add(objectEntry(key, Boolean.valueOf(value)));
+ }
+
+ private void addQueryStringValue(String key, String value)
+ {
+ queryStringValues.add(stringEntry(key, value));
+ }
+
+ private void addCookieValue(String key, String value)
+ {
+ cookieValues.add(stringEntry(key, value));
+ }
+
+ private void resetLists()
+ {
+ jsonObject = new ArrayList<>();
+ queryStringValues = new ArrayList<>();
+ cookieValues = new ArrayList<>();
+ }
+
+ public static Plausible getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new Plausible();
+ }
+ return instance;
+ }
+
+ public static void reset()
+ {
+ getInstance().resetLists();
+ }
+
+ private String buildQueryString()
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry<String, String> entry : queryStringValues)
+ {
+ if (sb.length() > 0)
+ {
+ sb.append('&');
+ }
+ try
+ {
+ sb.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
+ } catch (UnsupportedEncodingException e)
+ {
+ sb.append(entry.getKey());
+ }
+ sb.append('=');
+ try
+ {
+ sb.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
+ } catch (UnsupportedEncodingException e)
+ {
+ sb.append(entry.getValue());
+ }
+ }
+ return sb.toString();
+ }
+
+ private void buildCookieHeaders()
+ {
+ // TODO not needed yet
+ }
+
+ private String buildJson()
+ {
+ StringBuilder sb = new StringBuilder();
+ addJsonObject(sb, 0, jsonObject);
+ return sb.toString();
+ }
+
+ private void addJsonObject(StringBuilder sb, int indent,
+ List<Map.Entry<String, Object>> entries)
+ {
+ indent(sb, indent);
+ sb.append('{');
+ newline(sb);
+ Iterator<Map.Entry<String, Object>> entriesI = entries.iterator();
+ while (entriesI.hasNext())
+ {
+ Map.Entry<String, Object> entry = entriesI.next();
+ String key = entry.getKey();
+ // TODO sensibly escape " characters in key
+ Object value = entry.getValue();
+ indent(sb, indent + 1);
+ sb.append('"').append(quoteEscape(key)).append('"').append(':');
+ space(sb);
+ if (value != null && value instanceof List)
+ {
+ newline(sb);
+ }
+ addJsonValue(sb, indent + 2, value);
+ if (entriesI.hasNext())
+ {
+ sb.append(',');
+ }
+ newline(sb);
+ }
+ indent(sb, indent);
+ sb.append('}');
+ }
+
+ private void addJsonValue(StringBuilder sb, int indent, Object value)
+ {
+ if (value == null)
+ {
+ return;
+ }
+ try
+ {
+ if (value instanceof Map.Entry)
+ {
+ Map.Entry<String, Object> entry = (Map.Entry<String, Object>) value;
+ List<Map.Entry<String, Object>> object = new ArrayList<>();
+ object.add(entry);
+ addJsonObject(sb, indent, object);
+ }
+ else if (value instanceof List)
+ {
+ // list of Map.Entries or list of values?
+ List<Object> valueList = (List<Object>) value;
+ if (valueList.size() > 0 && valueList.get(0) instanceof Map.Entry)
+ {
+ // entries
+ // indent(sb, indent);
+ List<Map.Entry<String, Object>> entryList = (List<Map.Entry<String, Object>>) value;
+ addJsonObject(sb, indent, entryList);
+ }
+ else
+ {
+ // values
+ indent(sb, indent);
+ sb.append('[');
+ newline(sb);
+ Iterator<Object> valueListI = valueList.iterator();
+ while (valueListI.hasNext())
+ {
+ Object v = valueListI.next();
+ addJsonValue(sb, indent + 1, v);
+ if (valueListI.hasNext())
+ {
+ sb.append(',');
+ }
+ newline(sb);
+ }
+ indent(sb, indent);
+ sb.append("]");
+ }
+ }
+ else if (value instanceof String)
+ {
+ sb.append('"').append(quoteEscape((String) value)).append('"');
+ }
+ else if (value instanceof Integer)
+ {
+ sb.append(((Integer) value).toString());
+ }
+ else if (value instanceof Boolean)
+ {
+ sb.append('"').append(((Boolean) value).toString()).append('"');
+ }
+ } catch (ClassCastException e)
+ {
+ Console.debug(
+ "Could not deal with type of json Object " + value.toString(),
+ e);
+ }
+ }
+
+ private static String quoteEscape(String s)
+ {
+ if (s == null)
+ {
+ return null;
+ }
+ // this escapes quotation marks (") that aren't already escaped (in the
+ // string) ready to go into a quoted JSON string value
+ return s.replaceAll("((?<!\\\\)(?:\\\\{2})*)\"", "$1\\\\\"");
+ }
+
+ private static void prettyWhitespace(StringBuilder sb, String whitespace,
+ int repeat)
+ {
+ // only add whitespace if we're in DEBUG mode
+ if (!Console.getLogger().isDebugEnabled())
+ {
+ return;
+ }
+ if (repeat >= 0 && whitespace != null)
+ {
+ // sb.append(whitespace.repeat(repeat));
+ sb.append(String.join("", Collections.nCopies(repeat, whitespace)));
+
+ }
+ else
+ {
+ sb.append(whitespace);
+ }
+ }
+
+ private static void indent(StringBuilder sb, int indent)
+ {
+ prettyWhitespace(sb, " ", indent);
+ }
+
+ private static void newline(StringBuilder sb)
+ {
+ prettyWhitespace(sb, "\n", -1);
+ }
+
+ private static void space(StringBuilder sb)
+ {
+ prettyWhitespace(sb, " ", -1);
+ }
+
+ protected static Map.Entry<String, Object> objectEntry(String s, Object o)
+ {
+ return new AbstractMap.SimpleEntry<String, Object>(s, o);
+ }
+
+ protected static Map.Entry<String, String> stringEntry(String s, String v)
+ {
+ return new AbstractMap.SimpleEntry<String, String>(s, v);
+ }
+
+ private static String getAPIBaseURL()
+ {
+ try
+ {
+ URL url = new URL(CONFIG_API_BASE_URL);
+ URLConnection urlConnection = url.openConnection();
+ HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
+ httpURLConnection.setRequestMethod("GET");
+ httpURLConnection.setRequestProperty("User-Agent", USER_AGENT);
+ httpURLConnection.setConnectTimeout(5000);
+ httpURLConnection.setReadTimeout(3000);
+ httpURLConnection.connect();
+ int responseCode = httpURLConnection.getResponseCode();
+ String responseMessage = httpURLConnection.getResponseMessage();
+
+ if (responseCode < 200 || responseCode > 299)
+ {
+ Console.warn("Config URL connection to '" + CONFIG_API_BASE_URL
+ + "' failed: '" + responseCode + " " + responseMessage
+ + "'");
+ }
+
+ BufferedReader br = new BufferedReader(
+ new InputStreamReader((httpURLConnection.getInputStream())));
+ StringBuilder sb = new StringBuilder();
+ String response;
+ while ((response = br.readLine()) != null)
+ {
+ sb.append(response);
+ }
+ if (sb.length() > 7 && sb.substring(0, 5).equals("https"))
+ {
+ return sb.toString();
+ }
+
+ } catch (MalformedURLException e)
+ {
+ Console.debug("Somehow the config URL is malformed: '"
+ + CONFIG_API_BASE_URL + "'", e);
+ } catch (IOException e)
+ {
+ Console.debug("Connection to Plausible BASE_URL '" + API_BASE_URL
+ + "' failed.", e);
+ } catch (ClassCastException e)
+ {
+ Console.debug(
+ "Couldn't cast URLConnection to HttpURLConnection in Plausible.",
+ e);
+ }
+ return DEFAULT_API_BASE_URL;
+ }
+}
/*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TreeSet;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
+import jalview.analytics.Plausible;
import jalview.datamodel.PDBEntry;
import jalview.gui.Preferences;
import jalview.gui.UserDefinedColours;
* service</li>
* <li>QUESTIONNAIRE last questionnaire:responder id string from questionnaire
* service</li>
- * <li>USAGESTATS (false - user prompted) Enable google analytics tracker for
+ * <li>USAGESTATS (false - user prompted) Enable analytics tracker for
* collecting usage statistics</li>
* <li>SHOW_OVERVIEW boolean for overview window display</li>
* <li>ANTI_ALIAS boolean for smooth fonts</li>
// in-memory only storage of proxy password, safer to use char array
public static char[] proxyAuthPassword = null;
+ /**
+ * Session properties, set by command line, try not to affect stored
+ * properties!
+ */
+ private static Map<String, String> sessionProperties = new HashMap<>();
+
+ private static boolean bypassSessionProperties = false;
+
+ public static void enableSessionProperties()
+ {
+ bypassSessionProperties = false;
+ }
+
+ public static void disableSessionProperties()
+ {
+ bypassSessionProperties = true;
+ }
+
/** Jalview Properties */
public static Properties applicationProperties = new Properties()
{
*/
public static String getProperty(String key)
{
- String prop = applicationProperties.getProperty(key);
+ return getProperty(key, false);
+ }
+
+ public static String getProperty(String key,
+ boolean skipSessionProperties)
+ {
+ String prop = null;
+ if (!(skipSessionProperties || bypassSessionProperties))
+ {
+ prop = getSessionProperty(key);
+ }
+ if (prop == null)
+ {
+ prop = applicationProperties.getProperty(key);
+ }
if (prop == null && Platform.isJS())
{
prop = applicationProperties.getProperty(Platform.getUniqueAppletID()
try
{
oldValue = applicationProperties.setProperty(key, obj);
- if (propertiesFile != null && !propsAreReadOnly)
+ if (propertiesFile != null && !propsAreReadOnly
+ // don't rewrite if new value is same as old value
+ && !((obj == null && oldValue == null)
+ || (obj != null && obj.equals(oldValue))))
{
+ // reset the session property too
+ if (sessionProperties.containsKey(key))
+ {
+ sessionProperties.remove(key);
+ }
FileOutputStream out = new FileOutputStream(propertiesFile);
applicationProperties.store(out, "---JalviewX Properties File---");
out.close();
}
/**
- * GA tracker object - actually JGoogleAnalyticsTracker null if tracking not
- * enabled.
- */
- protected static Object tracker = null;
-
- protected static Class trackerfocus = null;
-
- protected static Class jgoogleanalyticstracker = null;
-
- /**
- * Initialise the google tracker if it is not done already.
+ * Initialise the tracker if it is not done already.
*/
- public static void initGoogleTracker()
+ public static void initAnalytics()
{
- if (tracker == null)
+ Plausible.setEnabled(true);
+
+ String appName = ChannelProperties.getProperty("app_name") + " Desktop";
+ String version = Cache.getProperty("VERSION") + "_"
+ + Cache.getDefault("BUILD_DATE", "unknown");
+ String path;
+ /* we don't want to encode ':' as "%3A" for backward compatibility with the UA setup
+ try
{
- if (jgoogleanalyticstracker == null)
- {
- // try to get the tracker class
- try
- {
- jgoogleanalyticstracker = Cache.class.getClassLoader().loadClass(
- "com.boxysystems.jgoogleanalytics.JGoogleAnalyticsTracker");
- trackerfocus = Cache.class.getClassLoader()
- .loadClass("com.boxysystems.jgoogleanalytics.FocusPoint");
- } catch (Exception e)
- {
- Console.debug(
- "com.boxysystems.jgoogleanalytics package is not present - tracking not enabled.");
- tracker = null;
- jgoogleanalyticstracker = null;
- trackerfocus = null;
- return;
- }
- }
- // now initialise tracker
- Exception re = null, ex = null;
- Error err = null;
- String vrs = "No Version Accessible";
- try
- {
- // Google analytics tracking code for Library Finder
- tracker = jgoogleanalyticstracker
- .getConstructor(new Class[]
- { String.class, String.class, String.class })
- .newInstance(new Object[]
- { ChannelProperties.getProperty("app_name") + " Desktop",
- (vrs = Cache.getProperty("VERSION") + "_"
- + Cache.getDefault("BUILD_DATE", "unknown")),
- "UA-9060947-1" });
- jgoogleanalyticstracker
- .getMethod("trackAsynchronously", new Class[]
- { trackerfocus })
- .invoke(tracker, new Object[]
- { trackerfocus.getConstructor(new Class[] { String.class })
- .newInstance(new Object[]
- { "Application Started." }) });
- } catch (RuntimeException e)
- {
- re = e;
- } catch (Exception e)
- {
- ex = e;
- } catch (Error e)
- {
- err = e;
- }
- if (re != null || ex != null || err != null)
- {
- if (re != null)
- {
- Console.debug("Caught runtime exception in googletracker init:",
- re);
- }
- if (ex != null)
- {
- Console.warn(
- "Failed to initialise GoogleTracker for Jalview Desktop with version "
- + vrs,
- ex);
- }
- if (err != null)
- {
- Console.error(
- "Whilst initing GoogleTracker for Jalview Desktop version "
- + vrs,
- err);
- }
- }
- else
- {
- Console.debug("Successfully initialised tracker.");
- }
+ path = "/" + String.join("/", URLEncoder.encode(appName, "UTF-8"),
+ URLEncoder.encode(version, "UTF-8"),
+ URLEncoder.encode(APPLICATION_STARTED, "UTF-8"));
+ } catch (UnsupportedEncodingException e)
+ {
+ */
+ List<String> pathParts = new ArrayList<>();
+ pathParts.add(appName);
+ pathParts.add(version);
+ pathParts.add(APPLICATION_STARTED);
+ path = ("/" + String.join("/", pathParts)).replace(' ', '+');
+ /*
}
+ */
+ Plausible plausible = Plausible.getInstance();
+
+ // This will send a new "application_launch" event with parameters
+ // including the old-style "path", the channel name and version
+ plausible.sendEvent("application_launch", path, true);
}
+ private static final String APPLICATION_STARTED = "Application Started";
+
/**
* get the user's default colour if available
*
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
}
return bootstrapProps;
}
+
+ public static void setSessionProperty(String key, String val)
+ {
+ if (key != null)
+ {
+ sessionProperties.put(key, val);
+ }
+ }
+
+ public static String getSessionProperty(String key)
+ {
+ return key == null ? null : sessionProperties.get(key);
+ }
}
import jalview.io.HtmlSvgOutput;
import jalview.io.IdentifyFile;
import jalview.io.NewickFile;
+import jalview.io.exceptions.ImageOutputException;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
import jalview.structure.StructureImportSettings.TFType;
import jalview.structure.StructureSelectionManager;
import jalview.util.FileUtils;
theseArgsWereParsed &= processLinked(id);
processGroovyScript(id);
boolean processLinkedOkay = theseArgsWereParsed;
+
+ // wait around until alignFrame isn't busy
+ AlignFrame af = afMap.get(id);
+ while (af != null && af.getViewport().isCalcInProgress())
+ {
+ try
+ {
+ Thread.sleep(25);
+ } catch (Exception q)
+ {
+ }
+ ;
+ }
+
theseArgsWereParsed &= processImages(id);
if (processLinkedOkay)
theseArgsWereParsed &= processOutput(id);
// close ap
if (avm.getBoolean(Arg.CLOSE))
{
- AlignFrame af = afMap.get(id);
+ af = afMap.get(id);
if (af != null)
{
af.closeMenuItem_actionPerformed(true);
Arg.COLOUR, sv, null, "DEFAULT_COLOUR_PROT", "");
if ("" != colour)
{
- af.changeColour_actionPerformed(colour);
+ ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
+ af.getViewport(), af.getViewport().getAlignment(),
+ colour);
+
+ if (cs == null && !"None".equals(colour))
+ {
+ Console.warn(
+ "Couldn't parse '" + colour + "' as a colourscheme.");
+ }
+ else
+ {
+ af.changeColour(cs);
+ }
Jalview.testoutput(argParser, Arg.COLOUR, "zappo", colour);
}
structureFilepath, tft, paeFilepath, false,
ssFromStructure, false, viewerType);
- if (headless)
+ if (sv == null)
{
- sv.setAsync(false);
+ Console.error("Failed to import and open structure view.");
+ continue;
}
-
+ try
+ {
+ long tries = 1000;
+ while (sv.isBusy() && tries > 0)
+ {
+ Thread.sleep(25);
+ if (sv.isBusy())
+ {
+ tries--;
+ Console.debug(
+ "Waiting for viewer for " + structureFilepath);
+ }
+ }
+ if (tries == 0 && sv.isBusy())
+ {
+ Console.warn(
+ "Gave up waiting for structure viewer to load. Something may have gone wrong.");
+ }
+ } catch (Exception x)
+ {
+ Console.warn("Exception whilst waiting for structure viewer "
+ + structureFilepath, x);
+ }
+ Console.debug(
+ "Successfully opened viewer for " + structureFilepath);
String structureImageFilename = ArgParser.getValueFromSubValOrArg(
avm, av, Arg.STRUCTUREIMAGE, subVals);
if (sv != null && structureImageFilename != null)
}
BitmapImageSizing userBis = ImageMaker
.parseScaleWidthHeightStrings(scale, width, height);
+ // TODO MAKE THIS VIEWER INDEPENDENT!!
switch (StructureViewer.getViewerType())
{
case JMOL:
try
{
- Thread.sleep(1000);
+ Thread.sleep(1000); // WHY ???
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
if (sview instanceof AppJmol)
{
AppJmol jmol = (AppJmol) sview;
- jmol.makePDBImage(structureImageFile, imageType, renderer,
- userBis);
+ try
+ {
+ Console.debug("Rendering image to " + structureImageFile);
+ jmol.makePDBImage(structureImageFile, imageType, renderer,
+ userBis);
+ Console.debug("Finished Rendering image to "
+ + structureImageFile);
+
+ } catch (ImageOutputException ioexc)
+ {
+ Console.warn("Unexpected error whilst exporting image to "
+ + structureImageFile, ioexc);
+ }
+
}
break;
default:
Cache.setProperty("EXPORT_EMBBED_BIOJSON", "false");
Console.info("Writing " + file);
-
- switch (type)
+ try
{
-
- case "svg":
- Console.debug("Outputting type '" + type + "' to " + fileName);
- af.createSVG(file, renderer);
- break;
-
- case "png":
- Console.debug("Outputting type '" + type + "' to " + fileName);
- af.createPNG(file, null, userBis);
- break;
-
- case "html":
- Console.debug("Outputting type '" + type + "' to " + fileName);
- HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
- htmlSVG.exportHTML(fileName, renderer);
- break;
-
- case "biojs":
- try
+ switch (type)
{
- BioJsHTMLOutput.refreshVersionInfo(
- BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
- } catch (URISyntaxException e)
- {
- e.printStackTrace();
+
+ case "svg":
+ Console.debug("Outputting type '" + type + "' to " + fileName);
+ af.createSVG(file, renderer);
+ break;
+
+ case "png":
+ Console.debug("Outputting type '" + type + "' to " + fileName);
+ af.createPNG(file, null, userBis);
+ break;
+
+ case "html":
+ Console.debug("Outputting type '" + type + "' to " + fileName);
+ HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
+ htmlSVG.exportHTML(fileName, renderer);
+ break;
+
+ case "biojs":
+ Console.debug(
+ "Outputting BioJS MSA Viwer HTML file: " + fileName);
+ try
+ {
+ BioJsHTMLOutput.refreshVersionInfo(
+ BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
+ } catch (URISyntaxException e)
+ {
+ e.printStackTrace();
+ }
+ BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
+ bjs.exportHTML(fileName);
+ break;
+
+ case "eps":
+ Console.debug("Outputting EPS file: " + fileName);
+ af.createEPS(file, renderer);
+ break;
+
+ case "imagemap":
+ Console.debug("Outputting ImageMap file: " + fileName);
+ af.createImageMap(file, name);
+ break;
+
+ default:
+ Console.warn(Arg.IMAGE.argString() + " type '" + type
+ + "' not known. Ignoring");
+ break;
}
- BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
- bjs.exportHTML(fileName);
- Console.debug("Creating BioJS MSA Viwer HTML file: " + fileName);
- break;
-
- case "eps":
- af.createEPS(file, name);
- Console.debug("Creating EPS file: " + fileName);
- break;
-
- case "imagemap":
- af.createImageMap(file, name);
- Console.debug("Creating ImageMap file: " + fileName);
- break;
-
- default:
- Console.warn(Arg.IMAGE.argString() + " type '" + type
- + "' not known. Ignoring");
- break;
+ } catch (Exception ioex)
+ {
+ Console.warn("Unexpected error during export", ioex);
}
}
}
return JLogger.toLevel(level);
}
+ public static JLogger getLogger()
+ {
+ return log;
+ }
+
public static boolean initLogger()
{
return initLogger(null);
JLogger.LogLevel logLevel = JLogger.LogLevel.INFO;
if (JLogger.isLevel(providedLogLevel))
+ {
logLevel = Console.getLogLevel(providedLogLevel);
+ }
else
+ {
logLevel = getCachedLogLevel();
+ }
if (!Platform.isJS())
{
import jalview.io.HtmlSvgOutput;
import jalview.io.IdentifyFile;
import jalview.io.NewickFile;
+import jalview.io.exceptions.ImageOutputException;
import jalview.io.gff.SequenceOntologyFactory;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemeProperty;
}
}
+ // set individual session preferences
+ if (bootstrapArgs.contains(Arg.P))
+ {
+ for (String kev : bootstrapArgs.getValueList(Arg.P))
+ {
+ if (kev == null)
+ {
+ continue;
+ }
+ int equalsIndex = kev.indexOf(ArgParser.EQUALS);
+ if (equalsIndex > -1)
+ {
+ String key = kev.substring(0, equalsIndex);
+ String val = kev.substring(equalsIndex + 1);
+ Cache.setSessionProperty(key, val);
+ }
+ }
+ }
+
// Move any new getdown-launcher-new.jar into place over old
// getdown-launcher.jar
String appdirString = System.getProperty("getdownappdir");
{
headless = true;
}
- System.setProperty("http.agent",
- "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
+ System.setProperty("http.agent", HttpUtils.getUserAgent());
try
{
testoutput(argparser, Arg.WEBSERVICEDISCOVERY);
}
- boolean usagestats = bootstrapArgs.getBoolean(Arg.USAGESTATS);
+ boolean usagestats = !bootstrapArgs.getBoolean(Arg.NOUSAGESTATS);
if (aparser.contains("nousagestats"))
usagestats = false;
if (usagestats)
{
startUsageStats(desktop);
- testoutput(argparser, Arg.USAGESTATS);
+ testoutput(argparser, Arg.NOUSAGESTATS);
}
else
{
System.out.println("CMD [-nousagestats] executed successfully!");
- testoutput(argparser, Arg.USAGESTATS);
+ testoutput(argparser, Arg.NOUSAGESTATS);
}
boolean questionnaire = bootstrapArgs.getBoolean(Arg.QUESTIONNAIRE);
// Run Commands from cli
cmds = new Commands(argparser, headlessArg);
boolean commandsSuccess = cmds.argsWereParsed();
+
if (commandsSuccess)
{
if (headlessArg)
ex.printStackTrace(System.err);
}
}
- // TODO - load PDB structure(s) to alignment JAL-629
- // (associate with identical sequence in alignment, or a specified
- // sequence)
+
if (groovyscript != null)
{
// Execute the groovy script after we've done all the rendering stuff
String imageName = "unnamed.png";
while (aparser.getSize() > 1)
{
- String outputFormat = aparser.nextValue();
- file = aparser.nextValue();
-
- if (outputFormat.equalsIgnoreCase("png"))
- {
- af.createPNG(new File(file));
- imageName = (new File(file)).getName();
- System.out.println("Creating PNG image: " + file);
- continue;
- }
- else if (outputFormat.equalsIgnoreCase("svg"))
- {
- File imageFile = new File(file);
- imageName = imageFile.getName();
- af.createSVG(imageFile);
- System.out.println("Creating SVG image: " + file);
- continue;
- }
- else if (outputFormat.equalsIgnoreCase("html"))
+ try
{
- File imageFile = new File(file);
- imageName = imageFile.getName();
- HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
- htmlSVG.exportHTML(file);
+ String outputFormat = aparser.nextValue();
+ file = aparser.nextValue();
- System.out.println("Creating HTML image: " + file);
- continue;
- }
- else if (outputFormat.equalsIgnoreCase("biojsmsa"))
- {
- if (file == null)
+ if (outputFormat.equalsIgnoreCase("png"))
{
- System.err.println("The output html file must not be null");
- return;
+ System.out.println("Creating PNG image: " + file);
+ af.createPNG(new File(file));
+ imageName = (new File(file)).getName();
+ continue;
}
- try
+ else if (outputFormat.equalsIgnoreCase("svg"))
{
- BioJsHTMLOutput.refreshVersionInfo(
- BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
- } catch (URISyntaxException e)
+ System.out.println("Creating SVG image: " + file);
+ File imageFile = new File(file);
+ imageName = imageFile.getName();
+ af.createSVG(imageFile);
+ continue;
+ }
+ else if (outputFormat.equalsIgnoreCase("html"))
{
- e.printStackTrace();
+ File imageFile = new File(file);
+ imageName = imageFile.getName();
+ HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
+
+ System.out.println("Creating HTML image: " + file);
+ htmlSVG.exportHTML(file);
+ continue;
}
- BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
- bjs.exportHTML(file);
- System.out
- .println("Creating BioJS MSA Viwer HTML file: " + file);
- continue;
- }
- else if (outputFormat.equalsIgnoreCase("imgMap"))
- {
- af.createImageMap(new File(file), imageName);
- System.out.println("Creating image map: " + file);
- continue;
- }
- else if (outputFormat.equalsIgnoreCase("eps"))
- {
- File outputFile = new File(file);
- System.out.println(
- "Creating EPS file: " + outputFile.getAbsolutePath());
- af.createEPS(outputFile);
- continue;
- }
- FileFormatI outFormat = null;
- try
- {
- outFormat = FileFormats.getInstance().forName(outputFormat);
- } catch (Exception formatP)
- {
- System.out.println("Couldn't parse " + outFormat
- + " as a valid Jalview format string.");
- }
- if (outFormat != null)
- {
- if (!outFormat.isWritable())
+ else if (outputFormat.equalsIgnoreCase("biojsmsa"))
{
+ if (file == null)
+ {
+ System.err.println("The output html file must not be null");
+ return;
+ }
+ try
+ {
+ BioJsHTMLOutput.refreshVersionInfo(
+ BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
+ } catch (URISyntaxException e)
+ {
+ e.printStackTrace();
+ }
+ BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
System.out.println(
- "This version of Jalview does not support alignment export as "
- + outputFormat);
+ "Creating BioJS MSA Viwer HTML file: " + file);
+ bjs.exportHTML(file);
+ continue;
+ }
+ else if (outputFormat.equalsIgnoreCase("imgMap"))
+ {
+ System.out.println("Creating image map: " + file);
+ af.createImageMap(new File(file), imageName);
+ continue;
}
- else
+ else if (outputFormat.equalsIgnoreCase("eps"))
{
- af.saveAlignment(file, outFormat);
- if (af.isSaveAlignmentSuccessful())
+ File outputFile = new File(file);
+ System.out.println(
+ "Creating EPS file: " + outputFile.getAbsolutePath());
+ af.createEPS(outputFile);
+ continue;
+ }
+
+ FileFormatI outFormat = null;
+ try
+ {
+ outFormat = FileFormats.getInstance().forName(outputFormat);
+ } catch (Exception formatP)
+ {
+ System.out.println("Couldn't parse " + outFormat
+ + " as a valid Jalview format string.");
+ }
+ if (outFormat != null)
+ {
+ if (!outFormat.isWritable())
{
- System.out.println("Written alignment in "
- + outFormat.getName() + " format to " + file);
+ System.out.println(
+ "This version of Jalview does not support alignment export as "
+ + outputFormat);
}
else
{
- System.out.println("Error writing file " + file + " in "
- + outFormat.getName() + " format!!");
+ af.saveAlignment(file, outFormat);
+ if (af.isSaveAlignmentSuccessful())
+ {
+ System.out.println("Written alignment in "
+ + outFormat.getName() + " format to " + file);
+ }
+ else
+ {
+ System.out.println("Error writing file " + file + " in "
+ + outFormat.getName() + " format!!");
+ }
}
}
+ } catch (ImageOutputException ioexc)
+ {
+ System.out.println(
+ "Unexpected error whilst exporting image to " + file);
+ ioexc.printStackTrace();
}
}
if (!Platform.isJS() && !headless && file == null
&& Cache.getDefault("SHOW_STARTUP_FILE", true)
- && !cmds.commandArgsProvided())
+ && !cmds.commandArgsProvided()
+ && !bootstrapArgs.getBoolean(Arg.NOSTARTUPFILE))
// don't open the startup file if command line args have been processed
// (&& !Commands.commandArgsProvided())
/**
private static void setLookAndFeel()
{
- // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
- // "mac" or "flat"
- // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
- // try Quaqua/Vaqua.
- String lafProp = System.getProperty("laf");
- String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
- String laf = "none";
- if (lafProp != null)
- {
- laf = lafProp;
- }
- else if (lafSetting != null)
- {
- laf = lafSetting;
- }
- boolean lafSet = false;
- switch (laf)
+ if (!Platform.isJS())
+ /**
+ * Java only
+ *
+ * @j2sIgnore
+ */
{
- case "crossplatform":
- lafSet = setCrossPlatformLookAndFeel();
- if (!lafSet)
- {
- Console.error("Could not set requested laf=" + laf);
+ // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
+ // "mac" or "flat"
+ // If not set (or chosen laf fails), use the normal SystemLaF and if on
+ // Mac,
+ // try Quaqua/Vaqua.
+ String lafProp = System.getProperty("laf");
+ String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
+ String laf = "none";
+ if (lafProp != null)
+ {
+ laf = lafProp;
}
- break;
- case "system":
- lafSet = setSystemLookAndFeel();
- if (!lafSet)
- {
- Console.error("Could not set requested laf=" + laf);
- }
- break;
- case "gtk":
- lafSet = setGtkLookAndFeel();
- if (!lafSet)
+ else if (lafSetting != null)
{
- Console.error("Could not set requested laf=" + laf);
+ laf = lafSetting;
}
- break;
- case "metal":
- lafSet = setMetalLookAndFeel();
- if (!lafSet)
- {
- Console.error("Could not set requested laf=" + laf);
- }
- break;
- case "nimbus":
- lafSet = setNimbusLookAndFeel();
- if (!lafSet)
- {
- Console.error("Could not set requested laf=" + laf);
- }
- break;
- case "flat":
- lafSet = setFlatLookAndFeel();
- if (!lafSet)
+ boolean lafSet = false;
+ switch (laf)
{
- Console.error("Could not set requested laf=" + laf);
- }
- break;
- case "mac":
- lafSet = setMacLookAndFeel();
- if (!lafSet)
- {
- Console.error("Could not set requested laf=" + laf);
+ case "crossplatform":
+ lafSet = setCrossPlatformLookAndFeel();
+ if (!lafSet)
+ {
+ Console.error("Could not set requested laf=" + laf);
+ }
+ break;
+ case "system":
+ lafSet = setSystemLookAndFeel();
+ if (!lafSet)
+ {
+ Console.error("Could not set requested laf=" + laf);
+ }
+ break;
+ case "gtk":
+ lafSet = setGtkLookAndFeel();
+ if (!lafSet)
+ {
+ Console.error("Could not set requested laf=" + laf);
+ }
+ break;
+ case "metal":
+ lafSet = setMetalLookAndFeel();
+ if (!lafSet)
+ {
+ Console.error("Could not set requested laf=" + laf);
+ }
+ break;
+ case "nimbus":
+ lafSet = setNimbusLookAndFeel();
+ if (!lafSet)
+ {
+ Console.error("Could not set requested laf=" + laf);
+ }
+ break;
+ case "flat":
+ lafSet = setFlatLookAndFeel();
+ if (!lafSet)
+ {
+ Console.error("Could not set requested laf=" + laf);
+ }
+ break;
+ case "mac":
+ lafSet = setMacLookAndFeel();
+ if (!lafSet)
+ {
+ Console.error("Could not set requested laf=" + laf);
+ }
+ break;
+ case "none":
+ break;
+ default:
+ Console.error("Requested laf=" + laf + " not implemented");
}
- break;
- case "none":
- break;
- default:
- Console.error("Requested laf=" + laf + " not implemented");
- }
- if (!lafSet)
- {
- // Flatlaf default for everyone!
- lafSet = setFlatLookAndFeel();
if (!lafSet)
{
- setSystemLookAndFeel();
- }
- if (Platform.isLinux())
- {
- setLinuxLookAndFeel();
- }
- if (Platform.isMac())
- {
- setMacLookAndFeel();
+ // Flatlaf default for everyone!
+ lafSet = setFlatLookAndFeel();
+ if (!lafSet)
+ {
+ setSystemLookAndFeel();
+ }
+ if (Platform.isLinux())
+ {
+ setLinuxLookAndFeel();
+ }
+ if (Platform.isMac())
+ {
+ setMacLookAndFeel();
+ }
}
}
}
+ "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
+ "-noquestionnaire\tTurn off questionnaire check.\n"
+ "-nonews\tTurn off check for Jalview news.\n"
- + "-nousagestats\tTurn off google analytics tracking for this session.\n"
+ + "-nousagestats\tTurn off analytics tracking for this session.\n"
+ "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
// +
// "-setprop PROPERTY=VALUE\tSet the given Jalview property,
* start a User Config prompt asking if we can log usage statistics.
*/
PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
- "USAGESTATS", "Jalview Usage Statistics",
- "Do you want to help make Jalview better by enabling "
- + "the collection of usage statistics with Google Analytics ?"
- + "\n\n(you can enable or disable usage tracking in the preferences)",
+ "USAGESTATS",
+ MessageManager.getString("prompt.plausible_analytics_title"),
+ MessageManager.getString("prompt.plausible_analytics"),
new Runnable()
{
@Override
public void run()
{
- Console.debug(
- "Initialising googletracker for usage stats.");
- Cache.initGoogleTracker();
+ Console.debug("Initialising analytics for usage stats.");
+ Cache.initAnalytics();
Console.debug("Tracking enabled.");
}
}, new Runnable()
@Override
public void run()
{
- Console.debug("Not enabling Google Tracking.");
+ Console.debug("Not enabling analytics.");
}
}, null, true);
desktop.addDialogThread(prompter);
}
}
- /*
- * testoutput for string values
+ /******************************
+ *
+ * TEST OUTPUT METHODS
+ *
+ ******************************/
+ /**
+ * method for reporting string values parsed/processed during tests
+ *
*/
protected static void testoutput(ArgParser ap, Arg a, String s1,
String s2)
testoutput(true, a, s1, s2);
}
+ /**
+ * method for reporting string values parsed/processed during tests
+ */
+
protected static void testoutput(BootstrapArgs bsa, Arg a, String s1,
String s2)
{
testoutput(true, a, s1, s2);
}
+ /**
+ * report value set for string values parsed/processed during tests
+ */
private static void testoutput(boolean yes, Arg a, String s1, String s2)
{
if (yes && ((s1 == null && s2 == null)
}
/*
- * testoutput for boolean values
+ * testoutput for boolean and unary values
*/
protected static void testoutput(ArgParser ap, Arg a)
{
private static void testoutput(boolean yes, Arg a)
{
- System.out.println("[TESTOUTPUT] arg "
- + (yes ? a.argString() : a.negateArgString()) + " was set");
+ String message = null;
+ if (a.hasOption(Opt.BOOLEAN))
+ {
+ message = (yes ? a.argString() : a.negateArgString()) + " was set";
+ }
+ else if (a.hasOption(Opt.UNARY))
+ {
+ message = a.argString() + (yes ? " was set" : " was not set");
+ }
+ System.out.println("[TESTOUTPUT] arg " + message);
}
}
QUESTIONNAIRE(Type.CONFIG,
"Show (or don't show) the questionnaire if one is available.",
true, Opt.BOOLEAN, Opt.BOOTSTRAP),
- USAGESTATS(Type.CONFIG,
- "Send (or don't send) initial launch usage stats.", true,
- Opt.BOOLEAN, Opt.BOOTSTRAP),
+ NOUSAGESTATS(Type.CONFIG, "Don't send initial launch usage stats.",
+ Opt.UNARY, Opt.BOOTSTRAP),
+ NOSTARTUPFILE(Type.CONFIG, "Don't show the default startup file.",
+ Opt.UNARY, Opt.BOOTSTRAP),
WEBSERVICEDISCOVERY(Type.CONFIG,
"Attempt (or don't attempt) to connect to JABAWS web services.",
true, Opt.BOOLEAN, Opt.BOOTSTRAP),
INITSUBSTITUTIONS(Type.CONFIG,
"Set ‑‑substitutions to be initially enabled (or initially disabled).",
true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET),
+ P(Type.CONFIG, "Set a Jalview preference value for this session.",
+ Opt.PREFIXKEV, Opt.PRESERVECASE, Opt.STRING, Opt.BOOTSTRAP,
+ Opt.MULTI, Opt.NOACTION, Opt.SECRET), // keep this secret for now.
// Opening an alignment
OPEN(Type.OPENING,
"Specifies the title for the open alignment window as string.",
Opt.STRING, Opt.LINKED),
COLOUR(Type.OPENING, "color", // being a bit soft on the Americans!
- "Applies the colour scheme to the open alignment window. Valid values are:\n"
+ "Applies the colour scheme to the open alignment window. Valid values include:\n"
+ "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
+ "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
+ "gecos-blossom,\n" + "gecos-sunset,\n"
+ "turn-propensity,\n" + "buried-index,\n"
+ "nucleotide,\n" + "nucleotide-ambiguity,\n"
+ "purine-pyrimidine,\n" + "rna-helices,\n"
- + "t-coffee-scores,\n" + "sequence-id.",
+ + "t-coffee-scores,\n" + "sequence-id.\n"
+ +"\n"
+ + "Names of user defined colourschemes will also work,\n"
+ +"and jalview colourscheme specifications like\n"
+ +"--colour=\"D,E=red; K,R,H=0022FF; C,c=yellow\"",
Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
* A LAST arg gets moved to appear last in the usage statement (within type)
*/
LAST(null),
+ /*
+ * After other args are checked, the following args can prefix a KEY=VALUE argument
+ */
+ PREFIXKEV("prefixes key=value"),
+ /*
+ * do not lowercase the name when getting the arg name or arg string
+ */
+ PRESERVECASE(null),
//
;
private Arg(Type type, String alternativeName, String description,
boolean defaultBoolean, Opt... options)
{
+ this.type = type;
+ this.description = description;
+ this.defaultBoolValue = defaultBoolean;
+ this.setOptions(options);
this.argNames = alternativeName != null
? new String[]
{ this.getName(), alternativeName }
: new String[]
{ this.getName() };
- this.type = type;
- this.description = description;
- this.defaultBoolValue = defaultBoolean;
- this.setOptions(options);
}
public String argString()
public String getName()
{
- return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
+ String name = hasOption(Opt.PRESERVECASE) ? this.name()
+ : this.name().toLowerCase(Locale.ROOT);
+ return name.replace('_', '-');
}
@Override
argSb.append(
a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString());
if (a.hasOption(Opt.STRING))
- argSb.append("=value");
+ {
+ if (a.hasOption(Opt.PREFIXKEV))
+ {
+ argSb.append("key=value");
+ }
+ else
+ {
+ argSb.append("=value");
+ }
+ }
return argSb.toString();
}
protected static final String DOUBLEDASH = "--";
- protected static final char EQUALS = '=';
+ public static final char EQUALS = '=';
protected static final String NEGATESTRING = "no";
- // the default linked id prefix used for no id (not even square braces)
+ /**
+ * the default linked id prefix used for no id (ie when not even square braces
+ * are provided)
+ */
protected static final String DEFAULTLINKEDIDPREFIX = "JALVIEW:";
- // the linkedId string used to match all linkedIds seen so far
+ /**
+ * the linkedId string used to match all linkedIds seen so far
+ */
protected static final String MATCHALLLINKEDIDS = "*";
- // the linkedId string used to match all of the last --open'ed linkedIds
+ /**
+ * the linkedId string used to match all of the last --open'ed linkedIds
+ */
protected static final String MATCHOPENEDLINKEDIDS = "open*";
- // the counter added to the default linked id prefix
+ /**
+ * the counter added to the default linked id prefix
+ */
private int defaultLinkedIdCounter = 0;
- // the substitution string used to use the defaultLinkedIdCounter
+ /**
+ * the substitution string used to use the defaultLinkedIdCounter
+ */
private static final String DEFAULTLINKEDIDCOUNTER = "{}";
- // the counter added to the default linked id prefix. NOW using
- // linkedIdAutoCounter
- // private int openLinkedIdCounter = 0;
-
- // the linked id prefix used for --open files. NOW the same as DEFAULT
+ /**
+ * the linked id prefix used for --open files. NOW the same as DEFAULT
+ */
protected static final String OPENLINKEDIDPREFIX = DEFAULTLINKEDIDPREFIX;
- // the counter used for {n} substitutions
+ /**
+ * the counter used for {n} substitutions
+ */
private int linkedIdAutoCounter = 0;
- // the linked id substitution string used to increment the idCounter (and use
- // the incremented value)
+ /**
+ * the linked id substitution string used to increment the idCounter (and use
+ * the incremented value)
+ */
private static final String INCREMENTLINKEDIDAUTOCOUNTER = "{++n}";
- // the linked id substitution string used to use the idCounter
+ /**
+ * the linked id substitution string used to use the idCounter
+ */
private static final String LINKEDIDAUTOCOUNTER = "{n}";
- // the linked id substitution string used to use the filename extension of
- // --append
- // or --open
+ /**
+ * the linked id substitution string used to use the filename extension of
+ * --append or --open
+ */
private static final String LINKEDIDEXTENSION = "{extension}";
- // the linked id substitution string used to use the base filename of --append
- // or --open
+ /**
+ * the linked id substitution string used to use the base filename of --append
+ */
+ /** or --open */
private static final String LINKEDIDBASENAME = "{basename}";
- // the linked id substitution string used to use the dir path of --append
- // or --open
+ /**
+ * the linked id substitution string used to use the dir path of --append or
+ * --open
+ */
private static final String LINKEDIDDIRNAME = "{dirname}";
- // the current argfile
+ /**
+ * the current argfile
+ */
private String argFile = null;
- // the linked id substitution string used to use the dir path of the latest
- // --argfile name
+ /**
+ * the linked id substitution string used to use the dir path of the latest
+ */
+ /** --argfile name */
private static final String ARGFILEBASENAME = "{argfilebasename}";
- // the linked id substitution string used to use the dir path of the latest
- // --argfile name
+ /**
+ * the linked id substitution string used to use the dir path of the latest
+ * --argfile name
+ */
private static final String ARGFILEDIRNAME = "{argfiledirname}";
- // flag to say whether {n} subtitutions in output filenames should be made.
- // Turn on and off with --substitutions and --nosubstitutions
- // Start with it on
+ /**
+ * flag to say whether {n} subtitutions in output filenames should be made.
+ * Turn on and off with --substitutions and --nosubstitutions Start with it on
+ */
private boolean substitutions = true;
- // flag to say whether the default linkedId is the current default linked id
- // or ALL linkedIds
+ /**
+ * flag to say whether the default linkedId is the current default linked id
+ *
+ * or ALL linkedIds
+ */
private boolean allLinkedIds = false;
- // flag to say whether the default linkedId is the current default linked id
- // or OPENED linkedIds
+ /**
+ * flag to say whether the default linkedId is the current default linked id
+ * or OPENED linkedIds
+ */
private boolean openedLinkedIds = false;
- // flag to say whether the structure arguments should be applied to all
- // structures with this linked id
+ /**
+ * flag to say whether the structure arguments should be applied to all
+ * structures with this linked id
+ */
private boolean allStructures = false;
protected static final Map<String, Arg> argMap;
Arg a = argMap.get(argName);
// check for boolean prepended by "no" e.g. --nowrap
boolean negated = false;
- if (a == null && argName.startsWith(NEGATESTRING) && argMap
- .containsKey(argName.substring(NEGATESTRING.length())))
+ if (a == null)
{
- argName = argName.substring(NEGATESTRING.length());
- a = argMap.get(argName);
- negated = true;
+ if (argName.startsWith(NEGATESTRING) && argMap
+ .containsKey(argName.substring(NEGATESTRING.length())))
+ {
+ argName = argName.substring(NEGATESTRING.length());
+ a = argMap.get(argName);
+ negated = true;
+ }
+ else
+ {
+ // after all other args, look for Opt.PREFIXKEV args if still not
+ // found
+ for (Arg potentialArg : EnumSet.allOf(Arg.class))
+ {
+ if (potentialArg.hasOption(Opt.PREFIXKEV) && argName != null
+ && argName.startsWith(potentialArg.getName())
+ && equalPos > -1)
+ {
+ val = argName.substring(potentialArg.getName().length())
+ + EQUALS + val;
+ argName = argName.substring(0,
+ potentialArg.getName().length());
+ a = potentialArg;
+ break;
+ }
+ }
+ }
}
// check for config errors
val = LINKEDIDDIRNAME + File.separator + LINKEDIDBASENAME
+ val.substring(MATCHALLLINKEDIDS.length());
}
- else if (a.hasOption(Opt.OUTPUTFILE) && a.hasOption(Opt.ALLOWALL)
+ else if (a.hasOption(Opt.OUTPUTFILE)
+ && a.hasOption(Opt.ALLOWALL)
&& val.startsWith(MATCHOPENEDLINKEDIDS))
{
// --output=open*.ext is shorthand for --opened --output
FIRST, BEFORE, AFTER
}
- // get from following Arg of type a or subval of same name (lowercase)
+ /**
+ * get from following Arg of type a or subval of same name (lowercase)
+ */
public static String getValueFromSubValOrArg(ArgValuesMap avm,
ArgValue av, Arg a, SubVals sv)
{
return getFromSubValArgOrPref(avm, av, a, sv, null, null, null);
}
- // get from following Arg of type a or subval key or preference pref or
- // default def
+ /**
+ * get from following Arg of type a or subval key or preference pref or
+ * default def
+ */
public static String getFromSubValArgOrPref(ArgValuesMap avm, ArgValue av,
Arg a, SubVals sv, String key, String pref, String def)
{
def);
}
- // get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
- // Arg of type a or subval key or preference pref or default def
+ /**
+ * get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
+ * Arg of type a or subval key or preference pref or default def
+ */
public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
Position pos, ArgValue av, SubVals sv, String key, String pref,
String def)
// the following methods look for the "*" linkedId and add the argvalue to all
// linkedId ArgValues if it does.
- // This version inserts the subvals sv into all created values
+ /**
+ * This version inserts the subvals sv into all created values
+ */
private void addValue(String linkedId, Type type, ArgValues avs,
SubVals sv, String v, int argIndex, boolean doSubs)
{
doSubs);
}
- /*
+ /**
* The following operations look for the "*" and "open*" linkedIds and add the
- * argvalue to all appropriate linkedId ArgValues if it does.
- * If subvals are supplied, they are inserted into all new set values.
+ * argvalue to all appropriate linkedId ArgValues if it does. If subvals are
+ * supplied, they are inserted into all new set values.
*
- * @param op The ArgParser.Op operation
- * @param linkedId The String linkedId from the ArgValuesMap
- * @param type The Arg.Type to attach to this ArgValue
- * @param avs The ArgValues for this linkedId
- * @param sv Use these SubVals on the ArgValue
- * @param merge Merge the SubVals with any existing on the value. False will replace unless sv is null
- * @param v The value of the ArgValue (may contain subvals).
- * @param b The boolean value of the ArgValue.
- * @param argIndex The argIndex for the ArgValue.
- * @param doSubs Whether to perform substitutions on the subvals and value.
+ * @param op
+ * The ArgParser.Op operation
+ * @param linkedId
+ * The String linkedId from the ArgValuesMap
+ * @param type
+ * The Arg.Type to attach to this ArgValue
+ * @param avs
+ * The ArgValues for this linkedId
+ * @param sv
+ * Use these SubVals on the ArgValue
+ * @param merge
+ * Merge the SubVals with any existing on the value. False will
+ * replace unless sv is null
+ * @param v
+ * The value of the ArgValue (may contain subvals).
+ * @param b
+ * The boolean value of the ArgValue.
+ * @param argIndex
+ * The argIndex for the ArgValue.
+ * @param doSubs
+ * Whether to perform substitutions on the subvals and value.
*/
private void argValueOperation(Op op, String linkedId, Type type,
ArgValues avs, SubVals sv, boolean merge, String v, boolean b,
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
}
}
+ // after all other args, look for Opt.PREFIX args if still not found
+ if (!ArgParser.argMap.containsKey(argName))
+ {
+ for (Arg potentialArg : EnumSet.allOf(Arg.class))
+ {
+ if (potentialArg.hasOption(Opt.PREFIXKEV) && argName != null
+ && argName.startsWith(potentialArg.getName())
+ && val != null)
+ {
+ val = argName.substring(potentialArg.getName().length())
+ + ArgParser.EQUALS + val;
+ argName = argName.substring(0,
+ potentialArg.getName().length());
+ break;
+ }
+ }
+ }
+
if (ArgParser.argMap.containsKey(argName) && val == null)
{
val = "true";
{
from_column = 0;
}
- if (to_column > getContactHeight())
+ if (to_column >= getContactHeight())
{
- to_column = getContactHeight();
+ to_column = getContactHeight()-1;
}
ContactRange cr = new ContactRange();
cr.setFrom_column(from_column);
import java.util.BitSet;
import java.util.List;
+import jalview.util.ColorUtils;
+import jalview.ws.datamodel.MappableContactMatrixI;
+
public interface ContactMatrixI
{
}
void setGroupSet(GroupSet makeGroups);
+
+ default void randomlyReColourGroups() {
+ if (hasGroupSet())
+ {
+ GroupSetI groups = getGroupSet();
+ for (BitSet group:groups.getGroups())
+ {
+ groups.setColorForGroup(group, ColorUtils.getARandomColor());
+ }
+ }
+ }
+
+ default void transferGroupColorsTo(AlignmentAnnotation aa)
+ {
+ if (hasGroupSet())
+ {
+ GroupSetI groups = getGroupSet();
+ // stash colors in linked annotation row.
+ // doesn't work yet. TESTS!
+ int sstart = aa.sequenceRef != null ? aa.sequenceRef.getStart() - 1
+ : 0;
+ Annotation ae;
+ Color gpcol = null;
+ int[] seqpos = null;
+ for (BitSet gp : groups.getGroups())
+ {
+ gpcol = groups.getColourForGroup(gp);
+ for (int p = gp.nextSetBit(0); p >= 0
+ && p < Integer.MAX_VALUE; p = gp.nextSetBit(p + 1))
+ {
+ if (this instanceof MappableContactMatrixI)
+ {
+ MappableContactMatrixI mcm = (MappableContactMatrixI) this;
+ seqpos = mcm.getMappedPositionsFor(aa.sequenceRef, p);
+ if (seqpos == null)
+ {
+ // no mapping for this column.
+ continue;
+ }
+ // TODO: handle ranges...
+ ae = aa.getAnnotationForPosition(seqpos[0]);
+ }
+ else
+ {
+ ae = aa.getAnnotationForPosition(p + sstart);
+ }
+ if (ae != null)
+ {
+ ae.colour = gpcol.brighter().darker();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * look up the colour for a column in the associated contact matrix
+ * @return Color.white or assigned colour
+ */
+ default Color getGroupColorForPosition(int column)
+ {
+ if (hasGroupSet())
+ {
+ GroupSetI groups = getGroupSet();
+ for (BitSet gp:groups.getGroups())
+ {
+ if (gp.get(column))
+ {
+ return groups.getColourForGroup(gp);
+ }
+ }
+ }
+ return Color.white;
+ }
+
}
public static boolean isPrimaryCandidate(String ucversion)
{
+ if (ucversion==null)
+ {
+ // Null/empty version is not a real reference ?
+ return false;
+ }
// tricky - this test really needs to search the sequence's set of dbrefs to
// see if there is a primary reference that derived this reference.
for (int i = allSources.length; --i >= 0;)
return treeType;
}
- public static GroupSet makeGroups(ContactMatrixI matrix, float thresh,
+ public static GroupSet makeGroups(ContactMatrixI matrix, boolean autoCut)
+ {
+ return makeGroups(matrix, autoCut, 0, autoCut);
+ }
+ public static GroupSet makeGroups(ContactMatrixI matrix, boolean auto, float thresh,
boolean abs)
{
AverageDistanceEngine clusterer = new AverageDistanceEngine(null, null,
- matrix);
+ matrix, true);
double height = clusterer.findHeight(clusterer.getTopNode());
+ Console.debug("Column tree height: " + height);
String newick = new jalview.io.NewickFile(clusterer.getTopNode(), false,
true).print();
String treeType = "UPGMA";
Console.trace("Newick string\n" + newick);
List<BinaryNode> nodegroups;
- if (abs ? height > thresh : 0 < thresh && thresh < 1)
+ float cut = -1f;
+ if (auto)
{
- float cut = abs ? (float) (thresh / height) : thresh;
- Console.debug("Threshold " + cut + " for height=" + height);
-
- nodegroups = clusterer.groupNodes(cut);
+ double rootw = 0;
+ int p = 2;
+ BinaryNode bn = clusterer.getTopNode();
+ while (p-- > 0 & bn.left() != null)
+ {
+ if (bn.left() != null)
+ {
+ bn = bn.left();
+ }
+ if (bn.left() != null)
+ {
+ rootw = bn.height;
+ }
+ }
+ thresh = Math.max((float) (rootw / height) - 0.01f, 0);
+ cut = thresh;
+ nodegroups = clusterer.groupNodes(thresh);
}
else
{
- nodegroups = new ArrayList<BinaryNode>();
- nodegroups.add(clusterer.getTopNode());
+ if (abs ? (height > thresh) : (0 < thresh && thresh < 1))
+ {
+ cut = abs ? thresh : (float) (thresh * height);
+ Console.debug("Threshold " + cut + " for height=" + height);
+ nodegroups = clusterer.groupNodes(cut);
+ }
+ else
+ {
+ nodegroups = new ArrayList<BinaryNode>();
+ nodegroups.add(clusterer.getTopNode());
+ }
}
+
List<BitSet> groups = new ArrayList<>();
for (BinaryNode root : nodegroups)
{
}
groups.add(gpset);
}
- GroupSet grps = new GroupSet(abs, thresh, groups, treeType, newick);
+ GroupSet grps = new GroupSet(abs, (cut == -1f) ? thresh : cut, groups,
+ treeType, newick);
return grps;
}
transferAnnotation(entry.getDatasetSequence(), mp);
return;
}
+ // transfer from entry to sequence
+ // if entry has a description and sequence doesn't, then transfer
+ if (entry.getDescription()!=null && (description==null || description.trim().length()==0))
+ {
+ description = entry.getDescription();
+ }
+
// transfer any new features from entry onto sequence
if (entry.getSequenceFeatures() != null)
{
{
int length = sq.getLength();
boolean ssFound = false;
- Annotation asecstr[] = new Annotation[length + firstResNum - 1];
+ Annotation asecstr[] = new Annotation[length + (firstResNum-sq.getStart())];
for (int p = 0; p < length; p++)
{
if (secstr[p] >= 'A' && secstr[p] <= 'z')
import jalview.io.NewickFile;
import jalview.io.ScoreMatrixFile;
import jalview.io.TCoffeeScoreFile;
+import jalview.io.exceptions.ImageOutputException;
import jalview.io.vcf.VCFLoader;
import jalview.jbgui.GAlignFrame;
import jalview.project.Jalview2XML;
protected void htmlMenuItem_actionPerformed(ActionEvent e)
{
HtmlSvgOutput htmlSVG = new HtmlSvgOutput(alignPanel);
- htmlSVG.exportHTML(null);
+ try {
+ htmlSVG.exportHTML(null);
+ } catch (ImageOutputException x) {
+ // report problem to console and raise dialog
+ }
}
@Override
public void bioJSMenuItem_actionPerformed(ActionEvent e)
{
BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel);
+ try {
bjs.exportHTML(null);
+ } catch (ImageOutputException x) {
+ // report problem to console and raise dialog
+ }
}
public void createImageMap(File file, String image)
{
+ try {
alignPanel.makePNGImageMap(file, image);
+ } catch (ImageOutputException x) {
+ // report problem to console and raise dialog
+ }
}
+ @Override
+ public void createPNG_actionPerformed(ActionEvent e) {
+ try{
+ createPNG(null);
+ } catch (ImageOutputException ioex)
+ {
+ // raise dialog, and report via console
+ }
+ }
+ @Override
+ public void createEPS_actionPerformed(ActionEvent e) {
+ try{
+ createEPS(null);
+ } catch (ImageOutputException ioex)
+ {
+ // raise dialog, and report via console
+ }
+
+ }
+ @Override
+ public void createSVG_actionPerformed(ActionEvent e) {
+ try{
+ createSVG(null);
+ } catch (ImageOutputException ioex)
+ {
+ // raise dialog, and report via console
+ }
+
+ }
/**
* Creates a PNG image of the alignment and writes it to the given file. If
* the file is null, the user is prompted to choose a file.
*
* @param f
*/
- @Override
- public void createPNG(File f)
+ public void createPNG(File f) throws ImageOutputException
{
createPNG(f, null, BitmapImageSizing.nullBitmapImageSizing());
}
- public void createPNG(File f, String renderer, BitmapImageSizing userBis)
+ public void createPNG(File f, String renderer, BitmapImageSizing userBis) throws ImageOutputException
{
alignPanel.makeAlignmentImage(TYPE.PNG, f, renderer, userBis);
}
*
* @param f
*/
- @Override
- public void createEPS(File f)
+ public void createEPS(File f) throws ImageOutputException
{
createEPS(f, null);
}
- public void createEPS(File f, String renderer)
+ public void createEPS(File f, String renderer) throws ImageOutputException
{
alignPanel.makeAlignmentImage(TYPE.EPS, f, renderer);
}
*
* @param f
*/
- @Override
- public void createSVG(File f)
+ public void createSVG(File f) throws ImageOutputException
{
createSVG(f, null);
}
- public void createSVG(File f, String renderer)
+ public void createSVG(File f, String renderer) throws ImageOutputException
{
alignPanel.makeAlignmentImage(TYPE.SVG, f, renderer);
}
{
NewickFile fin = new NewickFile(
new FileParse(cm.getNewick(), DataSourceType.PASTE));
- String title = cm.getAnnotLabel() + " " + cm.getTreeMethod() + " tree"
- + aa.sequenceRef != null
+ String title = aa.label + " "
+ + cm.getTreeMethod() + " tree" + (aa.sequenceRef != null
? (" for " + aa.sequenceRef.getDisplayId(false))
- : "";
+ : "");
showColumnWiseTree(fin, aa, title, w, h, x, y);
} catch (Throwable xx)
{
return null;
}
- TreePanel tp = new TreePanel(alignPanel, nf, aa, title);
+ TreePanel tp = new TreePanel(alignPanel, nf, aa, treeTitle);
tp.setSize(w, h);
tp.setLocation(x, y);
}
- Desktop.addInternalFrame(tp, title, w, h);
+ Desktop.addInternalFrame(tp, treeTitle, w, h);
return tp;
} catch (Throwable xx)
{
import jalview.datamodel.SequenceI;
import jalview.gui.ImageExporter.ImageWriterI;
import jalview.io.HTMLOutput;
+import jalview.io.exceptions.ImageOutputException;
import jalview.jbgui.GAlignmentPanel;
import jalview.math.AlignmentDimension;
import jalview.schemes.ResidueProperties;
}
void makeAlignmentImage(ImageMaker.TYPE type, File file, String renderer)
+ throws ImageOutputException
{
makeAlignmentImage(type, file, renderer,
BitmapImageSizing.nullBitmapImageSizing());
* @param bitmapscale
*/
void makeAlignmentImage(ImageMaker.TYPE type, File file, String renderer,
- BitmapImageSizing userBis)
+ BitmapImageSizing userBis) throws ImageOutputException
{
final int borderBottomOffset = 5;
}
public void makePNGImageMap(File imgMapFile, String imageName)
+ throws ImageOutputException
{
// /////ONLY WORKS WITH NON WRAPPED ALIGNMENTS
// ////////////////////////////////////////////
} catch (Exception ex)
{
- ex.printStackTrace();
+ throw new ImageOutputException(
+ "couldn't write ImageMap due to unexpected error", ex);
}
} // /////////END OF IMAGE MAP
public void actionPerformed(ActionEvent e)
{
sel_row.setShowGroupsForContactMatrix(chitem.getState());
- ap.getAnnotationPanel()
- .paint(ap.getAnnotationPanel().getGraphics());
+ // so any annotation colour changes are propagated - though they
+ // probably won't be unless the annotation row colours are removed
+ // too!
+ ap.alignmentChanged();
}
});
pop.add(chitem);
{
final long progBar;
ap.alignFrame.setProgressBar(MessageManager.formatMessage("action.clustering_matrix_for",cm.getAnnotDescr(),5f), progBar = System.currentTimeMillis());
- cm.setGroupSet(GroupSet.makeGroups(cm, 5f, true));
+ cm.setGroupSet(GroupSet.makeGroups(cm, true));
+ cm.randomlyReColourGroups();
+ cm.transferGroupColorsTo(alignmentAnnotation);
+ ap.alignmentChanged();
ap.alignFrame.showContactMapTree(alignmentAnnotation, cm);
ap.alignFrame.setProgressBar(null, progBar);
}
if (evt.isControlDown()
&& PAEContactMatrix.PAEMATRIX.equals(clicked.getCalcId()))
{
- int c = fr - 1;
+ int c = fr;
ContactRange cr = forCurrentX.getRangeFor(fr, to);
double cval;
// TODO: could use GraphLine instead of arbitrary picking
// controls feathering - what other elements in row/column
// should we select
double thresh = cr.getMean() + (cr.getMax() - cr.getMean()) * .15;
- while (c > 0)
+ while (c >= 0)
{
cval = forCurrentX.getContactAt(c);
if (// cr.getMin() <= cval &&
ContactGeometry lastXcgeom = new ContactGeometry(forFromX,
cma.graphHeight);
ContactGeometry.contactInterval lastXci = lastXcgeom
- .mapFor(rowIndex[1], rowIndex[1] - deltaY);
+ .mapFor(rowIndex[1], rowIndex[1] + deltaY);
ContactGeometry cXcgeom = new ContactGeometry(forToX,
cma.graphHeight);
ContactGeometry.contactInterval cXci = cXcgeom.mapFor(rowIndex[1],
- rowIndex[1] - deltaY);
+ rowIndex[1] + deltaY);
// mark rectangular region formed by drag
jalview.bin.Console.trace("Matrix Selection from last(" + fromXc
{
row = i;
res[0] = row;
- res[1] = height - yPos;
+ res[1] = yPos-lheight;
break;
}
}
// TODO abstract tooltip generator so different implementations can be built
if (ann.graph == AlignmentAnnotation.CONTACT_MAP)
{
+ if (rowAndOffset>=ann.graphHeight)
+ {
+ return null;
+ }
ContactListI clist = av.getContactList(ann, column);
if (clist != null)
{
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.io.File;
+import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import jalview.datamodel.StructureViewerModel.StructureData;
import jalview.gui.ImageExporter.ImageWriterI;
import jalview.gui.StructureViewer.ViewerType;
+import jalview.io.exceptions.ImageOutputException;
import jalview.structure.StructureCommand;
import jalview.structures.models.AAStructureBindingModel;
import jalview.util.BrowserLauncher;
@Override
public void makePDBImage(ImageMaker.TYPE type)
{
+ try {
makePDBImage(null, type, null,
BitmapImageSizing.nullBitmapImageSizing());
+ } catch (ImageOutputException ioex) {
+ Console.error("Unexpected error whilst writing "+type.toString(),ioex);
+ }
}
public void makePDBImage(File file, ImageMaker.TYPE type, String renderer,
- BitmapImageSizing userBis)
+ BitmapImageSizing userBis) throws ImageOutputException
{
int width = getWidth();
int height = getHeight();
};
String view = MessageManager.getString("action.view")
.toLowerCase(Locale.ROOT);
- ImageExporter exporter = new ImageExporter(writer,
+ final ImageExporter exporter = new ImageExporter(writer,
getProgressIndicator(), type, getTitle());
- exporter.doExport(file, this, width, height, view, renderer, userBis);
+
+ final Throwable[] exceptions = new Throwable[1];
+ exceptions[0] = null;
+ final AppJmol us = this;
+ try
+ {
+ Thread runner = Executors.defaultThreadFactory().newThread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ exporter.doExport(file, us, width, height, view, renderer,
+ userBis);
+ } catch (Throwable t)
+ {
+ exceptions[0] = t;
+ }
+ }
+ });
+ runner.start();
+ do { Thread.sleep(25); } while (runner.isAlive());
+ } catch (Throwable e)
+ {
+ throw new ImageOutputException(
+ "Unexpected error when generating image", e);
+ }
+ if (exceptions[0] != null)
+ {
+ if (exceptions[0] instanceof ImageOutputException)
+ {
+ throw ((ImageOutputException) exceptions[0]);
+ }
+ else
+ {
+ throw new ImageOutputException(
+ "Unexpected error when generating image", exceptions[0]);
+ }
+ }
}
@Override
import jalview.io.IdentifyFile;
import jalview.io.JalviewFileChooser;
import jalview.io.JalviewFileView;
+import jalview.io.exceptions.ImageOutputException;
import jalview.jbgui.GSplitFrame;
import jalview.jbgui.GStructureViewer;
import jalview.project.Jalview2XML;
setBounds(xPos, yPos, 900, 650);
}
+ // start dialogue queue for single dialogues
+ startDialogQueue();
+
if (!Platform.isJS())
/**
* Java only
}
});
desktop.addMouseListener(ma);
+
+ if (Platform.isJS())
+ {
+ // used for jalviewjsTest
+ jalview.bin.Console.info("JALVIEWJS: CREATED DESKTOP");
+ }
}
/**
setKeyBindings(frame);
- desktop.add(frame);
+ // Since the latest FlatLaf patch, we occasionally have problems showing structureViewer frames...
+ int tries=3;
+ boolean shown=false;
+ Exception last=null;
+ do
+ {
+ try
+ {
+ desktop.add(frame);
+ shown=true;
+ } catch (IllegalArgumentException iaex)
+ {
+ last=iaex;
+ tries--;
+ jalview.bin.Console.info(
+ "Squashed IllegalArgument Exception (" + tries + " left) for "+frame.getTitle(),
+ iaex);
+ try
+ {
+ Thread.sleep(5);
+ } catch (InterruptedException iex)
+ {
+ }
+ ;
+ }
+ } while (!shown && tries > 0);
+ if (!shown)
+ {
+ jalview.bin.Console.error("Serious Problem whilst showing window "+frame.getTitle(),last);
+ }
windowMenu.add(menuItem);
/**
* pause the queue
*/
- private java.util.concurrent.Semaphore block = new Semaphore(0);
+ private Semaphore block = new Semaphore(0);
private static groovy.ui.Console groovyConsole;
{
if (dialogPause)
{
- try
- {
- block.acquire();
- } catch (InterruptedException x)
- {
- }
+ acquireDialogQueue();
}
if (instance == null)
{
});
}
+ private boolean dialogQueueStarted = false;
+
public void startDialogQueue()
{
+ if (dialogQueueStarted)
+ {
+ return;
+ }
// set the flag so we don't pause waiting for another permit and semaphore
// the current task to begin
- dialogPause = false;
+ releaseDialogQueue();
+ dialogQueueStarted = true;
+ }
+
+ public void acquireDialogQueue()
+ {
+ try
+ {
+ block.acquire();
+ dialogPause = true;
+ } catch (InterruptedException e)
+ {
+ jalview.bin.Console.debug("Interruption when acquiring DialogueQueue",
+ e);
+ }
+ }
+
+ public void releaseDialogQueue()
+ {
+ if (!dialogPause)
+ {
+ return;
+ }
block.release();
+ dialogPause = false;
}
/**
String title = "View of desktop";
ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
title);
- exporter.doExport(of, this, width, height, title);
+ try
+ {
+ exporter.doExport(of, this, width, height, title);
+ } catch (ImageOutputException ioex)
+ {
+ jalview.bin.Console.error(
+ "Unexpected error whilst writing Jalview desktop snapshot as EPS",
+ ioex);
+ }
}
/**
jalview.bin.Console.debug(Cache.getStackTraceString(e));
}
}
+
+ /**
+ * closes the current instance window, disposes and forgets about it.
+ */
+ public static void closeDesktop()
+ {
+ if (Desktop.instance != null)
+ {
+ Desktop.instance.closeAll_actionPerformed(null);
+ Desktop.instance.setVisible(false);
+ Desktop us = Desktop.instance;
+ Desktop.instance = null;
+ // call dispose in a separate thread - try to avoid indirect deadlocks
+ new Thread(new Runnable() {
+ @Override
+ public void run()
+ {
+ ExecutorService dex = us.dialogExecutor;
+ if (dex!=null) {
+ dex.shutdownNow();
+ us.dialogExecutor=null;
+ us.block.drainPermits();
+ }
+ us.dispose();
+ }
+ }).start();
+ }
+ }
+
+ /**
+ * checks if any progress bars are being displayed in any of the windows managed by the desktop
+ * @return
+ */
+ public boolean operationsAreInProgress()
+ {
+ JInternalFrame[] frames = getAllFrames();
+ for (JInternalFrame frame:frames)
+ {
+ if (frame instanceof IProgressIndicator)
+ {
+ if (((IProgressIndicator)frame).operationInProgress())
+ {
+ return true;
+ }
+ }
+ }
+ return operationInProgress();
+ }
}
import jalview.bin.Jalview;
import jalview.io.JalviewFileChooser;
import jalview.io.JalviewFileView;
+import jalview.io.exceptions.ImageOutputException;
import jalview.util.ImageMaker;
import jalview.util.ImageMaker.TYPE;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.util.StringUtils;
import jalview.util.imagemaker.BitmapImageSizing;
/**
* what the image is of e.g. Tree, Alignment
*/
public void doExport(File file, Component parent, int width, int height,
- String imageSource)
+ String imageSource) throws ImageOutputException
{
doExport(file, parent, width, height, imageSource, null,
BitmapImageSizing.nullBitmapImageSizing());
public void doExport(File file, Component parent, int width, int height,
String imageSource, String renderer, BitmapImageSizing userBis)
+ throws ImageOutputException
{
final long messageId = System.currentTimeMillis();
setStatus(
*/
if (file == null && !Jalview.isHeadlessMode())
{
+ if (Desktop.instance.isInBatchMode())
+ {
+ // defensive error report - we could wait for user input.. I guess ?
+ throw (new ImageOutputException(
+ "Need an output file to render to when exporting images in batch mode!"));
+ }
JalviewFileChooser chooser = imageType.getFileChooser();
chooser.setFileView(new JalviewFileView());
MessageManager.formatMessage("label.create_image_of",
renderStyle = "Text";
}
AtomicBoolean textSelected = new AtomicBoolean(
- !"Lineart".equals(renderStyle));
- if ((imageType == TYPE.EPS || imageType == TYPE.SVG)
- && LineartOptions.PROMPT_EACH_TIME.equals(renderStyle)
+ !StringUtils.equalsIgnoreCase("lineart", renderStyle));
+ if ((imageType == TYPE.EPS || imageType == TYPE.SVG) && StringUtils
+ .equalsIgnoreCase(LineartOptions.PROMPT_EACH_TIME, renderStyle)
&& !Jalview.isHeadlessMode())
{
final File chosenFile = file;
else
{
/*
- * character rendering not required, or preference already set
- * - just do the export
+ * character rendering not required, or preference already set
+ * or we're in headless mode - just do the export
*/
exportImage(file, !textSelected.get(), width, height, messageId,
userBis);
messageId);
} catch (Exception e)
{
- System.out.println(String.format("Error creating %s file: %s", type,
- e.toString()));
+ jalview.bin.Console.error(String.format("Error creating %s file: %s",
+ type, e.toString()), e);
setStatus(MessageManager.formatMessage("info.error_creating_file",
type), messageId);
}
import jalview.datamodel.SequenceI;
import jalview.gui.ImageExporter.ImageWriterI;
import jalview.gui.JalviewColourChooser.ColourChooserListener;
+import jalview.io.exceptions.ImageOutputException;
import jalview.jbgui.GPCAPanel;
import jalview.math.RotatableMatrix.Axis;
import jalview.util.ImageMaker;
};
String pca = MessageManager.getString("label.pca");
ImageExporter exporter = new ImageExporter(writer, null, type, pca);
- exporter.doExport(null, this, width, height, pca);
+ try {
+ exporter.doExport(null, this, width, height, pca);
+ } catch (ImageOutputException ioex) {
+ Console.error("Unexpected error whilst writing "+type.toString(),ioex);
+ }
}
@Override
protected void addReferenceAnnotations_actionPerformed(
Map<SequenceI, List<AlignmentAnnotation>> candidates)
{
- final SequenceGroup selectionGroup = this.ap.av.getSelectionGroup();
final AlignmentI alignment = this.ap.getAlignment();
AlignmentUtils.addReferenceAnnotations(candidates, alignment,
- selectionGroup);
+ null);
refresh();
}
public static List<String> groupURLLinks;
static
{
+ // don't populate with session properties
+ Cache.disableSessionProperties();
+
// get links selected to be in the menu (SEQUENCE_LINKS)
// and links entered by the user but not selected (STORED_LINKS)
String inMenuString = Cache.getDefault("SEQUENCE_LINKS", "");
*/
groupURLLinks = new ArrayList<>();
+
+ // reenable
+ Cache.enableSessionProperties();
}
JInternalFrame frame;
private Preferences()
{
super();
+ // don't populate with session properties
+ Cache.disableSessionProperties();
+
frame = new JInternalFrame();
frame.setFrameIcon(null);
frame.setContentPane(this);
* Set Startup tab defaults
*/
+ // re-enable
+ Cache.enableSessionProperties();
}
/**
protected void setupOutputCombo(JComboBox<Object> comboBox,
String propertyKey)
{
+ Cache.disableSessionProperties();
+
comboBox.addItem(promptEachTimeOpt);
comboBox.addItem(lineArtOpt);
comboBox.addItem(textOpt);
{
comboBox.setSelectedItem(promptEachTimeOpt);
}
+
+ Cache.enableSessionProperties();
}
/**
@Override
public void ok_actionPerformed(ActionEvent e)
{
+ Cache.disableSessionProperties();
+
if (!validateSettings())
{
return;
/*
* Save Visual settings
*/
+
Cache.applicationProperties.setProperty("SHOW_JVSUFFIX",
Boolean.toString(seqLimit.isSelected()));
Cache.applicationProperties.setProperty("RIGHT_ALIGN_IDS",
} catch (Exception ex)
{
}
+
+ Cache.enableSessionProperties();
}
public void saveProxySettings()
{
+ Cache.disableSessionProperties();
+
String newProxyType = customProxy.isSelected() ? Cache.PROXYTYPE_CUSTOM
: noProxy.isSelected() ? Cache.PROXYTYPE_NONE
: Cache.PROXYTYPE_SYSTEM;
wsPrefs.update++;
}
previousProxyType = newProxyType;
+
+ Cache.enableSessionProperties();
}
/**
@Override
public void startupFileTextfield_mouseClicked()
{
+ Cache.disableSessionProperties();
+
// TODO: JAL-3048 not needed for Jalview-JS
String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
JalviewFileChooser chooser = JalviewFileChooser
startupFileTextfield
.setText(chooser.getSelectedFile().getAbsolutePath());
}
+
+ Cache.enableSessionProperties();
}
/**
*/
String viewerPath = "";
List<String> paths = null;
+ Cache.disableSessionProperties();
try
{
ViewerType viewerType = ViewerType.valueOf(selectedItem);
{
// only valid entries should be in the drop-down
}
+ Cache.enableSessionProperties();
structureViewerPath.setText(viewerPath);
paths.add(0, structureViewerPath.getText());
}
else if (inGroup)
{
- drawVerticals(g, sx, xwidth, visWidth, oldY, sy);
- drawHorizontals(g, sx, xwidth, visWidth, top, bottom);
+ drawVerticals(g, sx, xwidth, visWidth, oldY, bottom);
+ drawHorizontals(g, sx, xwidth, visWidth, top, bottom+1);
// reset top and bottom
top = -1;
if (inGroup)
{
sy = verticalOffset + ((i - startSeq) * charHeight);
- drawVerticals(g, sx, xwidth, visWidth, oldY, sy);
- drawHorizontals(g, sx, xwidth, visWidth, top, bottom);
+ drawVerticals(g, sx, xwidth, visWidth, oldY, bottom);
+ drawHorizontals(g, sx, xwidth, visWidth, top, bottom+1);
}
}
}
*/
public SplashScreen(boolean isTransient)
{
+ Desktop.instance.acquireDialogQueue();
this.transientDialog = isTransient;
if (Platform.isJS()) // BH 2019
}
closeSplash();
- Desktop.instance.startDialogQueue();
+ Desktop.instance.releaseDialogQueue();
}
/**
import jalview.analysis.Conservation;
import jalview.analysis.TreeModel;
import jalview.api.AlignViewportI;
+import jalview.bin.Console;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
import jalview.datamodel.BinaryNode;
import jalview.gui.JalviewColourChooser.ColourChooserListener;
import jalview.schemes.ColourSchemeI;
import jalview.structure.SelectionSource;
+import jalview.util.ColorUtils;
import jalview.util.Format;
import jalview.util.MessageManager;
import jalview.ws.datamodel.MappableContactMatrixI;
boolean has_placeholders = false;
longestName = "";
+ AlignmentAnnotation aa = tp.getAssocAnnotation();
+ ContactMatrixI cm = (aa!=null) ? av.getContactMatrix(aa) : null;
+ if (cm!=null && cm.hasCutHeight())
+ {
+ threshold=(float) cm.getCutHeight();
+ }
+
for (int i = 0; i < leaves.size(); i++)
{
BinaryNode lf = leaves.elementAt(i);
longestName = TreeCanvas.PLACEHOLDER
+ ((Sequence) lf.element()).getName();
}
+ if (tp.isColumnWise() && cm!=null)
+ {
+ // get color from group colours, if they are set for the matrix
+ try {
+ Color col = cm.getGroupColorForPosition(parseColumnNode(lf));
+ setColor(lf,col.brighter());
+ } catch (NumberFormatException ex) {};
+ }
}
setMarkPlaceholders(has_placeholders);
* @param offy
* DOCUMENT ME!
*/
- public void drawNode(Graphics g, BinaryNode node, float chunk,
+ public void drawNode(Graphics g, BinaryNode node, double chunk,
double wscale, int width, int offx, int offy)
{
if (node == null)
+ ((BinaryNode) top.right()).count;
}
- float chunk = (float) (height - (offy)) / top.count;
+ double chunk = (double) (height - (offy)) / (double)top.count;
drawNode(g2, tree.getTopNode(), chunk, wscale, width, offx, offy);
threshold = 0f;
}
}
-
+ Console.log.debug("Tree cut threshold set at:" + threshold);
PaintRefresher.Refresh(tp,
getAssociatedPanel().av.getSequenceSetId());
repaint();
Map<BitSet, Color> colors = new HashMap();
for (int i = 0; i < groups.size(); i++)
{
- Color col = new Color((int) (Math.random() * 255),
- (int) (Math.random() * 255), (int) (Math.random() * 255));
+ Color col = ColorUtils.getARandomColor();
+
setColor(groups.get(i), col.brighter());
Vector<BinaryNode> l = tree.findLeaves(groups.get(i));
cm.setColorForGroup(gp, colors.get(gp));
}
}
- // stash colors in linked annotation row.
- // doesn't work yet. TESTS!
- int sstart = aa.sequenceRef != null ? aa.sequenceRef.getStart() - 1
- : 0;
- Annotation ae;
- Color gpcol = null;
- int[] seqpos = null;
- for (BitSet gp : colors.keySet())
- {
- gpcol = colors.get(gp);
- for (int p = gp.nextSetBit(0); p >= 0
- && p < Integer.MAX_VALUE; p = gp.nextSetBit(p + 1))
- {
- if (cm instanceof MappableContactMatrixI)
- {
- MappableContactMatrixI mcm = (MappableContactMatrixI) cm;
- seqpos = mcm.getMappedPositionsFor(aa.sequenceRef, p);
- if (seqpos == null)
- {
- // no mapping for this column.
- continue;
- }
- // TODO: handle ranges...
- ae = aa.getAnnotationForPosition(seqpos[0]);
- }
- else
- {
- ae = aa.getAnnotationForPosition(p + sstart);
- }
- if (ae != null)
- {
- ae.colour = gpcol.brighter().darker();
- }
- }
- }
+ cm.transferGroupColorsTo(aa);
}
}
}
}
}
-
+ private int parseColumnNode(BinaryNode bn) throws NumberFormatException
+ {
+ return Integer.parseInt(
+ bn.getName().substring(bn.getName().indexOf("c") + 1));
+ }
private boolean isColumnForNodeSelected(BinaryNode bn)
{
SequenceI rseq = tp.assocAnnotation.sequenceRef;
int colm = -1;
try
{
- colm = Integer.parseInt(
- bn.getName().substring(bn.getName().indexOf("c") + 1));
+ colm = parseColumnNode(bn);
} catch (Exception e)
{
return false;
// parse out from nodename
try
{
- colm = Integer.parseInt(
- bn.getName().substring(bn.getName().indexOf("c") + 1));
+ colm = parseColumnNode(bn);
} catch (Exception e)
{
continue;
if (mcm!=null)
{
int[] seqpos = mcm.getMappedPositionsFor(
- tp.assocAnnotation.sequenceRef, colm);
+ rseq, colm);
if (seqpos == null)
{
// no mapping for this column.
continue;
}
// TODO: handle ranges...
- offp = seqpos[0]-1;
+ offp = rseq.findIndex(seqpos[0])-1;
}
else
{
import jalview.io.JalviewFileChooser;
import jalview.io.JalviewFileView;
import jalview.io.NewickFile;
+import jalview.io.exceptions.ImageOutputException;
import jalview.jbgui.GTreePanel;
import jalview.util.ImageMaker.TYPE;
import jalview.util.MessageManager;
this.treeType = type;
this.scoreModelName = modelName;
+ treeCanvas = new TreeCanvas(this, ap, scrollPane);
+ scrollPane.setViewportView(treeCanvas);
+
if (columnWise)
{
bootstrapMenu.setVisible(false);
- placeholdersMenu.setSelected(false);
+ placeholdersMenu.setState(false);
placeholdersMenu.setVisible(false);
- fitToWindow.setSelected(false);
+ fitToWindow.setState(false);
sortAssocViews.setVisible(false);
}
- treeCanvas = new TreeCanvas(this, ap, scrollPane);
- scrollPane.setViewportView(treeCanvas);
addKeyListener(new KeyAdapter()
{
? new NJTree(av, sm, similarityParams)
: new AverageDistanceTree(av, sm, similarityParams);
tree = new TreeModel(njtree);
- showDistances(true);
+ // don't display distances for columnwise trees
}
-
+ showDistances(!columnWise);
tree.reCount(tree.getTopNode());
tree.findHeight(tree.getTopNode());
treeCanvas.setTree(tree);
String tree = MessageManager.getString("label.tree");
ImageExporter exporter = new ImageExporter(writer, null, imageFormat,
tree);
+ try {
exporter.doExport(null, this, width, height,
tree.toLowerCase(Locale.ROOT));
+ } catch (ImageOutputException ioex) {
+ Console.error("Unexpected error whilst writing "+imageFormat.toString(),ioex);
+ }
}
/**
import jalview.datamodel.AlignmentExportData;
import jalview.gui.AlignmentPanel;
import jalview.gui.IProgressIndicator;
+import jalview.io.exceptions.ImageOutputException;
import jalview.util.MessageManager;
public abstract class HTMLOutput implements Runnable
return generatedFile;
}
- public void exportHTML(String outputFile)
+ public void exportHTML(String outputFile) throws ImageOutputException
{
exportHTML(outputFile, null);
}
- public void exportHTML(String outputFile, String renderer)
+ public void exportHTML(String outputFile, String renderer) throws ImageOutputException
{
setProgressMessage(MessageManager.formatMessage(
"status.exporting_alignment_as_x_file", getDescription()));
}
// used to pass an option such as render to run
- public abstract void run(String string);
+ public abstract void run(String string) throws ImageOutputException;
}
\ No newline at end of file
}
}
sqs[i] = new Sequence(id, seq, begin, end);
-
- sqs[i].setEnd(sqs[i].findPosition(sqs[i].getLength()));
+ if (seq.length()!=(end-begin+1))
+ {
+ sqs[i].setEnd(sqs[i].findPosition(sqs[i].getLength()));
+ }
String[] annot = new String[rna.length()];
Annotation[] ann = new Annotation[rna.length()];
--- /dev/null
+package jalview.io.exceptions;
+
+/**
+ * wrapper for passing error messages and exceptions back to UI when image io goes wrong
+ * @author jprocter
+ *
+ */
+public class ImageOutputException extends Exception
+{
+
+ public ImageOutputException()
+ {
+ }
+
+ public ImageOutputException(String message)
+ {
+ super(message);
+ }
+
+ public ImageOutputException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public ImageOutputException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ public ImageOutputException(String message, Throwable cause,
+ boolean enableSuppression, boolean writableStackTrace)
+ {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+}
import jalview.gui.JvSwingUtils;
import jalview.gui.Preferences;
import jalview.io.FileFormats;
+import jalview.io.exceptions.ImageOutputException;
import jalview.schemes.ResidueColourScheme;
import jalview.util.MessageManager;
import jalview.util.Platform;
@Override
public void actionPerformed(ActionEvent e)
{
- createPNG(null);
+ createPNG_actionPerformed(e);
}
});
createPNG.setActionCommand(
@Override
public void actionPerformed(ActionEvent e)
{
- createEPS(null);
+ createEPS_actionPerformed(e);
}
});
@Override
public void actionPerformed(ActionEvent e)
{
- createSVG(null);
+ createSVG_actionPerformed(e);
}
});
// selectMenu.add(listenToViewSelections);
}
+ protected void createPNG_actionPerformed(ActionEvent object)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ protected void createEPS_actionPerformed(ActionEvent object)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ protected void createSVG_actionPerformed(ActionEvent object)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
protected void copyHighlightedColumns_actionPerformed(
ActionEvent actionEvent)
{
{
}
- public void createPNG(java.io.File f)
- {
- }
protected void font_actionPerformed(ActionEvent e)
{
}
- public void createEPS(java.io.File f)
- {
- }
-
- public void createSVG(java.io.File f)
- {
-
- }
protected void loadTreeMenuItem_actionPerformed(ActionEvent e)
{
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.image.ImageObserver;
import java.util.BitSet;
import java.util.Hashtable;
+import org.jfree.graphics2d.svg.SVGGraphics2D;
+import org.jibble.epsgraphics.EpsGraphics2D;
+
import jalview.analysis.AAFrequency;
import jalview.analysis.CodingUtils;
import jalview.analysis.Rna;
import jalview.analysis.StructureFrequency;
import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
+import jalview.bin.Console;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
import jalview.datamodel.ColumnSelection;
private boolean av_ignoreGapsConsensus;
+ private boolean vectorRendition = false;
+
+ private boolean glyphLineDrawn = false;
+
/**
* attributes set from AwtRenderPanelI
*/
* if new annotation with a closing base pair half of the stem,
* display a backward arrow
*/
- g.fillPolygon(new int[] { lastSSX + 5, lastSSX + 5, lastSSX },
+ fillPolygon(g, new int[] { lastSSX + 5, lastSSX + 5, lastSSX },
new int[]
{ y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset },
3);
* if annotation ending with an opeing base pair half of the stem,
* display a forward arrow
*/
- g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 },
+ fillPolygon(g, new int[] { x2 - 5, x2 - 5, x2 },
new int[]
{ y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset },
3);
}
}
// draw arrow body
- g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 7);
+ fillRect(g, x1, y + 4 + iconOffset, x2 - x1, 7);
}
void drawNotCanonicalAnnot(Graphics g, Color nonCanColor,
int iconOffset, int startRes, int column, boolean validRes,
boolean validEnd)
{
- // System.out.println(nonCanColor);
+ // Console.info(nonCanColor);
- g.setColor(nonCanColor);
int sCol = (lastSSX / charWidth)
+ hiddenColumns.visibleToAbsoluteColumn(startRes);
int x1 = lastSSX;
boolean diffdownstream = !validRes || !validEnd
|| row_annotations[column] == null
|| !dc.equals(row_annotations[column].displayCharacter);
- // System.out.println("Column "+column+" diff up: "+diffupstream+"
+ // Console.info("Column "+column+" diff up:
+ // "+diffupstream+"
// down:"+diffdownstream);
// If a closing base pair half of the stem, display a backward arrow
+ if (diffupstream || diffdownstream)
+ {
+ // draw glyphline under arrow
+ drawGlyphLine(g, lastSSX, x, y, iconOffset);
+ }
+ g.setColor(nonCanColor);
if (column > 0 && Rna.isClosingParenthesis(dc))
{
// if (validRes && column>1 && row_annotations[column-2]!=null &&
// dc.equals(row_annotations[column-2].displayCharacter))
{
- g.fillPolygon(new int[] { lastSSX + 5, lastSSX + 5, lastSSX },
+ fillPolygon(g, new int[] { lastSSX + 5, lastSSX + 5, lastSSX },
new int[]
- { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset },
+ { y + iconOffset + 1, y + 13 + iconOffset,
+ y + 7 + iconOffset },
3);
x1 += 5;
}
// display a forward arrow
if (diffdownstream)
{
- g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 },
+ fillPolygon(g, new int[] { x2 - 6, x2 - 6, x2 - 1 },
new int[]
- { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset },
+ { y + iconOffset + 1, y + 13 + iconOffset,
+ y + 7 + iconOffset },
3);
x2 -= 5;
}
}
}
// draw arrow body
- g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 7);
+ unsetAntialias(g);
+ fillRect(g, x1, y + 4 + iconOffset, x2 - x1, 6);
}
// public void updateFromAnnotationPanel(FontMetrics annotFM, AlignViewportI
AlignViewportI av, Graphics g, int activeRow, int startRes,
int endRes)
{
+ if (g instanceof EpsGraphics2D || g instanceof SVGGraphics2D)
+ {
+ this.setVectorRendition(true);
+ }
+ Graphics2D g2d = (Graphics2D) g;
+
long stime = System.currentTimeMillis();
boolean usedFaded = false;
// NOTES:
*
* continue; }
*/
+
// first pass sets up state for drawing continuation from left-hand
// column
// of startRes
+
+ // flag used for vector rendition
+ this.glyphLineDrawn = false;
x = (startRes == 0) ? 0 : -1;
while (x < endRes - startRes)
{
: null;
if (x > -1)
{
+ unsetAntialias(g);
if (activeRow == i)
{
g.setColor(Color.red);
{
if (columnSelection.contains(column))
{
- g.fillRect(x * charWidth, y, charWidth, charHeight);
+ fillRect(g, x * charWidth, y, charWidth, charHeight);
}
}
}
if (row.getInvalidStrucPos() > x)
{
g.setColor(Color.orange);
- g.fillRect(x * charWidth, y, charWidth, charHeight);
+ fillRect(g, x * charWidth, y, charWidth, charHeight);
}
else if (row.getInvalidStrucPos() == x)
{
g.setColor(Color.orange.darker());
- g.fillRect(x * charWidth, y, charWidth, charHeight);
+ fillRect(g, x * charWidth, y, charWidth, charHeight);
}
if (validCharWidth && validRes && displayChar != null
&& (displayChar.length() > 0))
{
- Graphics2D gg = ((Graphics2D) g);
+ // Graphics2D gg = (g);
float fmWidth = fm.charsWidth(displayChar.toCharArray(), 0,
displayChar.length());
if (row_annotations[column].colour == null)
{
- gg.setColor(Color.black);
+ g2d.setColor(Color.black);
}
else
{
- gg.setColor(row_annotations[column].colour);
+ g2d.setColor(row_annotations[column].colour);
}
/*
/*
* translate to drawing position _before_ applying any scaling
*/
- gg.translate(xPos, yPos);
+ g2d.translate(xPos, yPos);
if (scaledToFit)
{
/*
* use a scaling transform to make the label narrower
* (JalviewJS doesn't have Font.deriveFont(AffineTransform))
*/
- gg.transform(
+ g2d.transform(
AffineTransform.getScaleInstance(fmScaling, 1.0));
}
+ setAntialias(g);
if (column == 0 || row.graph > 0)
{
- gg.drawString(displayChar, 0, 0);
+ g2d.drawString(displayChar, 0, 0);
}
else if (row_annotations[column - 1] == null || (labelAllCols
|| !displayChar.equals(
|| (displayChar.length() < 2
&& row_annotations[column].secondaryStructure == ' ')))
{
- gg.drawString(displayChar, 0, 0);
+ g2d.drawString(displayChar, 0, 0);
}
if (scaledToFit)
{
* undo scaling before translating back
* (restoring saved transform does NOT work in JS PDFGraphics!)
*/
- gg.transform(AffineTransform
+ g2d.transform(AffineTransform
.getScaleInstance(1D / fmScaling, 1.0));
}
- gg.translate(-xPos, -yPos);
+ g2d.translate(-xPos, -yPos);
}
}
if (row.hasIcons)
{
// int nb_annot = x - temp;
- // System.out.println("\t type :"+lastSS+"\t x :"+x+"\t nbre
+ // Console.info("\t type :"+lastSS+"\t x
+ // :"+x+"\t nbre
// annot :"+nb_annot);
switch (lastSS)
{
// temp = x;
break;
default:
- g.setColor(Color.gray);
- g.fillRect(lastSSX, y + 6 + iconOffset,
- (x * charWidth) - lastSSX, 2);
- // temp = x;
+ if (isVectorRendition())
+ {
+ // draw single full width glyphline
+ drawGlyphLine(g, lastSSX, endRes - x, y, iconOffset);
+ // disable more glyph lines
+ this.glyphLineDrawn = true;
+ }
+ else
+ {
+ drawGlyphLine(g, lastSSX, x, y, iconOffset);
+ }
break;
}
}
case 'y':
case 'Z':
case 'z':
- // System.out.println(lastSS);
+ // Console.info(lastSS);
Color nonCanColor = getNotCanonicalColor(lastSS);
drawNotCanonicalAnnot(g, nonCanColor, row_annotations, lastSSX,
x, y, iconOffset, startRes, column, validRes, validEnd);
break;
default:
- drawGlyphLine(g, row_annotations, lastSSX, x, y, iconOffset,
- startRes, column, validRes, validEnd);
+ if (isVectorRendition())
+ {
+ // draw single full width glyphline
+ drawGlyphLine(g, lastSSX, endRes - x, y, iconOffset);
+ // disable more glyph lines
+ this.glyphLineDrawn = true;
+ }
+ else
+ {
+ drawGlyphLine(g, lastSSX, x, y, iconOffset);
+ }
break;
}
}
}
else
{
- System.err.println(
+ Console.warn(
"rendered with " + renderer.getClass().toString());
}
}
{
if (clipst)
{
- System.err.println(
- "Start clip at : " + yfrom + " (index " + f_i + ")");
+ Console.warn("Start clip at : " + yfrom + " (index " + f_i + ")");
}
if (clipend)
{
- System.err.println(
- "End clip at : " + yto + " (index " + f_to + ")");
+ Console.warn("End clip at : " + yto + " (index " + f_to + ")");
}
}
;
- System.err.println("Annotation Rendering time:"
+ Console.warn("Annotation Rendering time:"
+ (System.currentTimeMillis() - stime));
}
;
// private Color sdNOTCANONICAL_COLOUR;
- void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX, int x,
- int y, int iconOffset, int startRes, int column, boolean validRes,
- boolean validEnd)
+ void drawGlyphLine(Graphics g, int lastSSX, int x, int y, int iconOffset)
{
+ if (glyphLineDrawn)
+ {
+ // if we've drawn a single long glyphline for an export, don't draw the
+ // bits
+ return;
+ }
+ unsetAntialias(g);
g.setColor(GLYPHLINE_COLOR);
g.fillRect(lastSSX, y + 6 + iconOffset, (x * charWidth) - lastSSX, 2);
}
int lastSSX, int x, int y, int iconOffset, int startRes,
int column, boolean validRes, boolean validEnd)
{
- g.setColor(SHEET_COLOUR);
-
if (!validEnd || !validRes || row == null || row[column] == null
|| row[column].secondaryStructure != 'E')
{
- g.fillRect(lastSSX, y + 4 + iconOffset, (x * charWidth) - lastSSX - 4,
- 7);
- g.fillPolygon(
+ // draw the glyphline underneath
+ drawGlyphLine(g, lastSSX, x, y, iconOffset);
+
+ g.setColor(SHEET_COLOUR);
+ fillRect(g, lastSSX, y + 4 + iconOffset,
+ (x * charWidth) - lastSSX - 4, 6);
+ fillPolygon(g,
new int[]
- { (x * charWidth) - 4, (x * charWidth) - 4, (x * charWidth) },
+ { (x * charWidth) - 6, (x * charWidth) - 6,
+ (x * charWidth - 1) },
new int[]
- { y + iconOffset, y + 14 + iconOffset, y + 7 + iconOffset },
+ { y + iconOffset + 1, y + 13 + iconOffset,
+ y + 7 + iconOffset },
3);
}
else
{
- g.fillRect(lastSSX, y + 4 + iconOffset, (x + 1) * charWidth - lastSSX,
- 7);
+ g.setColor(SHEET_COLOUR);
+ fillRect(g, lastSSX, y + 4 + iconOffset, (x * charWidth) - lastSSX,
+ 6);
}
-
}
void drawHelixAnnot(Graphics g, Annotation[] row, int lastSSX, int x,
int y, int iconOffset, int startRes, int column, boolean validRes,
boolean validEnd)
{
- g.setColor(HELIX_COLOUR);
-
int sCol = (lastSSX / charWidth)
+ hiddenColumns.visibleToAbsoluteColumn(startRes);
int x1 = lastSSX;
int x2 = (x * charWidth);
- if (USE_FILL_ROUND_RECT)
+ if (USE_FILL_ROUND_RECT || isVectorRendition())
{
+ // draw glyph line behind helix (visible in EPS or SVG output)
+ drawGlyphLine(g, lastSSX, x, y, iconOffset);
+
+ g.setColor(HELIX_COLOUR);
+ setAntialias(g);
int ofs = charWidth / 2;
// Off by 1 offset when drawing rects and ovals
// to offscreen image on the MAC
- g.fillRoundRect(lastSSX, y + 4 + iconOffset, x2 - x1, 8, 8, 8);
+ fillRoundRect(g, lastSSX, y + 3 + iconOffset, x2 - x1 - 1, 8, 8, 8);
if (sCol == 0 || row[sCol - 1] == null
|| row[sCol - 1].secondaryStructure != 'H')
{
else
{
// g.setColor(Color.orange);
- g.fillRoundRect(lastSSX, y + 4 + iconOffset, x2 - x1 - ofs + 1, 8,
- 0, 0);
+ fillRoundRect(g, lastSSX, y + 3 + iconOffset, x2 - x1 - ofs, 8, 0,
+ 0);
}
if (!validRes || row[column] == null
|| row[column].secondaryStructure != 'H')
else
{
// g.setColor(Color.magenta);
- g.fillRoundRect(lastSSX + ofs, y + 4 + iconOffset,
- x2 - x1 - ofs + 1, 8, 0, 0);
-
+ fillRoundRect(g, lastSSX + ofs, y + 3 + iconOffset, x2 - x1 - ofs,
+ 8, 0, 0);
}
return;
}
- if (sCol == 0 || row[sCol - 1] == null
- || row[sCol - 1].secondaryStructure != 'H')
+ boolean leftEnd = sCol == 0 || row[sCol - 1] == null
+ || row[sCol - 1].secondaryStructure != 'H';
+ boolean rightEnd = !validRes || row[column] == null
+ || row[column].secondaryStructure != 'H';
+
+ if (leftEnd || rightEnd)
+ {
+ drawGlyphLine(g, lastSSX, x, y, iconOffset);
+ }
+ g.setColor(HELIX_COLOUR);
+
+ if (leftEnd)
{
- g.fillArc(lastSSX, y + 4 + iconOffset, charWidth, 8, 90, 180);
+ fillArc(g, lastSSX, y + 3 + iconOffset, charWidth, 8, 90, 180);
x1 += charWidth / 2;
}
- if (!validRes || row[column] == null
- || row[column].secondaryStructure != 'H')
+ if (rightEnd)
{
- g.fillArc((x * charWidth) - charWidth, y + 4 + iconOffset, charWidth,
- 8, 270, 180);
+ fillArc(g, ((x - 1) * charWidth), y + 3 + iconOffset, charWidth, 8,
+ 270, 180);
x2 -= charWidth / 2;
}
- g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
+ fillRect(g, x1, y + 3 + iconOffset, x2 - x1, 8);
}
void drawLineGraph(Graphics g, AlignmentAnnotation _aa,
{
return;
}
+ Stroke roundStroke = new BasicStroke(1, BasicStroke.CAP_ROUND,
+ BasicStroke.JOIN_ROUND);
+ Stroke squareStroke = new BasicStroke(1, BasicStroke.CAP_SQUARE,
+ BasicStroke.JOIN_MITER);
+ Graphics2D g2d = (Graphics2D) g;
+ Stroke prevStroke = g2d.getStroke();
+ g2d.setStroke(roundStroke);
int x = 0;
}
g.setColor(Color.gray);
- g.drawLine(x - charWidth, y2, (eRes - sRes + 1) * charWidth, y2);
+ drawLine(g, squareStroke, x * charWidth - charWidth, y2,
+ (eRes - sRes) * charWidth, y2);
eRes = Math.min(eRes, aa_annotations.length);
// standalone value
y1 = y - (int) (((aa_annotations[column].value - min) / range)
* graphHeight);
- g.drawLine(x * charWidth + charWidth / 4, y1,
+ drawLine(g, x * charWidth + charWidth / 4, y1,
x * charWidth + 3 * charWidth / 4, y1);
x++;
continue;
y2 = y - (int) (((aa_annotations[column].value - min) / range)
* graphHeight);
- g.drawLine(x * charWidth - charWidth / 2, y1,
+ drawLine(g, (x - 1) * charWidth + charWidth / 2, y1,
x * charWidth + charWidth / 2, y2);
x++;
}
{
g.setColor(_aa.threshold.colour);
Graphics2D g2 = (Graphics2D) g;
- g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE,
+ Stroke s = new BasicStroke(1, BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_ROUND, 3f, new float[]
- { 5f, 3f }, 0f));
+ { 5f, 3f }, 0f);
y2 = (int) (y - ((_aa.threshold.value - min) / range) * graphHeight);
- g.drawLine(0, y2, (eRes - sRes) * charWidth, y2);
- g2.setStroke(new BasicStroke());
+ drawLine(g, s, 0, y2, (eRes - sRes) * charWidth, y2);
}
+ g2d.setStroke(prevStroke);
}
@SuppressWarnings("unused")
g.setColor(Color.gray);
- g.drawLine(x, y2, (eRes - sRes) * charWidth, y2);
+ drawLine(g, x, y2, (eRes - sRes) * charWidth, y2);
int column;
int aaMax = aa_annotations.length - 1;
{
if (y1 - y2 > 0)
{
- g.fillRect(x * charWidth, y2, charWidth, y1 - y2);
+ fillRect(g, x * charWidth, y2, charWidth, y1 - y2);
}
else
{
- g.fillRect(x * charWidth, y1, charWidth, y2 - y1);
+ fillRect(g, x * charWidth, y1, charWidth, y2 - y1);
}
}
// draw profile if available
// lm is not necessary - we can just use fm - could be off by no more
// than 0.5 px
// LineMetrics lm = g.getFontMetrics(ofont).getLineMetrics("Q", g);
- // System.out.println(asc + " " + dec + " " + (asc - lm.getAscent())
+ // Console.info(asc + " " + dec + " " + (asc -
+ // lm.getAscent())
// + " " + (dec - lm.getDescent()));
double asc = fm.getAscent();
if (_aa.threshold != null)
{
g.setColor(_aa.threshold.colour);
- Graphics2D g2 = (Graphics2D) g;
- g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE,
+ Stroke s = new BasicStroke(1, BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_ROUND, 3f, new float[]
- { 5f, 3f }, 0f));
+ { 5f, 3f }, 0f);
y2 = (int) (y
- ((_aa.threshold.value - min) / range) * _aa.graphHeight);
- g.drawLine(0, y2, (eRes - sRes) * charWidth, y2);
- g2.setStroke(new BasicStroke());
+ drawLine(g, s, 0, y2, (eRes - sRes) * charWidth, y2);
}
}
{
eRes = Math.min(eRes, aa_annotations.length);
g.setColor(Color.white);
- g.fillRect(0, 0, width, y);
+ fillRect(g, 0, 0, width, y);
g.setColor(new Color(0, 0, 180));
int x = 0, height;
height = y;
}
- g.fillRect(x, y - height, charWidth, height);
+ fillRect(g, x, y - height, charWidth, height);
}
x += charWidth;
}
return new Color(0, 80, 255);
default:
- System.out.println("This is not a interaction : " + lastss);
+ Console.info("This is not a interaction : " + lastss);
return null;
}
}
+
+ private void fillPolygon(Graphics g, int[] xpoints, int[] ypoints, int n)
+ {
+ setAntialias(g);
+ g.fillPolygon(xpoints, ypoints, n);
+ }
+
+ /*
+ private void fillRect(Graphics g, int a, int b, int c, int d)
+ {
+ fillRect(g, false, a, b, c, d);
+ }*/
+
+ private void fillRect(Graphics g, int a, int b, int c, int d)
+ {
+ unsetAntialias(g);
+ g.fillRect(a, b, c, d);
+ }
+
+ private void fillRoundRect(Graphics g, int a, int b, int c, int d, int e,
+ int f)
+ {
+ setAntialias(g);
+ g.fillRoundRect(a, b, c, d, e, f);
+ }
+
+ private void fillArc(Graphics g, int a, int b, int c, int d, int e, int f)
+ {
+ setAntialias(g);
+ g.fillArc(a, b, c, d, e, f);
+ }
+
+ private void drawLine(Graphics g, Stroke s, int a, int b, int c, int d)
+ {
+ Graphics2D g2d = (Graphics2D) g;
+ Stroke p = g2d.getStroke();
+ g2d.setStroke(s);
+ drawLine(g, a, b, c, d);
+ g2d.setStroke(p);
+ }
+
+ private void drawLine(Graphics g, int a, int b, int c, int d)
+ {
+ setAntialias(g);
+ g.drawLine(a, b, c, d);
+ }
+
+ private void setAntialias(Graphics g)
+ {
+ if (isVectorRendition())
+ {
+ // no need to antialias vector drawings
+ return;
+ }
+ if (Cache.getDefault("ANTI_ALIAS", true))
+ {
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ }
+ }
+
+ private void unsetAntialias(Graphics g)
+ {
+ if (isVectorRendition())
+ {
+ // no need to antialias vector drawings
+ return;
+ }
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_OFF);
+ }
+
+ public void setVectorRendition(boolean b)
+ {
+ vectorRendition = b;
+ }
+
+ public boolean isVectorRendition()
+ {
+ return vectorRendition;
+ }
}
}
eRes = Math.min(eRes, aa_annotations.length);
- int x = 0, y2 = y;
+ int x = 0, topY = y;
- g.setColor(shade.no_data);
-
- g.drawLine(x, y2, (eRes - sRes) * charWidth, y2);
+ // uncomment below to render whole area of matrix as pink
+ // g.setColor(shade.no_data);
+ // g.fillRect(x, topY-_aa.height, (eRes - sRes) * charWidth, _aa.graphHeight);
+
boolean showGroups = _aa.isShowGroupsForContactMatrix();
int column;
int aaMax = aa_annotations.length - 1;
final ContactGeometry cgeom = new ContactGeometry(contacts,
_aa.graphHeight);
- for (int ht = y2, eht = y2
- - _aa.graphHeight; ht >= eht; ht -= cgeom.pixels_step)
+ for (int ht = 0, botY = topY
+ - _aa.height; ht < _aa.graphHeight; ht += cgeom.pixels_step)
{
- ContactGeometry.contactInterval ci = cgeom.mapFor(y2 - ht,
- y2 - ht + cgeom.pixels_step);
+ ContactGeometry.contactInterval ci = cgeom.mapFor(ht,
+ ht + cgeom.pixels_step);
// cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel);
// cend = (int) Math.min(contact_height,
// Math.ceil(cstart + contacts_per_pixel * pixels_step));
g.setColor(col);
if (cgeom.pixels_step > 1)
{
- g.fillRect(x * charWidth, ht, charWidth, 1 + cgeom.pixels_step);
+ g.fillRect(x * charWidth, botY+ht, charWidth, 1 + cgeom.pixels_step);
}
else
{
- g.drawLine(x * charWidth, ht, (x + 1) * charWidth, ht);
+ g.drawLine(x * charWidth, botY+ht, (x + 1) * charWidth, botY+ht);
}
}
x++;
return color;
}
+
+ /**
+ *
+ * @return random color
+ */
+ public static final Color getARandomColor()
+ {
+ Color col = new Color((int) (Math.random() * 255),
+ (int) (Math.random() * 255), (int) (Math.random() * 255));
+ return col;
+ }
/**
* Convert to Tk colour code format
*
// a long sequence.
// check for at least 55% nucleotide, and nucleotide and ambiguity codes
// (including N) must make up 95%
- return ntCount * 100 > NUCLEOTIDE_COUNT_PERCENT * allCount
+ return ntCount * 100 >= NUCLEOTIDE_COUNT_PERCENT * allCount
&& 100 * (ntCount + nCount
- + ntaCount) > NUCLEOTIDE_COUNT_LONG_SEQUENCE_AMBIGUITY_PERCENT
+ + ntaCount) >= NUCLEOTIDE_COUNT_LONG_SEQUENCE_AMBIGUITY_PERCENT
* allCount;
}
else if (allCount > NUCLEOTIDE_COUNT_VERY_SHORT_SEQUENCE)
// a short sequence.
// check if a short sequence is at least 55% nucleotide and the rest of
// the symbols are all X or all N
- if (ntCount * 100 > NUCLEOTIDE_COUNT_PERCENT * allCount
+ if (ntCount * 100 >= NUCLEOTIDE_COUNT_PERCENT * allCount
&& (nCount == aaCount || xCount == aaCount))
{
return true;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
-import java.util.List;
import javax.ws.rs.HttpMethod;
+import jalview.bin.Cache;
+
public class HttpUtils
{
return connection.getResponseCode() == 200;
}
+ public static String getUserAgent()
+ {
+ return getUserAgent(null);
+ }
+
+ public static String getUserAgent(String className)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Jalview");
+ sb.append('/');
+ sb.append(Cache.getDefault("VERSION", "Unknown"));
+ sb.append(" (");
+ sb.append(System.getProperty("os.name"));
+ sb.append("; ");
+ sb.append(System.getProperty("os.arch"));
+ sb.append(' ');
+ sb.append(System.getProperty("os.name"));
+ sb.append(' ');
+ sb.append(System.getProperty("os.version"));
+ sb.append("; ");
+ sb.append("java/");
+ sb.append(System.getProperty("java.version"));
+ sb.append("; ");
+ sb.append("jalview/");
+ sb.append(ChannelProperties.getProperty("channel"));
+ if (className != null)
+ {
+ sb.append("; ");
+ sb.append(className);
+ }
+ String installation = Cache.applicationProperties
+ .getProperty("INSTALLATION");
+ if (installation != null)
+ {
+ sb.append("; ");
+ sb.append(installation);
+ }
+ sb.append(')');
+ sb.append(" help@jalview.org");
+ return sb.toString();
+ }
+
}
return min < text.length() + 1 ? min : -1;
}
+ public static boolean equalsIgnoreCase(String s1, String s2)
+ {
+ if (s1 == null || s2 == null)
+ {
+ return s1 == s2;
+ }
+ return s1.toLowerCase(Locale.ROOT).equals(s2.toLowerCase(Locale.ROOT));
+ }
+
public static int indexOfFirstWhitespace(String text)
{
int index = -1;
if (aa.graph > 0)
{
- aa.height += aa.graphHeight;
+ aa.height += aa.graphHeight+20;
}
if (aa.height == 0)
import jalview.datamodel.AlignmentAnnotation;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
@Override
public boolean isWorking()
{
+ boolean working=false;
synchronized (inProgress)
{
// System.err.println("isWorking "+hashCode());
- return inProgress.size() > 0;
+ working |= inProgress.size() > 0;
}
+ synchronized (updating)
+ {
+ Collection<List<AlignCalcWorkerI>> workersLists = updating.values();
+ synchronized (workersLists)
+ {
+ for (List<AlignCalcWorkerI> workers : workersLists)
+ {
+ if (workers!=null)
+ {
+ synchronized (workers) {
+ working |= workers.size() > 0;
+ }
+ }
+ }
+ }
+ }
+ return working;
}
@Override
import jalview.util.MapUtils;
import jalview.ws.dbsources.EBIAlfaFold;
+/**
+ * routines and class for holding predicted alignment error matrices as produced
+ * by alphafold et al.
+ *
+ * getContactList(column) returns the vector of predicted alignment errors for
+ * reference position given by column getElementAt(column, i) returns the
+ * predicted superposition error for the ith position when column is used as
+ * reference
+ *
+ * Many thanks to Ora Schueler Furman for noticing that earlier development
+ * versions did not show the PAE oriented correctly
+ *
+ * @author jprocter
+ *
+ */
public class PAEContactMatrix extends
MappableContactMatrix<PAEContactMatrix> implements ContactMatrixI
{
Object d = scores.next();
if (d instanceof Double)
{
- elements[row][col++] = ((Double) d).longValue();
+ elements[col][row] = ((Double) d).longValue();
}
else
{
- elements[row][col++] = (float) ((Long) d).longValue();
+ elements[col][row] = (float) ((Long) d).longValue();
}
- if (maxscore < elements[row][col - 1])
+ if (maxscore < elements[col][row])
{
- maxscore = elements[row][col - 1];
+ maxscore = elements[col][row];
}
+ col++;
}
row++;
col = 0;
cols = ((List<Long>) pae_obj.get("residue2")).iterator();
Iterator<Double> scores = ((List<Double>) pae_obj.get("distance"))
.iterator();
- elements = new float[maxrow][maxcol];
+ elements = new float[maxcol][maxrow];
while (scores.hasNext())
{
float escore = scores.next().floatValue();
{
maxcol = col;
}
- elements[row - 1][col - 1] = escore;
+ elements[col - 1][row-1] = escore;
}
maxscore = ((Double) MapUtils.getFirst(pae_obj,
"max_predicted_aligned_error", "max_pae")).floatValue();
}
+ /**
+ * getContactList(column) @returns the vector of predicted alignment errors
+ * for reference position given by column
+ */
@Override
public ContactListI getContactList(final int column)
{
});
}
+ /**
+ * getElementAt(column, i) @returns the predicted superposition error for the
+ * ith position when column is used as reference
+ */
@Override
protected double getElementAt(int _column, int i)
{
import jalview.analysis.scoremodels.ScoreModels;
import jalview.api.DBRefEntryI;
import jalview.api.SiftsClientI;
+import jalview.bin.Console;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
import jalview.datamodel.SequenceI;
private static final String NOT_OBSERVED = "Not_Observed";
- private static final String SIFTS_FTP_BASE_URL = "http://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/";
+ private static final String SIFTS_SPLIT_FTP_BASE_URL = "https://ftp.ebi.ac.uk/pub/databases/msd/sifts/split_xml/";
private final static String NEWLINE = System.lineSeparator();
pdbId = pdbId.replace(".cif", "");
}
String siftFile = pdbId + ".xml.gz";
- String siftsFileFTPURL = SIFTS_FTP_BASE_URL + siftFile;
+ String siftsFileFTPURL = getDownloadUrlFor(siftFile);
/*
* Download the file from URL to either
return downloadTo;
}
+ public static String getDownloadUrlFor(String siftFile)
+ {
+ String durl = SIFTS_SPLIT_FTP_BASE_URL+siftFile.substring(1, 3)+"/"+siftFile;
+ Console.trace("SIFTS URL for "+siftFile+" is "+durl);
+ return durl;
+
+ }
+
/**
* Delete the SIFTs file for the given PDB Id in the local SIFTs download
* directory
if (mapping.isEmpty())
{
- throw new SiftsException("SIFTS mapping failed");
+ throw new SiftsException("SIFTS mapping failed for "+entityId+" and "+seq.getName());
}
// also construct a mapping object between the seq-coord sys and the PDB
// seq's coord sys
+ matrix.getMin());
long start = System.currentTimeMillis();
AverageDistanceEngine clusterer = new AverageDistanceEngine(
- af.getViewport(), null, matrix);
+ af.getViewport(), null, matrix, false);
System.out.println("built a tree in "
+ (System.currentTimeMillis() - start) * 0.001 + " seconds.");
StringBuffer sb = new StringBuffer();
import jalview.gui.JvOptionPane;
import java.io.PrintStream;
+import java.nio.charset.Charset;
+import java.util.Locale;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.google.common.base.Charsets;
+
/**
* Test the alignment -> Mapping routines
*
assertEquals(as.getAStr1(), as.getAStr2());
Mapping s1tos2 = as.getMappingFromS1(false);
+ checkMapping(s1tos2,s1,s2);
+ }
+
+ public void checkMapping(Mapping s1tos2,SequenceI _s1,SequenceI _s2)
+ {
System.out.println(s1tos2.getMap().toString());
- for (int i = s2.getStart(); i < s2.getEnd(); i++)
+ for (int i = _s2.getStart(); i < _s2.getEnd(); i++)
{
- System.out.println("Position in s2: " + i
- + " maps to position in s1: " + s1tos2.getPosition(i));
- // TODO fails: getCharAt doesn't allow for the start position??
- // assertEquals(String.valueOf(s2.getCharAt(i)),
- // String.valueOf(s1.getCharAt(s1tos2.getPosition(i))));
+ int p=s1tos2.getPosition(i);
+ char s2c=_s2.getCharAt(i-_s2.getStart());
+ char s1c=_s1.getCharAt(p-_s1.getStart());
+ System.out.println("Position in s2: " + i +s2c
+ + " maps to position in s1: " +p+s1c);
+ assertEquals(s1c,s2c);
}
}
+ @Test(groups = { "Functional" })
+ /**
+ * simple test that mapping from alignment corresponds identical positions.
+ */
+ public void testGetMappingForS1_withLowerCase()
+ {
+ // make one of the sequences lower case
+ SequenceI ns2 = new Sequence(s2);
+ ns2.replace('D', 'd');
+ AlignSeq as = AlignSeq.doGlobalNWAlignment(s1, ns2, AlignSeq.PEP);
+ System.out.println("s1: " + as.getAStr1());
+ System.out.println("s2: " + as.getAStr2());
+
+ // aligned results match
+ assertEquals("ASDFA", as.getAStr1());
+ assertEquals(as.getAStr1(), as.getAStr2().toUpperCase(Locale.ROOT));
+
+ Mapping s1tos2 = as.getMappingFromS1(false);
+ assertEquals("ASdFA",as.getAStr2());
+ // verify mapping is consistent between original all-caps sequences
+ checkMapping(s1tos2,s1,s2);
+ }
@Test(groups = { "Functional" })
public void testExtractGaps()
public void testAllInputOperations(String expectedString,
String failureMsg)
{
- if ("[TESTOUTPUT] arg --nousagestats was set".equals(expectedString))
- Assert.assertTrue(successfulCMDs.contains(expectedString),
- failureMsg);
+ Assert.assertTrue(successfulCMDs.contains(expectedString),
+ failureMsg + "; was expecting '" + expectedString + "'");
}
@Test(
file.deleteOnExit();
Worker worker = getJalviewDesktopRunner(withAWT, cmd, timeout);
assertNotNull(worker, "worker is null");
- String msg = "Didn't create an output" + type + " file.[" + cmd + "]";
+ String msg = "Didn't create an output" + type + " file '" + fileName
+ + "'. [" + cmd + "]";
assertTrue(file.exists(), msg);
FileAssert.assertFile(file, msg);
FileAssert.assertMinLength(file, expectedMinFileSize);
import jalview.gui.JvOptionPane;
import jalview.util.ArrayUtils;
-@Test
public class CommandsTest
{
private static final String testfiles = "test/jalview/bin/argparser/testfiles";
@AfterMethod(alwaysRun = true)
public void tearDown()
{
- if (Desktop.instance != null)
- Desktop.instance.closeAll_actionPerformed(null);
+ Desktop.closeDesktop();
+ }
+
+ public static void callJalviewMain(String[] args) {
+ if (Jalview.getInstance()!=null) {
+ Jalview.getInstance().doMain(args);
+ } else {
+ Jalview.main(args);
+ }
}
/* --setprops is currently disabled so this test won't work
public void commandsOpenTest(String cmdLine, boolean cmdArgs,
int numFrames, String[] sequences)
{
- String[] args = (cmdLine + " --gui").split("\\s+");
- Jalview.main(args);
- Commands cmds = Jalview.getInstance().getCommands();
- Assert.assertNotNull(cmds);
- Assert.assertEquals(cmds.commandArgsProvided(), cmdArgs,
- "Commands were not provided in the args");
- Assert.assertEquals(cmds.argsWereParsed(), cmdArgs,
- "Overall command parse and operation is false");
+ try
+ {
+ String[] args = (cmdLine + " --gui").split("\\s+");
+ callJalviewMain(args);
+ Commands cmds = Jalview.getInstance().getCommands();
+ Assert.assertNotNull(cmds);
+ Assert.assertEquals(cmds.commandArgsProvided(), cmdArgs,
+ "Commands were not provided in the args");
+ Assert.assertEquals(cmds.argsWereParsed(), cmdArgs,
+ "Overall command parse and operation is false");
- Assert.assertEquals(Desktop.getAlignFrames().length, numFrames,
- "Wrong number of AlignFrames");
+ Assert.assertEquals(Desktop.getAlignFrames().length, numFrames,
+ "Wrong number of AlignFrames");
- if (sequences != null)
- {
- Set<String> openedSequenceNames = new HashSet<>();
- AlignFrame[] afs = Desktop.getAlignFrames();
- for (AlignFrame af : afs)
- {
- openedSequenceNames
- .addAll(af.getViewport().getAlignment().getSequenceNames());
- }
- for (String sequence : sequences)
+ if (sequences != null)
{
- Assert.assertTrue(openedSequenceNames.contains(sequence),
- "Sequence '" + sequence
- + "' was not found in opened alignment files: "
- + cmdLine + ".\nOpened sequence names are:\n"
- + String.join("\n", openedSequenceNames));
+ Set<String> openedSequenceNames = new HashSet<>();
+ AlignFrame[] afs = Desktop.getAlignFrames();
+ for (AlignFrame af : afs)
+ {
+ openedSequenceNames.addAll(
+ af.getViewport().getAlignment().getSequenceNames());
+ }
+ for (String sequence : sequences)
+ {
+ Assert.assertTrue(openedSequenceNames.contains(sequence),
+ "Sequence '" + sequence
+ + "' was not found in opened alignment files: "
+ + cmdLine + ".\nOpened sequence names are:\n"
+ + String.join("\n", openedSequenceNames));
+ }
}
- }
- Assert.assertFalse(
- lookForSequenceName("THIS_SEQUENCE_ID_DOESN'T_EXIST"));
+ Assert.assertFalse(
+ lookForSequenceName("THIS_SEQUENCE_ID_DOESN'T_EXIST"));
+ } catch (Exception x)
+ {
+ Assert.fail("Unexpected exception during commandsOpenTest", x);
+ } finally
+ {
+ tearDown();
+
+ }
}
- @Test(groups = "Functional", dataProvider = "structureImageOutputFiles")
+ @Test(groups = {"Functional","testTask1"}, dataProvider = "structureImageOutputFiles")
public void structureImageOutputTest(String cmdLine, String[] filenames)
throws IOException
{
cleanupFiles(filenames);
String[] args = (cmdLine + " --gui").split("\\s+");
- Jalview.main(args);
- Commands cmds = Jalview.getInstance().getCommands();
- Assert.assertNotNull(cmds);
- File lastFile = null;
- for (String filename : filenames)
+ try
{
- File file = new File(filename);
- Assert.assertTrue(file.exists(), "File '" + filename
- + "' was not created by '" + cmdLine + "'");
- Assert.assertTrue(file.isFile(), "File '" + filename
- + "' is not a file from '" + cmdLine + "'");
- Assert.assertTrue(Files.size(file.toPath()) > 0, "File '" + filename
- + "' has no content from '" + cmdLine + "'");
- // make sure the successive output files get bigger!
- if (lastFile != null)
- Assert.assertTrue(
- Files.size(file.toPath()) > Files.size(lastFile.toPath()));
+ callJalviewMain(args);
+ Commands cmds = Jalview.getInstance().getCommands();
+ Assert.assertNotNull(cmds);
+ File lastFile = null;
+ for (String filename : filenames)
+ {
+ File file = new File(filename);
+ Assert.assertTrue(file.exists(), "File '" + filename
+ + "' was not created by '" + cmdLine + "'");
+ Assert.assertTrue(file.isFile(), "File '" + filename
+ + "' is not a file from '" + cmdLine + "'");
+ Assert.assertTrue(Files.size(file.toPath()) > 0, "File '" + filename
+ + "' has no content from '" + cmdLine + "'");
+ // make sure the successive output files get bigger!
+ if (lastFile != null)
+ Assert.assertTrue(Files.size(file.toPath()) > Files
+ .size(lastFile.toPath()));
+ }
+ } catch (Exception x)
+ {
+ Assert.fail("Unexpected exception during structureImageOutputTest",
+ x);
+ } finally
+ {
+ cleanupFiles(filenames);
+ tearDown();
}
- cleanupFiles(filenames);
- tearDown();
}
@Test(groups = "Functional", dataProvider = "argfileOutputFiles")
{
cleanupFiles(filenames);
String[] args = (cmdLine + " --gui").split("\\s+");
- Jalview.main(args);
+ try {
+ callJalviewMain(args);
Commands cmds = Jalview.getInstance().getCommands();
Assert.assertNotNull(cmds);
File lastFile = null;
Assert.assertTrue(
Files.size(file.toPath()) > Files.size(lastFile.toPath()));
}
- cleanupFiles(filenames);
- tearDown();
+ } catch (Exception x)
+ {
+ Assert.fail("Unexpected exception during argFilesGlobAndSubstitutions",
+ x);
+ } finally
+ {
+ cleanupFiles(filenames);
+ tearDown();
+ }
}
@DataProvider(name = "structureImageOutputFiles")
String[] nonfilenames)
{
String[] args = (cmdLine + " --gui").split("\\s+");
- Jalview.main(args);
+ callJalviewMain(args);
Commands cmds = Jalview.getInstance().getCommands();
Assert.assertNotNull(cmds);
for (String filename : filenames)
@AfterMethod(alwaysRun = true)
public void tearDown()
{
- if (Desktop.instance != null)
- Desktop.instance.closeAll_actionPerformed(null);
+ Desktop.closeDesktop();
}
@Test(
{
String[] args = cmdLine.split("\\s+");
- Jalview.main(args);
- try
- {
- // sleep for slow build server to open annotations and viewer windows
- Thread.sleep(seqNum * 50 + annNum * 50 + viewerNum * 500);
- } catch (InterruptedException e)
+ CommandsTest.callJalviewMain(args);
+ while (Desktop.instance!=null && Desktop.instance.operationsAreInProgress())
{
- e.printStackTrace();
+ try
+ {
+ // sleep for slow build server to open annotations and viewer windows
+ Thread.sleep(viewerNum * 50);
+ } catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
}
+ ;
AlignFrame[] afs = Desktop.getAlignFrames();
Assert.assertNotNull(afs);
verifyPAEmatrix(seq, aa, 0, 0, 4);
// test clustering
- paematrix.setGroupSet(GroupSet.makeGroups(paematrix, 0.1f, false));
+ paematrix.setGroupSet(GroupSet.makeGroups(paematrix, false,0.1f, false));
// remap - test the MappableContactMatrix.liftOver method
SequenceI newseq = new Sequence("Seq", "ASDQEASDQEASDQE");
{
Sequence origSeq = new Sequence("MYSEQ", "THISISASEQ");
Sequence toSeq = new Sequence("MYSEQ", "THISISASEQ");
+ origSeq.setDescription("DESCRIPTION");
origSeq.addDBRef(new DBRefEntry("UNIPROT", "0", "Q12345", null, true));
+
+ toSeq.transferAnnotation(origSeq, null);
+ assertEquals("DESCRIPTION",toSeq.getDescription());
+ toSeq = new Sequence("MYSEQ", "THISISASEQ");
+ toSeq.setDescription("unchanged");
toSeq.transferAnnotation(origSeq, null);
+ assertEquals("unchanged",toSeq.getDescription());
+
assertTrue(toSeq.getDBRefs().size() == 1);
assertTrue(toSeq.getDBRefs().get(0).isCanonical());
*/
package jalview.io;
+import jalview.datamodel.SequenceI;
import jalview.gui.JvOptionPane;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
import java.io.File;
+import java.io.IOException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import fr.orsay.lri.varna.utils.RNAMLParser;
+import groovy.lang.Sequence;
+
public class RNAMLfileTest
{
}
+ @Test(groups= {"Functional"})
+ public void testRnamlSeqImport() throws IOException
+ {
+ RnamlFile parser = new RnamlFile("examples/testdata/7WKP-rna1.xml", DataSourceType.FILE);
+ SequenceI[] seqs = parser.getSeqsAsArray();
+ assertNotNull(seqs);
+ assertEquals(seqs.length,1);
+ assertEquals(seqs[0].getEnd()-seqs[0].getStart()+1,seqs[0].getSequence().length);
+ }
+
}
*/
package jalview.io.cache;
+import java.lang.reflect.InvocationTargetException;
import java.util.LinkedHashSet;
+import javax.swing.SwingUtilities;
+
import org.junit.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
try
{
- // This delay is essential to prevent the
- // assertion below from executing before
- // swing thread finishes updating the combo-box
- Thread.sleep(350);
- } catch (InterruptedException e)
+ // fix for JAL-4153
+ // This delay is essential to prevent the assertion below from executing
+ // before swing thread finishes updating the combo-box
+ SwingUtilities.invokeAndWait(() -> {
+ try
+ {
+ Thread.sleep(1);
+ } catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ });
+ } catch (InvocationTargetException | InterruptedException e)
{
e.printStackTrace();
}
cacheBox.addItem(testInput);
cacheBox.setSelectedItem(testInput);
cacheBox.updateCache();
+
try
{
- // This delay is to let
- // cacheBox.updateCache() finish updating the cache
- Thread.sleep(350);
- } catch (InterruptedException e)
+ // fix for JAL-4153
+ // This delay is to let cacheBox.updateCache() finish updating the cache
+ SwingUtilities.invokeAndWait(() -> {
+ try
+ {
+ Thread.sleep(1);
+ } catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ });
+ } catch (InvocationTargetException | InterruptedException e)
{
e.printStackTrace();
}
{
paevals[i][j] = ((i - j < 2)
|| ((i > 1 && i < 5) && (j > 1 && i < 5))) ? 1 : 0f;
- paevals[j][i] = paevals[i][j];
+ paevals[j][i] = -paevals[i][j];
}
}
PAEContactMatrix dummyMat = new PAEContactMatrix(sq, paevals);
float[][] vals = ContactMatrix.fromFloatStringToContacts(content,
sq.getLength(), sq.getLength());
assertEquals(vals[3][4], paevals[3][4]);
- dummyMat.setGroupSet(GroupSet.makeGroups(dummyMat, 0.5f, false));
+ assertEquals(vals[4][3], paevals[4][3]);
+ dummyMat.setGroupSet(GroupSet.makeGroups(dummyMat, false,0.5f, false));
Assert.assertNotSame(dummyMat.getNewick(), "");
AlignmentAnnotation paeCm = sq.addContactList(dummyMat);
al.addAnnotation(paeCm);
SiftsSettings.setCacheThresholdInDays("2");
SiftsSettings.setFailSafePIDThreshold("70");
PDBfile pdbFile;
+
pdbFile = new PDBfile(false, false, false,
"test/jalview/io/" + testPDBId + ".pdb", DataSourceType.FILE);
+ // TODO: this uses a network connection - we should mock the sifts testPDBId.xml.gz
siftsClient = new SiftsClient(pdbFile);
}
{
siftsClient = null;
}
+
+ @Test(groups= {"Functional"})
+ public void testSIFTsDownloadURL() {
+ String expectedUrl = "https://ftp.ebi.ac.uk/pub/databases/msd/sifts/split_xml/xy/1xyz.sifts.xml.gz";
+ Assert.assertEquals(SiftsClient.getDownloadUrlFor("1xyz.sifts.xml.gz"), expectedUrl);
+ }
@Test(groups = { "Network" })
public void getSIFTsFileTest() throws SiftsException, IOException
long t1 = siftsFile.lastModified();
// re-read file should be returned from cache
- siftsFile = SiftsClient.downloadSiftsFile(testPDBId);
+ siftsFile = SiftsClient.getSiftsFile(testPDBId);
FileAssert.assertFile(siftsFile);
long t2 = siftsFile.lastModified();
assertEquals(t1, t2);
{
SequenceI invalidTestSeq = new Sequence("testSeq", "ABCDEFGH");
DBRefEntry invalidDBRef = new DBRefEntry();
- invalidDBRef.setAccessionId("BLAR");
+ invalidDBRef.setAccessionId("BLAR"); // note no version is set, so also invalid
invalidTestSeq.addDBRef(invalidDBRef);
siftsClient.getValidSourceDBRef(invalidTestSeq);
}
--- /dev/null
+{
+ "name": "Jalview",
+ "description": "Jalview is a free program for multiple sequence alignment editing, visualisation and analysis. Use it to view and edit sequence alignments, analyse them with phylogenetic trees and principal components analysis (PCA) plots and explore molecular structures and annotation.",
+ "homepage": "https://www.jalview.org/",
+ "biotoolsID": "Jalview",
+ "biotoolsCURIE": "biotools:Jalview",
+ "version": [
+ "2.11.2.7"
+ ],
+ "relation": [
+ {
+ "biotoolsID": "jabaws",
+ "type": "uses"
+ },
+ {
+ "biotoolsID": "chimera",
+ "type": "uses"
+ },
+ {
+ "biotoolsID": "chimerax",
+ "type": "uses"
+ },
+ {
+ "biotoolsID": "pymol",
+ "type": "uses"
+ },
+ {
+ "biotoolsID": "bioconda",
+ "type": "includedIn"
+ },
+ {
+ "biotoolsID": "3d-beacons",
+ "type": "uses"
+ },
+ {
+ "biotoolsID": "uniprot",
+ "type": "uses"
+ },
+ {
+ "biotoolsID": "pfam",
+ "type": "uses"
+ },
+ {
+ "biotoolsID": "ensembl",
+ "type": "uses"
+ },
+ {
+ "biotoolsID": "pdb",
+ "type": "uses"
+ },
+ {
+ "biotoolsID": "rfam",
+ "type": "uses"
+ }
+ ],
+ "function": [
+ {
+ "operation": [
+ {
+ "uri": "http://edamontology.org/operation_0564",
+ "term": "Sequence visualisation"
+ },
+ {
+ "uri": "http://edamontology.org/operation_0324",
+ "term": "Phylogenetic tree analysis"
+ },
+ {
+ "uri": "http://edamontology.org/operation_3081",
+ "term": "Sequence alignment editing"
+ }
+ ],
+ "input": [
+ {
+ "data": {
+ "uri": "http://edamontology.org/data_0863",
+ "term": "Sequence alignment"
+ },
+ "format": [
+ {
+ "uri": "http://edamontology.org/format_1939",
+ "term": "GFF3-seq"
+ },
+ {
+ "uri": "http://edamontology.org/format_1982",
+ "term": "ClustalW format"
+ },
+ {
+ "uri": "http://edamontology.org/format_1961",
+ "term": "Stockholm format"
+ },
+ {
+ "uri": "http://edamontology.org/format_1984",
+ "term": "FASTA-aln"
+ },
+ {
+ "uri": "http://edamontology.org/format_1938",
+ "term": "GFF2-seq"
+ },
+ {
+ "uri": "http://edamontology.org/format_1929",
+ "term": "FASTA"
+ },
+ {
+ "uri": "http://edamontology.org/format_1948",
+ "term": "nbrf/pir"
+ },
+ {
+ "uri": "http://edamontology.org/format_3774",
+ "term": "BioJSON (Jalview)"
+ },
+ {
+ "uri": "http://edamontology.org/format_1997",
+ "term": "PHYLIP format"
+ },
+ {
+ "uri": "http://edamontology.org/format_3313",
+ "term": "BLC"
+ },
+ {
+ "uri": "http://edamontology.org/format_3311",
+ "term": "RNAML"
+ },
+ {
+ "uri": "http://edamontology.org/format_1947",
+ "term": "GCG MSF"
+ },
+ {
+ "uri": "http://edamontology.org/format_3015",
+ "term": "Pileup"
+ },
+ {
+ "uri": "http://edamontology.org/format_1477",
+ "term": "mmCIF"
+ },
+ {
+ "uri": "http://edamontology.org/format_3016",
+ "term": "VCF"
+ },
+ {
+ "uri": "http://edamontology.org/format_1915",
+ "term": "Format"
+ }
+ ]
+ },
+ {
+ "data": {
+ "uri": "http://edamontology.org/data_0886",
+ "term": "Structure alignment"
+ },
+ "format": [
+ {
+ "uri": "http://edamontology.org/format_1476",
+ "term": "PDB"
+ }
+ ]
+ }
+ ],
+ "output": [
+ {
+ "data": {
+ "uri": "http://edamontology.org/data_0863",
+ "term": "Sequence alignment"
+ },
+ "format": [
+ {
+ "uri": "http://edamontology.org/format_1948",
+ "term": "nbrf/pir"
+ },
+ {
+ "uri": "http://edamontology.org/format_3464",
+ "term": "JSON"
+ },
+ {
+ "uri": "http://edamontology.org/format_1961",
+ "term": "Stockholm format"
+ },
+ {
+ "uri": "http://edamontology.org/format_1929",
+ "term": "FASTA"
+ },
+ {
+ "uri": "http://edamontology.org/format_1997",
+ "term": "PHYLIP format"
+ },
+ {
+ "uri": "http://edamontology.org/format_3313",
+ "term": "BLC"
+ },
+ {
+ "uri": "http://edamontology.org/format_3774",
+ "term": "BioJSON (Jalview)"
+ },
+ {
+ "uri": "http://edamontology.org/format_1947",
+ "term": "GCG MSF"
+ },
+ {
+ "uri": "http://edamontology.org/format_3015",
+ "term": "Pileup"
+ },
+ {
+ "uri": "http://edamontology.org/format_1982",
+ "term": "ClustalW format"
+ }
+ ]
+ },
+ {
+ "data": {
+ "uri": "http://edamontology.org/data_2884",
+ "term": "Plot"
+ },
+ "format": [
+ {
+ "uri": "http://edamontology.org/format_3603",
+ "term": "PNG"
+ },
+ {
+ "uri": "http://edamontology.org/format_2331",
+ "term": "HTML"
+ },
+ {
+ "uri": "http://edamontology.org/format_3466",
+ "term": "EPS"
+ },
+ {
+ "uri": "http://edamontology.org/format_3604",
+ "term": "SVG"
+ },
+ {
+ "uri": "http://edamontology.org/format_1915",
+ "term": "Format"
+ }
+ ]
+ }
+ ],
+ "note": "Other Input formats:\nAMSA (.amsa);\nJnetFile (.concise, .jnet);\nPFAM (.pfam);\nSubstitution matrix (.matrix);\nJalview Project File (.jvp);\nJalview Feature File (.features, .jvfeatures);\nJalview Annotations File (.annotations, .jvannotations);\n\n...\nOther Output formats:\nPFAM (.pfam);\nBioJS (.biojs) (interactive HTML/Javascript);\nJalview Project File (.jvp);"
+ }
+ ],
+ "toolType": [
+ "Desktop application"
+ ],
+ "topic": [
+ {
+ "uri": "http://edamontology.org/topic_0080",
+ "term": "Sequence analysis"
+ },
+ {
+ "uri": "http://edamontology.org/topic_0092",
+ "term": "Data visualisation"
+ }
+ ],
+ "operatingSystem": [
+ "Linux",
+ "Windows",
+ "Mac"
+ ],
+ "license": "GPL-3.0",
+ "maturity": "Mature",
+ "cost": "Free of charge",
+ "accessibility": "Open access",
+ "elixirPlatform": [
+ "Tools"
+ ],
+ "elixirNode": [
+ "UK"
+ ],
+ "link": [
+ {
+ "url": "https://discourse.jalview.org/",
+ "type": [
+ "Discussion forum"
+ ]
+ },
+ {
+ "url": "https://issues.jalview.org/",
+ "type": [
+ "Issue tracker"
+ ]
+ },
+ {
+ "url": "https://www.jalview.org/development/jalview_develop/",
+ "type": [
+ "Other"
+ ],
+ "note": "Latest development version"
+ },
+ {
+ "url": "https://source.jalview.org/crucible/browse/jalview",
+ "type": [
+ "Repository"
+ ]
+ },
+ {
+ "url": "https://twitter.com/Jalview",
+ "type": [
+ "Social media"
+ ],
+ "note": "Twitter feed"
+ },
+ {
+ "url": "https://www.youtube.com/channel/UCIjpnvZB770yz7ftbrJ0tfw",
+ "type": [
+ "Social media"
+ ],
+ "note": "YouTube training videos"
+ }
+ ],
+ "download": [
+ {
+ "url": "https://www.jalview.org/download",
+ "type": "Downloads page"
+ },
+ {
+ "url": "https://www.jalview.org/download/source/",
+ "type": "Source code"
+ },
+ {
+ "url": "https://www.jalview.org/download/?os=all",
+ "type": "Binaries",
+ "note": "Binaries for all platforms"
+ },
+ {
+ "url": "https://www.jalview.org/favicon.svg",
+ "type": "Icon"
+ },
+ {
+ "url": "https://www.jalview.org/download/other/jar/",
+ "type": "Binaries",
+ "note": "Executable JAR file"
+ }
+ ],
+ "documentation": [
+ {
+ "url": "https://www.jalview.org/about/citation",
+ "type": [
+ "Citation instructions"
+ ]
+ },
+ {
+ "url": "https://www.jalview.org/training/",
+ "type": [
+ "Training material"
+ ],
+ "note": "Hands-on exercises, Training courses and Training videos"
+ },
+ {
+ "url": "https://www.jalview.org/help/faq",
+ "type": [
+ "FAQ"
+ ]
+ },
+ {
+ "url": "https://www.jalview.org/help/documentation/",
+ "type": [
+ "User manual"
+ ]
+ }
+ ],
+ "publication": [
+ {
+ "doi": "10.1093/bioinformatics/btp033",
+ "metadata": {
+ "title": "Jalview Version 2-A multiple sequence alignment editor and analysis workbench",
+ "abstract": "Summary: Jalview Version 2 is a system for interactive WYSIWYG editing, analysis and annotation of multiple sequence alignments. Core features include keyboard and mouse-based editing, multiple views and alignment overviews, and linked structure display with Jmol. Jalview 2 is available in two forms: a lightweight Java applet for use in web applications, and a powerful desktop application that employs web services for sequence alignment, secondary structure prediction and the retrieval of alignments, sequences, annotation and structures from public databases and any DAS 1.53 compliant sequence or annotation server. © 2009 The Author(s).",
+ "date": "2009-05-07T00:00:00Z",
+ "citationCount": 5999,
+ "authors": [
+ {
+ "name": "Waterhouse A.M."
+ },
+ {
+ "name": "Procter J.B."
+ },
+ {
+ "name": "Martin D.M.A."
+ },
+ {
+ "name": "Clamp M."
+ },
+ {
+ "name": "Barton G.J."
+ }
+ ],
+ "journal": "Bioinformatics"
+ }
+ }
+ ],
+ "credit": [
+ {
+ "name": "Jim Procter",
+ "url": "http://www.lifesci.dundee.ac.uk/people/jim-procter",
+ "orcidid": "https://orcid.org/0000-0002-7865-7382",
+ "typeEntity": "Person",
+ "typeRole": [
+ "Primary contact"
+ ]
+ },
+ {
+ "name": "Geoff Barton",
+ "url": "https://www.lifesci.dundee.ac.uk/people/geoff-barton",
+ "orcidid": "https://orcid.org/0000-0002-9014-5355"
+ }
+ ],
+ "owner": "ben_s",
+ "additionDate": "2019-02-13T17:01:40Z",
+ "lastUpdate": "2023-07-22T09:24:44.755337Z",
+ "editPermission": {
+ "type": "group",
+ "authors": [
+ "ben_s",
+ "jimprocter"
+ ]
+ },
+ "validated": 1,
+ "homepage_status": 0,
+ "elixir_badge": 0
+}
--- /dev/null
+This is the JSON representation of the latest Jalview release's record on bio.tools
+
+To update:
+1. go to https://bio.tools/Jalview
+2. log in and scroll down to the 'Update Record' button to open the edit interface.
+3. Make any chances to the entry - press Validate to ensure all is good
+4. Select the JSON tab and copy paste into
+
+``
+cat > utils/biotools/Jalview.json
+``
+
+Thanks to Herve Menager for the tutorial on storing bio.tools records with the tool's software repository at [CoFest 2023](https://www.open-bio.org/events/bosc-2023/obf-bosc-collaborationfest-2023)
\ No newline at end of file
---- a/build.gradle 2021-09-21 09:52:04.653972716 +0100
-+++ b/build.gradle 2021-09-21 09:52:18.117985307 +0100
-@@ -2,56 +2,12 @@
+diff --git a/build.gradle b/build.gradle
+index ca599a85a..ce7f13634 100644
+--- a/build.gradle
++++ b/build.gradle
+@@ -2,66 +2,12 @@
* For properties set within build.gradle, use camelCaseNoSpace.
*/
import org.apache.tools.ant.filters.ReplaceTokens
-import org.gradle.plugins.ide.eclipse.model.Output
-import org.gradle.plugins.ide.eclipse.model.Library
-import java.security.MessageDigest
+-import java.util.regex.Matcher
-import groovy.transform.ExternalizeMethods
-import groovy.util.XmlParser
-import groovy.xml.XmlUtil
+-import groovy.json.JsonBuilder
-import com.vladsch.flexmark.util.ast.Node
-import com.vladsch.flexmark.html.HtmlRenderer
-import com.vladsch.flexmark.parser.Parser
-import com.vladsch.flexmark.ext.autolink.AutolinkExtension
-import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
-import com.vladsch.flexmark.ext.toc.TocExtension
+-import com.google.common.hash.HashCode
+-import com.google.common.hash.Hashing
+-import com.google.common.io.Files
+-import org.jsoup.Jsoup
+-import org.jsoup.nodes.Element
-
-buildscript {
- repositories {
- }
- 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"
- }
-}
-
- id 'eclipse'
- id "com.diffplug.gradle.spotless" version "3.28.0"
- id 'com.github.johnrengelman.shadow' version '4.0.3'
-- id 'com.install4j.gradle' version '8.0.10'
-- id 'com.dorongold.task-tree' version '1.5' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
-- id 'com.palantir.git-version' version '0.12.3'
+- id 'com.install4j.gradle' version '10.0.3'
+- id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
+- id 'com.palantir.git-version' version '0.13.0' apply false
-}
-
-repositories {
}
-
+-
// in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
def string(Object o) {
return o == null ? "" : o.toString()
-@@ -92,23 +48,15 @@
+@@ -102,34 +48,20 @@ def overrideProperties(String propsFileName, boolean output = false) {
}
}
+project.ext {
jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
jalviewDirRelativePath = jalviewDir
+- date = new Date()
- getdownChannelName = CHANNEL.toLowerCase()
- // default to "default". Currently only has different cosmetics for "develop", "release", "default"
- propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
+- channelDirName = propertiesChannelName
- // Import channel_properties
+- if (getdownChannelName.startsWith("develop-")) {
+- channelDirName = "develop-SUFFIX"
+- }
+- channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
+ propertiesChannelName = "release"
- channelDir = string("${jalviewDir}/${channel_properties_dir}/${propertiesChannelName}")
++ channelDir = string("${jalviewDir}/${channel_properties_dir}/${propertiesChannelName}")
channelGradleProperties = string("${channelDir}/channel_gradle.properties")
+- channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
overrideProperties(channelGradleProperties, false)
- // local build environment properties
- // can be "projectDir/local.properties"
////
// Import releaseProps from the RELEASE file
// or a file specified via JALVIEW_RELEASE_FILE if defined
-@@ -128,41 +76,6 @@
+ // Expect jalview.version and target release branch in jalview.release
+- releaseProps = new Properties();
++ def releaseProps = new Properties();
+ def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
+ def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
+ try {
+@@ -144,42 +76,6 @@ ext {
if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
JALVIEW_VERSION = releaseProps.get("jalview.version")
}
+- println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
-
- // this property set when running Eclipse headlessly
- j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
// essentials
bareSourceDir = string(source_dir)
-@@ -173,218 +86,18 @@
+@@ -190,273 +86,18 @@ ext {
classesDir = string("${jalviewDir}/${classes_dir}")
- cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
- //cloverTestClassesDir = cloverClassesDir
- cloverDb = string("${cloverBuildDir}/clover.db")
--
++ useClover = false
+
- testSourceDir = useClover ? cloverTestInstrDir : testDir
- testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
--
-- getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
++ resourceClassesDir = classesDir
+
+- channelSuffix = ""
+- backgroundImageText = BACKGROUNDIMAGETEXT
+- getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
+- getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
+- getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
+- getdownFullArchiveDir = null
+- getdownTextLines = []
+- getdownLaunchJvl = null
+- getdownVersionLaunchJvl = null
- buildDist = true
- buildProperties = null
--
++ testSourceDir = testDir
++ testClassesDir = "${jalviewDir}/${test_output_dir}"
+
- // the following values might be overridden by the CHANNEL switch
- getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
- getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
+- getdownArchiveAppBase = getdown_archive_base
- getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
- getdownAppDistDir = getdown_app_dir_alt
- getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
-- getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
+- getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
++ buildProperties = string("${classesDir}/${build_properties_file}")
+ getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
- reportRsyncCommand = false
- jvlChannelName = CHANNEL.toLowerCase()
- install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
- install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
-- install4jDMGBackgroundImage = "${install4j_images_dir}/${install4j_dmg_background}"
+- install4jDMGBackgroundImageDir = "${install4j_images_dir}"
+- install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
+- install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
- install4jInstallerName = "${jalview_name} Non-Release Installer"
- install4jExecutableName = install4j_executable_name
- install4jExtraScheme = "jalviewx"
- install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
- install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
- install4jBackground = string("${install4j_images_dir}/${install4j_background}")
+- install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
+- install4jCheckSums = true
+-
+- applicationName = "${jalview_name}"
- switch (CHANNEL) {
-
- case "BUILD":
- testng_excluded_groups = "Not-bamboo"
- }
- install4jExtraScheme = "jalviewb"
+- backgroundImageText = true
- break
-+ useClover = false
-
+-
- case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
- getdownAppDistDir = getdown_app_dir_release
+- getdownSetAppBaseProperty = true
- reportRsyncCommand = true
- install4jSuffix = ""
- install4jInstallerName = "${jalview_name} Installer"
- case "ARCHIVELOCAL":
- getdownChannelName = string("archive/${JALVIEW_VERSION}")
- getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
-- getdownAppBase = file(getdownWebsiteDir).toURI().toString()
+- getdownAppBase = file(getdownAppBaseDir).toURI().toString()
- if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
-- throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
+- throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
- } else {
- package_dir = string("${ARCHIVEDIR}/${package_dir}")
- buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
- install4jExtraScheme = "jalviewa"
- break
-
+- case ~/^DEVELOP-([\.\-\w]*)$/:
+- def suffix = Matcher.lastMatcher[0][1]
+- reportRsyncCommand = true
+- getdownSetAppBaseProperty = true
+- JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
+- install4jSuffix = "Develop ${suffix}"
+- install4jExtraScheme = "jalviewd"
+- install4jInstallerName = "${jalview_name} Develop ${suffix} Installer"
+- getdownChannelName = string("develop-${suffix}")
+- getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
+- getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
+- getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
+- getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
+- channelSuffix = string(suffix)
+- backgroundImageText = true
+- break
+-
- case "DEVELOP":
- reportRsyncCommand = true
- getdownSetAppBaseProperty = true
- install4jSuffix = "Develop"
- install4jExtraScheme = "jalviewd"
- install4jInstallerName = "${jalview_name} Develop Installer"
+- backgroundImageText = true
- break
-
- case "TEST-RELEASE":
- reportRsyncCommand = true
+- getdownSetAppBaseProperty = true
- // Don't ignore transpile errors for release build
- if (jalviewjs_ignore_transpile_errors.equals("true")) {
- jalviewjs_ignore_transpile_errors = "false"
- install4jSuffix = "Test"
- install4jExtraScheme = "jalviewt"
- install4jInstallerName = "${jalview_name} Test Installer"
+- backgroundImageText = true
- break
-
- case ~/^SCRATCH(|-[-\w]*)$/:
- install4jSuffix = "Test-Local"
- install4jExtraScheme = "jalviewt"
- install4jInstallerName = "${jalview_name} Test Installer"
+- backgroundImageText = true
- break
-
- case [ "LOCAL", "JALVIEWJS" ]:
- JALVIEW_VERSION = "TEST"
-- getdownAppBase = file(getdownWebsiteDir).toURI().toString()
+- getdownAppBase = file(getdownAppBaseDir).toURI().toString()
+- getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
- getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
- install4jExtraScheme = "jalviewl"
+- install4jCheckSums = false
- break
-
- default: // something wrong specified
- break
-
- }
+- JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
+- hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
+- hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
- // override getdownAppBase if requested
- if (findProperty("getdown_appbase_override") != null) {
- // revert to LOCAL if empty string
- if (string(getdown_appbase_override) == "") {
-- getdownAppBase = file(getdownWebsiteDir).toURI().toString()
+- getdownAppBase = file(getdownAppBaseDir).toURI().toString()
- getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
- } else if (string(getdown_appbase_override).startsWith("file://")) {
- getdownAppBase = string(getdown_appbase_override)
- jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
- // install4j application and folder names
- if (install4jSuffix == "") {
-- install4jApplicationName = "${jalview_name}"
- install4jBundleId = "${install4j_bundle_id}"
- install4jWinApplicationId = install4j_release_win_application_id
- } else {
-- install4jApplicationName = "${jalview_name} ${install4jSuffix}"
+- applicationName = "${jalview_name} ${install4jSuffix}"
- install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
- // add int hash of install4jSuffix to the last part of the application_id
- def id = install4j_release_win_application_id
- }
- // sanitise folder and id names
- // install4jApplicationFolder = e.g. "Jalview Build"
-- install4jApplicationFolder = install4jApplicationName
+- install4jApplicationFolder = applicationName
- .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
- .replaceAll("_+", "_") // collapse __
-- install4jInternalId = install4jApplicationName
+- install4jInternalId = applicationName
- .replaceAll(" ","_")
- .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
- .replaceAll("_+", "") // collapse __
- //.replaceAll("_*-_*", "-") // collapse _-_
-- install4jUnixApplicationFolder = install4jApplicationName
+- install4jUnixApplicationFolder = applicationName
- .replaceAll(" ","_")
- .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
- .replaceAll("_+", "_") // collapse __
- .toLowerCase()
-
- getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
-- getdownAppDir = string("${getdownWebsiteDir}/${getdownAppDistDir}")
-- //getdownJ11libDir = "${getdownWebsiteDir}/${getdown_j11lib_dir}"
-- getdownResourceDir = string("${getdownWebsiteDir}/${getdown_resource_dir}")
-- getdownInstallDir = string("${getdownWebsiteDir}/${getdown_install_dir}")
+- getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
+- //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
+- getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
+- getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
- getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
- getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
- /* compile without modules -- using classpath libraries
- modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
- modules_runtimeClasspath = modules_compileClasspath
- */
-- def details = versionDetails()
-- gitHash = details.gitHash
-- gitBranch = details.branchName
-+ resourceClassesDir = classesDir
-+
-+ testSourceDir = testDir
-+ testClassesDir = "${jalviewDir}/${test_output_dir}"
+-
+- gitHash = "SOURCE"
+- gitBranch = "Source"
+- try {
+- apply plugin: "com.palantir.git-version"
+- def details = versionDetails()
+- gitHash = details.gitHash
+- gitBranch = details.branchName
+- } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
+- println("Not in a git repository. Using git values from RELEASE properties file.")
+- gitHash = releaseProps.getProperty("git.hash")
+- gitBranch = releaseProps.getProperty("git.branch")
+- } catch(java.lang.RuntimeException e1) {
+- throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
+- }
-+ buildProperties = string("${classesDir}/${build_properties_file}")
-+ getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
-+
+ install4jApplicationName = "${jalview_name}"
+
println("Using a ${CHANNEL} profile.")
additional_compiler_args = []
-@@ -396,71 +109,16 @@
+@@ -468,65 +109,16 @@ ext {
libDistDir = j8libDir
compile_source_compatibility = 1.8
compile_target_compatibility = 1.8
- '--add-modules', j11modules
- ]
- */
-- } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
-- JAVA_INTEGER_VERSION = JAVA_VERSION
-- libDir = j11libDir
-- libDistDir = j11libDir
-- compile_source_compatibility = JAVA_VERSION
-- compile_target_compatibility = JAVA_VERSION
+- } else if (JAVA_VERSION.equals("17")) {
+- JAVA_INTEGER_VERSION = string("17")
+- libDir = j17libDir
+- libDistDir = j17libDir
+- compile_source_compatibility = 17
+- compile_target_compatibility = 17
- getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
- getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
- getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
-- eclipseJavaRuntimeName = string("JavaSE-11")
+- eclipseJavaRuntimeName = string("JavaSE-17")
- /* compile without modules -- using classpath libraries
- additional_compiler_args += [
- '--module-path', modules_compileClasspath.asPath,
- // for install4j
- JAVA_MIN_VERSION = JAVA_VERSION
- JAVA_MAX_VERSION = JAVA_VERSION
-- def jreInstallsDir = string(jre_installs_dir)
+- jreInstallsDir = string(jre_installs_dir)
- if (jreInstallsDir.startsWith("~/")) {
- jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
- }
-- macosJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-mac-x64/jre")
-- macosJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-mac-x64.tar.gz")
-- windowsJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-windows-x64/jre")
-- windowsJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-windows-x64.tar.gz")
-- linuxJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-linux-x64/jre")
-- linuxJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-linux-x64.tar.gz")
- install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
- install4jConfFileName = string("jalview-install4j-conf.install4j")
- install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
resourceBuildDir = string("${buildDir}/resources")
resourcesBuildDir = string("${resourceBuildDir}/resources_build")
helpBuildDir = string("${resourceBuildDir}/help_build")
-@@ -474,31 +132,6 @@
+@@ -540,39 +132,6 @@ ext {
helpSourceDir = string("${helpParentDir}/${help_dir}")
helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
+- convertBinary = null
+- convertBinaryExpectedLocation = imagemagick_convert
+- if (convertBinaryExpectedLocation.startsWith("~/")) {
+- convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
+- }
+- if (file(convertBinaryExpectedLocation).exists()) {
+- convertBinary = convertBinaryExpectedLocation
+- }
-
- relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
- jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
// ENDEXT
}
-@@ -517,27 +150,12 @@
+@@ -591,27 +150,12 @@ sourceSets {
compileClasspath = files(sourceSets.main.java.outputDir)
compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
}
test {
-@@ -557,453 +175,41 @@
+@@ -631,453 +175,41 @@ sourceSets {
runtimeClasspath = compileClasspath
runtimeClasspath += files(sourceSets.test.resources.srcDirs)
}
- if (cloverreport_jvmargs.length() > 0) {
- jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
- }
--
+
- def argsList = [
- "--alwaysreport",
- "--initstring",
-
- args argsList.toArray()
-}
-
-+ compileClasspath = files( sourceSets.test.java.outputDir )
-+ compileClasspath += sourceSets.main.compileClasspath
-+ compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["** REMOVE_THIS_GAP /*.jar"])
-
+-
+-
-task cloverReport {
- group = "Verification"
- description = "Creates clover reports"
-
-
-compileCloverJava {
--
++ compileClasspath = files( sourceSets.test.java.outputDir )
++ compileClasspath += sourceSets.main.compileClasspath
++ compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["** REMOVE_THIS_GAP /*.jar"])
+
- doFirst {
- sourceCompatibility = compile_source_compatibility
- targetCompatibility = compile_target_compatibility
- // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
sourceCompatibility = compile_source_compatibility
targetCompatibility = compile_target_compatibility
- options.compilerArgs = additional_compiler_args
+- options.compilerArgs += additional_compiler_args
- options.encoding = "UTF-8"
++ options.compilerArgs = additional_compiler_args
doFirst {
print ("Setting target compatibility to "+compile_target_compatibility+"\n")
}
compileTestJava {
- sourceCompatibility = compile_source_compatibility
- targetCompatibility = compile_target_compatibility
-- options.compilerArgs = additional_compiler_args
+- options.compilerArgs += additional_compiler_args
doFirst {
+ sourceCompatibility = compile_source_compatibility
+ targetCompatibility = compile_target_compatibility
print ("Setting target compatibility to "+targetCompatibility+"\n")
}
}
-@@ -1017,7 +223,6 @@
+@@ -1091,7 +223,6 @@ clean {
cleanTest {
doFirst {
delete sourceSets.test.java.outputDir
}
-@@ -1031,85 +236,6 @@
+@@ -1100,89 +231,11 @@ cleanTest {
+
+ // format is a string like date.format("dd MMMM yyyy")
+ def getDate(format) {
++ def date = new Date()
+ return date.format(format)
}
task copyDocs(type: Copy) {
def inputDir = "${jalviewDir}/${doc_dir}"
def outputDir = "${docBuildDir}/${doc_dir}"
-@@ -1140,27 +266,6 @@
+@@ -1213,235 +266,6 @@ task copyDocs(type: Copy) {
}
-}
-
-
+-def hugoTemplateSubstitutions(String input, Map extras=null) {
+- def replacements = [
+- DATE: getDate("yyyy-MM-dd"),
+- CHANNEL: propertiesChannelName,
+- APPLICATION_NAME: applicationName,
+- GIT_HASH: gitHash,
+- GIT_BRANCH: gitBranch,
+- VERSION: JALVIEW_VERSION,
+- JAVA_VERSION: JAVA_VERSION,
+- VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
+- DRAFT: "false",
+- JVL_HEADER: ""
+- ]
+- def output = input
+- if (extras != null) {
+- extras.each{ k, v ->
+- output = output.replaceAll("__${k}__", ((v == null)?"":v))
+- }
+- }
+- replacements.each{ k, v ->
+- output = output.replaceAll("__${k}__", ((v == null)?"":v))
+- }
+- return output
+-}
+-
+-def mdFileComponents(File mdFile, def dateOnly=false) {
+- def map = [:]
+- def content = ""
+- if (mdFile.exists()) {
+- def inFrontMatter = false
+- def firstLine = true
+- mdFile.eachLine { line ->
+- if (line.matches("---")) {
+- def prev = inFrontMatter
+- inFrontMatter = firstLine
+- if (inFrontMatter != prev)
+- return false
+- }
+- if (inFrontMatter) {
+- def m = null
+- if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
+- map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
+- } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
+- map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
+- } else if (m = line =~ /^channel:\s*(\S+)/) {
+- map["channel"] = m[0][1]
+- } else if (m = line =~ /^version:\s*(\S+)/) {
+- map["version"] = m[0][1]
+- } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
+- map[ m[0][1] ] = m[0][2]
+- }
+- if (dateOnly && map["date"] != null) {
+- return false
+- }
+- } else {
+- if (dateOnly)
+- return false
+- content += line+"\n"
+- }
+- firstLine = false
+- }
+- }
+- return dateOnly ? map["date"] : [map, content]
+-}
+-
+-task hugoTemplates {
+- group "website"
+- description "Create partially populated md pages for hugo website build"
+-
+- def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
+- def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
+- def templateFiles = fileTree(dir: hugoTemplatesDir)
+- def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
+- def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
+- def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
+- def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
+-
+- doFirst {
+- // specific release template for version archive
+- def changes = ""
+- def whatsnew = null
+- def givenDate = null
+- def givenChannel = null
+- def givenVersion = null
+- if (CHANNEL == "RELEASE") {
+- def (map, content) = mdFileComponents(releaseMdFile)
+- givenDate = map.date
+- givenChannel = map.channel
+- givenVersion = map.version
+- changes = content
+- if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
+- throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
+- }
+-
+- if (whatsnewMdFile.exists())
+- whatsnew = whatsnewMdFile.text
+- }
+-
+- def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
+- def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
+-
+- def changesHugo = null
+- if (changes != null) {
+- changesHugo = '<div class="release_notes">\n\n'
+- def inSection = false
+- changes.eachLine { line ->
+- def m = null
+- if (m = line =~ /^##([^#].*)$/) {
+- if (inSection) {
+- changesHugo += "</div>\n\n"
+- }
+- def section = m[0][1].trim()
+- section = section.toLowerCase()
+- section = section.replaceAll(/ +/, "_")
+- section = section.replaceAll(/[^a-z0-9_\-]/, "")
+- changesHugo += "<div class=\"${section}\">\n\n"
+- inSection = true
+- } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
+- def comment = m[0][2].trim()
+- if (comment != "") {
+- comment = comment.replaceAll('"', """)
+- def issuekeys = []
+- comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
+- def newline = m[0][1]
+- if (comment.trim() != "")
+- newline += "{{<comment>}}${comment}{{</comment>}} "
+- newline += m[0][3].trim()
+- if (issuekeys.size() > 0)
+- newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
+- if (m[0][4] != null)
+- newline += m[0][4]
+- line = newline
+- }
+- }
+- changesHugo += line+"\n"
+- }
+- if (inSection) {
+- changesHugo += "\n</div>\n\n"
+- }
+- changesHugo += '</div>'
+- }
+-
+- templateFiles.each{ templateFile ->
+- def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
+- def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
+- def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
+-
+- def outPathName = string("${hugoBuildDir}/$newRelPathName")
+-
+- copy {
+- from templateFile
+- rename(templateFile.getName(), newFileName)
+- into outPathName
+- }
+-
+- def newFile = file("${outPathName}/${newFileName}".toString())
+- def content = newFile.text
+- newFile.text = hugoTemplateSubstitutions(content,
+- [
+- WHATSNEW: whatsnew,
+- CHANGES: changesHugo,
+- DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
+- DRAFT: givenDate == null ? "true" : "false",
+- JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
+- JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
+- ]
+- )
+- }
+-
+- }
+-
+- inputs.file(oldJvlFile)
+- inputs.dir(hugoTemplatesDir)
+- inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
+- inputs.property("CHANNEL", { CHANNEL })
+-}
+-
+-def getMdDate(File mdFile) {
+- return mdFileComponents(mdFile, true)
+-}
+-
+-def getMdSections(String content) {
+- def sections = [:]
+- def sectionContent = ""
+- def sectionName = null
+- content.eachLine { line ->
+- def m = null
+- if (m = line =~ /^##([^#].*)$/) {
+- if (sectionName != null) {
+- sections[sectionName] = sectionContent
+- sectionName = null
+- sectionContent = ""
+- }
+- sectionName = m[0][1].trim()
+- sectionName = sectionName.toLowerCase()
+- sectionName = sectionName.replaceAll(/ +/, "_")
+- sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
+- } else if (sectionName != null) {
+- sectionContent += line+"\n"
+- }
+- }
+- if (sectionContent != null) {
+- sections[sectionName] = sectionContent
+- }
+- return sections
+-}
+-
+-
task copyHelp(type: Copy) {
def inputDir = helpSourceDir
def outputDir = "${helpBuildDir}/${help_dir}"
-@@ -1242,24 +347,15 @@
+@@ -1476,7 +300,6 @@ task copyHelp(type: Copy) {
+ outputs.dir(outputDir)
+ }
+
+-
+ task releasesTemplates {
+ group "help"
+ description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
+@@ -1491,6 +314,7 @@ task releasesTemplates {
+ def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
+
+ doFirst {
++ def JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
+ def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
+ def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
+
+@@ -1505,7 +329,7 @@ task releasesTemplates {
+
+ def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
+ def releaseFilesDates = releaseFiles.collectEntries {
+- [(it): getMdDate(it)]
++ [(it): getDate("")]
+ }
+ releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
+
+@@ -1513,96 +337,13 @@ task releasesTemplates {
+ def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
+ def versionTemplate = m[0][1]
+
+- MutableDataSet options = new MutableDataSet()
+-
+- def extensions = new ArrayList<>()
+- options.set(Parser.EXTENSIONS, extensions)
+- options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
+-
+- Parser parser = Parser.builder(options).build()
+- HtmlRenderer renderer = HtmlRenderer.builder(options).build()
+-
+- def actualVersions = releaseFiles.collect { rf ->
+- def (rfMap, rfContent) = mdFileComponents(rf)
+- return rfMap.version
+- }
+ def versionsHtml = ""
+ def linkedVersions = []
+- releaseFiles.reverse().each { rFile ->
+- def (rMap, rContent) = mdFileComponents(rFile)
+-
+- def versionLink = ""
+- def partialVersion = ""
+- def firstPart = true
+- rMap.version.split("\\.").each { part ->
+- def displayPart = ( firstPart ? "" : "." ) + part
+- partialVersion += displayPart
+- if (
+- linkedVersions.contains(partialVersion)
+- || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
+- ) {
+- versionLink += displayPart
+- } else {
+- versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
+- linkedVersions += partialVersion
+- }
+- firstPart = false
+- }
+- def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
+-
+- def lm = null
+- def rContentProcessed = ""
+- rContent.eachLine { line ->
+- if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
+- line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
+- } else if (lm = line =~ /^###([^#]+.*)$/) {
+- line = "_${lm[0][1].trim()}_"
+- }
+- rContentProcessed += line + "\n"
+- }
+-
+- def rContentSections = getMdSections(rContentProcessed)
+- def rVersion = versionTemplate
+- if (rVersion != "") {
+- def rNewFeatures = rContentSections["new_features"]
+- def rIssuesResolved = rContentSections["issues_resolved"]
+- Node newFeaturesNode = parser.parse(rNewFeatures)
+- String newFeaturesHtml = renderer.render(newFeaturesNode)
+- Node issuesResolvedNode = parser.parse(rIssuesResolved)
+- String issuesResolvedHtml = renderer.render(issuesResolvedNode)
+- rVersion = hugoTemplateSubstitutions(rVersion,
+- [
+- VERSION: rMap.version,
+- VERSION_LINK: versionLink,
+- DISPLAY_DATE: displayDate,
+- NEW_FEATURES: newFeaturesHtml,
+- ISSUES_RESOLVED: issuesResolvedHtml
+- ]
+- )
+- versionsHtml += rVersion
+- }
+- }
+
+ releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
+- releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
+ releasesHtmlFile.text = releasesTemplate
+
+- if (whatsnewMdFile.exists()) {
+- def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
+- def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
+- Node whatsnewNode = parser.parse(whatsnewMd)
+- String whatsnewHtml = renderer.render(whatsnewNode)
+- whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
+- whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
+- [
+- VERSION: JALVIEW_VERSION,
+- DISPLAY_DATE: wnDisplayDate
+- ]
+- )
+- } else if (gradle.taskGraph.hasTask(":linkCheck")) {
+- whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
+- }
+-
++ whatsnewHtmlFile.text = "Debian build " + getDate("yyyy-MM-dd HH:mm:ss")
+ }
+
+ inputs.file(releasesTemplateFile)
+@@ -1613,7 +354,6 @@ task releasesTemplates {
+ outputs.file(whatsnewHtmlFile)
+ }
+
+-
+ task copyResources(type: Copy) {
+ group = "build"
+ description = "Copy (and make text substitutions in) the resources dir to the build area"
+@@ -1653,44 +393,22 @@ task copyChannelResources(type: Copy) {
+
+ def inputDir = "${channelDir}/${resource_dir}"
+ def outputDir = resourcesBuildDir
+- from(inputDir) {
+- include(channel_props)
+- filter(ReplaceTokens,
+- beginToken: '__',
+- endToken: '__',
+- tokens: [
+- 'SUFFIX': channelSuffix
+- ]
+- )
+- }
+- from(inputDir) {
+- exclude(channel_props)
+- }
++ from inputDir
+ into outputDir
+
+ inputs.dir(inputDir)
outputs.dir(outputDir)
}
- property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
- property "VERSION", JALVIEW_VERSION
- property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
+- property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
- if (getdownSetAppBaseProperty) {
- property "GETDOWNAPPBASE", getdownAppBase
- property "GETDOWNAPPDISTDIR", getdownAppDistDir
outputs.file(outputFile)
}
-@@ -1293,7 +389,6 @@
- dependsOn buildResources
+@@ -1725,123 +443,31 @@ task prepare {
dependsOn copyDocs
dependsOn copyHelp
+ dependsOn releasesTemplates
- dependsOn convertMdFiles
dependsOn buildIndices
}
-@@ -1306,12 +401,7 @@
- //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
+
+ compileJava.dependsOn prepare
+ run.dependsOn compileJava
+-compileTestJava.dependsOn compileJava
+-
++//run.dependsOn prepare
+
+
++//testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
test {
- dependsOn prepare
+- group = "Verification"
+- description = "Runs all testTaskN tasks)"
-
- if (useClover) {
- dependsOn cloverClasses
-- } else { //?
-- dependsOn compileJava //?
+- } else { //?
+- dependsOn testClasses
+- }
+-
+- // not running tests in this task
+- exclude "**/*"
+-}
+-/* testTask0 is the main test task */
+-task testTask0(type: Test) {
+- group = "Verification"
+- description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
+- useTestNG() {
+- includeGroups testng_groups.split(",")
+- excludeGroups testng_excluded_groups.split(",")
+- tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
+- preserveOrder true
+- useDefaultListeners=true
+- }
+-}
+-
+-/* separated tests */
+-task testTask1(type: Test) {
+- group = "Verification"
+- description = "Tests that need to be isolated from the main test run"
+- useTestNG() {
+- includeGroups name
+- excludeGroups testng_excluded_groups.split(",")
+- preserveOrder true
+- useDefaultListeners=true
- }
+-}
++ dependsOn prepare
+ dependsOn compileJava //?
+-/* insert more testTaskNs here -- change N to next digit or other string */
+-/*
+-task testTaskN(type: Test) {
+- group = "Verification"
+- description = "Tests that need to be isolated from the main test run"
useTestNG() {
- includeGroups testng_groups
-@@ -1323,6 +413,7 @@
+- includeGroups name
+- excludeGroups testng_excluded_groups.split(",")
++ includeGroups testng_groups
++ excludeGroups testng_excluded_groups
+ preserveOrder true
+ useDefaultListeners=true
+ }
+-}
+-*/
+-
+-/*
+- * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
+- * to summarise test results from all Test tasks
+- */
+-/* START of test tasks results summary */
+-import groovy.time.TimeCategory
+-import org.gradle.api.tasks.testing.logging.TestExceptionFormat
+-import org.gradle.api.tasks.testing.logging.TestLogEvent
+-rootProject.ext.testsResults = [] // Container for tests summaries
+-
+-tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
+-
+- // from original test task
+- if (useClover) {
+- dependsOn cloverClasses
+- } else { //?
+- dependsOn testClasses //?
+- }
+-
+- // run main tests first
+- if (!testTask.name.equals("testTask0"))
+- testTask.mustRunAfter "testTask0"
+-
+- testTask.testLogging { logging ->
+- events TestLogEvent.FAILED
+-// TestLogEvent.SKIPPED,
+-// TestLogEvent.STANDARD_OUT,
+-// TestLogEvent.STANDARD_ERROR
+-
+- exceptionFormat TestExceptionFormat.FULL
+- showExceptions true
+- showCauses true
+- showStackTraces true
+-
+- info.events = [ TestLogEvent.FAILED ]
+- }
+-
+-
+-
+- ignoreFailures = true // Always try to run all tests for all modules
+-
+- afterSuite { desc, result ->
+- if (desc.parent)
+- return // Only summarize results for whole modules
+-
+- def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
+-
+- rootProject.ext.testsResults.add(resultsInfo)
+- }
+
+- // from original test task
maxHeapSize = "1024m"
workingDir = jalviewDir
def testLaf = project.findProperty("test_laf")
if (testLaf != null) {
println("Setting Test LaF to '${testLaf}'")
-@@ -1338,9 +429,6 @@
+@@ -1857,143 +483,8 @@ tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { te
jvmArgs += additional_compiler_args
doFirst {
+- // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
+- // testTasks that include the tests, and exclude all from the others.
+- // get --test argument
+- filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
+- // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
+- // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
+-
+-
- if (useClover) {
- println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
- }
+- }
+-
+-
+- /* don't fail on no matching tests (so --tests will run across all testTasks) */
+- testTask.filter.setFailOnNoMatchingTests(false)
+-
+- /* ensure the "test" task dependsOn all the testTasks */
+- test.dependsOn testTask
+-}
+-
+-gradle.buildFinished {
+- def allResults = rootProject.ext.testsResults
+-
+- if (!allResults.isEmpty()) {
+- printResults allResults
+- allResults.each {r ->
+- if (r[2].resultType == TestResult.ResultType.FAILURE)
+- throw new GradleException("Failed tests!")
+- }
+- }
+-}
+-
+-private static String colString(styler, col, colour, text) {
+- return col?"${styler[colour](text)}":text
+-}
+-
+-private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
+- def colour = 'black'
+- def text = rt
+- def nocol = false
+- if (rc == 0) {
+- text = "-----"
+- nocol = true
+- } else {
+- switch(rt) {
+- case TestResult.ResultType.SUCCESS:
+- colour = 'green'
+- break;
+- case TestResult.ResultType.FAILURE:
+- colour = 'red'
+- break;
+- default:
+- nocol = true
+- break;
+- }
}
+- StringBuilder sb = new StringBuilder()
+- sb.append("${pn}")
+- if (tn != null)
+- sb.append(":${tn}")
+- sb.append(" results: ")
+- sb.append(colString(s, col && !nocol, colour, text))
+- sb.append(" (")
+- sb.append("${rc} tests, ")
+- sb.append(colString(s, col && rs > 0, 'green', rs))
+- sb.append(" successes, ")
+- sb.append(colString(s, col && rf > 0, 'red', rf))
+- sb.append(" failures, ")
+- sb.append("${rsk} skipped) in ${t}")
+- return sb.toString()
+-}
+-
+-private static void printResults(allResults) {
+-
+- // styler from https://stackoverflow.com/a/56139852
+- def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
+-
+- def maxLength = 0
+- def failedTests = false
+- def summaryLines = []
+- def totalcount = 0
+- def totalsuccess = 0
+- def totalfail = 0
+- def totalskip = 0
+- def totaltime = TimeCategory.getSeconds(0)
+- // sort on project name then task name
+- allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
+- def projectName = it[0]
+- def taskName = it[1]
+- def result = it[2]
+- def time = it[3]
+- def report = it[4]
+- def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
+- def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
+- def reportLine = "Report file: ${report}"
+- def ls = summaryPlain.length()
+- def lr = reportLine.length()
+- def m = [ls, lr].max()
+- if (m > maxLength)
+- maxLength = m
+- def info = [ls, summaryCol, reportLine]
+- summaryLines.add(info)
+- failedTests |= result.resultType == TestResult.ResultType.FAILURE
+- totalcount += result.testCount
+- totalsuccess += result.successfulTestCount
+- totalfail += result.failedTestCount
+- totalskip += result.skippedTestCount
+- totaltime += time
+- }
+- def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
+- def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
+- def tls = totalSummaryPlain.length()
+- if (tls > maxLength)
+- maxLength = tls
+- def info = [tls, totalSummaryCol, null]
+- summaryLines.add(info)
+-
+- def allSummaries = []
+- for(sInfo : summaryLines) {
+- def ls = sInfo[0]
+- def summary = sInfo[1]
+- def report = sInfo[2]
+-
+- StringBuilder sb = new StringBuilder()
+- sb.append("│" + summary + " " * (maxLength - ls) + "│")
+- if (report != null) {
+- sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
+- }
+- allSummaries += sb.toString()
+- }
+-
+- println "┌${"${"─" * maxLength}"}┐"
+- println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
+- println "└${"${"─" * maxLength}"}┘"
}
+-/* END of test tasks results summary */
-@@ -1420,1752 +508,7 @@
+
+ task compileLinkCheck(type: JavaCompile) {
+@@ -2052,7 +543,7 @@ jar {
+ manifest {
+ attributes "Main-Class": main_class,
+ "Permissions": "all-permissions",
+- "Application-Name": applicationName,
++ "Application-Name": install4jApplicationName,
+ "Codebase": application_codebase,
+ "Implementation-Version": JALVIEW_VERSION
+ }
+@@ -2060,8 +551,6 @@ jar {
+ def outputDir = "${jalviewDir}/${package_dir}"
+ destinationDirectory = file(outputDir)
+ archiveFileName = rootProject.name+".jar"
+- duplicatesStrategy "EXCLUDE"
+-
+
+ exclude "cache*/**"
+ exclude "*.jar"
+@@ -2073,2137 +562,7 @@ jar {
sourceSets.main.resources.srcDirs.each{ dir ->
inputs.dir(dir)
}
- }
- manifest {
- attributes "Implementation-Version": JALVIEW_VERSION,
-- "Application-Name": install4jApplicationName
+- "Application-Name": applicationName
- }
+-
+- duplicatesStrategy "INCLUDE"
+-
- mainClassName = shadow_jar_main_class
- mergeServiceFiles()
- classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
- minimize()
-}
-
+-task getdownImagesCopy() {
+- inputs.dir getdownImagesDir
+- outputs.dir getdownImagesBuildDir
+-
+- doFirst {
+- copy {
+- from(getdownImagesDir) {
+- include("*getdown*.png")
+- }
+- into getdownImagesBuildDir
+- }
+- }
+-}
+-
+-task getdownImagesProcess() {
+- dependsOn getdownImagesCopy
+-
+- doFirst {
+- if (backgroundImageText) {
+- if (convertBinary == null) {
+- throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
+- }
+- if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
+- throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
+- }
+- fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
+- exec {
+- executable convertBinary
+- args = [
+- file.getPath(),
+- '-font', getdown_background_image_text_font,
+- '-fill', getdown_background_image_text_colour,
+- '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
+- '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
+- '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
+- file.getPath()
+- ]
+- }
+- }
+- }
+- }
+-}
+-
+-task getdownImages() {
+- dependsOn getdownImagesProcess
+-}
-
-task getdownWebsite() {
- group = "distribution"
- description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
+-
+- dependsOn getdownImages
- if (buildDist) {
- dependsOn makeDist
- }
-
- def getdownWebsiteResourceFilenames = []
-- def getdownTextString = ""
- def getdownResourceDir = getdownResourceDir
- def getdownResourceFilenames = []
-
- doFirst {
- // clean the getdown website and files dir before creating getdown folders
-- delete getdownWebsiteDir
+- delete getdownAppBaseDir
- delete getdownFilesDir
-
- copy {
- }
- getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
-
-- // set some getdown_txt_ properties then go through all properties looking for getdown_txt_...
+- copy {
+- from channelPropsFile
+- filter(ReplaceTokens,
+- beginToken: '__',
+- endToken: '__',
+- tokens: [
+- 'SUFFIX': channelSuffix
+- ]
+- )
+- into getdownAppBaseDir
+- }
+- getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
+-
+- // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
- def props = project.properties.sort { it.key }
- if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
- props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
- if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
- props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
- }
-- if (getdownImagesDir != null && file(getdownImagesDir).exists()) {
-- props.put("getdown_txt_ui.background_image", "${getdownImagesDir}/${getdown_background_image}")
-- props.put("getdown_txt_ui.instant_background_image", "${getdownImagesDir}/${getdown_instant_background_image}")
-- props.put("getdown_txt_ui.error_background", "${getdownImagesDir}/${getdown_error_background}")
-- props.put("getdown_txt_ui.progress_image", "${getdownImagesDir}/${getdown_progress_image}")
+- if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
+- props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
+- props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
+- props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
+- props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
- props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
- props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
- }
-
- props.put("getdown_txt_title", jalview_name)
-- props.put("getdown_txt_ui.name", install4jApplicationName)
+- props.put("getdown_txt_ui.name", applicationName)
-
- // start with appbase
-- getdownTextString += "appbase = ${getdownAppBase}\n"
+- getdownTextLines += "appbase = ${getdownAppBase}"
- props.each{ prop, val ->
- if (prop.startsWith("getdown_txt_") && val != null) {
- if (prop.startsWith("getdown_txt_multi_")) {
- def key = prop.substring(18)
- val.split(",").each{ v ->
-- def line = "${key} = ${v}\n"
-- getdownTextString += line
+- def line = "${key} = ${v}"
+- getdownTextLines += line
- }
- } else {
- // file values rationalised
- }
- }
- if (! prop.startsWith("getdown_txt_resource")) {
-- def line = prop.substring(12) + " = ${val}\n"
-- getdownTextString += line
+- def line = prop.substring(12) + " = ${val}"
+- getdownTextLines += line
- }
- }
- }
- }
-
- getdownWebsiteResourceFilenames.each{ filename ->
-- getdownTextString += "resource = ${filename}\n"
+- getdownTextLines += "resource = ${filename}"
- }
- getdownResourceFilenames.each{ filename ->
- copy {
- if (s.exists()) {
- copy {
- from s
-- into "${getdownWebsiteDir}/${getdown_wrapper_script_dir}"
+- into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
- }
-- getdownTextString += "resource = ${getdown_wrapper_script_dir}/${script}\n"
+- getdownTextLines += "resource = ${getdown_wrapper_script_dir}/${script}"
- }
- }
-
- codeFiles += f
- }
- }
-- codeFiles.sort().each{f ->
+- def jalviewJar = jar.archiveFileName.getOrNull()
+- // put jalview.jar first for CLASSPATH and .properties files reasons
+- codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
- def name = f.getName()
-- def line = "code = ${getdownAppDistDir}/${name}\n"
-- getdownTextString += line
+- def line = "code = ${getdownAppDistDir}/${name}"
+- getdownTextLines += line
- copy {
- from f.getPath()
- into getdownAppDir
- def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
- j11libFiles.sort().each{f ->
- def name = f.getName()
-- def line = "code = ${getdown_j11lib_dir}/${name}\n"
-- getdownTextString += line
+- def line = "code = ${getdown_j11lib_dir}/${name}"
+- getdownTextLines += line
- copy {
- from f.getPath()
- into getdownJ11libDir
- */
-
- // getdown-launcher.jar should not be in main application class path so the main application can move it when updated. Listed as a resource so it gets updated.
-- //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
-- getdownTextString += "resource = ${getdown_launcher_new}\n"
-- getdownTextString += "class = ${main_class}\n"
+- //getdownTextLines += "class = " + file(getdownLauncher).getName()
+- getdownTextLines += "resource = ${getdown_launcher_new}"
+- getdownTextLines += "class = ${main_class}"
- // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
- if (getdownSetAppBaseProperty) {
-- getdownTextString += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}\n"
-- getdownTextString += "jvmarg = -Dgetdownappbase=${getdownAppBase}\n"
+- getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
+- getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
- }
-
-- def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
-- getdown_txt.write(getdownTextString)
+- def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
+- getdownTxt.write(getdownTextLines.join("\n"))
-
-- def getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
-- def launchJvl = file("${getdownWebsiteDir}/${getdownLaunchJvl}")
+- getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
+- def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
- launchJvl.write("appbase=${getdownAppBase}")
-
- // files going into the getdown website dir: getdown-launcher.jar
- copy {
- from getdownLauncher
- rename(file(getdownLauncher).getName(), getdown_launcher_new)
-- into getdownWebsiteDir
+- into getdownAppBaseDir
- }
-
- // files going into the getdown website dir: getdown-launcher(-local).jar
- if (file(getdownLauncher).getName() != getdown_launcher) {
- rename(file(getdownLauncher).getName(), getdown_launcher)
- }
-- into getdownWebsiteDir
+- into getdownAppBaseDir
- }
-
- // files going into the getdown website dir: ./install dir and files
- if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
- copy {
-- from getdown_txt
+- from getdownTxt
- from getdownLauncher
- from "${getdownAppDir}/${getdown_build_properties}"
- if (file(getdownLauncher).getName() != getdown_launcher) {
-
- // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
- copy {
-- from getdown_txt
+- from getdownTxt
- from launchJvl
- from getdownLauncher
-- from "${getdownWebsiteDir}/${getdown_build_properties}"
+- from "${getdownAppBaseDir}/${getdown_build_properties}"
+- from "${getdownAppBaseDir}/${channel_props}"
- if (file(getdownLauncher).getName() != getdown_launcher) {
- rename(file(getdownLauncher).getName(), getdown_launcher)
- }
- into getdownFilesDir
- }
-
-- // and ./resources (not all downloaded by getdown)
+- // and ./resource (not all downloaded by getdown)
- copy {
- from getdownResourceDir
- into "${getdownFilesDir}/${getdown_resource_dir}"
- if (buildDist) {
- inputs.dir("${jalviewDir}/${package_dir}")
- }
-- outputs.dir(getdownWebsiteDir)
+- outputs.dir(getdownAppBaseDir)
- outputs.dir(getdownFilesDir)
-}
-
- classpath = files(getdownLauncher)
- }
- main = "com.threerings.getdown.tools.Digester"
-- args getdownWebsiteDir
-- inputs.dir(getdownWebsiteDir)
-- outputs.file("${getdownWebsiteDir}/digest2.txt")
+- args getdownAppBaseDir
+- inputs.dir(getdownAppBaseDir)
+- outputs.file("${getdownAppBaseDir}/digest2.txt")
-}
-
-
- dependsOn getdownDigest
- doLast {
- if (reportRsyncCommand) {
-- def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
+- def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
- def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
- println "LIKELY RSYNC COMMAND:"
- println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
- }
- }
-}
+
+-
+-task getdownArchiveBuild() {
+- group = "distribution"
+- description = "Put files in the archive dir to go on the website"
+-
+- dependsOn getdownWebsite
+-
+- def v = "v${JALVIEW_VERSION_UNDERSCORES}"
+- def vDir = "${getdownArchiveDir}/${v}"
+- getdownFullArchiveDir = "${vDir}/getdown"
+- getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
+-
+- def vAltDir = "alt_${v}"
+- def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
+-
+- doFirst {
+- // cleanup old "old" dir
+- delete getdownArchiveDir
+-
+- def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
+- getdownArchiveTxt.getParentFile().mkdirs()
+- def getdownArchiveTextLines = []
+- def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
+-
+- // the libdir
+- copy {
+- from "${getdownAppBaseDir}/${getdownAppDistDir}"
+- into "${getdownFullArchiveDir}/${vAltDir}"
+- }
+-
+- getdownTextLines.each { line ->
+- line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
+- line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
+- line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
+- line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
+- line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
+- line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
+- // remove the existing resource = resource/ or bin/ lines
+- if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
+- getdownArchiveTextLines += line
+- }
+- }
+-
+- // the resource dir -- add these files as resource lines in getdown.txt
+- copy {
+- from "${archiveImagesDir}"
+- into "${getdownFullArchiveDir}/${getdown_resource_dir}"
+- eachFile { file ->
+- getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
+- }
+- }
+-
+- getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
+-
+- def vLaunchJvl = file(getdownVersionLaunchJvl)
+- vLaunchJvl.getParentFile().mkdirs()
+- vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
+- def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
+- def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
+- // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
+- //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
+- java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
+-
+- // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
+- copy {
+- from getdownLauncher
+- from "${getdownAppBaseDir}/${getdownLaunchJvl}"
+- from "${getdownAppBaseDir}/${getdown_launcher_new}"
+- from "${getdownAppBaseDir}/${channel_props}"
+- if (file(getdownLauncher).getName() != getdown_launcher) {
+- rename(file(getdownLauncher).getName(), getdown_launcher)
+- }
+- into getdownFullArchiveDir
+- }
+-
+- }
+-}
+-
+-task getdownArchiveDigest(type: JavaExec) {
+- group = "distribution"
+- description = "Digest the getdown archive folder"
+-
+- dependsOn getdownArchiveBuild
+-
+- doFirst {
+- classpath = files(getdownLauncher)
+- args getdownFullArchiveDir
+- }
+- main = "com.threerings.getdown.tools.Digester"
+- inputs.dir(getdownFullArchiveDir)
+- outputs.file("${getdownFullArchiveDir}/digest2.txt")
+-}
-
+-task getdownArchive() {
+- group = "distribution"
+- description = "Build the website archive dir with getdown digest"
+-
+- dependsOn getdownArchiveBuild
+- dependsOn getdownArchiveDigest
+-}
-
-tasks.withType(JavaCompile) {
- options.encoding = 'UTF-8'
-
-clean {
- doFirst {
-- delete getdownWebsiteDir
+- delete getdownAppBaseDir
- delete getdownFilesDir
+- delete getdownArchiveDir
- }
-}
-
- }
- }
-
+- // disable install screen for OSX dmg (for 2.11.2.0)
+- install4jConfigXml.'**'.macosArchive.each { macosArchive ->
+- macosArchive.attributes().remove('executeSetupApp')
+- macosArchive.attributes().remove('setupAppId')
+- }
+-
- // turn off checksum creation for LOCAL channel
- def e = install4jConfigXml.application[0]
-- if (CHANNEL == "LOCAL") {
-- e.'@createChecksums' = "false"
-- } else {
-- e.'@createChecksums' = "true"
-- }
+- e.'@createChecksums' = string(install4jCheckSums)
-
- // put file association actions where placeholder action is
- def install4jFileAssociationsText = install4jFileAssociationsFile.text
- }
-}
-
+-task cleanInstallersDataFiles {
+- def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
+- def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
+- def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
+- doFirst {
+- delete installersOutputTxt
+- delete installersSha256
+- delete hugoDataJsonFile
+- }
+-}
+-
+-task install4jDMGBackgroundImageCopy {
+- inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
+- outputs.dir "${install4jDMGBackgroundImageBuildDir}"
+- doFirst {
+- copy {
+- from(install4jDMGBackgroundImageDir) {
+- include(install4jDMGBackgroundImageFile)
+- }
+- into install4jDMGBackgroundImageBuildDir
+- }
+- }
+-}
+-
+-task install4jDMGBackgroundImageProcess {
+- dependsOn install4jDMGBackgroundImageCopy
+-
+- doFirst {
+- if (backgroundImageText) {
+- if (convertBinary == null) {
+- throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
+- }
+- if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
+- throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
+- }
+- fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
+- exec {
+- executable convertBinary
+- args = [
+- file.getPath(),
+- '-font', install4j_background_image_text_font,
+- '-fill', install4j_background_image_text_colour,
+- '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
+- '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
+- '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
+- file.getPath()
+- ]
+- }
+- }
+- }
+- }
+-}
+-
+-task install4jDMGBackgroundImage {
+- dependsOn install4jDMGBackgroundImageProcess
+-}
-
--task installers(type: com.install4j.gradle.Install4jTask) {
+-task installerFiles(type: com.install4j.gradle.Install4jTask) {
- group = "distribution"
- description = "Create the install4j installers"
- dependsOn getdown
- dependsOn copyInstall4jTemplate
+- dependsOn cleanInstallersDataFiles
+- dependsOn install4jDMGBackgroundImage
-
- projectFile = install4jConfFile
-
- filesMd5 = filesMd5.substring(0,8)
- }
- def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
-- // make install4jBuildDir relative to jalviewDir
-- def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
-
- variables = [
- 'JALVIEW_NAME': jalview_name,
-- 'JALVIEW_APPLICATION_NAME': install4jApplicationName,
+- 'JALVIEW_APPLICATION_NAME': applicationName,
- 'JALVIEW_DIR': "../..",
- 'OSX_KEYSTORE': OSX_KEYSTORE,
- 'OSX_APPLEID': OSX_APPLEID,
- 'JAVA_VERSION': JAVA_VERSION,
- 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
- 'VERSION': JALVIEW_VERSION,
-- 'MACOS_JAVA_VM_DIR': macosJavaVMDir,
-- 'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
-- 'LINUX_JAVA_VM_DIR': linuxJavaVMDir,
-- 'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
-- 'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
-- 'LINUX_JAVA_VM_TGZ': linuxJavaVMTgz,
- 'COPYRIGHT_MESSAGE': install4j_copyright_message,
- 'BUNDLE_ID': install4jBundleId,
- 'INTERNAL_ID': install4jInternalId,
- 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
- 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
-- 'MACOS_DMG_BG_IMAGE': install4jDMGBackgroundImage,
+- 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
- 'WRAPPER_LINK': getdownWrapperLink,
- 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
- 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
+- 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
- 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
- 'INSTALLER_NAME': install4jInstallerName,
- 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
-- 'GETDOWN_WEBSITE_DIR': getdown_website_dir,
+- 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
- 'GETDOWN_FILES_DIR': getdown_files_dir,
- 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
- 'GETDOWN_DIST_DIR': getdownAppDistDir,
- 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
- 'PNG_ICON_FILE': install4jPngIconFile,
- 'BACKGROUND': install4jBackground,
+- ]
-
+- def varNameMap = [
+- 'mac': 'MACOS',
+- 'windows': 'WINDOWS',
+- 'linux': 'LINUX'
- ]
+-
+- // these are the bundled OS/architecture VMs needed by install4j
+- def osArch = [
+- [ "mac", "x64" ],
+- [ "mac", "aarch64" ],
+- [ "windows", "x64" ],
+- [ "linux", "x64" ],
+- [ "linux", "aarch64" ]
+- ]
+- osArch.forEach { os, arch ->
+- variables[ sprintf("%s_%s_JAVA_VM_DIR", varNameMap[os], arch.toUpperCase(Locale.ROOT)) ] = sprintf("%s/jre-%s-%s-%s/jre", jreInstallsDir, JAVA_INTEGER_VERSION, os, arch)
+- // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
+- // otherwise running `gradle installers` generates a non-useful error:
+- // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
+- variables[ sprintf("%s_%s_JAVA_VM_TGZ", varNameMap[os], arch.toUpperCase(Locale.ROOT)) ] = sprintf("%s/tgz/jre_%s_%s_%s.tar.gz", jreInstallsDir, JAVA_INTEGER_VERSION, os, arch)
+- }
-
- //println("INSTALL4J VARIABLES:")
- //variables.each{k,v->println("${k}=${v}")}
- }
- //verbose=true
-
-- inputs.dir(getdownWebsiteDir)
+- inputs.dir(getdownAppBaseDir)
- inputs.file(install4jConfFile)
- inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
-- inputs.dir(macosJavaVMDir)
-- inputs.dir(windowsJavaVMDir)
- outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
-}
-
+-def getDataHash(File myFile) {
+- HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
+- return myFile.exists()
+- ? [
+- "file" : myFile.getName(),
+- "filesize" : myFile.length(),
+- "sha256" : hash.toString()
+- ]
+- : null
+-}
+-
+-def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
+- def hash = [
+- "channel" : getdownChannelName,
+- "date" : getDate("yyyy-MM-dd HH:mm:ss"),
+- "git-commit" : "${gitHash} [${gitBranch}]",
+- "version" : JALVIEW_VERSION
+- ]
+- // install4j installer files
+- if (installersOutputTxt.exists()) {
+- def idHash = [:]
+- installersOutputTxt.readLines().each { def line ->
+- if (line.startsWith("#")) {
+- return;
+- }
+- line.replaceAll("\n","")
+- def vals = line.split("\t")
+- def filename = vals[3]
+- def filesize = file(filename).length()
+- filename = filename.replaceAll(/^.*\//, "")
+- hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
+- idHash."${filename}" = vals[0]
+- }
+- if (install4jCheckSums && installersSha256.exists()) {
+- installersSha256.readLines().each { def line ->
+- if (line.startsWith("#")) {
+- return;
+- }
+- line.replaceAll("\n","")
+- def vals = line.split(/\s+\*?/)
+- def filename = vals[1]
+- def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
+- }
+- }
+- }
+-
+- [
+- "JAR": shadowJar.archiveFile, // executable JAR
+- "JVL": getdownVersionLaunchJvl, // version JVL
+- "SOURCE": sourceDist.archiveFile // source TGZ
+- ].each { key, value ->
+- def file = file(value)
+- if (file.exists()) {
+- def fileHash = getDataHash(file)
+- if (fileHash != null) {
+- hash."${key}" = fileHash;
+- }
+- }
+- }
+- return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
+-}
+-
+-task staticMakeInstallersJsonFile {
+- doFirst {
+- def output = findProperty("i4j_output")
+- def sha256 = findProperty("i4j_sha256")
+- def json = findProperty("i4j_json")
+- if (output == null || sha256 == null || json == null) {
+- throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
+- }
+- writeDataJsonFile(file(output), file(sha256), file(json))
+- }
+-}
+-
+-task installers {
+- dependsOn installerFiles
+-}
+-
-
-spotless {
- java {
- }
-}
-
+-task createSourceReleaseProperties(type: WriteProperties) {
+- group = "distribution"
+- description = "Create the source RELEASE properties file"
+-
+- def sourceTarBuildDir = "${buildDir}/sourceTar"
+- def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
+- outputFile (sourceReleasePropertiesFile)
+-
+- doFirst {
+- releaseProps.each{ key, val -> property key, val }
+- property "git.branch", gitBranch
+- property "git.hash", gitHash
+- }
+-
+- outputs.file(outputFile)
+-}
-
-task sourceDist(type: Tar) {
- group "distribution"
-
- dependsOn createBuildProperties
- dependsOn convertMdFiles
+- dependsOn eclipseAllPreferences
+- dependsOn createSourceReleaseProperties
+-
-
-- def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
-- def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
+- def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
- archiveFileName = outputFileName
-
- compression Compression.GZIP
- "*locales/**",
- "utils/InstallAnywhere",
- "**/*.log",
+- "RELEASE",
- ]
- def PROCESS_FILES=[
- "AUTHORS",
- "FEATURETODO",
- "LICENSE",
- "**/README",
-- "RELEASE",
- "THIRDPARTYLIBS",
- "TESTNG",
- "build.gradle",
- "**/*.sh",
- ]
- def INCLUDE_FILES=[
-- ".settings/org.eclipse.jdt.core.jalview.prefs",
+- ".classpath",
+- ".settings/org.eclipse.buildship.core.prefs",
+- ".settings/org.eclipse.jdt.core.prefs"
- ]
-
- from(jalviewDir) {
- exclude ("utils/InstallAnywhere")
-
- exclude (getdown_files_dir)
-- exclude (getdown_website_dir)
+- // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
+- //exclude (getdown_website_dir)
+- //exclude (getdown_archive_dir)
-
- // exluding these as not using jars as modules yet
- exclude ("${j11modDir}/**/*.jar")
- })
- }
-
+- def sourceTarBuildDir = "${buildDir}/sourceTar"
+- from(sourceTarBuildDir) {
+- // this includes the appended RELEASE properties file
+- }
-}
-
+-task dataInstallersJson {
+- group "website"
+- description "Create the installers-VERSION.json data file for installer files created"
+-
+- mustRunAfter installers
+- mustRunAfter shadowJar
+- mustRunAfter sourceDist
+- mustRunAfter getdownArchive
+-
+- def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
+- def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
+-
+- if (installersOutputTxt.exists()) {
+- inputs.file(installersOutputTxt)
+- }
+- if (install4jCheckSums && installersSha256.exists()) {
+- inputs.file(installersSha256)
+- }
+- [
+- shadowJar.archiveFile, // executable JAR
+- getdownVersionLaunchJvl, // version JVL
+- sourceDist.archiveFile // source TGZ
+- ].each { fileName ->
+- if (file(fileName).exists()) {
+- inputs.file(fileName)
+- }
+- }
+-
+- outputs.file(hugoDataJsonFile)
+-
+- doFirst {
+- writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
+- }
+-}
-
-task helppages {
+- group "help"
+- description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
+-
- dependsOn copyHelp
- dependsOn pubhtmlhelp
-
- preserve {
- include "**"
- }
+-
+- // should this be exclude really ?
+- duplicatesStrategy "INCLUDE"
+-
- outputs.files outputFiles
- inputs.files inputFiles
-}
- println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
- }
- }
-
+-
- //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
- def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
- executable(eclipseBinary)
- new org.apache.tools.ant.util.TeeOutputStream(
- logErrFOS,
- stderr),
-- errorOutput)
+- System.err)
- } else {
- standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
- logOutFOS,
-task eclipseAutoBuildTask {
- //dependsOn jalviewjsIDE_checkJ2sPlugin
- //dependsOn jalviewjsIDE_PrepareSite
-+ outputs.file("${outputDir}/${archiveFileName}")
- }
-
+-}
+-
-
-task jalviewjs {
- group "JalviewJS"
- description "Build the site"
- dependsOn jalviewjsBuildSite
--}
++ outputs.file("${outputDir}/${archiveFileName}")
+ }
+
outputs.dir(outputDir)
}
+task releasesTemplates {
+ group "help"
+ description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
+
+ dependsOn copyHelp
+
+ def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
+ def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
+ def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
+ def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
+ def releasesMdDir = "${jalviewDir}/${releases_dir}"
+ def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
+
+ doFirst {
+ def JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
+ def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
+ def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
+
+ if (CHANNEL == "RELEASE") {
+ if (!releaseMdFile.exists()) {
+ throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
+ }
+ if (!whatsnewMdFile.exists()) {
+ throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
+ }
+ }
+
+ def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
+ def releaseFilesDates = releaseFiles.collectEntries {
+ [(it): getDate("")]
+ }
+ releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
+
+ def releasesTemplate = releasesTemplateFile.text
+ def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
+ def versionTemplate = m[0][1]
+
+ def versionsHtml = ""
+ def linkedVersions = []
+
+ releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
+ releasesHtmlFile.text = releasesTemplate
+
+ whatsnewHtmlFile.text = "Debian build " + getDate("yyyy-MM-dd HH:mm:ss")
+ }
+
+ inputs.file(releasesTemplateFile)
+ inputs.file(whatsnewTemplateFile)
+ inputs.dir(releasesMdDir)
+ inputs.dir(whatsnewMdDir)
+ outputs.file(releasesHtmlFile)
+ outputs.file(whatsnewHtmlFile)
+}
task copyResources(type: Copy) {
group = "build"
dependsOn buildResources
dependsOn copyDocs
dependsOn copyHelp
+ dependsOn releasesTemplates
dependsOn buildIndices
}
def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
classpath = files("${jalviewDir}/${utils_dir}")
main = "HelpLinksChecker"
- workingDir = jalviewDir
+ workingDir = "${helpBuildDir}"
args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
<?xml version="1.0" encoding="UTF-8"?>
-<install4j version="10.0.5" transformSequenceNumber="10">
+<install4j version="10.0.6" transformSequenceNumber="10">
<directoryPresets config="bin/Jalview" />
<application name="${compiler:JALVIEW_APPLICATION_NAME}" applicationId="${compiler:WINDOWS_APPLICATION_ID}" mediaDir="${compiler:BUILD_DIR}" lzmaCompression="true" shortName="${compiler:INTERNAL_ID}" publisher="University of Dundee" publisherWeb="https://www.jalview.org/" version="${compiler:JALVIEW_VERSION}" allPathsRelative="true" macVolumeId="5aac4968c304f65" javaMinVersion="${compiler:JAVA_MIN_VERSION}" javaMaxVersion="${compiler:JAVA_MAX_VERSION}" allowBetaVM="true" jdkMode="jdk" jdkName="JDK 11.0">
<searchSequence>
</exclude>
<jreBundle jreBundleSource="preCreated" includedJre="${compiler:WINDOWS_X64_JAVA_VM_TGZ}" manualJreEntry="true" />
</windows>
- <macosArchive name="macOS x64 Disk Image" id="878" customizedId="MACOS-X64-DMG" mediaFileName="${compiler:APPLICATION_FOLDER}-${compiler:JALVIEW_VERSION}-${compiler:sys.platform}-x64-java_${compiler:JAVA_INTEGER_VERSION}" volumeName="${compiler:INSTALLER_NAME}" launcherId="737" setupAppId="2746">
+ <macosArchive name="macOS x64 (intel) Disk Image" id="878" customizedId="MACOS-X64-DMG" mediaFileName="${compiler:APPLICATION_FOLDER}-${compiler:JALVIEW_VERSION}-${compiler:sys.platform}-x64-java_${compiler:JAVA_INTEGER_VERSION}" volumeName="${compiler:INSTALLER_NAME}" launcherId="737" setupAppId="2746">
<exclude>
<entry defaultFileset="true" />
<entry filesetId="2803" />
<symlink name="${compiler:JALVIEW_APPLICATION_NAME}.app/Contents/Resources/app/jre/Contents/Home/bin/${compiler:JALVIEW_NAME}" target="java" />
</topLevelFiles>
</macosArchive>
- <macosArchive name="macOS aarch64 Disk Image" id="2796" customizedId="MACOS-AARCH64-DMG" mediaFileName="${compiler:APPLICATION_FOLDER}-${compiler:JALVIEW_VERSION}-${compiler:sys.platform}-aarch64-java_${compiler:JAVA_INTEGER_VERSION}" volumeName="${compiler:INSTALLER_NAME}" architecture="aarch64" launcherId="737" setupAppId="2746">
+ <macosArchive name="macOS aarch64 (Apple Silicon) Disk Image" id="2796" customizedId="MACOS-AARCH64-DMG" mediaFileName="${compiler:APPLICATION_FOLDER}-${compiler:JALVIEW_VERSION}-${compiler:sys.platform}-aarch64-java_${compiler:JAVA_INTEGER_VERSION}" volumeName="${compiler:INSTALLER_NAME}" architecture="aarch64" launcherId="737" setupAppId="2746">
<exclude>
<entry defaultFileset="true" />
<entry filesetId="2801" />
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>SwingJS test Jalview</title><meta charset="utf-8" />
+<script src="swingjs/swingjs2.js"></script>
+<script>
+if (!self.SwingJS)alert('swingjs2.js was not found. It needs to be in swingjs folder in the same directory as ' + document.location.href)
+Info = {
+ code: null,
+ main: "jalview.bin.Jalview",
+ core: "NONE",
+ width: 850,
+ height: 550,
+ readyFunction: null,
+ serverURL: 'https://chemapps.stolaf.edu/jmol/jsmol/php/jsmol.php',
+ j2sPath: 'swingjs/j2s',
+ console: window.console,
+ allowjavascript: true
+}
+</script>
+</head>
+<body>
+<script>
+// we define console.err because swingjs2.js calls it instead of console.error
+window.console.err = function() {
+ this.error.apply(this,arguments);
+}
+SwingJS.getApplet('testApplet', Info)
+getClassList = function(){J2S._saveFile('_j2sclasslist.txt', Clazz.ClassFilesLoaded.sort().join('\n'))}
+</script>
+<div style="position:absolute;left:900px;top:30px;width:600px;height:300px;">
+<div id="sysoutdiv" contentEditable="true" style="border:1px solid green;width:100%;height:95%;overflow:auto"></div>
+This is System.out. <a href="javascript:testApplet._clearConsole()">clear it</a> <br>Add ?j2snocore to URL to see full class list; ?j2sdebug to use uncompressed j2s/core files <br><a href="javascript:getClassList()">get _j2sClassList.txt</a>
+</div>
+</body>
+</html>