Merge branch 'releases/Release_2_11_1_Branch' into merge/JAL-3628+JAL-3608+JAL-3609... bug/JAL-3702_Drag_and_drop_miscalculation_in_linux_HiDPI
authorBen Soares <b.soares@dundee.ac.uk>
Thu, 30 Jul 2020 13:08:06 +0000 (14:08 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Thu, 30 Jul 2020 13:08:06 +0000 (14:08 +0100)
35 files changed:
build.gradle
getdown/lib/FJVL_VERSION
getdown/lib/JVL_VERSION
getdown/lib/getdown-core.jar
getdown/lib/getdown-launcher-local.jar
getdown/lib/getdown-launcher.jar
getdown/src/getdown/ant/pom.xml
getdown/src/getdown/core/pom.xml
getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java
getdown/src/getdown/launcher/pom.xml
getdown/src/getdown/mvn_cmd
getdown/src/getdown/pom.xml
gradle.properties
help/help/html/features/preferences.html
help/help/html/releases.html
j11lib/getdown-core.jar
j8lib/getdown-core.jar
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/bin/Cache.java
src/jalview/bin/Jalview.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/Console.java
src/jalview/gui/Desktop.java
src/jalview/gui/Preferences.java
src/jalview/gui/WsPreferences.java
src/jalview/io/BackupFiles.java
src/jalview/io/BackupFilesPresetEntry.java
src/jalview/jbgui/GPreferences.java
src/jalview/project/Jalview2XML.java
src/jalview/util/HttpUtils.java
src/jalview/ws/sifts/SiftsClient.java
utils/clover/lib/clover-ant-4.4.1.jar [new file with mode: 0644]
utils/cmd-nox.sh [new file with mode: 0755]
utils/gradle-nox.sh [new symlink]

index 2c7f138..682b5c2 100644 (file)
@@ -1,3 +1,6 @@
+/* Convention for properties.  Read from gradle.properties, use lower_case_underlines for property names.
+ * For properties set within build.gradle, use camelCaseNoSpace.
+ */
 import org.apache.tools.ant.filters.ReplaceTokens
 import org.gradle.internal.os.OperatingSystem
 import org.gradle.plugins.ide.eclipse.model.Output
@@ -13,9 +16,6 @@ buildscript {
     mavenCentral()
     mavenLocal()
   }
-  dependencies {
-    classpath 'org.openclover:clover:4.4.1'
-  }
 }
 
 
@@ -130,21 +130,25 @@ ext {
   sourceDir = string("${jalviewDir}/${bareSourceDir}")
   resourceDir = string("${jalviewDir}/${resource_dir}")
   bareTestSourceDir = string(test_source_dir)
-  testSourceDir = string("${jalviewDir}/${bareTestSourceDir}")
+  testDir = string("${jalviewDir}/${bareTestSourceDir}")
 
-  // clover
-  cloverInstrDir = file("${buildDir}/${cloverSourcesInstrDir}")
-  cloverDb = string("${buildDir}/clover/clover.db")
   classesDir = string("${jalviewDir}/${classes_dir}")
-  if (clover.equals("true")) {
-    use_clover = true
-    classesDir = string("${buildDir}/${cloverClassesDir}")
-  } else {
-    use_clover = false
-    classesDir = string("${jalviewDir}/${classes_dir}")
-  }
 
-  classes = classesDir
+  // clover
+  useClover = clover.equals("true")
+  cloverBuildDir = "${buildDir}/clover"
+  cloverInstrDir = file("${cloverBuildDir}/clover-instr")
+  cloverClassesDir = file("${cloverBuildDir}/clover-classes")
+  cloverReportDir = file("${buildDir}/reports/clover")
+  cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
+  cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
+  //cloverTestClassesDir = cloverClassesDir
+  cloverDb = string("${cloverBuildDir}/clover.db")
+
+  resourceClassesDir = useClover ? cloverClassesDir : classesDir
+
+  testSourceDir = useClover ? cloverTestInstrDir : testDir
+  testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
 
   getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
   buildDist = true
@@ -173,8 +177,8 @@ ext {
     getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
     jvlChannelName += "_${getdownChannelName}"
     // automatically add the test group Not-bamboo for exclusion 
-    if ("".equals(testngExcludedGroups)) { 
-      testngExcludedGroups = "Not-bamboo"
+    if ("".equals(testng_excluded_groups)) { 
+      testng_excluded_groups = "Not-bamboo"
     }
     install4jExtraScheme = "jalviewb"
     break
@@ -192,10 +196,10 @@ ext {
     getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
     getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
-    if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
+    if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
       throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
     } else {
-      packageDir = string("${ARCHIVEDIR}/${packageDir}")
+      package_dir = string("${ARCHIVEDIR}/${package_dir}")
       buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
       buildDist = false
     }
@@ -207,10 +211,10 @@ ext {
     getdownChannelName = string("archive/${JALVIEW_VERSION}")
     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
     getdownAppBase = file(getdownWebsiteDir).toURI().toString()
-    if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
+    if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
       throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
     } else {
-      packageDir = string("${ARCHIVEDIR}/${packageDir}")
+      package_dir = string("${ARCHIVEDIR}/${package_dir}")
       buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
       buildDist = false
     }
@@ -409,8 +413,8 @@ ext {
 
 
 
-  buildingHTML = string("${jalviewDir}/${docDir}/building.html")
-  helpFile = string("${classesDir}/${help_dir}/help.jhm")
+  buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
+  helpFile = string("${resourceClassesDir}/${help_dir}/help.jhm")
   helpParentDir = string("${jalviewDir}/${help_parent_dir}")
   helpSourceDir = string("${helpParentDir}/${help_dir}")
 
@@ -453,10 +457,9 @@ sourceSets {
       srcDirs += helpParentDir
     }
 
-    jar.destinationDir = file("${jalviewDir}/${packageDir}")
+    jar.destinationDir = file("${jalviewDir}/${package_dir}")
 
     compileClasspath = files(sourceSets.main.java.outputDir)
-    //compileClasspath += files(sourceSets.main.resources.srcDirs)
     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
 
     runtimeClasspath = compileClasspath
@@ -464,18 +467,19 @@ sourceSets {
 
   clover {
     java {
-      srcDirs = [ cloverInstrDir ]
-      outputDir = file("${buildDir}/${cloverClassesDir}")
+      srcDirs cloverInstrDir
+      outputDir = cloverClassesDir
     }
 
     resources {
       srcDirs = sourceSets.main.resources.srcDirs
     }
-    compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
-    compileClasspath += files(sourceSets.main.java.outputDir)
-    compileClasspath += sourceSets.main.compileClasspath
-    compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["**/*.jar"])
+
+    compileClasspath = files( sourceSets.clover.java.outputDir )
+    //compileClasspath += files( testClassesDir )
     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
+    compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
+    compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
 
     runtimeClasspath = compileClasspath
   }
@@ -483,41 +487,20 @@ sourceSets {
   test {
     java {
       srcDirs testSourceDir
-      outputDir = file("${jalviewDir}/${testOutputDir}")
+      outputDir = file(testClassesDir)
     }
 
     resources {
-      srcDirs = sourceSets.main.resources.srcDirs
+      srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
     }
 
     compileClasspath = files( sourceSets.test.java.outputDir )
-
-    if (use_clover) {
-      compileClasspath = sourceSets.clover.compileClasspath
-    } else {
-      compileClasspath += files(sourceSets.main.java.outputDir)
-    }
-
-    compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
-    compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testnglibs", include: ["**/*.jar"])
-    compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testlibs", include: ["**/*.jar"])
+    compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
+    compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
 
     runtimeClasspath = compileClasspath
   }
-}
-
 
-// clover bits
-dependencies {
-  if (use_clover) {
-    cloverCompile 'org.openclover:clover:4.4.1'
-    testCompile 'org.openclover:clover:4.4.1'
-  }
-}
-
-configurations {
-  cloverRuntime
-  cloverRuntime.extendsFrom cloverCompile
 }
 
 
@@ -656,61 +639,209 @@ eclipse {
 }
 
 
-task cloverInstr {
-  // only instrument source, we build test classes as normal
-  inputs.files files (sourceSets.main.allJava,sourceSets.test.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
-  outputs.dir cloverInstrDir
+// clover bits
 
+
+task cleanClover {
   doFirst {
-    delete cloverInstrDir
-    def argsList = [
-      "--initstring",
-      cloverDb,
-      "-d",
-      cloverInstrDir.getPath(),
-    ]
-    argsList.addAll(
-      inputs.files.files.collect(
-        { file -> file.absolutePath }
-      )
+    delete cloverBuildDir
+    delete cloverReportDir
+  }
+}
+
+
+task cloverInstrJava(type: JavaExec) {
+  group = "Verification"
+  description = "Create clover instrumented source java files"
+
+  dependsOn cleanClover
+
+  inputs.files(sourceSets.main.allJava)
+  outputs.dir(cloverInstrDir)
+
+  //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
+  classpath = sourceSets.clover.compileClasspath
+  main = "com.atlassian.clover.CloverInstr"
+
+  def argsList = [
+    "--encoding",
+    "UTF-8",
+    "--initstring",
+    cloverDb,
+    "--destdir",
+    cloverInstrDir.getPath(),
+  ]
+  def srcFiles = sourceSets.main.allJava.files
+  argsList.addAll(
+    srcFiles.collect(
+      { file -> file.absolutePath }
     )
-    String[] args = argsList.toArray()
-    println("About to instrument "+args.length +" files")
-    com.atlassian.clover.CloverInstr.mainImpl(args)
+  )
+  args argsList.toArray()
+
+  doFirst {
+    delete cloverInstrDir
+    println("Clover: About to instrument "+srcFiles.size() +" files")
   }
 }
 
 
+task cloverInstrTests(type: JavaExec) {
+  group = "Verification"
+  description = "Create clover instrumented source test files"
+
+  dependsOn cleanClover
+
+  inputs.files(testDir)
+  outputs.dir(cloverTestInstrDir)
+
+  classpath = sourceSets.clover.compileClasspath
+  main = "com.atlassian.clover.CloverInstr"
+
+  def argsList = [
+    "--encoding",
+    "UTF-8",
+    "--initstring",
+    cloverDb,
+    "--srcdir",
+    testDir,
+    "--destdir",
+    cloverTestInstrDir.getPath(),
+  ]
+  args argsList.toArray()
+
+  doFirst {
+    delete cloverTestInstrDir
+    println("Clover: About to instrument test files")
+  }
+}
+
+
+task cloverInstr {
+  group = "Verification"
+  description = "Create clover instrumented all source files"
+
+  dependsOn cloverInstrJava
+  dependsOn cloverInstrTests
+}
+
+
 cloverClasses.dependsOn cloverInstr
 
 
-task cloverReport {
+task cloverConsoleReport(type: JavaExec) {
   group = "Verification"
-  description = "Creates the Clover report"
-  inputs.dir "${buildDir}/clover"
-  outputs.dir "${reportsDir}/clover"
+  description = "Creates clover console report"
+
   onlyIf {
     file(cloverDb).exists()
   }
-  doFirst {
-    def argsList = [
-      "--initstring",
-      cloverDb,
-      "-o",
-      "${reportsDir}/clover"
-    ]
-    String[] args = argsList.toArray()
-    com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
-
-    // and generate ${reportsDir}/clover/clover.xml
-    args = [
-      "--initstring",
-      cloverDb,
-      "-o",
-      "${reportsDir}/clover/clover.xml"
-    ].toArray()
-    com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
+
+  inputs.dir cloverClassesDir
+
+  classpath = sourceSets.clover.runtimeClasspath
+  main = "com.atlassian.clover.reporters.console.ConsoleReporter"
+
+  if (cloverreport_mem.length() > 0) {
+    maxHeapSize = cloverreport_mem
   }
+  if (cloverreport_jvmargs.length() > 0) {
+    jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
+  }
+
+  def argsList = [
+    "--alwaysreport",
+    "--initstring",
+    cloverDb,
+    "--unittests"
+  ]
+
+  args argsList.toArray()
+}
+
+
+task cloverHtmlReport(type: JavaExec) {
+  group = "Verification"
+  description = "Creates clover HTML report"
+
+  onlyIf {
+    file(cloverDb).exists()
+  }
+
+  def cloverHtmlDir = cloverReportDir
+  inputs.dir cloverClassesDir
+  outputs.dir cloverHtmlDir
+
+  classpath = sourceSets.clover.runtimeClasspath
+  main = "com.atlassian.clover.reporters.html.HtmlReporter"
+
+  if (cloverreport_mem.length() > 0) {
+    maxHeapSize = cloverreport_mem
+  }
+  if (cloverreport_jvmargs.length() > 0) {
+    jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
+  }
+
+  def argsList = [
+    "--alwaysreport",
+    "--initstring",
+    cloverDb,
+    "--outputdir",
+    cloverHtmlDir
+  ]
+
+  if (cloverreport_html_options.length() > 0) {
+    argsList += cloverreport_html_options.split(" ")
+  }
+
+  args argsList.toArray()
+}
+
+
+task cloverXmlReport(type: JavaExec) {
+  group = "Verification"
+  description = "Creates clover XML report"
+
+  onlyIf {
+    file(cloverDb).exists()
+  }
+
+  def cloverXmlFile = "${cloverReportDir}/clover.xml"
+  inputs.dir cloverClassesDir
+  outputs.file cloverXmlFile
+
+  classpath = sourceSets.clover.runtimeClasspath
+  main = "com.atlassian.clover.reporters.xml.XMLReporter"
+
+  if (cloverreport_mem.length() > 0) {
+    maxHeapSize = cloverreport_mem
+  }
+  if (cloverreport_jvmargs.length() > 0) {
+    jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
+  }
+
+  def argsList = [
+    "--alwaysreport",
+    "--initstring",
+    cloverDb,
+    "--outfile",
+    cloverXmlFile
+  ]
+
+  if (cloverreport_xml_options.length() > 0) {
+    argsList += cloverreport_xml_options.split(" ")
+  }
+
+  args argsList.toArray()
+}
+
+
+task cloverReport {
+  group = "Verification"
+  description = "Creates clover reports"
+
+  dependsOn cloverXmlReport
+  dependsOn cloverHtmlReport
 }
 
 
@@ -722,15 +853,7 @@ compileCloverJava {
     options.compilerArgs += additional_compiler_args
     print ("Setting target compatibility to "+targetCompatibility+"\n")
   }
-  classpath += configurations.cloverRuntime
-}
-
-
-task cleanClover {
-  doFirst {
-    delete cloverInstrDir
-    delete cloverDb
-  }
+  //classpath += configurations.cloverRuntime
 }
 // end clover bits
 
@@ -748,12 +871,6 @@ compileJava {
 
 
 compileTestJava {
-  if (use_clover) {
-    dependsOn compileCloverJava
-    classpath += configurations.cloverRuntime
-  } else {
-    classpath += sourceSets.main.runtimeClasspath
-  }
   doFirst {
     sourceCompatibility = compile_source_compatibility
     targetCompatibility = compile_target_compatibility
@@ -832,8 +949,8 @@ task cleanBuildingHTML(type: Delete) {
 
 task convertBuildingMD(type: Exec) {
   dependsOn cleanBuildingHTML
-  def buildingMD = "${jalviewDir}/${docDir}/building.md"
-  def css = "${jalviewDir}/${docDir}/github.css"
+  def buildingMD = "${jalviewDir}/${doc_dir}/building.md"
+  def css = "${jalviewDir}/${doc_dir}/github.css"
 
   def pandoc = null
   pandoc_exec.split(",").each {
@@ -875,8 +992,8 @@ clean {
 
 task syncDocs(type: Sync) {
   dependsOn convertBuildingMD
-  def syncDir = "${classesDir}/${docDir}"
-  from fileTree("${jalviewDir}/${docDir}")
+  def syncDir = "${resourceClassesDir}/${doc_dir}"
+  from fileTree("${jalviewDir}/${doc_dir}")
   into syncDir
 
 }
@@ -884,7 +1001,7 @@ task syncDocs(type: Sync) {
 
 task copyHelp(type: Copy) {
   def inputDir = helpSourceDir
-  def outputDir = "${classesDir}/${help_dir}"
+  def outputDir = "${resourceClassesDir}/${help_dir}"
   from(inputDir) {
     exclude '**/*.gif'
     exclude '**/*.jpg'
@@ -912,7 +1029,7 @@ task copyHelp(type: Copy) {
 
 
 task syncLib(type: Sync) {
-  def syncDir = "${classesDir}/${libDistDir}"
+  def syncDir = "${resourceClassesDir}/${libDistDir}"
   from fileTree("${jalviewDir}/${libDistDir}")
   into syncDir
 }
@@ -921,7 +1038,7 @@ task syncLib(type: Sync) {
 task syncResources(type: Sync) {
   from resourceDir
   include "**/*.*"
-  into "${classesDir}"
+  into "${resourceClassesDir}"
   preserve {
     include "**"
   }
@@ -938,18 +1055,17 @@ task prepare {
 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
 test {
   dependsOn prepare
-  dependsOn compileJava
-  if (use_clover) {
-    dependsOn cloverInstr
-  }
+  //dependsOn compileJava ////? DELETE
 
-  if (use_clover) {
-    print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
+  if (useClover) {
+    dependsOn cloverClasses
+   } else { //?
+     dependsOn compileJava //?
   }
 
   useTestNG() {
-    includeGroups testngGroups
-    excludeGroups testngExcludedGroups
+    includeGroups testng_groups
+    excludeGroups testng_excluded_groups
     preserveOrder true
     useDefaultListeners=true
   }
@@ -972,6 +1088,11 @@ test {
   targetCompatibility = compile_target_compatibility
   jvmArgs += additional_compiler_args
 
+  doFirst {
+    if (useClover) {
+      println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
+    }
+  }
 }
 
 
@@ -997,22 +1118,22 @@ task buildIndices(type: JavaExec) {
 
 task compileLinkCheck(type: JavaCompile) {
   options.fork = true
-  classpath = files("${jalviewDir}/${utilsDir}")
-  destinationDir = file("${jalviewDir}/${utilsDir}")
-  source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
-
-  inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
-  inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
-  outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
-  outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
+  classpath = files("${jalviewDir}/${utils_dir}")
+  destinationDir = file("${jalviewDir}/${utils_dir}")
+  source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
+
+  inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
+  inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
+  outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
+  outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
 }
 
 
 task linkCheck(type: JavaExec) {
   dependsOn prepare, compileLinkCheck
 
-  def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
-  classpath = files("${jalviewDir}/${utilsDir}")
+  def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
+  classpath = files("${jalviewDir}/${utils_dir}")
   main = "HelpLinksChecker"
   workingDir = jalviewDir
   args = [ "${classesDir}/${help_dir}", "-nointernet" ]
@@ -1033,12 +1154,12 @@ task linkCheck(type: JavaExec) {
 // import the pubhtmlhelp target
 ant.properties.basedir = "${jalviewDir}"
 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes_dir}/${help_dir}"
-ant.importBuild "${utilsDir}/publishHelp.xml"
+ant.importBuild "${utils_dir}/publishHelp.xml"
 
 
 task cleanPackageDir(type: Delete) {
   doFirst {
-    delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
+    delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
   }
 }
 
@@ -1048,13 +1169,13 @@ jar {
   dependsOn createBuildProperties
 
   manifest {
-    attributes "Main-Class": mainClass,
+    attributes "Main-Class": main_class,
     "Permissions": "all-permissions",
     "Application-Name": "Jalview Desktop",
     "Codebase": application_codebase
   }
 
-  destinationDir = file("${jalviewDir}/${packageDir}")
+  destinationDir = file("${jalviewDir}/${package_dir}")
   archiveName = rootProject.name+".jar"
 
   exclude "cache*/**"
@@ -1064,20 +1185,20 @@ jar {
   exclude "**/*.jar.*"
 
   inputs.dir(classesDir)
-  outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
+  outputs.file("${jalviewDir}/${package_dir}/${archiveName}")
 }
 
 
 task copyJars(type: Copy) {
   from fileTree(dir: classesDir, include: "**/*.jar").files
-  into "${jalviewDir}/${packageDir}"
+  into "${jalviewDir}/${package_dir}"
 }
 
 
 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
 task syncJars(type: Sync) {
   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
-  into "${jalviewDir}/${packageDir}"
+  into "${jalviewDir}/${package_dir}"
   preserve {
     include jar.archiveName
   }
@@ -1093,7 +1214,7 @@ task makeDist {
   dependsOn cleanPackageDir
   dependsOn syncJars
   dependsOn jar
-  outputs.dir("${jalviewDir}/${packageDir}")
+  outputs.dir("${jalviewDir}/${package_dir}")
 }
 
 
@@ -1114,7 +1235,7 @@ shadowJar {
   manifest {
     attributes 'Implementation-Version': JALVIEW_VERSION
   }
-  mainClassName = shadowJarMainClass
+  mainClassName = shadow_jar_main_class
   mergeServiceFiles()
   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
   minimize()
@@ -1206,7 +1327,7 @@ task getdownWebsite() {
     }
 
     def codeFiles = []
-    fileTree(file(packageDir)).each{ f ->
+    fileTree(file(package_dir)).each{ f ->
       if (f.isDirectory()) {
         def files = fileTree(dir: f, include: ["*"]).getFiles()
         codeFiles += files
@@ -1243,7 +1364,7 @@ task getdownWebsite() {
     // 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 = ${mainClass}\n"
+    getdownTextString += "class = ${main_class}\n"
 
     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
     getdown_txt.write(getdownTextString)
@@ -1301,7 +1422,7 @@ task getdownWebsite() {
   }
 
   if (buildDist) {
-    inputs.dir("${jalviewDir}/${packageDir}")
+    inputs.dir("${jalviewDir}/${package_dir}")
   }
   outputs.dir(getdownWebsiteDir)
   outputs.dir(getdownFilesDir)
index fdf3dcc..042c805 100644 (file)
@@ -1 +1 @@
-1.8.3-1.2.6_FJVL
+1.8.3-1.2.7_FJVL
index 4492183..0cd0530 100644 (file)
@@ -1 +1 @@
-1.8.3-1.2.6_JVL
+1.8.3-1.2.7_JVL
index 6748a25..8c0de5d 100644 (file)
Binary files a/getdown/lib/getdown-core.jar and b/getdown/lib/getdown-core.jar differ
index 9a27f55..331bbbc 100644 (file)
Binary files a/getdown/lib/getdown-launcher-local.jar and b/getdown/lib/getdown-launcher-local.jar differ
index e441bc6..5e884cb 100644 (file)
Binary files a/getdown/lib/getdown-launcher.jar and b/getdown/lib/getdown-launcher.jar differ
index 65686d2..cb427ba 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.2.6_FJVL</version>
+    <version>1.8.3-1.2.7_FJVL</version>
   </parent>
 
   <artifactId>getdown-ant</artifactId>
index 6a9e169..1f4b310 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.2.6_FJVL</version>
+    <version>1.8.3-1.2.7_FJVL</version>
   </parent>
 
   <artifactId>getdown-core</artifactId>
index b11a380..2640ceb 100644 (file)
@@ -9,6 +9,8 @@ import java.io.*;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.Proxy;
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
@@ -1058,13 +1060,30 @@ public class Application
         }
 
         // pass along our proxy settings
-        String proxyHost;
-        if ((proxyHost = System.getProperty("http.proxyHost")) != null) {
+        String proxyHost = System.getProperty("http.proxyHost");
+       String proxyPort = StringUtil.isBlank(System.getProperty("http.proxyPort")) ? "80" : System.getProperty("http.proxyPort");
+        if (StringUtil.isBlank(proxyHost) && ! proxy.equals(Proxy.NO_PROXY)) {
+           try {
+               SocketAddress a = proxy.address();
+               if (a != null && a instanceof InetSocketAddress) {
+                   InetSocketAddress ia = (InetSocketAddress)a;
+                   proxyHost = ia.getHostString();
+                   proxyPort = String.valueOf(ia.getPort());
+               }
+           } catch (Exception e) {
+               log.error("Problem obtaining proxy settings from Proxy object");
+               e.printStackTrace();
+           }
+       }
+        if (proxyHost != null) {
+           log.info("Using proxy settings "+proxyHost+":"+proxyPort);
             args.add("-Dhttp.proxyHost=" + proxyHost);
-            args.add("-Dhttp.proxyPort=" + System.getProperty("http.proxyPort"));
+            args.add("-Dhttp.proxyPort=" + proxyPort);
             args.add("-Dhttps.proxyHost=" + proxyHost);
-            args.add("-Dhttps.proxyPort=" + System.getProperty("http.proxyPort"));
-        }
+            args.add("-Dhttps.proxyPort=" + proxyPort);
+       } else {
+           log.info("Not setting proxy");
+       }
 
         // add the marker indicating the app is running in getdown
         args.add("-D" + Properties.GETDOWN + "=true");
index 0410815..dac34c0 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.2.6_FJVL</version>
+    <version>1.8.3-1.2.7_FJVL</version>
   </parent>
 
   <artifactId>getdown-launcher</artifactId>
index 25faf6f..ff16a2a 100755 (executable)
@@ -3,7 +3,7 @@
 if [ x$JVLVERSION != x ]; then
   export VERSION=$JVLVERSION
 else
-  export VERSION=1.8.3-1.2.6_JVL
+  export VERSION=1.8.3-1.2.7_JVL
 fi
 
 if [ x${VERSION%_JVL} = x$VERSION ]; then
@@ -25,7 +25,7 @@ fi
 VERSION=${VERSION/JVL/FJVL}
 echo "Setting VERSION to '$VERSION'"
 perl -p -i -e 's|(<version>)[^<]*JVL[^<]*(</version>)|${1}$ENV{VERSION}${2}|;' pom.xml */pom.xml
-mvn package -Dgetdown.host.whitelist="jalview.org,*.jalview.org" -Dallow_file_protocol=true -Dconnect_timeout=4 -Dread_timeout=4
+mvn package -Dgetdown.host.whitelist="jalview.org,*.jalview.org,localhost" -Dallow_file_protocol=true -Dconnect_timeout=4 -Dread_timeout=4
 RET=$?
 if [ x$RET = x0 ]; then
   cp launcher/target/getdown-launcher-$VERSION.jar ../../../getdown/lib/getdown-launcher-local.jar && echo "Copied getdown-launcher-$VERSION.jar to getdown/lib/getdown-launcher-local.jar"
index 0011325..c3f51d2 100644 (file)
@@ -10,7 +10,7 @@
   <groupId>com.threerings.getdown</groupId>
   <artifactId>getdown</artifactId>
   <packaging>pom</packaging>
-  <version>1.8.3-1.2.6_FJVL</version>
+  <version>1.8.3-1.2.7_FJVL</version>
 
   <name>getdown</name>
   <description>An application installer and updater.</description>
index 782a495..dbf124b 100644 (file)
@@ -1,4 +1,6 @@
-org.gradle.jvmargs=-Xmx1536m -Xms512m
+# Convention for properties.  Read from gradle.properties, use lower_case_underlines for property names.
+# For properties set within build.gradle, use camelCaseNoSpace.
+#
 
 jalviewDir = .
 
@@ -23,38 +25,35 @@ proxyHost = sqid
 jalview_keyalg = SHA1withRSA
 jalview_keydig = SHA1
 
-testngGroups = Functional
-testngExcludedGroups = 
+testng_groups = Functional
+testng_excluded_groups = 
 
 j8libDir = j8lib
 j11libDir = j11lib
 resource_dir = resources
 help_parent_dir = help
 help_dir = help
-docDir = doc
-schemaDir = schemas
+doc_dir = doc
 classes_dir = classes
-examplesDir = examples
 clover = false
-use_clover = false
-cloverReportJVMHeap = 2g
-cloverReportJVMArgs = -Dfile.encoding=UTF-8
-cloverReportHTMLOptions = 
-cloverReportXMLOptions =
-cloverClassesDir = clover-classes
-cloverSourcesInstrDir = sources-instr
-packageDir = dist
+clover_classes_dir = clover-classes
+clover_sources_instr_dir = clover-instr
+clover_report_dir = clover-report
+clover_lib_dir = utils/clover/lib
+cloverreport_mem = 2g
+cloverreport_jvmargs = -Dfile.encoding=UTF-8
+cloverreport_html_options = 
+cloverreport_xml_options =
+package_dir = dist
 ARCHIVEDIR =
-outputJar = jalview.jar
 
-testOutputDir = tests
-utilsDir = utils
+test_output_dir = tests
+utils_dir = utils
 
 build_properties_file = .build_properties
 application_codebase = *.jalview.org
-mainClass = jalview.bin.Jalview
-shadowJarMainClass = jalview.bin.Launcher
-launcherClass = jalview.bin.Jalview
+main_class = jalview.bin.Jalview
+shadow_jar_main_class = jalview.bin.Launcher
 
 jalview_name = Jalview
 
index 5fda2df..58b06db 100755 (executable)
     browser application.
   </p>
   <p>
-    <em>Proxy Server</em><br> If you normally use a proxy server
-    for using the internet, you must tick the box &quot;Use a Proxy
-    Server&quot; and enter the address and port details as necessary.
+    <em>Proxy Server</em><br>
+    There are three settings to choose from:<br>
+    <ul>
+           <li><em>No proxy servers</em> will configure Jalview to use a
+                   direct internet connection.</li>
+           <li><em>System proxy servers</em> will configure Jalview to use
+                   the proxy server passed to it by your system at startup.</li>
+           <li><em>Use these proxy servers:</em> allows you to set a custom
+                   proxy server.</li>
+    </ul>
+    If you normally use a proxy server for using the internet, you must
+    choose one of <em>System proxy servers</em>, or if these have not been
+    passed correctly you should set your own proxy servers to use by selecting
+    <em>Use these proxy servers</em>.
+    You will then need to enter the host and port details as necessary.
     Web Services will not work if you are using a proxy server and do
-    not enter the settings here.
+    not choose the system proxy or enter your own settings here.<br>
+    There are separate host and port settings for HTTP and HTTPS proxies.
+    Often these are the same but you should enter the host and port into both
+    rows.<br>
+    You can also check the <em>Authentication required</em> box if your proxy
+    requires username and password authentication.  You can enter both the
+    <em>Username</em> and <em>Password</em> but only the <em>Username</em> will
+    be stored in Jalview's preferences file, the password will only be stored
+    until the end of the current Jalview session.<br>
+    This means that if the proxy settings are still valid, Jalview will ask for
+    the password when it starts the next session.
   </p>
   <p>
     <em>Usage statistics, Questionnaire and Version checks</em><br>
index 3512375..8c4ba37 100755 (executable)
@@ -67,6 +67,14 @@ li:before {
             residue in cursor mode
           </li>
           <li>
+            <!-- JAL-3608 -->Set choice of Look and Feel via system property or command line option, and
+           force use of Metal look and feel as default on linux.
+          </li>
+          <li>
+            <!-- JAL-3633 -->Preferences -&gt; Connections, Proxy server settings now allow selecting "No proxy", "System proxy settings" or custom proxy settings
+           which can be configured for HTTP, HTTPS and allows for an authenticated proxy server.
+          </li>
+          <li>
             <!-- JAL-3695 -->Support import of VCF 4.3 by updating
             HTSJDK from 2.12 to 2.23
           </li>
@@ -99,6 +107,16 @@ li:before {
             multiple EMBL gene products shown for a single contig
           </li>
           <li>
+            <!-- JAL-3628 -->Unable to save update to an existing file on Windows (partially resolved)
+           and Backups -&gt; Single backup scheme not always saving backup file. 
+          </li>
+          <li>
+            <!-- JAL-3609 -->Java 11 only: Automatically set scaling for HiDPI displays in linux.
+          </li>
+          <li>
+            <!-- JAL-3632 JAL-3633 -->Proxy properties don't set HTTPS proxy for launcher or application.
+          </li>
+          <li>
             <!-- JAL-3696 -->Errors encountered when processing variants
             from VCF files yield "Error processing VCF: Format specifier
             '%s'" on the console
index 6748a25..8c0de5d 100644 (file)
Binary files a/j11lib/getdown-core.jar and b/j11lib/getdown-core.jar differ
index 6748a25..8c0de5d 100644 (file)
Binary files a/j8lib/getdown-core.jar and b/j8lib/getdown-core.jar differ
index a4b24ed..0cef6f2 100644 (file)
@@ -377,7 +377,7 @@ label.example = Example
 label.example_param = Example: {0}
 label.select_file_format_before_saving = You must select a file format before saving!
 label.file_format_not_specified = File format not specified
-label.couldnt_save_file = Couldn't save file: {0}
+label.couldnt_save_file = Couldn''t save file: {0}
 label.error_saving_file = Error Saving File
 label.remove_from_default_list = Remove from default list?
 label.remove_user_defined_colour = Remove user defined colour
@@ -406,11 +406,11 @@ label.pdb_entries_couldnt_be_retrieved = The following pdb entries could not be
 label.couldnt_load_file = Couldn't load file
 label.couldnt_find_pdb_id_in_file = Couldn't find a PDB id in the file supplied. Please enter an Id to identify this structure.
 label.no_pdb_id_in_file = No PDB Id in File
-label.couldnt_read_pasted_text = Couldn't read the pasted text {0}
+label.couldnt_read_pasted_text = Couldn''t read the pasted text {0}
 label.error_parsing_text = Error parsing text
 label.input_alignment_from_url = Input Alignment From URL
 label.input_alignment = Input Alignment
-label.couldnt_import_as_vamsas_session = Couldn't import {0} as a new vamsas session.
+label.couldnt_import_as_vamsas_session = Couldn''t import {0} as a new vamsas session.
 label.vamsas_document_import_failed = Vamsas Document Import Failed
 label.couldnt_locate = Could not locate {0}
 label.url_not_found = URL not found
@@ -591,13 +591,21 @@ label.gap_symbol = Gap Symbol
 label.prot_alignment_colour = Protein Alignment Colour
 label.nuc_alignment_colour = Nucleotide Alignment Colour
 label.address = Address
+label.host = Host
 label.port = Port
 label.default_browser_unix = Default Browser (Unix)
 label.send_usage_statistics = Send usage statistics
 label.check_for_questionnaires = Check for questionnaires
 label.check_for_latest_version = Check for latest version
 label.url_linkfrom_sequence_id = URL link from Sequence ID
-label.use_proxy_server = Use a proxy server
+label.no_proxy = No proxy servers
+label.system_proxy = System proxy servers (http={0}; https={1})
+label.use_proxy_server = Use these proxy servers
+label.auth_required = Authentication required
+label.username = Username
+label.password = Password
+label.proxy_password_required = Proxy password required
+label.not_stored = not stored in Preferences file
 label.eps_rendering_style = EPS rendering style
 label.append_start_end = Append /start-end (/15-380)
 label.full_sequence_id = Full Sequence Id
@@ -635,7 +643,7 @@ label.delete_service_url = Delete Service URL
 label.details = Details
 label.options = Options
 label.parameters = Parameters
-label.proxy_server = Proxy Server
+label.proxy_servers = Proxy Servers
 label.file_output = File Output
 label.select_input_type = Select input type
 label.set_options_for_type = Set options for type
@@ -855,7 +863,7 @@ label.invalid_name = Invalid name
 label.set_proxy_settings = Please set up your proxy settings in the 'Connections' tab of the Preferences window
 label.proxy_authorization_failed = Proxy Authorization Failed
 label.internal_jalview_error = Internal Jalview Error
-label.secondary_structure_prediction_service_couldnt_be_located = The Secondary Structure Prediction Service named {0} at {1} couldn't be located.
+label.secondary_structure_prediction_service_couldnt_be_located = The Secondary Structure Prediction Service named {0} at {1} couldn''t be located.
 label.service_called_is_not_msa_service = The Service called \n{0}\nis not a \nMultiple Sequence Alignment Service\!
 label.msa_service_is_unknown = The Multiple Sequence Alignment Service named {0} is unknown
 label.service_called_is_not_seq_search_service = The Service called \n{0}\nis not a \nSequence Search Service\!
@@ -985,7 +993,7 @@ error.cannot_set_arguments_to_jabaws_param_set = Cannot set arguments to a JabaW
 error.implementation_error_runner_config_not_available = Implementation Error: Runner Config not available for a JABAWS service of type {0} ({1})
 error.implementation_error_cannot_handle_jaba_param = Implementation Error: Cannot handle Jaba parameter object {0}
 error.implementation_error_attempt_to_delete_service_preset = Implementation error: Attempt to delete a service preset!
-error.implementation_error_cannot_locate_oldname_presetname = Implementation error: Can't locate either oldname ({0}) or presetName ({1}in the datastore!"
+error.implementation_error_cannot_locate_oldname_presetname = Implementation error: Can''t locate either oldname ({0}) or presetName ({1}in the datastore!"
 error.implementation_error_jabaws_param_set_only_handled_by = Implementation error: JabaWsParamSets can only be handled by JabaParamStore
 error.cannot_set_source_file_for = Cannot set source file for {0}
 error.mismatch_service_instance_preset = Probable mismatch between service instance and preset!
@@ -993,7 +1001,7 @@ error.cannot_set_params_for_ws_preset = Cannot set Parameters for a Jaba Web ser
 error.implementation_error_can_only_instantiate_jaba_param_sets = Implementation error: Can only instantiate Jaba parameter sets
 error.no_aacon_service_found = No AACon service found
 error.implementation_error_couldnt_copy_value_constraint = Implementation error: could not copy ValueConstrain!
-error.couldnt_encode_as_utf8 = Couldn't encode {0} as UTF-8.
+error.couldnt_encode_as_utf8 = Couldn''t encode {0} as UTF-8.
 error.tree_inputtype_not_yet_implemented = Tree InputType not yet implemented
 error.implementation_error_need_to_have_httpresponse = Implementation Error: need to have an HttpResponse to process
 error.dbrefsource_implementation_exception =DBRefSource Implementation Exception
@@ -1049,18 +1057,18 @@ error.implementation_error_reset_called_for_invalid_source = Implementation Erro
 exception.number_of_residues_in_query_sequence_differ_from_prediction = Number of residues in {0} supposed query sequence ({1}\n{2})\ndiffer from number of prediction sites in prediction ({3})
 label.mapped = mapped
 exception.jpredconcide_entry_has_unexpected_number_of_columns = JPredConcise: Entry ({0}) has an unexpected number of columns
-exception.couldnt_parse_concise_annotation_for_prediction = Couldn't parse concise annotation for prediction profile.\n{0}
+exception.couldnt_parse_concise_annotation_for_prediction = Couldn''t parse concise annotation for prediction profile.\n{0}
 exception.newfile = NewickFile\: {0}\n
 label.no_tree_read_in = No Tree read in
-exception.rnaml_couldnt_access_datasource = Couldn't access datasource ({0})
-exception.ranml_couldnt_process_data = Couldn't process data as RNAML file ({0})
+exception.rnaml_couldnt_access_datasource = Couldn''t access datasource ({0})
+exception.ranml_couldnt_process_data = Couldn''t process data as RNAML file ({0})
 exception.ranml_invalid_file = Invalid RNAML file ({0})
 exception.ranml_problem_parsing_data = Problem parsing data as RNAML ({0})
 exception.pfam_no_sequences_found = No sequences found (PFAM input)
 exception.stockholm_invalid_format = This file is not in valid STOCKHOLM format: First line does not contain '# STOCKHOLM'
 exception.couldnt_parse_sequence_line = Could not parse sequence line: {0}
 exception.unknown_annotation_detected = Unknown annotation detected: {0} {1}
-exception.couldnt_store_sequence_mappings = Couldn't store sequence mappings for {0}
+exception.couldnt_store_sequence_mappings = Couldn''t store sequence mappings for {0}
 exception.matrix_too_many_iteration = Too many iterations in {0} (max is {1})
 exception.browser_not_found = Exception in finding browser: {0}
 exception.browser_unable_to_locate = Unable to locate browser: {0}
@@ -1094,7 +1102,7 @@ warn.service_not_supported = Service not supported!
 warn.input_is_too_big = Input is too big!
 warn.invalid_job_param_set = Invalid job parameter set!
 warn.oneseq_msainput_selection = The current selection only contains a single sequence. Do you want to submit all sequences for alignment instead ?   
-info.job_couldnt_be_run_server_doesnt_support_program = Job could not be run because the server doesn't support this program.\n{0}
+info.job_couldnt_be_run_server_doesnt_support_program = Job could not be run because the server doesn''t support this program.\n{0}
 info.job_couldnt_be_run_exceeded_hard_limit = Job could not be run because it exceeded a hard limit on the server.\n{0}
 info.job_couldnt_be_run_incorrect_param_setting = Job could not be run because some of the parameter settings are not supported by the server.\n{0}\nPlease check to make sure you have used the correct parameter set for this service\!\n
 info.no_jobs_ran = No jobs ran
@@ -1346,6 +1354,7 @@ label.backupfiles_confirm_save_file = Confirm save file
 label.backupfiles_confirm_save_file_backupfiles_roll_wrong = Something possibly went wrong with the backups of this file.
 label.backupfiles_confirm_save_new_saved_file_ok = The new saved file seems okay.
 label.backupfiles_confirm_save_new_saved_file_not_ok = The new saved file might not be okay.
+label.continue_operation = Continue operation?
 label.backups = Backups
 label.backup = Backup
 label.backup_files = Backup Files
@@ -1412,3 +1421,7 @@ label.include_linked_features = Include {0} features
 label.include_linked_tooltip = Include visible {0} features<br>converted to local sequence coordinates
 label.features_not_shown = {0} feature(s) not shown
 label.no_features_to_sort_by = No features to sort by
+label.log_level = Log level
+label.log_level_tooltip = Temporarily set the log level for this console
+label.copy_to_clipboard = Copy to clipboard
+label.copy_to_clipboard_tooltip = Copy all of the log text in this console to the system clipboard
index 3d7065b..9fa1fd8 100644 (file)
@@ -543,13 +543,21 @@ label.database_references = Referencias a base de datos
 #label.scroll_highlighted_regions = Desplazarse hasta las regiones resaltadas
 label.gap_symbol = Símbolo del hueco
 label.address = Dirección
+label.host = Host
 label.port = Puerto
 label.default_browser_unix = Navegador por defecto (Unix)
 label.send_usage_statistics = Enviar estadísticas de uso
 label.check_for_questionnaires = Comprobar los cuestionarios
 label.check_for_latest_version = Comprobar la Ãºltima versión
 label.url_linkfrom_sequence_id = URL del enlace del ID de la secuencia
-label.use_proxy_server = Utilizar un servidor proxy
+label.no_proxy = Sin servidores proxy
+label.system_proxy = Servidores proxy del sistema (http={0}; https={1})
+label.use_proxy_server = Utilizar estos servidores proxy
+label.auth_required = Authentication required
+label.username = Usario
+label.password = Contraseña
+label.proxy_password_required = Se requiere contraseña de proxy
+label.not_stored = no almacenado en el archivo de Preferencias
 label.eps_rendering_style = Estilo de visualización EPS
 label.append_start_end = Añadir /inicio-fin (/15-380)
 label.full_sequence_id = ID de la secuencia completo
@@ -584,7 +592,7 @@ label.delete_service_url = Borrar la URL del servicio
 label.details = Detalles
 label.options = Opciones
 label.parameters = Paramétros
-label.proxy_server = Servidor proxy
+label.proxy_servers = Servidores proxy
 label.file_output = Fichero de salida
 label.select_input_type = Seleccionar el tipo de entrada
 label.set_options_for_type = Establecer opciones para el tipo
@@ -1347,6 +1355,7 @@ label.backupfiles_confirm_save_file = Confirmar guardar archivo
 label.backupfiles_confirm_save_file_backupfiles_roll_wrong = Posiblemente algo está mal con los archivos de respaldos.
 label.backupfiles_confirm_save_new_saved_file_ok = El nuevo archivo guardado parece estar bien.
 label.backupfiles_confirm_save_new_saved_file_not_ok = El nuevo archivo guardado podría no estar bien.
+label.continue_operation = Â¿Continuar operación?
 label.backups = Respaldos
 label.backup = Respaldo
 label.backup_files = Archivos de respaldos
@@ -1413,3 +1422,7 @@ label.include_linked_features = Incluir caracter
 label.include_linked_tooltip = Incluir características de {0}<br>convertidas a coordenadas de secuencia local
 label.features_not_shown = {0} característica(s) no mostradas
 label.no_features_to_sort_by = No hay características para ordenar
+label.log_level = Nivel del registro
+label.log_level_tooltip = Establezca temporalmente el nivel de registro para esta consola
+label.copy_to_clipboard = Copiar en el portapapeles
+label.copy_to_clipboard_tooltip = Copie todo el texto de registro en esta consola al portapapeles del sistema
index 751461f..8e36d68 100755 (executable)
@@ -27,8 +27,13 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
@@ -47,6 +52,7 @@ import org.apache.log4j.Logger;
 import org.apache.log4j.SimpleLayout;
 
 import jalview.datamodel.PDBEntry;
+import jalview.gui.Preferences;
 import jalview.gui.UserDefinedColours;
 import jalview.schemes.ColourSchemeLoader;
 import jalview.schemes.ColourSchemes;
@@ -54,6 +60,7 @@ import jalview.schemes.UserColourScheme;
 import jalview.structure.StructureImportSettings;
 import jalview.urls.IdOrgSettings;
 import jalview.util.ColorUtils;
+import jalview.util.MessageManager;
 import jalview.ws.sifts.SiftsSettings;
 
 /**
@@ -267,6 +274,28 @@ public class Cache
    */
   public static Logger log;
 
+  // save the proxy properties set at startup
+  public final static String[] startupProxyProperties = {
+      System.getProperty("http.proxyHost"),
+      System.getProperty("http.proxyPort"),
+      System.getProperty("https.proxyHost"),
+      System.getProperty("https.proxyPort"),
+      System.getProperty("http.proxyUser"),
+      System.getProperty("http.proxyPassword"),
+      System.getProperty("https.proxyUser"),
+      System.getProperty("https.proxyPassword"),
+      System.getProperty("http.nonProxyHosts") };
+
+  public final static String PROXYTYPE_NONE = "none";
+
+  // "false" and "true" for backward compatibility
+  public final static String PROXYTYPE_SYSTEM = "false";
+
+  public final static String PROXYTYPE_CUSTOM = "true";
+
+  // in-memory only storage of proxy password, safer to use char array
+  public static char[] proxyAuthPassword = null;
+
   /** Jalview Properties */
   public static Properties applicationProperties = new Properties()
   {
@@ -377,16 +406,34 @@ public class Cache
       System.out.println("Error reading properties file: " + ex);
     }
 
-    if (getDefault("USE_PROXY", false))
+    // PROXY TYPE settings (now three options "none", "false", "true", but using
+    // backward compatible strings)
+    String proxyType = getDefault("USE_PROXY", PROXYTYPE_SYSTEM);
+    // default to upgrading old settings
+    switch (proxyType)
     {
-      String proxyServer = getDefault("PROXY_SERVER", ""),
-              proxyPort = getDefault("PROXY_PORT", "8080");
-
-      System.out.println("Using proxyServer: " + proxyServer
-              + " proxyPort: " + proxyPort);
-
-      System.setProperty("http.proxyHost", proxyServer);
-      System.setProperty("http.proxyPort", proxyPort);
+    case PROXYTYPE_NONE:
+      clearProxyProperties();
+      break;
+    case PROXYTYPE_SYSTEM: // use system settings
+      resetProxyProperties();
+      break;
+    case PROXYTYPE_CUSTOM: // use specified proxy settings
+      String httpHost = getDefault("PROXY_SERVER", "");
+      String httpPort = getDefault("PROXY_PORT", "8080");
+      String httpsHost = getDefault("PROXY_SERVER_HTTPS", httpHost);
+      String httpsPort = getDefault("PROXY_PORT_HTTPS", httpPort);
+      String httpUser = getDefault("PROXY_AUTH_USER", null);
+      // https.proxyUser and https.proxyPassword are not able to be
+      // independently set in Preferences yet (or http.nonProxyHosts)
+      String httpsUser = getDefault("PROXY_AUTH_USER_HTTPS", httpUser);
+      setProxyProperties(httpHost, httpPort, httpsHost, httpsPort, httpUser,
+              proxyAuthPassword, httpsUser, proxyAuthPassword, "localhost");
+      break;
+    default:
+      String message = "Incorrect PROXY_TYPE - should be 'none' (clear proxy properties), 'false' (system settings), 'true' (custom settings): "
+              + proxyType;
+      Cache.warn(message);
     }
 
     // LOAD THE AUTHORS FROM THE authors.props file
@@ -440,8 +487,7 @@ public class Cache
     String jnlpVersion = System.getProperty("jalview.version");
 
     // jnlpVersion will be null if a latest version check for the channel needs
-    // to
-    // be done
+    // to be done
     // Dont do this check if running in headless mode
 
     if (jnlpVersion == null && getDefault("VERSION_CHECK", true)
@@ -1104,20 +1150,23 @@ public class Cache
   public static String getVersionDetailsForConsole()
   {
     StringBuilder sb = new StringBuilder();
-    sb.append("Jalview Version: "
-            + jalview.bin.Cache.getDefault("VERSION", "TEST"));
+    sb.append("Jalview Version: ");
+    sb.append(jalview.bin.Cache.getDefault("VERSION", "TEST"));
     sb.append("\n");
-    sb.append("Jalview Installation: "
-            + jalview.bin.Cache.getDefault("INSTALLATION", "unknown"));
+    sb.append("Jalview Installation: ");
+    sb.append(jalview.bin.Cache.getDefault("INSTALLATION", "unknown"));
     sb.append("\n");
-    sb.append("Build Date: "
-            + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
+    sb.append("Build Date: ");
+    sb.append(jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
     sb.append("\n");
-    sb.append("Java version: " + System.getProperty("java.version"));
+    sb.append("Java version: ");
+    sb.append(System.getProperty("java.version"));
     sb.append("\n");
-    sb.append(System.getProperty("os.arch") + " "
-            + System.getProperty("os.name") + " "
-            + System.getProperty("os.version"));
+    sb.append(System.getProperty("os.arch"));
+    sb.append(" ");
+    sb.append(System.getProperty("os.name"));
+    sb.append(" ");
+    sb.append(System.getProperty("os.version"));
     sb.append("\n");
     appendIfNotNull(sb, "Install4j version: ",
             System.getProperty("sys.install4jVersion"), "\n", null);
@@ -1126,11 +1175,18 @@ public class Cache
     appendIfNotNull(sb, "Launcher version: ",
             System.getProperty("launcher_version"), "\n", null);
     LookAndFeel laf = UIManager.getLookAndFeel();
-    String lafName = laf == null?"Not obtained":laf.getName();
-    String lafClass = laf == null?"unknown":laf.getClass().getName();
-    appendIfNotNull(sb, "LookAndFeel: ", lafName+" ("+lafClass+")", "\n", null);
-    // Not displayed in release version ( determined by possible version number regex 9[9.]*9[.-_a9]* )
-    if (Pattern.matches("^\\d[\\d\\.]*\\d[\\.\\-\\w]*$", jalview.bin.Cache.getDefault("VERSION", "TEST"))) {
+    String lafName = laf == null ? "Not obtained" : laf.getName();
+    String lafClass = laf == null ? "unknown" : laf.getClass().getName();
+    sb.append("LookAndFeel: ");
+    sb.append(lafName);
+    sb.append(" (");
+    sb.append(lafClass);
+    sb.append(")\n");
+    // Not displayed in release version ( determined by possible version number
+    // regex 9[9.]*9[.-_a9]* )
+    if (Pattern.matches("^\\d[\\d\\.]*\\d[\\.\\-\\w]*$",
+            jalview.bin.Cache.getDefault("VERSION", "TEST")))
+    {
       appendIfNotNull(sb, "Getdown appdir: ",
               System.getProperty("getdownappdir"), "\n", null);
       appendIfNotNull(sb, "Java home: ", System.getProperty("java.home"),
@@ -1149,4 +1205,324 @@ public class Cache
     // eg 'built from Source' or update channel
     return jalview.bin.Cache.getDefault("INSTALLATION", "unknown");
   }
+
+  public static String getStackTraceString(Throwable t)
+  {
+    StringWriter sw = new StringWriter();
+    PrintWriter pw = new PrintWriter(sw);
+    t.printStackTrace(pw);
+    return sw.toString();
+  }
+
+  // proxy properties methods
+  public static void clearProxyProperties()
+  {
+    setProxyProperties(null, null, null, null, null, null, null, null,
+            null);
+  }
+
+  public static void resetProxyProperties()
+  {
+    setProxyProperties(startupProxyProperties[0], startupProxyProperties[1],
+            startupProxyProperties[2], startupProxyProperties[3],
+            startupProxyProperties[4],
+            startupProxyProperties[5] == null ? null
+                    : startupProxyProperties[5].toCharArray(),
+            startupProxyProperties[6],
+            startupProxyProperties[7] == null ? null
+                    : startupProxyProperties[7].toCharArray(),
+            startupProxyProperties[8]);
+    StringBuilder sb = new StringBuilder();
+    sb.append("Setting proxy properties to: http.proxyHost=")
+            .append(startupProxyProperties[0]).append(", http.proxyPort=")
+            .append(startupProxyProperties[1])
+            .append(startupProxyProperties[4] != null
+                    && !startupProxyProperties[4].isEmpty()
+                            ? " [" + startupProxyProperties[4] + "]"
+                            : "")
+            .append(", https.proxyHost=").append(startupProxyProperties[2])
+            .append(", https.proxyPort=").append(startupProxyProperties[3])
+            .append(startupProxyProperties[6] != null
+                    && !startupProxyProperties[6].isEmpty()
+                            ? " [" + startupProxyProperties[6] + "]"
+                            : "");
+
+    Cache.debug(sb.toString());
+  }
+
+  public static void setProxyPropertiesFromPreferences()
+  {
+    setProxyPropertiesFromPreferences(Cache.PROXYTYPE_SYSTEM);
+  }
+
+  public static void setProxyPropertiesFromPreferences(
+          String previousProxyType)
+  {
+    String proxyType = Cache.getDefault("USE_PROXY",
+            Cache.PROXYTYPE_SYSTEM);
+    if (previousProxyType != null
+            && !proxyType.equals(Cache.PROXYTYPE_CUSTOM) // always apply
+                                                         // customProxy
+            && proxyType.equals(previousProxyType))
+    {
+      // no change
+      return;
+    }
+    switch (proxyType)
+    {
+    case Cache.PROXYTYPE_NONE:
+      if (!previousProxyType.equals(proxyType))
+      {
+        Cache.log.info("Setting no proxy settings");
+        Cache.setProxyProperties(null, null, null, null, null, null, null,
+                null, null);
+      }
+      break;
+    case Cache.PROXYTYPE_CUSTOM:
+      // always re-set a custom proxy -- it might have changed, particularly
+      // password
+      Cache.log.info("Setting custom proxy settings");
+      boolean proxyAuthSet = Cache.getDefault("PROXY_AUTH", false);
+      Cache.setProxyProperties(Cache.getDefault("PROXY_SERVER", null),
+              Cache.getDefault("PROXY_PORT", null),
+              Cache.getDefault("PROXY_SERVER_HTTPS", null),
+              Cache.getDefault("PROXY_PORT_HTTPS", null),
+              proxyAuthSet ? Cache.getDefault("PROXY_AUTH_USERNAME", "")
+                      : null,
+              proxyAuthSet ? Cache.proxyAuthPassword : null,
+              proxyAuthSet ? Cache.getDefault("PROXY_AUTH_USERNAME", "")
+                      : null,
+              proxyAuthSet ? Cache.proxyAuthPassword : null, "localhost");
+      break;
+    default: // system proxy settings by default
+      Cache.log.info("Setting system proxy settings");
+      Cache.resetProxyProperties();
+    }
+  }
+
+  public static void setProxyProperties(String httpHost, String httpPort,
+          String httpsHost, String httpsPort, String httpUser,
+          char[] httpPassword, String httpsUser, char[] httpsPassword,
+          String nonProxyHosts)
+  {
+    setOrClearSystemProperty("http.proxyHost", httpHost);
+    setOrClearSystemProperty("http.proxyPort", httpPort);
+    setOrClearSystemProperty("https.proxyHost", httpsHost);
+    setOrClearSystemProperty("https.proxyPort", httpsPort);
+    setOrClearSystemProperty("http.proxyUser", httpUser);
+    setOrClearSystemProperty("https.proxyUser", httpsUser);
+    // note: passwords for http.proxyPassword and https.proxyPassword are sent
+    // via the Authenticator, properties do not need to be set
+
+    // are we using a custom proxy (password prompt might be required)?
+    boolean customProxySet = getDefault("USE_PROXY", PROXYTYPE_SYSTEM)
+            .equals(PROXYTYPE_CUSTOM);
+
+    /*
+     * A bug in Java means the AuthCache does not get reset, so once it has working credentials,
+     * it never asks for more, so changing the Authenticator has no effect (as getPasswordAuthentication()
+     * is not re-called).
+     * This could lead to password leak to a hostile proxy server, so I'm putting in a hack to clear
+     * the AuthCache.
+     * see https://www.generacodice.com/en/articolo/154918/Reset-the-Authenticator-credentials
+     * ...
+     * Turns out this is only accessible in Java 8, and not in Java 9 onwards, so commenting out
+     */
+    /*
+    try
+    {
+      sun.net.www.protocol.http.AuthCacheValue
+              .setAuthCache(new sun.net.www.protocol.http.AuthCacheImpl());
+    } catch (Throwable t)
+    {
+      Cache.error(t.getMessage());
+      Cache.debug(getStackTraceString(t));
+    }
+    */
+
+    if (httpUser != null || httpsUser != null)
+    {
+      try
+      {
+        char[] displayHttpPw = new char[httpPassword == null ? 0
+                : httpPassword.length];
+        Arrays.fill(displayHttpPw, '*');
+        Cache.debug("CACHE Proxy: setting new Authenticator with httpUser='"
+                + httpUser + "' httpPassword='" + displayHttpPw + "'");
+        Authenticator.setDefault(new Authenticator()
+        {
+          @Override
+          protected PasswordAuthentication getPasswordAuthentication()
+          {
+            if (getRequestorType() == RequestorType.PROXY)
+            {
+              String protocol = getRequestingProtocol();
+              boolean needProxyPasswordSet = false;
+              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("https")
+                              && (httpsUser != null
+                                      && httpsUser.length() > 0
+                                      && (httpsPassword == null
+                                              || httpsPassword.length == 0))))
+              {
+                // open Preferences -> Connections
+                String message = MessageManager
+                        .getString("label.proxy_password_required");
+                Preferences.openPreferences(Preferences.CONNECTIONS_TAB,
+                        message);
+                Preferences.getInstance()
+                        .proxyAuthPasswordCheckHighlight(true, true);
+              }
+              else
+              {
+                try
+                {
+                  if (protocol.equalsIgnoreCase("http")
+                          && getRequestingHost().equalsIgnoreCase(httpHost)
+                          && getRequestingPort() == Integer
+                                  .valueOf(httpPort))
+                  {
+                    Cache.debug(
+                            "AUTHENTICATOR returning PasswordAuthentication(\""
+                                    + httpUser + "\", '"
+                                    + new String(displayHttpPw) + "')");
+                    return new PasswordAuthentication(httpUser,
+                            httpPassword);
+                  }
+                  if (protocol.equalsIgnoreCase("https")
+                          && getRequestingHost().equalsIgnoreCase(httpsHost)
+                          && getRequestingPort() == Integer
+                                  .valueOf(httpsPort))
+                  {
+                    char[] displayHttpsPw = new char[httpPassword.length];
+                    Arrays.fill(displayHttpsPw, '*');
+                    Cache.debug(
+                            "AUTHENTICATOR returning PasswordAuthentication(\""
+                                    + httpsUser + "\", '" + displayHttpsPw
+                                    + "'");
+                    return new PasswordAuthentication(httpsUser,
+                            httpsPassword);
+                  }
+                } catch (NumberFormatException e)
+                {
+                  Cache.error("Problem with proxy port values [http:"
+                          + httpPort + ", https:" + httpsPort + "]");
+                }
+                Cache.debug(
+                        "AUTHENTICATOR after trying to get PasswordAuthentication");
+              }
+            }
+            // non proxy request
+            Cache.debug("AUTHENTICATOR returning null");
+            return null;
+          }
+        });
+        // required to re-enable basic authentication (should be okay for a
+        // local proxy)
+        Cache.debug(
+                "AUTHENTICATOR setting property 'jdk.http.auth.tunneling.disabledSchemes' to \"\"");
+        System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
+      } catch (SecurityException e)
+      {
+        Cache.error("Could not set default Authenticator");
+        Cache.debug(getStackTraceString(e));
+      }
+    }
+    else
+    {
+      // reset the Authenticator to protect http.proxyUser and
+      // http.proxyPassword Just In Case
+      /* as noted above, due to bug in java this doesn't work if the sun.net.www.protocol.http.AuthCache
+       * has working credentials. No workaround for Java 11.
+       */
+      Cache.debug("AUTHENTICATOR setting default Authenticator to null");
+      Authenticator.setDefault(null);
+    }
+
+    // nonProxyHosts not currently configurable in Preferences
+    Cache.debug("AUTHENTICATOR setting property 'http.nonProxyHosts' to \""
+            + nonProxyHosts + "\"");
+    setOrClearSystemProperty("http.nonProxyHosts", nonProxyHosts);
+  }
+
+  public static void setOrClearSystemProperty(String key, char[] value)
+  {
+    setOrClearSystemProperty(key,
+            (value == null) ? null : new String(value));
+  }
+
+  public static void setOrClearSystemProperty(String key, String value)
+  {
+    if (key == null)
+    {
+      return;
+    }
+    if (value == null)
+    {
+      System.clearProperty(key);
+    }
+    else
+    {
+      System.setProperty(key, value);
+    }
+  }
+
+  public final static int DEBUG = 10;
+
+  public final static int INFO = 20;
+
+  public final static int WARN = 30;
+
+  public final static int ERROR = 40;
+
+  public static boolean println(int level, String message)
+  {
+    if (Cache.log == null)
+    {
+      if (level >= ERROR)
+        System.err.println(message);
+      else
+        System.out.println(message);
+      return false;
+    }
+    if (level >= WARN)
+    {
+      Cache.log.warn(message);
+    }
+    else if (level >= INFO)
+    {
+      Cache.log.info(message);
+    }
+    else
+    {
+      Cache.log.debug(message);
+    }
+    return true;
+  }
+
+  public static void debug(String message)
+  {
+    println(DEBUG, message);
+  }
+
+  public static void info(String message)
+  {
+    println(INFO, message);
+  }
+
+  public static void warn(String message)
+  {
+    println(WARN, message);
+  }
+
+  public static void error(String message)
+  {
+    println(ERROR, message);
+  }
 }
index 021aad6..a49c04d 100755 (executable)
@@ -64,6 +64,7 @@ import jalview.io.NewickFile;
 import jalview.io.gff.SequenceOntologyFactory;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
+import jalview.util.HttpUtils;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.ws.jws2.Jws2Discoverer;
@@ -297,90 +298,7 @@ public class Jalview
 
     desktop = null;
 
-    // property laf = "crossplatform", "system", "gtk", "metal" or "mac"
-    // 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)
-    {
-    case "crossplatform":
-      lafSet = setCrossPlatformLookAndFeel();
-      if (!lafSet)
-      {
-        System.err.println("Could not set requested laf=" + laf);
-      }
-      break;
-    case "system":
-      lafSet = setSystemLookAndFeel();
-      if (!lafSet)
-      {
-        System.err.println("Could not set requested laf=" + laf);
-      }
-      break;
-    case "gtk":
-      lafSet = setGtkLookAndFeel();
-    {
-      System.err.println("Could not set requested laf=" + laf);
-    }
-      break;
-    case "metal":
-      lafSet = setMetalLookAndFeel();
-    {
-      System.err.println("Could not set requested laf=" + laf);
-    }
-      break;
-    case "nimbus":
-      lafSet = setNimbusLookAndFeel();
-    {
-      System.err.println("Could not set requested laf=" + laf);
-    }
-      break;
-    case "quaqua":
-      lafSet = setQuaquaLookAndFeel();
-    {
-      System.err.println("Could not set requested laf=" + laf);
-    }
-      break;
-    case "vaqua":
-      lafSet = setVaquaLookAndFeel();
-    {
-      System.err.println("Could not set requested laf=" + laf);
-    }
-      break;
-    case "mac":
-      lafSet = setMacLookAndFeel();
-      if (!lafSet)
-      {
-        System.err.println("Could not set requested laf=" + laf);
-      }
-      break;
-    case "none":
-      break;
-    default:
-      System.err.println("Requested laf=" + laf + " not implemented");
-    }
-    if (!lafSet)
-    {
-      setSystemLookAndFeel();
-      if (Platform.isLinux()) {
-        setMetalLookAndFeel();
-      }
-      if (Platform.isAMac())
-      {
-        setMacLookAndFeel();
-      }
-    }
+    setLookAndFeel();
 
     /*
      * configure 'full' SO model if preferences say to, else use the default (SO
@@ -402,14 +320,19 @@ public class Jalview
         JalviewTaskbar.setTaskbar(this);
       } catch (Exception e)
       {
-        System.out.println("Cannot set Taskbar");
+        Cache.log.info("Cannot set Taskbar");
+        Cache.log.error(e.getMessage());
         // e.printStackTrace();
       } catch (Throwable t)
       {
-        System.out.println("Cannot set Taskbar");
+        Cache.log.info("Cannot set Taskbar");
+        Cache.log.error(t.getMessage());
         // t.printStackTrace();
       }
 
+      // set Proxy settings before all the internet calls
+      Cache.setProxyPropertiesFromPreferences();
+
       desktop.setVisible(true);
       desktop.startServiceDiscovery();
       if (!aparser.contains("nousagestats"))
@@ -510,7 +433,7 @@ public class Jalview
       }
       System.out.println("CMD [-open " + file + "] executed successfully!");
 
-      if (!file.startsWith("http://"))
+      if (!HttpUtils.startsWithHttpOrHttps(file))
       {
         if (!(new File(file)).exists())
         {
@@ -801,6 +724,101 @@ public class Jalview
     }
   }
 
+  private static void setLookAndFeel()
+  {
+    // property laf = "crossplatform", "system", "gtk", "metal", "nimbus" or
+    // "mac"
+    // 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)
+    {
+    case "crossplatform":
+      lafSet = setCrossPlatformLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "system":
+      lafSet = setSystemLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "gtk":
+      lafSet = setGtkLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "metal":
+      lafSet = setMetalLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "nimbus":
+      lafSet = setNimbusLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "quaqua":
+      lafSet = setQuaquaLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "vaqua":
+      lafSet = setVaquaLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "mac":
+      lafSet = setMacLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "none":
+      break;
+    default:
+      Cache.log.error("Requested laf=" + laf + " not implemented");
+    }
+    if (!lafSet)
+    {
+      setSystemLookAndFeel();
+      if (Platform.isLinux())
+      {
+        setMetalLookAndFeel();
+      }
+      if (Platform.isAMac())
+      {
+        setMacLookAndFeel();
+      }
+    }
+  }
+
   private static boolean setCrossPlatformLookAndFeel()
   {
     boolean set = false;
@@ -811,8 +829,9 @@ public class Jalview
       set = true;
     } catch (Exception ex)
     {
-      System.err.println("Unexpected Look and Feel Exception");
-      ex.printStackTrace();
+      Cache.log.error("Unexpected Look and Feel Exception");
+      Cache.log.error(ex.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(ex));
     }
     return set;
   }
@@ -826,8 +845,9 @@ public class Jalview
       set = true;
     } catch (Exception ex)
     {
-      System.err.println("Unexpected Look and Feel Exception");
-      ex.printStackTrace();
+      Cache.log.error("Unexpected Look and Feel Exception");
+      Cache.log.error(ex.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(ex));
     }
     return set;
   }
@@ -853,8 +873,9 @@ public class Jalview
       set = true;
     } catch (Exception ex)
     {
-      System.err.println("Unexpected Look and Feel Exception");
-      ex.printStackTrace();
+      Cache.log.error("Unexpected Look and Feel Exception");
+      Cache.log.error(ex.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(ex));
     }
     return set;
   }
index d03b2c7..4582f4d 100644 (file)
  */
 package jalview.gui;
 
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+import java.beans.PropertyChangeEvent;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JEditorPane;
+import javax.swing.JInternalFrame;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.CrossRef;
@@ -90,7 +138,9 @@ import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemes;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
+import jalview.util.HttpUtils;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.ws.DBRefFetcher;
@@ -100,53 +150,6 @@ import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.StringSelection;
-import java.awt.datatransfer.Transferable;
-import java.awt.dnd.DnDConstants;
-import java.awt.dnd.DropTargetDragEvent;
-import java.awt.dnd.DropTargetDropEvent;
-import java.awt.dnd.DropTargetEvent;
-import java.awt.dnd.DropTargetListener;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseEvent;
-import java.awt.print.PageFormat;
-import java.awt.print.PrinterJob;
-import java.beans.PropertyChangeEvent;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.PrintWriter;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Vector;
-
-import javax.swing.ButtonGroup;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JEditorPane;
-import javax.swing.JInternalFrame;
-import javax.swing.JLayeredPane;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JScrollPane;
-import javax.swing.SwingUtilities;
-
 /**
  * DOCUMENT ME!
  * 
@@ -1035,7 +1038,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         Desktop.instance.closeAssociatedWindows();
 
         FileLoader loader = new FileLoader();
-        DataSourceType protocol = fileName.startsWith("http:")
+        DataSourceType protocol = HttpUtils.startsWithHttpOrHttps(fileName)
                 ? DataSourceType.URL
                 : DataSourceType.FILE;
         loader.LoadFile(viewport, fileName, protocol, currentFileFormat);
@@ -1045,7 +1048,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         Rectangle bounds = this.getBounds();
 
         FileLoader loader = new FileLoader();
-        DataSourceType protocol = fileName.startsWith("http:")
+        DataSourceType protocol = HttpUtils.startsWithHttpOrHttps(fileName)
                 ? DataSourceType.URL
                 : DataSourceType.FILE;
         AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName,
@@ -1092,7 +1095,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void save_actionPerformed(ActionEvent e)
   {
     if (fileName == null || (currentFileFormat == null)
-            || fileName.startsWith("http"))
+            || HttpUtils.startsWithHttpOrHttps(fileName))
     {
       saveAs_actionPerformed(null);
     }
@@ -1169,7 +1172,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
       statusBar.setText(MessageManager.formatMessage(
               "label.successfully_saved_to_file_in_format", new Object[]
-              { fileName, format }));
+              { file, format }));
 
     }
     else
@@ -1198,39 +1201,66 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       else
       {
         // create backupfiles object and get new temp filename destination
+        Cache.log.debug("ALIGNFRAME making backupfiles object for " + file);
         BackupFiles backupfiles = new BackupFiles(file);
 
         try
         {
-          PrintWriter out = new PrintWriter(
-                  new FileWriter(backupfiles.getTempFilePath()));
+          String tempFilePath = backupfiles.getTempFilePath();
+          Cache.log.debug(
+                  "ALIGNFRAME setting PrintWriter to " + tempFilePath);
+          PrintWriter out = new PrintWriter(new FileWriter(tempFilePath));
+
+          Cache.log.debug(
+                  "ALIGNFRAME about to write to temp file " + tempFilePath);
 
           out.print(output);
+          Cache.log.debug("ALIGNFRAME about to close file");
           out.close();
+          Cache.log.debug("ALIGNFRAME closed file");
           this.setTitle(file);
           statusBar.setText(MessageManager.formatMessage(
                   "label.successfully_saved_to_file_in_format", new Object[]
-                  { fileName, format.getName() }));
+                  { file, format.getName() }));
+        } catch (IOException e)
+        {
+          success = false;
+          Cache.log.error(
+                  "ALIGNFRAME Something happened writing the temp file");
+          Cache.log.error(e.getMessage());
+          Cache.log.debug(Cache.getStackTraceString(e));
+
         } catch (Exception ex)
         {
           success = false;
-          ex.printStackTrace();
+          Cache.log.error(
+                  "ALIGNFRAME Something else happened writing the temp file");
+          Cache.log.error(ex.getMessage());
+          Cache.log.debug(Cache.getStackTraceString(ex));
         }
 
         backupfiles.setWriteSuccess(success);
+        Cache.log.debug("ALIGNFRAME writing temp file was "
+                + (success ? "" : "NOT ") + "successful");
         // do the backup file roll and rename the temp file to actual file
+        Cache.log.debug("ALIGNFRAME about to rollBackupsAndRenameTempFile");
         success = backupfiles.rollBackupsAndRenameTempFile();
+        Cache.log.debug("ALIGNFRAME performed rollBackupsAndRenameTempFile "
+                + (success ? "" : "un") + "successfully");
 
       }
     }
 
     if (!success)
     {
-      JvOptionPane.showInternalMessageDialog(this, MessageManager
-              .formatMessage("label.couldnt_save_file", new Object[]
-              { fileName }),
-              MessageManager.getString("label.error_saving_file"),
-              JvOptionPane.WARNING_MESSAGE);
+      if (!Platform.isHeadless())
+      {
+        JvOptionPane.showInternalMessageDialog(this, MessageManager
+                .formatMessage("label.couldnt_save_file", new Object[]
+                { file }),
+                MessageManager.getString("label.error_saving_file"),
+                JvOptionPane.WARNING_MESSAGE);
+      }
     }
 
     return success;
@@ -2737,8 +2767,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (viewport.getViewName() == null)
     {
-      viewport.setViewName(MessageManager
-              .getString("label.view_name_original"));
+      viewport.setViewName(
+              MessageManager.getString("label.view_name_original"));
     }
 
     /*
@@ -3367,8 +3397,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
      * otherwise set the chosen colour scheme (or null for 'None')
      */
     ColourSchemeI cs = ColourSchemes.getInstance().getColourScheme(name,
-            viewport,
-            viewport.getAlignment(), viewport.getHiddenRepSequences());
+            viewport, viewport.getAlignment(),
+            viewport.getHiddenRepSequences());
     changeColour(cs);
   }
 
@@ -5695,6 +5725,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   private Rectangle lastFeatureSettingsBounds = null;
+
   @Override
   public void setFeatureSettingsGeometry(Rectangle bounds)
   {
index 4c019a6..a493640 100644 (file)
  */
 package jalview.gui;
 
-import jalview.util.MessageManager;
-
 import java.awt.BorderLayout;
+import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.GraphicsEnvironment;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
 import java.awt.Rectangle;
 import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.awt.event.WindowListener;
@@ -38,12 +43,19 @@ import java.io.PipedOutputStream;
 import java.io.PrintStream;
 
 import javax.swing.JButton;
+import javax.swing.JComboBox;
 import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
 
+import org.apache.log4j.Level;
 import org.apache.log4j.SimpleLayout;
 
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+
 /**
  * Simple Jalview Java Console. Version 1 - allows viewing of console output
  * after desktop is created. Acquired with thanks from RJHM's site
@@ -88,6 +100,8 @@ public class Console extends WindowAdapter
 
   private int MIN_HEIGHT = 250;
 
+  private JComboBox logLevelCombo = new JComboBox();
+
   public Console()
   {
     // create all components and add them
@@ -115,17 +129,104 @@ public class Console extends WindowAdapter
     // textArea = cpt.getTextArea();
     textArea = new JTextArea();
     textArea.setEditable(false);
-    JButton button = new JButton(MessageManager.getString("action.clear"));
+    JButton clearButton = new JButton(
+            MessageManager.getString("action.clear"));
+    JButton copyToClipboardButton = new JButton(
+            MessageManager.getString("label.copy_to_clipboard"));
+    copyToClipboardButton.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        copyConsoleTextToClipboard();
+      }
+    });
+    copyToClipboardButton.addMouseListener(new MouseAdapter()
+    {
+      private Color bg = textArea.getBackground();
+
+      private Color fg = textArea.getForeground();
+
+      public void mousePressed(MouseEvent e)
+      {
+        textArea.setBackground(textArea.getSelectionColor());
+        textArea.setForeground(textArea.getSelectedTextColor());
+      }
+
+      public void mouseReleased(MouseEvent e)
+      {
+        textArea.setBackground(bg);
+        textArea.setForeground(fg);
+      }
+
+    });
+    copyToClipboardButton.setToolTipText(
+            MessageManager.getString("label.copy_to_clipboard_tooltip"));
+
+    JLabel logLevelLabel = new JLabel(
+            MessageManager.getString("label.log_level") + ":");
+
+    // logLevelCombo.addItem(Level.ALL);
+    logLevelCombo.addItem(Level.TRACE);
+    logLevelCombo.addItem(Level.DEBUG);
+    logLevelCombo.addItem(Level.INFO);
+    logLevelCombo.addItem(Level.WARN);
+    // logLevelCombo.addItem(Level.ERROR);
+    // logLevelCombo.addItem(Level.FATAL);
+    // logLevelCombo.addItem(Level.OFF);
+    setChosenLogLevelCombo();
+    logLevelCombo.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        if (Cache.log != null)
+        {
+          Cache.log.setLevel((Level) logLevelCombo.getSelectedItem());
+        }
+      }
+
+    });
 
     // frame = cpt;
     frame.getContentPane().setLayout(new BorderLayout());
     frame.getContentPane().add(new JScrollPane(textArea),
             BorderLayout.CENTER);
-    frame.getContentPane().add(button, BorderLayout.SOUTH);
+    JPanel southPanel = new JPanel();
+    southPanel.setLayout(new GridBagLayout());
+
+    JPanel logLevelPanel = new JPanel();
+    logLevelPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
+    logLevelPanel.add(logLevelLabel);
+    logLevelPanel.add(logLevelCombo);
+    logLevelLabel.setToolTipText(
+            MessageManager.getString("label.log_level_tooltip"));
+    logLevelCombo.setToolTipText(
+            MessageManager.getString("label.log_level_tooltip"));
+
+    GridBagConstraints gbc = new GridBagConstraints();
+    gbc.gridx = 0;
+    gbc.gridy = 0;
+    gbc.gridwidth = 1;
+    gbc.gridheight = 1;
+    gbc.weightx = 0.1;
+    southPanel.add(logLevelPanel, gbc);
+
+    gbc.gridx++;
+    gbc.weightx = 0.8;
+    gbc.fill = GridBagConstraints.HORIZONTAL;
+    southPanel.add(clearButton, gbc);
+
+    gbc.gridx++;
+    gbc.weightx = 0.1;
+    gbc.fill = GridBagConstraints.NONE;
+    southPanel.add(copyToClipboardButton, gbc);
+
+    southPanel.setVisible(true);
+    frame.getContentPane().add(southPanel, BorderLayout.SOUTH);
     frame.setVisible(visible);
     updateConsole = visible;
     frame.addWindowListener(this);
-    button.addActionListener(this);
+    clearButton.addActionListener(this);
+
     if (redirect)
     {
       redirectStreams();
@@ -151,6 +252,50 @@ public class Console extends WindowAdapter
     textAppender.start();
   }
 
+  private void setChosenLogLevelCombo()
+  {
+    Level currentLogLevel = Cache.log == null ? Level.INFO
+            : Cache.log.getLevel();
+    logLevelCombo.setSelectedItem(currentLogLevel);
+    if (!logLevelCombo.getSelectedItem().equals(currentLogLevel)) // currentLogLevel
+                                                                  // not in list
+    {
+      if (currentLogLevel != null && currentLogLevel instanceof Level)
+      {
+        // add new item to list (might be set via .jalview_properties)
+        boolean added = false;
+        for (int i = 0; i < logLevelCombo.getItemCount(); i++)
+        {
+          Level l = (Level) logLevelCombo.getItemAt(i);
+          if (l.isGreaterOrEqual(currentLogLevel))
+          {
+            logLevelCombo.insertItemAt(currentLogLevel, i);
+            added = true;
+            break;
+          }
+        }
+        if (!added) // lower priority than others or some confusion -- add to
+                    // end of list
+        {
+          logLevelCombo.addItem(currentLogLevel);
+        }
+        logLevelCombo.setSelectedItem(currentLogLevel);
+      }
+      else
+      {
+        logLevelCombo.setSelectedItem(Level.INFO);
+      }
+    }
+  }
+
+  private void copyConsoleTextToClipboard()
+  {
+    String consoleText = textArea.getText();
+    StringSelection consoleTextSelection = new StringSelection(consoleText);
+    Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
+    cb.setContents(consoleTextSelection, null);
+  }
+
   PipedOutputStream pout = null, perr = null;
 
   public void redirectStreams()
@@ -644,12 +789,21 @@ public class Console extends WindowAdapter
     frame.setVisible(selected);
     if (selected == true)
     {
+      setChosenLogLevelCombo();
       redirectStreams();
       updateConsole = true;
       frame.toFront();
     }
     else
     {
+      // reset log level to user preference
+      if (Cache.log != null)
+      {
+        String userLogLevel = Cache.getDefault("logs.Jalview.level",
+                Level.INFO.toString());
+        Cache.log.setLevel(Level.toLevel(userLogLevel));
+      }
+
       unredirectStreams();
       updateConsole = false;
     }
index 7564dda..79a9e24 100644 (file)
  */
 package jalview.gui;
 
-import jalview.api.AlignViewportI;
-import jalview.api.AlignmentViewPanel;
-import jalview.bin.Cache;
-import jalview.bin.Jalview;
-import jalview.io.BackupFiles;
-import jalview.io.DataSourceType;
-import jalview.io.FileFormat;
-import jalview.io.FileFormatException;
-import jalview.io.FileFormatI;
-import jalview.io.FileFormats;
-import jalview.io.FileLoader;
-import jalview.io.FormatAdapter;
-import jalview.io.IdentifyFile;
-import jalview.io.JalviewFileChooser;
-import jalview.io.JalviewFileView;
-import jalview.jbgui.GSplitFrame;
-import jalview.jbgui.GStructureViewer;
-import jalview.project.Jalview2XML;
-import jalview.structure.StructureSelectionManager;
-import jalview.urls.IdOrgSettings;
-import jalview.util.ImageMaker;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.util.UrlConstants;
-import jalview.viewmodel.AlignmentViewport;
-import jalview.ws.params.ParamManager;
-import jalview.ws.utils.UrlDownloadClient;
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
@@ -120,6 +92,34 @@ import javax.swing.event.InternalFrameEvent;
 
 import org.stackoverflowusers.file.WindowsShortcut;
 
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
+import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.io.BackupFiles;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileFormatException;
+import jalview.io.FileFormatI;
+import jalview.io.FileFormats;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
+import jalview.io.IdentifyFile;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
+import jalview.jbgui.GSplitFrame;
+import jalview.jbgui.GStructureViewer;
+import jalview.project.Jalview2XML;
+import jalview.structure.StructureSelectionManager;
+import jalview.urls.IdOrgSettings;
+import jalview.util.ImageMaker;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.util.UrlConstants;
+import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.params.ParamManager;
+import jalview.ws.utils.UrlDownloadClient;
+
 /**
  * Jalview Desktop
  * 
@@ -369,7 +369,6 @@ public class Desktop extends jalview.jbgui.GDesktop
       // t.printStackTrace();
     }
 
-
     addWindowListener(new WindowAdapter()
     {
 
@@ -956,7 +955,8 @@ public class Desktop extends jalview.jbgui.GDesktop
     KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
             InputEvent.CTRL_DOWN_MASK);
     KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
-            jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
+            jalview.util.ShortcutKeyMaskExWrapper
+                    .getMenuShortcutKeyMaskEx());
 
     InputMap inputMap = frame
             .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
@@ -1069,8 +1069,9 @@ public class Desktop extends jalview.jbgui.GDesktop
   public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
   {
     String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
-    JalviewFileChooser chooser = JalviewFileChooser
-            .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, BackupFiles.getEnabled());
+    JalviewFileChooser chooser = JalviewFileChooser.forRead(
+            Cache.getProperty("LAST_DIRECTORY"), fileFormat,
+            BackupFiles.getEnabled());
 
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
@@ -1577,7 +1578,7 @@ public class Desktop extends jalview.jbgui.GDesktop
   @Override
   protected void preferences_actionPerformed(ActionEvent e)
   {
-    new Preferences();
+    Preferences.openPreferences();
   }
 
   /**
@@ -1695,8 +1696,10 @@ public class Desktop extends jalview.jbgui.GDesktop
         "Jalview Project (old)" };
     JalviewFileChooser chooser = new JalviewFileChooser(
             Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
-            "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
-                                            // allowBackupFiles
+            "Jalview Project", true, BackupFiles.getEnabled()); // last two
+                                                                // booleans:
+                                                                // allFiles,
+    // allowBackupFiles
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
 
@@ -1925,9 +1928,7 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     // FIXME: ideally should use UI interface API
     FeatureSettings viewFeatureSettings = (af.featureSettings != null
-            && af.featureSettings.isOpen())
-            ? af.featureSettings
-            : null;
+            && af.featureSettings.isOpen()) ? af.featureSettings : null;
     Rectangle fsBounds = af.getFeatureSettingsGeometry();
     for (int i = 0; i < size; i++)
     {
@@ -1960,7 +1961,8 @@ public class Desktop extends jalview.jbgui.GDesktop
 
       addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
               AlignFrame.DEFAULT_HEIGHT);
-      // and materialise a new feature settings dialog instance for the new alignframe
+      // and materialise a new feature settings dialog instance for the new
+      // alignframe
       // (closes the old as if 'OK' was pressed)
       if (ap == af.alignPanel && newaf.featureSettings != null
               && newaf.featureSettings.isOpen()
@@ -2031,8 +2033,7 @@ public class Desktop extends jalview.jbgui.GDesktop
       }
     }
     // refresh the feature setting UI for the source frame if it exists
-    if (source.featureSettings != null
-            && source.featureSettings.isOpen())
+    if (source.featureSettings != null && source.featureSettings.isOpen())
     {
       source.showFeatureSettingsUI();
     }
@@ -2386,9 +2387,12 @@ public class Desktop extends jalview.jbgui.GDesktop
    */
   protected void addQuitHandler()
   {
-    getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
-            .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
-                    jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
+    getRootPane()
+            .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+                    KeyStroke
+                            .getKeyStroke(KeyEvent.VK_Q,
+                                    jalview.util.ShortcutKeyMaskExWrapper
+                                            .getMenuShortcutKeyMaskEx()),
                     "Quit");
     getRootPane().getActionMap().put("Quit", new AbstractAction()
     {
index 1f61bae..984d4e9 100755 (executable)
  */
 package jalview.gui;
 
-import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
-import jalview.bin.Cache;
-import jalview.gui.Help.HelpId;
-import jalview.gui.StructureViewer.ViewerType;
-import jalview.io.BackupFiles;
-import jalview.io.BackupFilesPresetEntry;
-import jalview.io.FileFormatI;
-import jalview.io.JalviewFileChooser;
-import jalview.io.JalviewFileView;
-import jalview.jbgui.GPreferences;
-import jalview.jbgui.GSequenceLink;
-import jalview.schemes.ColourSchemeI;
-import jalview.schemes.ColourSchemes;
-import jalview.schemes.ResidueColourScheme;
-import jalview.urls.UrlLinkTableModel;
-import jalview.urls.api.UrlProviderFactoryI;
-import jalview.urls.api.UrlProviderI;
-import jalview.urls.desktop.DesktopUrlProviderFactory;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.util.UrlConstants;
-import jalview.ws.sifts.SiftsSettings;
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
@@ -74,6 +51,28 @@ import javax.swing.table.TableModel;
 import javax.swing.table.TableRowSorter;
 
 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
+import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
+import jalview.bin.Cache;
+import jalview.gui.Help.HelpId;
+import jalview.gui.StructureViewer.ViewerType;
+import jalview.io.BackupFiles;
+import jalview.io.BackupFilesPresetEntry;
+import jalview.io.FileFormatI;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
+import jalview.jbgui.GPreferences;
+import jalview.jbgui.GSequenceLink;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemes;
+import jalview.schemes.ResidueColourScheme;
+import jalview.urls.UrlLinkTableModel;
+import jalview.urls.api.UrlProviderFactoryI;
+import jalview.urls.api.UrlProviderI;
+import jalview.urls.desktop.DesktopUrlProviderFactory;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.util.UrlConstants;
+import jalview.ws.sifts.SiftsSettings;
 
 /**
  * DOCUMENT ME!
@@ -81,6 +80,10 @@ import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
  * @author $author$
  * @version $Revision$
  */
+/*
+ * for merge with Jalview-JS
+ public class Preferences extends GPreferences implements ApplicationSingletonI
+ */
 public class Preferences extends GPreferences
 {
   public static final String ENABLE_SPLIT_FRAME = "ENABLE_SPLIT_FRAME";
@@ -123,6 +126,10 @@ public class Preferences extends GPreferences
 
   private static final int MAX_FONT_SIZE = 30;
 
+  private String previousProxyType;
+
+  private static Preferences INSTANCE = null; // add "final"
+
   /**
    * Holds name and link separated with | character. Sequence ID must be
    * $SEQUENCE_ID$ or $SEQUENCE_ID=/.possible | chars ./=$
@@ -182,10 +189,48 @@ public class Preferences extends GPreferences
   private OptionsParam textOpt = new OptionsParam(
           MessageManager.getString("action.text"), "Text");
 
+  // get singleton Preferences instance
+  public static Preferences getInstance()
+  {
+    if (INSTANCE == null || INSTANCE.frame == null
+            || INSTANCE.frame.isClosed())
+    {
+      INSTANCE = new Preferences();
+    }
+    return INSTANCE;
+
+    /*
+     * Replace code with the following for Jalvew-JS
+    Preferences INSTANCE = ApplicationSingletonProvider.getInstance(Preferences.class);
+    if (INSTANCE == null || INSTANCE.frame == null
+            || INSTANCE.frame.isClosed())
+    {
+      ApplicationSingletonProvider.remove(Preferences.class);
+      INSTANCE = ApplicationSingletonProvider.getInstance(Preferences.class);
+    }
+    return INSTANCE;
+    */
+  }
+
+  public static void openPreferences()
+  {
+    openPreferences(0, null);
+  }
+
+  public static void openPreferences(int selectTab, String message)
+  {
+    Preferences p = getInstance();
+    p.selectTab(selectTab);
+    p.setMessage(message);
+    p.frame.show();
+    p.frame.moveToFront();
+    p.frame.grabFocus();
+  }
+
   /**
    * Creates a new Preferences object.
    */
-  public Preferences()
+  private Preferences()
   {
     super();
     frame = new JInternalFrame();
@@ -317,12 +362,10 @@ public class Preferences extends GPreferences
     /*
      * Set overview panel defaults
      */
-    gapColour.setBackground(
-            Cache.getDefaultColour(GAP_COLOUR,
-                    jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP));
-    hiddenColour.setBackground(
-            Cache.getDefaultColour(HIDDEN_COLOUR,
-                    jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_HIDDEN));
+    gapColour.setBackground(Cache.getDefaultColour(GAP_COLOUR,
+            jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP));
+    hiddenColour.setBackground(Cache.getDefaultColour(HIDDEN_COLOUR,
+            jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_HIDDEN));
     useLegacyGap.setSelected(Cache.getDefault(USE_LEGACY_GAP, false));
     gapLabel.setEnabled(!useLegacyGap.isSelected());
     gapColour.setEnabled(!useLegacyGap.isSelected());
@@ -487,10 +530,36 @@ public class Preferences extends GPreferences
       }
     }
 
-    useProxy.setSelected(Cache.getDefault("USE_PROXY", false));
-    useProxy_actionPerformed(); // make sure useProxy is correctly initialised
-    proxyServerTB.setText(Cache.getDefault("PROXY_SERVER", ""));
-    proxyPortTB.setText(Cache.getDefault("PROXY_PORT", ""));
+    String proxyTypeString = Cache.getDefault("USE_PROXY", "false");
+    previousProxyType = proxyTypeString;
+    switch (proxyTypeString)
+    {
+    case Cache.PROXYTYPE_NONE:
+      proxyType.setSelected(noProxy.getModel(), true);
+      break;
+    case Cache.PROXYTYPE_SYSTEM:
+      proxyType.setSelected(systemProxy.getModel(), true);
+      break;
+    case Cache.PROXYTYPE_CUSTOM:
+      proxyType.setSelected(customProxy.getModel(), true);
+      break;
+    default:
+      Cache.log.warn(
+              "Incorrect PROXY_TYPE - should be 'none' (clear proxy properties), 'false' (system settings), 'true' (custom settings): "
+                      + proxyTypeString);
+    }
+    proxyServerHttpTB.setText(Cache.getDefault("PROXY_SERVER", ""));
+    proxyPortHttpTB.setText(Cache.getDefault("PROXY_PORT", ""));
+    proxyServerHttpsTB.setText(Cache.getDefault("PROXY_SERVER_HTTPS", ""));
+    proxyPortHttpsTB.setText(Cache.getDefault("PROXY_PORT_HTTPS", ""));
+    proxyAuth.setSelected(Cache.getDefault("PROXY_AUTH", false));
+    proxyAuthUsernameTB
+            .setText(Cache.getDefault("PROXY_AUTH_USERNAME", ""));
+    // we are not storing or retrieving proxy password from .jalview_properties
+    proxyAuthPasswordPB.setText(Cache.proxyAuthPassword == null ? ""
+            : new String(Cache.proxyAuthPassword));
+    setCustomProxyEnabled();
+    applyProxyButtonEnabled(false);
 
     defaultBrowser.setText(Cache.getDefault("DEFAULT_BROWSER", ""));
 
@@ -548,8 +617,7 @@ public class Preferences extends GPreferences
 
     annotations_actionPerformed(null); // update the display of the annotation
                                        // settings
-    
-    
+
     /*
      * Set Backups tab defaults
      */
@@ -570,6 +638,11 @@ public class Preferences extends GPreferences
       return;
     }
 
+    /* 
+     * Set proxy settings first (to be before web services refresh)
+     */
+    saveProxySettings();
+
     /*
      * Save Visual settings
      */
@@ -696,6 +769,8 @@ public class Preferences extends GPreferences
     /*
      * Save Connections settings
      */
+    // Proxy settings set first (to catch web services)
+
     Cache.setOrRemove("DEFAULT_BROWSER", defaultBrowser.getText());
 
     jalview.util.BrowserLauncher.resetBrowser();
@@ -726,23 +801,6 @@ public class Preferences extends GPreferences
     Cache.applicationProperties.setProperty("DEFAULT_URL",
             sequenceUrlLinks.getPrimaryUrlId());
 
-    Cache.applicationProperties.setProperty("USE_PROXY",
-            Boolean.toString(useProxy.isSelected()));
-
-    Cache.setOrRemove("PROXY_SERVER", proxyServerTB.getText());
-
-    Cache.setOrRemove("PROXY_PORT", proxyPortTB.getText());
-
-    if (useProxy.isSelected())
-    {
-      System.setProperty("http.proxyHost", proxyServerTB.getText());
-      System.setProperty("http.proxyPort", proxyPortTB.getText());
-    }
-    else
-    {
-      System.setProperty("http.proxyHost", "");
-      System.setProperty("http.proxyPort", "");
-    }
     Cache.setProperty("VERSION_CHECK",
             Boolean.toString(versioncheck.isSelected()));
     if (Cache.getProperty("USAGESTATS") != null || usagestats.isSelected())
@@ -809,16 +867,16 @@ public class Preferences extends GPreferences
     Cache.applicationProperties.setProperty(BackupFiles.ENABLED,
             Boolean.toString(enableBackupFiles.isSelected()));
     int preset = getComboIntStringKey(backupfilesPresetsCombo);
-    Cache.applicationProperties.setProperty(BackupFiles.NS + "_PRESET", Integer.toString(preset));
+    Cache.applicationProperties.setProperty(BackupFiles.NS + "_PRESET",
+            Integer.toString(preset));
 
     if (preset == BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM)
     {
       BackupFilesPresetEntry customBFPE = getBackupfilesCurrentEntry();
       BackupFilesPresetEntry.backupfilesPresetEntriesValues.put(
               BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM, customBFPE);
-      Cache.applicationProperties
-              .setProperty(BackupFilesPresetEntry.CUSTOMCONFIG,
-                      customBFPE.toString());
+      Cache.applicationProperties.setProperty(
+              BackupFilesPresetEntry.CUSTOMCONFIG, customBFPE.toString());
     }
 
     BackupFilesPresetEntry savedBFPE = BackupFilesPresetEntry.backupfilesPresetEntriesValues
@@ -836,6 +894,30 @@ public class Preferences extends GPreferences
     }
   }
 
+  public void saveProxySettings()
+  {
+    String newProxyType = customProxy.isSelected() ? Cache.PROXYTYPE_CUSTOM
+            : noProxy.isSelected() ? Cache.PROXYTYPE_NONE
+                    : Cache.PROXYTYPE_SYSTEM;
+    Cache.applicationProperties.setProperty("USE_PROXY", newProxyType);
+    Cache.setOrRemove("PROXY_SERVER", proxyServerHttpTB.getText());
+    Cache.setOrRemove("PROXY_PORT", proxyPortHttpTB.getText());
+    Cache.setOrRemove("PROXY_SERVER_HTTPS", proxyServerHttpsTB.getText());
+    Cache.setOrRemove("PROXY_PORT_HTTPS", proxyPortHttpsTB.getText());
+    Cache.setOrRemove("PROXY_AUTH",
+            Boolean.toString(proxyAuth.isSelected()));
+    Cache.setOrRemove("PROXY_AUTH_USERNAME", proxyAuthUsernameTB.getText());
+    Cache.proxyAuthPassword = proxyAuthPasswordPB.getPassword();
+    Cache.setProxyPropertiesFromPreferences(previousProxyType);
+    if (newProxyType.equals(Cache.PROXYTYPE_CUSTOM)
+            || !newProxyType.equals(previousProxyType))
+    {
+      // force a re-lookup of ws if proxytype is custom or has changed
+      wsPrefs.update++;
+    }
+    previousProxyType = newProxyType;
+  }
+
   /**
    * Do any necessary validation before saving settings. Return focus to the
    * first tab which fails validation.
@@ -1349,4 +1431,5 @@ public class Preferences extends GPreferences
       }
     }
   }
+
 }
index 5186a26..e37f77c 100644 (file)
  */
 package jalview.gui;
 
-import jalview.bin.Cache;
-import jalview.jbgui.GWsPreferences;
-import jalview.util.MessageManager;
-import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.rest.RestServiceDescription;
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
@@ -37,13 +31,18 @@ import java.util.List;
 import java.util.Vector;
 
 import javax.swing.JLabel;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JTable;
 import javax.swing.JTextField;
 import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableCellRenderer;
 
+import jalview.bin.Cache;
+import jalview.jbgui.GWsPreferences;
+import jalview.util.MessageManager;
+import jalview.ws.jws2.Jws2Discoverer;
+import jalview.ws.rest.RestServiceDescription;
+
 public class WsPreferences extends GWsPreferences
 {
 
@@ -634,7 +633,9 @@ public class WsPreferences extends GWsPreferences
   /**
    * state counters for ensuring that updates only happen if config has changed.
    */
-  private long update = 0, lastrefresh = 0;
+  protected long update = 0;
+
+  private long lastrefresh = 0;
 
   /*
    * (non-Javadoc)
index 0150579..ef966c4 100644 (file)
  */
 package jalview.io;
 
-import jalview.bin.Cache;
-import jalview.gui.Desktop;
-import jalview.gui.JvOptionPane;
-import jalview.util.MessageManager;
-
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.TreeMap;
 
+import jalview.bin.Cache;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
 /*
  * BackupFiles used for manipulating (naming rolling/deleting) backup/version files when an alignment or project file is saved.
  * User configurable options are:
@@ -95,6 +100,10 @@ public class BackupFiles
   private static final SimpleDateFormat sdf = new SimpleDateFormat(
           "yyyy-MM-dd HH:mm:ss");
 
+  private static final String newTempFileSuffix = "_newfile";
+
+  private static final String oldTempFileSuffix = "_oldfile_tobedeleted";
+
   public BackupFiles(String filename)
   {
     this(new File(filename));
@@ -106,7 +115,8 @@ public class BackupFiles
   {
     classInit();
     this.file = file;
-    BackupFilesPresetEntry bfpe = BackupFilesPresetEntry.getSavedBackupEntry();
+    BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
+            .getSavedBackupEntry();
     this.suffix = bfpe.suffix;
     this.noMax = bfpe.keepAll;
     this.max = bfpe.rollMax;
@@ -121,30 +131,46 @@ public class BackupFiles
       {
         String tempfilename = file.getName();
         File tempdir = file.getParentFile();
-        temp = File.createTempFile(tempfilename, TEMP_FILE_EXT + "_newfile",
-                tempdir);
+        Cache.debug(
+                "BACKUPFILES [file!=null] attempting to create temp file for "
+                        + tempfilename + " in dir " + tempdir);
+        temp = File.createTempFile(tempfilename,
+                TEMP_FILE_EXT + newTempFileSuffix, tempdir);
+        Cache.debug(
+                "BACKUPFILES using temp file " + temp.getAbsolutePath());
       }
       else
       {
+        Cache.debug(
+                "BACKUPFILES [file==null] attempting to create default temp file "
+                        + DEFAULT_TEMP_FILE + " with extension "
+                        + TEMP_FILE_EXT);
         temp = File.createTempFile(DEFAULT_TEMP_FILE, TEMP_FILE_EXT);
       }
     } catch (IOException e)
     {
-      System.out.println(
-              "Could not create temp file to save into (IOException)");
+      Cache.error("Could not create temp file to save to (IOException)");
+      Cache.error(e.getMessage());
+      Cache.debug(Cache.getStackTraceString(e));
     } catch (Exception e)
     {
-      System.out.println("Exception ctreating temp file for saving");
+      Cache.error("Exception ctreating temp file for saving");
+      Cache.debug(Cache.getStackTraceString(e));
     }
     this.setTempFile(temp);
   }
 
   public static void classInit()
   {
-    setEnabled(Cache.getDefault(ENABLED, true));
+    Cache.debug("BACKUPFILES classInit");
+    boolean e = Cache.getDefault(ENABLED, true);
+    setEnabled(e);
+    Cache.debug("BACKUPFILES " + (e ? "enabled" : "disabled"));
     BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
             .getSavedBackupEntry();
+    Cache.debug("BACKUPFILES preset scheme " + bfpe.toString());
     setConfirmDelete(bfpe.confirmDelete);
+    Cache.debug("BACKUPFILES confirm delete " + bfpe.confirmDelete);
   }
 
   public static void setEnabled(boolean flag)
@@ -188,9 +214,9 @@ public class BackupFiles
       path = this.getTempFile().getCanonicalPath();
     } catch (IOException e)
     {
-      System.out.println(
-              "IOException when getting Canonical Path of temp file '"
-                      + this.getTempFile().getName() + "'");
+      Cache.error("IOException when getting Canonical Path of temp file '"
+              + this.getTempFile().getName() + "'");
+      Cache.debug(Cache.getStackTraceString(e));
     }
     return path;
   }
@@ -209,7 +235,7 @@ public class BackupFiles
 
   public boolean renameTempFile()
   {
-    return tempFile.renameTo(file);
+    return moveFileToFile(tempFile, file);
   }
 
   // roll the backupfiles
@@ -226,24 +252,34 @@ public class BackupFiles
             || suffix.length() == 0)
     {
       // nothing to do
+      Cache.debug("BACKUPFILES rollBackupFiles nothing to do." + ", "
+              + "filename: " + (file != null ? file.getName() : "null")
+              + ", " + "file exists: " + file.exists() + ", " + "enabled: "
+              + enabled + ", " + "max: " + max + ", " + "suffix: '" + suffix
+              + "'");
       return true;
     }
 
+    Cache.debug("BACKUPFILES rollBackupFiles starting");
+
     String dir = "";
     File dirFile;
     try
     {
       dirFile = file.getParentFile();
       dir = dirFile.getCanonicalPath();
+      Cache.debug("BACKUPFILES dir: " + dir);
     } catch (Exception e)
     {
-      System.out.println(
-              "Could not get canonical path for file '" + file + "'");
+      Cache.error("Could not get canonical path for file '" + file + "'");
+      Cache.error(e.getMessage());
+      Cache.debug(Cache.getStackTraceString(e));
       return false;
     }
     String filename = file.getName();
     String basename = filename;
 
+    Cache.debug("BACKUPFILES filename is " + filename);
     boolean ret = true;
     // Create/move backups up one
 
@@ -255,9 +291,12 @@ public class BackupFiles
     File[] backupFiles = dirFile.listFiles(bff);
     int nextIndexNum = 0;
 
+    Cache.debug("BACKUPFILES backupFiles.length: " + backupFiles.length);
     if (backupFiles.length == 0)
     {
       // No other backup files. Just need to move existing file to backupfile_1
+      Cache.debug(
+              "BACKUPFILES no existing backup files, setting index to 1");
       nextIndexNum = 1;
     }
     else
@@ -270,7 +309,7 @@ public class BackupFiles
       if (reverseOrder)
       {
         // backup style numbering
-
+        Cache.debug("BACKUPFILES rolling files in reverse order");
 
         int tempMax = noMax ? -1 : max;
         // noMax == true means no limits
@@ -287,7 +326,7 @@ public class BackupFiles
             tempMax = i;
           }
         }
-        
+
         File previousFile = null;
         File fileToBeDeleted = null;
         for (int n = tempMax; n > 0; n--)
@@ -302,6 +341,7 @@ public class BackupFiles
             // no "oldest" file to delete
             previousFile = backupfile_n;
             fileToBeDeleted = null;
+            Cache.debug("BACKUPFILES No oldest file to delete");
             continue;
           }
 
@@ -312,19 +352,23 @@ public class BackupFiles
             File replacementFile = backupfile_n;
             long fileToBeDeletedLMT = fileToBeDeleted.lastModified();
             long replacementFileLMT = replacementFile.lastModified();
+            Cache.debug("BACKUPFILES fileToBeDeleted is "
+                    + fileToBeDeleted.getAbsolutePath());
+            Cache.debug("BACKUPFILES replacementFile is "
+                    + backupfile_n.getAbsolutePath());
 
             try
             {
               File oldestTempFile = nextTempFile(fileToBeDeleted.getName(),
                       dirFile);
-              
+
               if (fileToBeDeletedLMT > replacementFileLMT)
               {
                 String fileToBeDeletedLMTString = sdf
                         .format(fileToBeDeletedLMT);
                 String replacementFileLMTString = sdf
                         .format(replacementFileLMT);
-                System.out.println("WARNING! I am set to delete backupfile "
+                Cache.warn("WARNING! I am set to delete backupfile "
                         + fileToBeDeleted.getName()
                         + " has modification time "
                         + fileToBeDeletedLMTString
@@ -335,6 +379,11 @@ public class BackupFiles
 
                 boolean delete = confirmNewerDeleteFile(fileToBeDeleted,
                         replacementFile, true);
+                Cache.debug("BACKUPFILES " + (delete ? "confirmed" : "not")
+                        + " deleting file "
+                        + fileToBeDeleted.getAbsolutePath()
+                        + " which is newer than "
+                        + replacementFile.getAbsolutePath());
 
                 if (delete)
                 {
@@ -343,21 +392,27 @@ public class BackupFiles
                 }
                 else
                 {
-                  fileToBeDeleted.renameTo(oldestTempFile);
+                  Cache.debug("BACKUPFILES moving "
+                          + fileToBeDeleted.getAbsolutePath() + " to "
+                          + oldestTempFile.getAbsolutePath());
+                  moveFileToFile(fileToBeDeleted, oldestTempFile);
                 }
               }
               else
               {
-                fileToBeDeleted.renameTo(oldestTempFile);
+                Cache.debug("BACKUPFILES going to move "
+                        + fileToBeDeleted.getAbsolutePath() + " to "
+                        + oldestTempFile.getAbsolutePath());
+                moveFileToFile(fileToBeDeleted, oldestTempFile);
                 addDeleteFile(oldestTempFile);
               }
 
             } catch (Exception e)
             {
-              System.out.println(
+              Cache.error(
                       "Error occurred, probably making new temp file for '"
                               + fileToBeDeleted.getName() + "'");
-              e.printStackTrace();
+              Cache.error(Cache.getStackTraceString(e));
             }
 
             // reset
@@ -372,7 +427,9 @@ public class BackupFiles
           {
             if (previousFile != null)
             {
-              ret = ret && backupfile_n.renameTo(previousFile);
+              // using boolean '&' instead of '&&' as don't want moveFileToFile
+              // attempt to be conditional (short-circuit)
+              ret = ret & moveFileToFile(backupfile_n, previousFile);
             }
           }
 
@@ -382,19 +439,37 @@ public class BackupFiles
         // index to use for the latest backup
         nextIndexNum = 1;
       }
-      else
+      else // not reverse numbering
       {
         // version style numbering (with earliest file deletion if max files
         // reached)
 
         bfTreeMap.values().toArray(backupFiles);
+        StringBuilder bfsb = new StringBuilder();
+        for (int i = 0; i < backupFiles.length; i++)
+        {
+          if (bfsb.length() > 0)
+          {
+            bfsb.append(", ");
+          }
+          bfsb.append(backupFiles[i].getName());
+        }
+        Cache.debug("BACKUPFILES backupFiles: " + bfsb.toString());
 
         // noMax == true means keep all backup files
         if ((!noMax) && bfTreeMap.size() >= max)
         {
+          Cache.debug("BACKUPFILES noMax: " + noMax + ", " + "max: " + max
+                  + ", " + "bfTreeMap.size(): " + bfTreeMap.size());
           // need to delete some files to keep number of backups to designated
-          // max
-          int numToDelete = bfTreeMap.size() - max + 1;
+          // max.
+          // Note that if the suffix is not numbered then do not delete any
+          // backup files later or we'll delete the new backup file (there can
+          // be only one).
+          int numToDelete = suffix.indexOf(NUM_PLACEHOLDER) > -1
+                  ? bfTreeMap.size() - max + 1
+                  : 0;
+          Cache.debug("BACKUPFILES numToDelete: " + numToDelete);
           // the "replacement" file is the latest backup file being kept (it's
           // not replacing though)
           File replacementFile = numToDelete < backupFiles.length
@@ -407,6 +482,8 @@ public class BackupFiles
             File fileToBeDeleted = backupFiles[i];
             boolean delete = true;
 
+            Cache.debug("BACKUPFILES fileToBeDeleted: " + fileToBeDeleted);
+
             boolean newer = false;
             if (replacementFile != null)
             {
@@ -421,14 +498,13 @@ public class BackupFiles
                 String replacementFileLMTString = sdf
                         .format(replacementFileLMT);
 
-                System.out
-                        .println("WARNING! I am set to delete backupfile '"
-                                + fileToBeDeleted.getName()
-                                + "' has modification time "
+                Cache.warn("WARNING! I am set to delete backupfile '"
+                        + fileToBeDeleted.getName()
+                        + "' has modification time "
                         + fileToBeDeletedLMTString
-                                + " which is newer than the oldest backupfile being kept '"
+                        + " which is newer than the oldest backupfile being kept '"
                         + replacementFile.getName()
-                                + "' with modification time "
+                        + "' with modification time "
                         + replacementFileLMTString);
 
                 delete = confirmNewerDeleteFile(fileToBeDeleted,
@@ -437,17 +513,23 @@ public class BackupFiles
                 {
                   // User has confirmed delete -- no need to add it to the list
                   fileToBeDeleted.delete();
+                  Cache.debug("BACKUPFILES deleting fileToBeDeleted: "
+                          + fileToBeDeleted);
                   delete = false;
                 }
                 else
                 {
                   // keeping file, nothing to do!
+                  Cache.debug("BACKUPFILES keeping fileToBeDeleted: "
+                          + fileToBeDeleted);
                 }
               }
             }
             if (delete)
             {
               addDeleteFile(fileToBeDeleted);
+              Cache.debug("BACKUPFILES addDeleteFile(fileToBeDeleted): "
+                      + fileToBeDeleted);
             }
 
           }
@@ -462,10 +544,16 @@ public class BackupFiles
     String latestBackupFilename = dir + File.separatorChar
             + BackupFilenameParts.getBackupFilename(nextIndexNum, basename,
                     suffix, digits);
-    ret |= file.renameTo(new File(latestBackupFilename));
-
+    Cache.debug("BACKUPFILES Moving old file [" + file
+            + "] to latestBackupFilename [" + latestBackupFilename + "]");
+    // using boolean '&' instead of '&&' as don't want moveFileToFile attempt to
+    // be conditional (short-circuit)
+    ret = ret & moveFileToFile(file, new File(latestBackupFilename));
+    Cache.debug("BACKUPFILES moving " + file + " to " + latestBackupFilename
+            + " was " + (ret ? "" : "NOT ") + "successful");
     if (tidyUp)
     {
+      Cache.debug("BACKUPFILES tidying up files");
       tidyUpFiles();
     }
 
@@ -521,7 +609,7 @@ public class BackupFiles
         saveFile = nextTempFile(ftbd.getName(), ftbd.getParentFile());
       } catch (Exception e)
       {
-        System.out.println(
+        Cache.error(
                 "Error when confirming to keep backup file newer than other backup files.");
         e.printStackTrace();
       }
@@ -529,19 +617,27 @@ public class BackupFiles
               "label.newerdelete_replacement_line", new String[]
               { ftbd.getName(), rf.getName(), ftbdLMT, rfLMT, ftbdSize,
                   rfSize }));
+      // "Backup file\n''{0}''\t(modified {2}, size {4})\nis to be deleted and
+      // replaced by apparently older file \n''{1}''\t(modified {3}, size
+      // {5}).""
       messageSB.append("\n\n");
       messageSB.append(MessageManager.formatMessage(
               "label.confirm_deletion_or_rename", new String[]
               { ftbd.getName(), saveFile.getName() }));
+      // "Confirm deletion of ''{0}'' or rename to ''{1}''?"
       String[] options = new String[] {
           MessageManager.getString("label.delete"),
           MessageManager.getString("label.rename") };
 
-      confirmButton = JvOptionPane.showOptionDialog(Desktop.desktop,
-              messageSB.toString(),
-              MessageManager.getString("label.backupfiles_confirm_delete"),
-              JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE,
-              null, options, options[0]);
+      confirmButton = Platform.isHeadless() ? JvOptionPane.YES_OPTION
+              : JvOptionPane.showOptionDialog(Desktop.desktop,
+                      messageSB.toString(),
+                      MessageManager.getString(
+                              "label.backupfiles_confirm_delete"),
+                      // "Confirm delete"
+                      JvOptionPane.YES_NO_OPTION,
+                      JvOptionPane.WARNING_MESSAGE, null, options,
+                      options[0]);
     }
     else
     {
@@ -549,22 +645,29 @@ public class BackupFiles
               .formatMessage("label.newerdelete_line", new String[]
               { ftbd.getName(), rf.getName(), ftbdLMT, rfLMT, ftbdSize,
                   rfSize }));
+      // "Backup file\n''{0}''\t(modified {2}, size {4})\nis to be deleted but
+      // is newer than the oldest remaining backup file \n''{1}''\t(modified
+      // {3}, size {5})."
       messageSB.append("\n\n");
       messageSB.append(MessageManager
               .formatMessage("label.confirm_deletion", new String[]
               { ftbd.getName() }));
+      // "Confirm deletion of ''{0}''?"
       String[] options = new String[] {
           MessageManager.getString("label.delete"),
           MessageManager.getString("label.keep") };
 
-      confirmButton = JvOptionPane.showOptionDialog(Desktop.desktop,
-              messageSB.toString(),
-              MessageManager.getString("label.backupfiles_confirm_delete"),
-              JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE,
-              null, options, options[0]);
+      confirmButton = Platform.isHeadless() ? JvOptionPane.YES_OPTION
+              : JvOptionPane.showOptionDialog(Desktop.desktop,
+                      messageSB.toString(),
+                      MessageManager.getString(
+                              "label.backupfiles_confirm_delete"),
+                      // "Confirm delete"
+                      JvOptionPane.YES_NO_OPTION,
+                      JvOptionPane.WARNING_MESSAGE, null, options,
+                      options[0]);
     }
 
-
     // return should be TRUE if file is to be deleted
     return (confirmButton == JvOptionPane.YES_OPTION);
   }
@@ -580,6 +683,8 @@ public class BackupFiles
         messageSB = new StringBuilder();
         messageSB.append(MessageManager
                 .getString("label.backupfiles_confirm_delete_old_files"));
+        // "Delete the following older backup files? (see the Backups tab in
+        // Preferences for more options)"
         for (int i = 0; i < deleteFiles.size(); i++)
         {
           File df = deleteFiles.get(i);
@@ -590,13 +695,17 @@ public class BackupFiles
                   new String[]
                   { sdf.format(df.lastModified()),
                       Long.toString(df.length()) }));
+          // "(modified {0}, size {1})"
         }
 
-        int confirmButton = JvOptionPane.showConfirmDialog(Desktop.desktop,
-                messageSB.toString(),
-                MessageManager
-                        .getString("label.backupfiles_confirm_delete"),
-                JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE);
+        int confirmButton = Platform.isHeadless() ? JvOptionPane.YES_OPTION
+                : JvOptionPane.showConfirmDialog(Desktop.desktop,
+                        messageSB.toString(),
+                        MessageManager.getString(
+                                "label.backupfiles_confirm_delete"),
+                        // "Confirm delete"
+                        JvOptionPane.YES_NO_OPTION,
+                        JvOptionPane.WARNING_MESSAGE);
 
         doDelete = (confirmButton == JvOptionPane.YES_OPTION);
       }
@@ -610,8 +719,9 @@ public class BackupFiles
         for (int i = 0; i < deleteFiles.size(); i++)
         {
           File fileToDelete = deleteFiles.get(i);
+          Cache.debug("BACKUPFILES deleting fileToDelete:" + fileToDelete);
           fileToDelete.delete();
-          System.out.println("DELETING '" + fileToDelete.getName() + "'");
+          Cache.warn("deleting '" + fileToDelete.getName() + "'");
         }
       }
 
@@ -621,8 +731,7 @@ public class BackupFiles
   }
 
   private TreeMap<Integer, File> sortBackupFilesAsTreeMap(
-          File[] backupFiles,
-          String basename)
+          File[] backupFiles, String basename)
   {
     // sort the backup files (based on integer found in the suffix) using a
     // precomputed Hashmap for speed
@@ -647,7 +756,7 @@ public class BackupFiles
     boolean rename = false;
     if (write)
     {
-      roll = this.rollBackupFiles(false);
+      roll = this.rollBackupFiles(false); // tidyUpFiles at the end
       rename = this.renameTempFile();
     }
 
@@ -661,7 +770,9 @@ public class BackupFiles
     if (!okay)
     {
       StringBuilder messageSB = new StringBuilder();
-      messageSB.append(MessageManager.getString( "label.backupfiles_confirm_save_file_backupfiles_roll_wrong"));
+      messageSB.append(MessageManager.getString(
+              "label.backupfiles_confirm_save_file_backupfiles_roll_wrong"));
+      // "Something possibly went wrong with the backups of this file."
       if (rename)
       {
         if (messageSB.length() > 0)
@@ -670,6 +781,7 @@ public class BackupFiles
         }
         messageSB.append(MessageManager.getString(
                 "label.backupfiles_confirm_save_new_saved_file_ok"));
+        // "The new saved file seems okay."
       }
       else
       {
@@ -679,13 +791,22 @@ public class BackupFiles
         }
         messageSB.append(MessageManager.getString(
                 "label.backupfiles_confirm_save_new_saved_file_not_ok"));
+        // "The new saved file might not be okay."
       }
-
-      int confirmButton = JvOptionPane.showConfirmDialog(Desktop.desktop,
-              messageSB.toString(),
-              MessageManager
-                      .getString("label.backupfiles_confirm_save_file"),
-              JvOptionPane.OK_OPTION, JvOptionPane.WARNING_MESSAGE);
+      if (messageSB.length() > 0)
+      {
+        messageSB.append("\n");
+      }
+      messageSB
+              .append(MessageManager.getString("label.continue_operation"));
+
+      int confirmButton = Platform.isHeadless() ? JvOptionPane.OK_OPTION
+              : JvOptionPane.showConfirmDialog(Desktop.desktop,
+                      messageSB.toString(),
+                      MessageManager.getString(
+                              "label.backupfiles_confirm_save_file"),
+                      // "Confirm save file"
+                      JvOptionPane.OK_OPTION, JvOptionPane.WARNING_MESSAGE);
       okay = confirmButton == JvOptionPane.OK_OPTION;
     }
     if (okay)
@@ -709,8 +830,7 @@ public class BackupFiles
       dirFile = file.getParentFile();
     } catch (Exception e)
     {
-      System.out.println(
-              "Could not get canonical path for file '" + file + "'");
+      Cache.error("Could not get canonical path for file '" + file + "'");
       return new TreeMap<>();
     }
 
@@ -751,13 +871,48 @@ public class BackupFiles
     int pos = deleteFiles.indexOf(fileToBeDeleted);
     if (pos > -1)
     {
+      Cache.debug("BACKUPFILES not adding file "
+              + fileToBeDeleted.getAbsolutePath()
+              + " to the delete list (already at index" + pos + ")");
       return true;
     }
     else
     {
+      Cache.debug("BACKUPFILES adding file "
+              + fileToBeDeleted.getAbsolutePath() + " to the delete list");
       deleteFiles.add(fileToBeDeleted);
     }
     return ret;
   }
 
+  public static boolean moveFileToFile(File oldFile, File newFile)
+  {
+    boolean ret = false;
+    Path oldPath = Paths.get(oldFile.getAbsolutePath());
+    Path newPath = Paths.get(newFile.getAbsolutePath());
+    try
+    {
+      // delete destination file - not usually necessary but Just In Case...
+      Cache.debug("BACKUPFILES deleting " + newFile.getAbsolutePath());
+      newFile.delete();
+      Cache.debug("BACKUPFILES moving " + oldFile.getAbsolutePath() + " to "
+              + newFile.getAbsolutePath());
+      Files.move(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING);
+      ret = true;
+      Cache.debug("BACKUPFILES move seems to have succeeded");
+    } catch (IOException e)
+    {
+      Cache.warn("Could not move file '" + oldPath.toString() + "' to '"
+              + newPath.toString() + "'");
+      Cache.error(e.getMessage());
+      Cache.debug(Cache.getStackTraceString(e));
+      ret = false;
+    } catch (Exception e)
+    {
+      Cache.error(e.getMessage());
+      Cache.debug(Cache.getStackTraceString(e));
+      ret = false;
+    }
+    return ret;
+  }
 }
index 69130d0..0734665 100644 (file)
  */
 package jalview.io;
 
-import jalview.bin.Cache;
-import jalview.util.MessageManager;
-
 import java.util.HashMap;
 import java.util.Map;
 import java.util.StringTokenizer;
 
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+
 public class BackupFilesPresetEntry
 {
 
@@ -135,6 +135,8 @@ public class BackupFilesPresetEntry
   {
     String savedPresetString = Cache
             .getDefault(BackupFilesPresetEntry.SAVEDCONFIG, null);
+    Cache.log.debug("BACKUPFILESPRESETENTRY saved preset string is "
+            + savedPresetString);
     BackupFilesPresetEntry savedPreset = BackupFilesPresetEntry
             .createBackupFilesPresetEntry(savedPresetString);
     if (savedPreset == null)
index 1b4a8bd..a366f33 100755 (executable)
  */
 package jalview.jbgui;
 
-import jalview.bin.Cache;
-import jalview.fts.core.FTSDataColumnPreferences;
-import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
-import jalview.fts.service.pdb.PDBFTSRestClient;
-import jalview.gui.Desktop;
-import jalview.gui.JalviewBooleanRadioButtons;
-import jalview.gui.JvOptionPane;
-import jalview.gui.JvSwingUtils;
-import jalview.gui.StructureViewer.ViewerType;
-import jalview.io.BackupFilenameParts;
-import jalview.io.BackupFiles;
-import jalview.io.BackupFilesPresetEntry;
-import jalview.io.IntKeyStringValueEntry;
-import jalview.util.MessageManager;
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
@@ -66,6 +51,7 @@ import javax.swing.JComboBox;
 import javax.swing.JFileChooser;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
+import javax.swing.JPasswordField;
 import javax.swing.JRadioButton;
 import javax.swing.JScrollPane;
 import javax.swing.JSpinner;
@@ -83,9 +69,26 @@ import javax.swing.border.EtchedBorder;
 import javax.swing.border.TitledBorder;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
 import javax.swing.table.TableCellEditor;
 import javax.swing.table.TableCellRenderer;
 
+import jalview.bin.Cache;
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.gui.Desktop;
+import jalview.gui.JalviewBooleanRadioButtons;
+import jalview.gui.JvOptionPane;
+import jalview.gui.JvSwingUtils;
+import jalview.gui.StructureViewer.ViewerType;
+import jalview.io.BackupFilenameParts;
+import jalview.io.BackupFiles;
+import jalview.io.BackupFilesPresetEntry;
+import jalview.io.IntKeyStringValueEntry;
+import jalview.util.MessageManager;
+
 /**
  * Base class for the Preferences panel.
  * 
@@ -214,6 +217,8 @@ public class GPreferences extends JPanel
   /*
    * Connections tab components
    */
+  protected JPanel connectTab;
+
   protected JTable linkUrlTable = new JTable();
 
   protected JButton editLink = new JButton();
@@ -226,17 +231,49 @@ public class GPreferences extends JPanel
 
   protected JButton userOnly = new JButton();
 
+  protected JLabel httpLabel = new JLabel();
+
+  protected JLabel httpsLabel = new JLabel();
+
   protected JLabel portLabel = new JLabel();
 
   protected JLabel serverLabel = new JLabel();
 
-  protected JTextField proxyServerTB = new JTextField();
+  protected JLabel portLabel2 = new JLabel();
+
+  protected JLabel serverLabel2 = new JLabel();
+
+  protected JLabel proxyAuthUsernameLabel = new JLabel();
+
+  protected JLabel proxyAuthPasswordLabel = new JLabel();
+
+  protected JLabel passwordNotStoredLabel = new JLabel();
+
+  protected JTextField proxyServerHttpTB = new JTextField();
+
+  protected JTextField proxyPortHttpTB = new JTextField();
 
-  protected JTextField proxyPortTB = new JTextField();
+  protected JTextField proxyServerHttpsTB = new JTextField();
+
+  protected JTextField proxyPortHttpsTB = new JTextField();
+
+  protected JCheckBox proxyAuth = new JCheckBox();
+
+  protected JTextField proxyAuthUsernameTB = new JTextField();
+
+  protected JPasswordField proxyAuthPasswordPB = new JPasswordField();
 
   protected JTextField defaultBrowser = new JTextField();
 
-  protected JCheckBox useProxy = new JCheckBox();
+  protected ButtonGroup proxyType = new ButtonGroup();
+
+  protected JRadioButton noProxy = new JRadioButton();
+
+  protected JRadioButton systemProxy = new JRadioButton();
+
+  protected JRadioButton customProxy = new JRadioButton();
+
+  protected JButton applyProxyButton = new JButton();
 
   protected JCheckBox usagestats = new JCheckBox();
 
@@ -333,6 +370,10 @@ public class GPreferences extends JPanel
 
   protected JTextArea backupfilesExampleLabel = new JTextArea();
 
+  private final JTabbedPane tabbedPane = new JTabbedPane();
+
+  private JLabel messageLabel = new JLabel("", JLabel.CENTER);
+
   /**
    * Creates a new GPreferences object.
    */
@@ -354,8 +395,12 @@ public class GPreferences extends JPanel
    */
   private void jbInit() throws Exception
   {
-    final JTabbedPane tabbedPane = new JTabbedPane();
+    // final JTabbedPane tabbedPane = new JTabbedPane();
     this.setLayout(new BorderLayout());
+
+    // message label at top
+    this.add(messageLabel, BorderLayout.NORTH);
+
     JPanel okCancelPanel = initOkCancelPanel();
     this.add(tabbedPane, BorderLayout.CENTER);
     this.add(okCancelPanel, BorderLayout.SOUTH);
@@ -396,6 +441,7 @@ public class GPreferences extends JPanel
     /*
      * Handler to validate a tab before leaving it - currently only for
      * Structure.
+     * Adding a clearMessage() so messages are cleared when changing tabs.
      */
     tabbedPane.addChangeListener(new ChangeListener()
     {
@@ -414,11 +460,57 @@ public class GPreferences extends JPanel
           }
         }
         lastTab = tabbedPane.getSelectedComponent();
+
+        clearMessage();
       }
 
     });
   }
 
+  public void setMessage(String message)
+  {
+    if (message != null)
+    {
+      messageLabel.setText(message);
+      messageLabel.setFont(LABEL_FONT_BOLD);
+      messageLabel.setForeground(Color.RED.darker());
+      messageLabel.revalidate();
+      messageLabel.repaint();
+    }
+    // note message not cleared if message is null. call clearMessage()
+    // directly.
+    this.revalidate();
+    this.repaint();
+  }
+
+  public void clearMessage()
+  {
+    // only repaint if message exists
+    if (messageLabel.getText() != null
+            && messageLabel.getText().length() > 0)
+    {
+      messageLabel.setText("");
+      messageLabel.revalidate();
+      messageLabel.repaint();
+      this.revalidate();
+      this.repaint();
+    }
+  }
+
+  public final static int CONNECTIONS_TAB = 5;
+
+  public void selectTab(int selectTab)
+  {
+    // select a given tab - currently only for Connections
+    switch (selectTab)
+    {
+    case CONNECTIONS_TAB:
+      tabbedPane.setSelectedComponent(connectTab);
+      break;
+    default:
+    }
+  }
+
   /**
    * Initialises the Editing tabbed panel.
    * 
@@ -569,7 +661,7 @@ public class GPreferences extends JPanel
    */
   private JPanel initConnectionsTab()
   {
-    JPanel connectTab = new JPanel();
+    connectTab = new JPanel();
     connectTab.setLayout(new GridBagLayout());
 
     // Label for browser text box
@@ -840,63 +932,355 @@ public class GPreferences extends JPanel
   private JPanel initConnTabProxyPanel()
   {
     // Label for server text box
-    serverLabel.setText(MessageManager.getString("label.address"));
+    serverLabel.setText(MessageManager.getString("label.host") + ": ");
     serverLabel.setHorizontalAlignment(SwingConstants.RIGHT);
     serverLabel.setFont(LABEL_FONT);
+    serverLabel2.setText(MessageManager.getString("label.host") + ": ");
+    serverLabel2.setHorizontalAlignment(SwingConstants.RIGHT);
+    serverLabel2.setFont(LABEL_FONT);
 
     // Proxy server and port text boxes
-    proxyServerTB.setFont(LABEL_FONT);
-    proxyPortTB.setFont(LABEL_FONT);
+    proxyServerHttpTB.setFont(LABEL_FONT);
+    proxyServerHttpTB.setColumns(40);
+    proxyPortHttpTB.setFont(LABEL_FONT);
+    proxyPortHttpTB.setColumns(4);
+    proxyServerHttpsTB.setFont(LABEL_FONT);
+    proxyServerHttpsTB.setColumns(40);
+    proxyPortHttpsTB.setFont(LABEL_FONT);
+    proxyPortHttpsTB.setColumns(4);
+    proxyAuthUsernameTB.setFont(LABEL_FONT);
+    proxyAuthUsernameTB.setColumns(30);
+
+    // check for any change to enable applyProxyButton
+    DocumentListener d = new DocumentListener()
+    {
+      @Override
+      public void changedUpdate(DocumentEvent e)
+      {
+        applyProxyButtonEnabled(true);
+      }
+
+      @Override
+      public void insertUpdate(DocumentEvent e)
+      {
+        applyProxyButtonEnabled(true);
+      }
+
+      @Override
+      public void removeUpdate(DocumentEvent e)
+      {
+        applyProxyButtonEnabled(true);
+      }
+    };
+    proxyServerHttpTB.getDocument().addDocumentListener(d);
+    proxyPortHttpTB.getDocument().addDocumentListener(d);
+    proxyServerHttpsTB.getDocument().addDocumentListener(d);
+    proxyPortHttpsTB.getDocument().addDocumentListener(d);
+    proxyAuthUsernameTB.getDocument().addDocumentListener(d);
+    proxyAuthPasswordPB.setFont(LABEL_FONT);
+    proxyAuthPasswordPB.setColumns(30);
+    proxyAuthPasswordPB.getDocument()
+            .addDocumentListener(new DocumentListener()
+            {
+              @Override
+              public void changedUpdate(DocumentEvent e)
+              {
+                proxyAuthPasswordCheckHighlight(true);
+                applyProxyButtonEnabled(true);
+              }
+
+              @Override
+              public void insertUpdate(DocumentEvent e)
+              {
+                proxyAuthPasswordCheckHighlight(true);
+                applyProxyButtonEnabled(true);
+              }
+
+              @Override
+              public void removeUpdate(DocumentEvent e)
+              {
+                proxyAuthPasswordCheckHighlight(true);
+                applyProxyButtonEnabled(true);
+              }
+
+            });
 
     // Label for Port text box
     portLabel.setFont(LABEL_FONT);
     portLabel.setHorizontalAlignment(SwingConstants.RIGHT);
-    portLabel.setText(MessageManager.getString("label.port"));
-
-    // Use proxy server checkbox
-    useProxy.setFont(LABEL_FONT);
-    useProxy.setHorizontalAlignment(SwingConstants.RIGHT);
-    useProxy.setHorizontalTextPosition(SwingConstants.LEADING);
-    useProxy.setText(MessageManager.getString("label.use_proxy_server"));
-    useProxy.addActionListener(new ActionListener()
+    portLabel.setText(MessageManager.getString("label.port") + ": ");
+    portLabel2.setFont(LABEL_FONT);
+    portLabel2.setHorizontalAlignment(SwingConstants.RIGHT);
+    portLabel2.setText(MessageManager.getString("label.port") + ": ");
+
+    httpLabel.setText("HTTP");
+    httpLabel.setFont(LABEL_FONT_BOLD);
+    httpLabel.setHorizontalAlignment(SwingConstants.LEFT);
+    httpsLabel.setText("HTTPS");
+    httpsLabel.setFont(LABEL_FONT_BOLD);
+    httpsLabel.setHorizontalAlignment(SwingConstants.LEFT);
+
+    proxyAuthUsernameLabel
+            .setText(MessageManager.getString("label.username") + ": ");
+    proxyAuthUsernameLabel.setFont(LABEL_FONT);
+    proxyAuthUsernameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+    proxyAuthPasswordLabel
+            .setText(MessageManager.getString("label.password") + ": ");
+    proxyAuthPasswordLabel.setFont(LABEL_FONT);
+    proxyAuthPasswordLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+    passwordNotStoredLabel.setText(
+            "(" + MessageManager.getString("label.not_stored") + ")");
+    passwordNotStoredLabel.setFont(LABEL_FONT_ITALIC);
+    passwordNotStoredLabel.setHorizontalAlignment(SwingConstants.LEFT);
+
+    // Proxy type radio buttons
+    noProxy.setFont(LABEL_FONT);
+    noProxy.setHorizontalAlignment(SwingConstants.LEFT);
+    noProxy.setText(MessageManager.getString("label.no_proxy"));
+    systemProxy.setFont(LABEL_FONT);
+    systemProxy.setHorizontalAlignment(SwingConstants.LEFT);
+    systemProxy.setText(MessageManager.formatMessage("label.system_proxy",
+            displayUserHostPort(Cache.startupProxyProperties[4],
+                    Cache.startupProxyProperties[0],
+                    Cache.startupProxyProperties[1]),
+            displayUserHostPort(Cache.startupProxyProperties[6],
+                    Cache.startupProxyProperties[2],
+                    Cache.startupProxyProperties[3])));
+    customProxy.setFont(LABEL_FONT);
+    customProxy.setHorizontalAlignment(SwingConstants.LEFT);
+    customProxy.setText(
+            MessageManager.getString("label.use_proxy_server") + ":");
+    ActionListener al = new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        proxyType_actionPerformed();
+      }
+    };
+    noProxy.addActionListener(al);
+    systemProxy.addActionListener(al);
+    customProxy.addActionListener(al);
+    proxyType.add(noProxy);
+    proxyType.add(systemProxy);
+    proxyType.add(customProxy);
+
+    proxyAuth.setFont(LABEL_FONT);
+    proxyAuth.setHorizontalAlignment(SwingConstants.LEFT);
+    proxyAuth.setText(MessageManager.getString("label.auth_required"));
+    proxyAuth.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        useProxy_actionPerformed();
+        proxyAuth_actionPerformed();
       }
     });
 
+    setCustomProxyEnabled();
+
     // Make proxy server panel
     JPanel proxyPanel = new JPanel();
     TitledBorder titledBorder1 = new TitledBorder(
-            MessageManager.getString("label.proxy_server"));
+            MessageManager.getString("label.proxy_servers"));
     proxyPanel.setBorder(titledBorder1);
     proxyPanel.setLayout(new GridBagLayout());
-    proxyPanel.add(serverLabel,
-            new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
-                    GridBagConstraints.WEST, GridBagConstraints.NONE,
-                    new Insets(0, 2, 2, 0), 5, 0));
-    proxyPanel.add(portLabel,
-            new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0,
-                    GridBagConstraints.WEST, GridBagConstraints.NONE,
-                    new Insets(0, 0, 2, 0), 11, 0));
-    proxyPanel.add(useProxy,
-            new GridBagConstraints(0, 0, 2, 1, 0.0, 0.0,
-                    GridBagConstraints.WEST, GridBagConstraints.NONE,
-                    new Insets(0, 2, 5, 185), 2, -4));
-    proxyPanel.add(proxyPortTB,
-            new GridBagConstraints(3, 1, 1, 1, 1.0, 0.0,
-                    GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
-                    new Insets(0, 2, 2, 2), 54, 1));
-    proxyPanel.add(proxyServerTB,
-            new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0,
-                    GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
-                    new Insets(0, 2, 2, 0), 263, 1));
+    GridBagConstraints gbc = new GridBagConstraints();
+    gbc.fill = GridBagConstraints.HORIZONTAL;
+    gbc.weightx = 1.0;
+
+    GridBagConstraints c = new GridBagConstraints();
+    // Proxy type radio buttons (3)
+    JPanel ptPanel = new JPanel();
+    ptPanel.setLayout(new GridBagLayout());
+    c.weightx = 1.0;
+    c.gridy = 0;
+    c.gridx = 0;
+    c.gridwidth = 1;
+    c.fill = GridBagConstraints.HORIZONTAL;
+    ptPanel.add(noProxy, c);
+    c.gridy++;
+    ptPanel.add(systemProxy, c);
+    c.gridy++;
+    ptPanel.add(customProxy, c);
+
+    gbc.gridy = 0;
+    proxyPanel.add(ptPanel, gbc);
+
+    // host and port text boxes
+    JPanel hpPanel = new JPanel();
+    hpPanel.setLayout(new GridBagLayout());
+    // HTTP host port row
+    c.gridy = 0;
+    c.gridx = 0;
+
+    c.weightx = 0.1;
+    c.anchor = GridBagConstraints.LINE_START;
+    hpPanel.add(httpLabel, c);
+
+    c.gridx++;
+    c.weightx = 0.1;
+    c.anchor = GridBagConstraints.LINE_END;
+    hpPanel.add(serverLabel, c);
+
+    c.gridx++;
+    c.weightx = 1.0;
+    c.anchor = GridBagConstraints.LINE_START;
+    hpPanel.add(proxyServerHttpTB, c);
+
+    c.gridx++;
+    c.weightx = 0.1;
+    c.anchor = GridBagConstraints.LINE_END;
+    hpPanel.add(portLabel, c);
+
+    c.gridx++;
+    c.weightx = 0.2;
+    c.anchor = GridBagConstraints.LINE_START;
+    hpPanel.add(proxyPortHttpTB, c);
+
+    // HTTPS host port row
+    c.gridy++;
+    c.gridx = 0;
+    c.gridwidth = 1;
+
+    c.anchor = GridBagConstraints.LINE_START;
+    hpPanel.add(httpsLabel, c);
+
+    c.gridx++;
+    c.anchor = GridBagConstraints.LINE_END;
+    hpPanel.add(serverLabel2, c);
+
+    c.gridx++;
+    c.anchor = GridBagConstraints.LINE_START;
+    hpPanel.add(proxyServerHttpsTB, c);
+
+    c.gridx++;
+    c.anchor = GridBagConstraints.LINE_END;
+    hpPanel.add(portLabel2, c);
+
+    c.gridx++;
+    c.anchor = GridBagConstraints.LINE_START;
+    hpPanel.add(proxyPortHttpsTB, c);
+
+    gbc.gridy++;
+    proxyPanel.add(hpPanel, gbc);
+
+    // Require authentication checkbox
+    gbc.gridy++;
+    proxyPanel.add(proxyAuth, gbc);
+
+    // username and password
+    JPanel upPanel = new JPanel();
+    upPanel.setLayout(new GridBagLayout());
+    // username row
+    c.gridy = 0;
+    c.gridx = 0;
+    c.gridwidth = 1;
+    c.weightx = 0.4;
+    c.anchor = GridBagConstraints.LINE_END;
+    upPanel.add(proxyAuthUsernameLabel, c);
+
+    c.gridx++;
+    c.weightx = 1.0;
+    c.anchor = GridBagConstraints.LINE_START;
+    upPanel.add(proxyAuthUsernameTB, c);
+
+    // password row
+    c.gridy++;
+    c.gridx = 0;
+    c.weightx = 0.4;
+    c.anchor = GridBagConstraints.LINE_END;
+    upPanel.add(proxyAuthPasswordLabel, c);
+
+    c.gridx++;
+    c.weightx = 1.0;
+    c.anchor = GridBagConstraints.LINE_START;
+    upPanel.add(proxyAuthPasswordPB, c);
+
+    c.gridx++;
+    c.weightx = 0.4;
+    c.anchor = GridBagConstraints.LINE_START;
+    upPanel.add(passwordNotStoredLabel, c);
+
+    gbc.gridy++;
+    proxyPanel.add(upPanel, gbc);
+
+    applyProxyButton.setText(MessageManager.getString("action.apply"));
+    applyProxyButton.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        saveProxySettings();
+        applyProxyButton.setEnabled(false);
+      }
+    });
+    gbc.gridy++;
+    gbc.fill = GridBagConstraints.NONE;
+    gbc.anchor = GridBagConstraints.LINE_END;
+    proxyPanel.add(applyProxyButton, gbc);
 
     return proxyPanel;
   }
 
+  public void proxyAuthPasswordCheckHighlight(boolean enabled)
+  {
+    proxyAuthPasswordCheckHighlight(enabled, false);
+  }
+
+  public void proxyAuthPasswordCheckHighlight(boolean enabled,
+          boolean grabFocus)
+  {
+    if (enabled && proxyType.isSelected(customProxy.getModel())
+            && proxyAuth.isSelected()
+            && !proxyAuthUsernameTB.getText().isEmpty()
+            && proxyAuthPasswordPB.getDocument().getLength() == 0)
+    {
+      if (grabFocus)
+        proxyAuthPasswordPB.grabFocus();
+      proxyAuthPasswordPB.setBackground(Color.PINK);
+    }
+    else
+    {
+      proxyAuthPasswordPB.setBackground(Color.WHITE);
+    }
+  }
+
+  public void applyProxyButtonEnabled(boolean enabled)
+  {
+    applyProxyButton.setEnabled(enabled);
+  }
+
+  public void saveProxySettings()
+  {
+    // overridden in Preferences
+  }
+
+  private String displayUserHostPort(String user, String host, String port)
+  {
+    boolean hostBlank = (host == null || host.isEmpty());
+    boolean portBlank = (port == null || port.isEmpty());
+    if (hostBlank && portBlank)
+    {
+      return MessageManager.getString("label.none");
+    }
+
+    StringBuilder sb = new StringBuilder();
+    if (user != null)
+    {
+      sb.append(user.isEmpty() || user.indexOf(" ") > -1 ? '"' + user + '"'
+              : user);
+      sb.append("@");
+    }
+    sb.append(hostBlank ? "" : host);
+    if (!portBlank)
+    {
+      sb.append(":");
+      sb.append(port);
+    }
+    return sb.toString();
+  }
+
   /**
    * Initialises the checkboxes in the Connections tab
    */
@@ -1784,7 +2168,6 @@ public class GPreferences extends JPanel
       }
     });
 
-
     // enable checkbox 1 col
     gbc.gridwidth = 1;
     gbc.gridheight = 1;
@@ -1857,8 +2240,8 @@ public class GPreferences extends JPanel
     presetsComboLabel = new JLabel(title + ":");
     presetsPanel.add(presetsComboLabel, gbc);
 
-    List<Object> entries = Arrays
-            .asList((Object[]) BackupFilesPresetEntry.backupfilesPresetEntries);
+    List<Object> entries = Arrays.asList(
+            (Object[]) BackupFilesPresetEntry.backupfilesPresetEntries);
     List<String> tooltips = Arrays.asList(
             BackupFilesPresetEntry.backupfilesPresetEntryDescriptions);
     backupfilesPresetsCombo = JvSwingUtils.buildComboWithTooltips(entries,
@@ -1885,7 +2268,8 @@ public class GPreferences extends JPanel
         {
           if (customiseCheckbox.isSelected())
           {
-            // got here by clicking on customiseCheckbox so don't change the values
+            // got here by clicking on customiseCheckbox so don't change the
+            // values
             backupfilesCustomOptionsSetEnabled();
           }
           else
@@ -1964,13 +2348,11 @@ public class GPreferences extends JPanel
 
   private JPanel initBackupsTabFilenameExamplesPanel()
   {
-    String title = MessageManager
-            .getString("label.scheme_examples");
+    String title = MessageManager.getString("label.scheme_examples");
     TitledBorder tb = new TitledBorder(title);
     exampleFilesPanel.setBorder(tb);
     exampleFilesPanel.setLayout(new GridBagLayout());
 
-
     backupfilesExampleLabel.setEditable(false);
     backupfilesExampleLabel
             .setBackground(exampleFilesPanel.getBackground());
@@ -2031,8 +2413,7 @@ public class GPreferences extends JPanel
   }
 
   protected void setComboIntStringKey(
-          JComboBox<Object> backupfilesPresetsCombo2,
-          int key)
+          JComboBox<Object> backupfilesPresetsCombo2, int key)
   {
     for (int i = 0; i < backupfilesPresetsCombo2.getItemCount(); i++)
     {
@@ -2302,9 +2683,8 @@ public class GPreferences extends JPanel
 
     JPanel jp = new JPanel();
     jp.setLayout(new FlowLayout());
-    oldBackupFilesLabel
-            .setText(MessageManager
-                    .getString("label.autodelete_old_backup_files"));
+    oldBackupFilesLabel.setText(
+            MessageManager.getString("label.autodelete_old_backup_files"));
     oldBackupFilesLabel.setFont(LABEL_FONT);
     oldBackupFilesLabel.setHorizontalAlignment(SwingConstants.LEFT);
     jp.add(oldBackupFilesLabel);
@@ -2464,7 +2844,8 @@ public class GPreferences extends JPanel
 
     }
 
-    // add some extra empty lines to pad out the example files box. ugh, please tell
+    // add some extra empty lines to pad out the example files box. ugh, please
+    // tell
     // me how to do this better
     int remainingLines = lowersurround + uppersurround + 1 - lineNumber;
     if (remainingLines > 0)
@@ -2543,8 +2924,7 @@ public class GPreferences extends JPanel
   private void backupfilesKeepAllSetEnabled(boolean tryEnabled)
   {
     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
-            && customiseCheckbox.isSelected()
-            && suffixTemplate.getText()
+            && customiseCheckbox.isSelected() && suffixTemplate.getText()
                     .indexOf(BackupFiles.NUM_PLACEHOLDER) > -1;
     keepfilesPanel.setEnabled(enabled);
     backupfilesKeepAll.setEnabled(enabled);
@@ -2756,13 +3136,45 @@ public class GPreferences extends JPanel
 
   }
 
-  public void useProxy_actionPerformed()
+  public void setProxyAuthEnabled()
   {
-    boolean enabled = useProxy.isSelected();
+    boolean enabled = proxyAuth.isSelected() && proxyAuth.isEnabled();
+    proxyAuthUsernameLabel.setEnabled(enabled);
+    proxyAuthPasswordLabel.setEnabled(enabled);
+    passwordNotStoredLabel.setEnabled(enabled);
+    proxyAuthUsernameTB.setEnabled(enabled);
+    proxyAuthPasswordPB.setEnabled(enabled);
+  }
+
+  public void setCustomProxyEnabled()
+  {
+    boolean enabled = customProxy.isSelected();
     portLabel.setEnabled(enabled);
     serverLabel.setEnabled(enabled);
-    proxyServerTB.setEnabled(enabled);
-    proxyPortTB.setEnabled(enabled);
+    portLabel2.setEnabled(enabled);
+    serverLabel2.setEnabled(enabled);
+    httpLabel.setEnabled(enabled);
+    httpsLabel.setEnabled(enabled);
+    proxyServerHttpTB.setEnabled(enabled);
+    proxyPortHttpTB.setEnabled(enabled);
+    proxyServerHttpsTB.setEnabled(enabled);
+    proxyPortHttpsTB.setEnabled(enabled);
+    proxyAuth.setEnabled(enabled);
+    setProxyAuthEnabled();
+  }
+
+  public void proxyType_actionPerformed()
+  {
+    setCustomProxyEnabled();
+    proxyAuthPasswordCheckHighlight(true);
+    applyProxyButtonEnabled(true);
+  }
+
+  public void proxyAuth_actionPerformed()
+  {
+    setProxyAuthEnabled();
+    proxyAuthPasswordCheckHighlight(true);
+    applyProxyButtonEnabled(true);
   }
 
   /**
@@ -2837,4 +3249,3 @@ public class GPreferences extends JPanel
 
   }
 }
-
index ca0423b..0e062ac 100644 (file)
@@ -24,6 +24,54 @@ import static jalview.math.RotatableMatrix.Axis.X;
 import static jalview.math.RotatableMatrix.Axis.Y;
 import static jalview.math.RotatableMatrix.Axis.Z;
 
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Rectangle;
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigInteger;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Vector;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+
+import javax.swing.JInternalFrame;
+import javax.swing.SwingUtilities;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Marshaller;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamReader;
+
 import jalview.analysis.Conservation;
 import jalview.analysis.PCA;
 import jalview.analysis.scoremodels.ScoreModels;
@@ -85,6 +133,7 @@ import jalview.schemes.UserColourScheme;
 import jalview.structure.StructureSelectionManager;
 import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.Format;
+import jalview.util.HttpUtils;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.util.StringUtils;
@@ -150,54 +199,6 @@ import jalview.xml.binding.jalview.SequenceSet.SequenceSetProperties;
 import jalview.xml.binding.jalview.ThresholdType;
 import jalview.xml.binding.jalview.VAMSAS;
 
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Rectangle;
-import java.io.BufferedReader;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.lang.reflect.InvocationTargetException;
-import java.math.BigInteger;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.Vector;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
-import java.util.jar.JarOutputStream;
-
-import javax.swing.JInternalFrame;
-import javax.swing.SwingUtilities;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.Marshaller;
-import javax.xml.datatype.DatatypeConfigurationException;
-import javax.xml.datatype.DatatypeFactory;
-import javax.xml.datatype.XMLGregorianCalendar;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamReader;
-
 /**
  * Write out the current jalview desktop state as a Jalview XML stream.
  * 
@@ -946,7 +947,7 @@ public class Jalview2XML
         else
         {
           vamsasSeq = createVamsasSequence(id, jds);
-//          vamsasSet.addSequence(vamsasSeq);
+          // vamsasSet.addSequence(vamsasSeq);
           vamsasSet.getSequence().add(vamsasSeq);
           vamsasSetIds.put(id, vamsasSeq);
           seqRefIds.put(id, jds);
@@ -1339,9 +1340,8 @@ public class Jalview2XML
 
             if (colourScheme instanceof jalview.schemes.UserColourScheme)
             {
-              jGroup.setColour(
-                      setUserColourScheme(colourScheme, userColours,
-                              object));
+              jGroup.setColour(setUserColourScheme(colourScheme,
+                      userColours, object));
             }
             else
             {
@@ -1387,7 +1387,7 @@ public class Jalview2XML
         }
       }
 
-      //jms.setJGroup(groups);
+      // jms.setJGroup(groups);
       Object group;
       for (JGroup grp : groups)
       {
@@ -1524,11 +1524,13 @@ public class Jalview2XML
              * save any filter for the feature type
              */
             FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
-            if (filter != null)  {
-              Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
+            if (filter != null)
+            {
+              Iterator<FeatureMatcherI> filters = filter.getMatchers()
+                      .iterator();
               FeatureMatcherI firstFilter = filters.next();
-              setting.setMatcherSet(Jalview2XML.marshalFilter(
-                      firstFilter, filters, filter.isAnded()));
+              setting.setMatcherSet(Jalview2XML.marshalFilter(firstFilter,
+                      filters, filter.isAnded()));
             }
 
             /*
@@ -1577,8 +1579,7 @@ public class Jalview2XML
 
             setting.setDisplay(
                     av.getFeaturesDisplayed().isVisible(featureType));
-            float rorder = fr
-                    .getOrder(featureType);
+            float rorder = fr.getOrder(featureType);
             if (rorder > -1)
             {
               setting.setOrder(rorder);
@@ -1602,7 +1603,7 @@ public class Jalview2XML
           Group g = new Group();
           g.setName(grp);
           g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
-                          .booleanValue());
+                  .booleanValue());
           // fs.addGroup(g);
           fs.getGroup().add(g);
           groupsAdded.addElement(grp);
@@ -2368,7 +2369,8 @@ public class Jalview2XML
   {
     if (calcIdParam.getVersion().equals("1.0"))
     {
-      final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
+      final String[] calcIds = calcIdParam.getServiceURL()
+              .toArray(new String[0]);
       Jws2Instance service = Jws2Discoverer.getDiscoverer()
               .getPreferredServiceFor(calcIds);
       if (service != null)
@@ -2654,12 +2656,12 @@ public class Jalview2XML
     return id;
   }
 
-  jalview.schemes.UserColourScheme getUserColourScheme(
-          JalviewModel jm, String id)
+  jalview.schemes.UserColourScheme getUserColourScheme(JalviewModel jm,
+          String id)
   {
     List<UserColours> uc = jm.getUserColours();
     UserColours colours = null;
-/*
+    /*
     for (int i = 0; i < uc.length; i++)
     {
       if (uc[i].getId().equals(id))
@@ -2668,7 +2670,7 @@ public class Jalview2XML
         break;
       }
     }
-*/
+    */
     for (UserColours c : uc)
     {
       if (c.getId().equals(id))
@@ -2696,10 +2698,9 @@ public class Jalview2XML
       newColours = new java.awt.Color[23];
       for (int i = 0; i < 23; i++)
       {
-        newColours[i] = new java.awt.Color(Integer.parseInt(
-                colours.getUserColourScheme().getColour().get(i + 24)
-                        .getRGB(),
-                16));
+        newColours[i] = new java.awt.Color(
+                Integer.parseInt(colours.getUserColourScheme().getColour()
+                        .get(i + 24).getRGB(), 16));
       }
       ucs.setLowerCaseColours(newColours);
     }
@@ -2778,7 +2779,7 @@ public class Jalview2XML
     viewportsAdded.clear();
     frefedSequence = null;
 
-    if (file.startsWith("http://"))
+    if (HttpUtils.startsWithHttpOrHttps(file))
     {
       url = new URL(file);
     }
@@ -2855,8 +2856,8 @@ public class Jalview2XML
           XMLStreamReader streamReader = XMLInputFactory.newInstance()
                   .createXMLStreamReader(jin);
           javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
-          JAXBElement<JalviewModel> jbe = um
-                  .unmarshal(streamReader, JalviewModel.class);
+          JAXBElement<JalviewModel> jbe = um.unmarshal(streamReader,
+                  JalviewModel.class);
           JalviewModel object = jbe.getValue();
 
           /*
@@ -3276,7 +3277,8 @@ public class Jalview2XML
   AlignFrame loadFromObject(JalviewModel jalviewModel, String file,
           boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
   {
-    SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet().get(0);
+    SequenceSet vamsasSet = jalviewModel.getVamsasModel().getSequenceSet()
+            .get(0);
     List<Sequence> vamsasSeqs = vamsasSet.getSequence();
 
     // JalviewModelSequence jms = object.getJalviewModelSequence();
@@ -3335,11 +3337,10 @@ public class Jalview2XML
           if (tmpSeq.getStart() != jseq.getStart()
                   || tmpSeq.getEnd() != jseq.getEnd())
           {
-            System.err.println(
-                    String.format("Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
-                            tmpSeq.getName(), tmpSeq.getStart(),
-                            tmpSeq.getEnd(), jseq.getStart(),
-                            jseq.getEnd()));
+            System.err.println(String.format(
+                    "Warning JAL-2154 regression: updating start/end for sequence %s from %d/%d to %d/%d",
+                    tmpSeq.getName(), tmpSeq.getStart(), tmpSeq.getEnd(),
+                    jseq.getStart(), jseq.getEnd()));
           }
         }
         else
@@ -3622,8 +3623,8 @@ public class Jalview2XML
               else
               {
                 // defer to later
-                frefedSequence.add(
-                        newAlcodMapRef(map.getDnasq(), cf, mapping));
+                frefedSequence
+                        .add(newAlcodMapRef(map.getDnasq(), cf, mapping));
               }
             }
           }
@@ -3831,8 +3832,7 @@ public class Jalview2XML
         jaa.setCalcId(annotation.getCalcId());
         if (annotation.getProperty().size() > 0)
         {
-          for (Annotation.Property prop : annotation
-                  .getProperty())
+          for (Annotation.Property prop : annotation.getProperty())
           {
             jaa.setProperty(prop.getName(), prop.getValue());
           }
@@ -3913,9 +3913,9 @@ public class Jalview2XML
         sg.setShowNonconserved(safeBoolean(jGroup.isShowUnconserved()));
         sg.thresholdTextColour = safeInt(jGroup.getTextColThreshold());
         // attributes with a default in the schema are never null
-          sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
-          sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
-          sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
+        sg.setShowConsensusHistogram(jGroup.isShowConsensusHistogram());
+        sg.setshowSequenceLogo(jGroup.isShowSequenceLogo());
+        sg.setNormaliseSequenceLogo(jGroup.isNormaliseSequenceLogo());
         sg.setIgnoreGapsConsensus(jGroup.isIgnoreGapsinConsensus());
         if (jGroup.getConsThreshold() != null
                 && jGroup.getConsThreshold().intValue() != 0)
@@ -3959,8 +3959,9 @@ public class Jalview2XML
         if (addAnnotSchemeGroup)
         {
           // reconstruct the annotation colourscheme
-          sg.setColourScheme(constructAnnotationColour(
-                  jGroup.getAnnotationColours(), null, al, jalviewModel, false));
+          sg.setColourScheme(
+                  constructAnnotationColour(jGroup.getAnnotationColours(),
+                          null, al, jalviewModel, false));
         }
       }
     }
@@ -4166,8 +4167,8 @@ public class Jalview2XML
    * @param av
    * @param ap
    */
-  protected void loadTrees(JalviewModel jm, Viewport view,
-          AlignFrame af, AlignViewport av, AlignmentPanel ap)
+  protected void loadTrees(JalviewModel jm, Viewport view, AlignFrame af,
+          AlignViewport av, AlignmentPanel ap)
   {
     // TODO result of automated refactoring - are all these parameters needed?
     try
@@ -4275,8 +4276,8 @@ public class Jalview2XML
           for (int s = 0; s < structureStateCount; s++)
           {
             // check to see if we haven't already created this structure view
-            final StructureState structureState = pdbid
-                    .getStructureState().get(s);
+            final StructureState structureState = pdbid.getStructureState()
+                    .get(s);
             String sviewid = (structureState.getViewId() == null) ? null
                     : structureState.getViewId() + uniqueSetSuffix;
             jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
@@ -4339,8 +4340,8 @@ public class Jalview2XML
             colourByViewer &= structureState.isColourByJmol();
             jmoldat.setColourByViewer(colourByViewer);
 
-            if (jmoldat.getStateData().length() < structureState
-                    .getValue()/*Content()*/.length())
+            if (jmoldat.getStateData().length() < structureState.getValue()
+                    /*Content()*/.length())
             {
               jmoldat.setStateData(structureState.getValue());// Content());
             }
@@ -4535,7 +4536,8 @@ public class Jalview2XML
           String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
           filedat = oldFiles.get(new File(reformatedOldFilename));
         }
-        newFileLoc.append(Platform.escapeBackslashes(filedat.getFilePath()));
+        newFileLoc
+                .append(Platform.escapeBackslashes(filedat.getFilePath()));
         pdbfilenames.add(filedat.getFilePath());
         pdbids.add(filedat.getPdbId());
         seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
@@ -4848,9 +4850,9 @@ public class Jalview2XML
   }
 
   AlignFrame loadViewport(String file, List<JSeq> JSEQ,
-          List<SequenceI> hiddenSeqs, AlignmentI al,
-          JalviewModel jm, Viewport view, String uniqueSeqSetId,
-          String viewId, List<JvAnnotRow> autoAlan)
+          List<SequenceI> hiddenSeqs, AlignmentI al, JalviewModel jm,
+          Viewport view, String uniqueSeqSetId, String viewId,
+          List<JvAnnotRow> autoAlan)
   {
     AlignFrame af = null;
     af = new AlignFrame(al, safeInt(view.getWidth()),
@@ -4931,9 +4933,8 @@ public class Jalview2XML
 
     viewport.setColourText(safeBoolean(view.isShowColourText()));
 
-    viewport
-            .setConservationSelected(
-                    safeBoolean(view.isConservationSelected()));
+    viewport.setConservationSelected(
+            safeBoolean(view.isConservationSelected()));
     viewport.setIncrement(safeInt(view.getConsThreshold()));
     viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
     viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
@@ -5009,9 +5010,8 @@ public class Jalview2XML
     af.changeColour(cs);
     viewport.setColourAppliesToAllGroups(true);
 
-    viewport
-            .setShowSequenceFeatures(
-                    safeBoolean(view.isShowSequenceFeatures()));
+    viewport.setShowSequenceFeatures(
+            safeBoolean(view.isShowSequenceFeatures()));
 
     viewport.setCentreColumnLabels(view.isCentreColumnLabels());
     viewport.setIgnoreGapsConsensus(view.isIgnoreGapsinConsensus(), null);
@@ -5035,13 +5035,13 @@ public class Jalview2XML
               .getFeatureRenderer();
       FeaturesDisplayed fdi;
       viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
-      String[] renderOrder = new String[jm.getFeatureSettings()
-              .getSetting().size()];
+      String[] renderOrder = new String[jm.getFeatureSettings().getSetting()
+              .size()];
       Map<String, FeatureColourI> featureColours = new Hashtable<>();
       Map<String, Float> featureOrder = new Hashtable<>();
 
-      for (int fs = 0; fs < jm.getFeatureSettings()
-              .getSetting().size(); fs++)
+      for (int fs = 0; fs < jm.getFeatureSettings().getSetting()
+              .size(); fs++)
       {
         Setting setting = jm.getFeatureSettings().getSetting().get(fs);
         String featureType = setting.getType();
@@ -5053,8 +5053,8 @@ public class Jalview2XML
                 .getMatcherSet();
         if (filters != null)
         {
-          FeatureMatcherSetI filter = Jalview2XML
-                  .parseFilter(featureType, filters);
+          FeatureMatcherSetI filter = Jalview2XML.parseFilter(featureType,
+                  filters);
           if (!filter.isEmpty())
           {
             fr.setFeatureFilter(featureType, filter);
@@ -5086,8 +5086,7 @@ public class Jalview2XML
           float max = setting.getMax() == null ? 1f
                   : setting.getMax().floatValue();
           FeatureColourI gc = new FeatureColour(maxColour, minColour,
-                  maxColour,
-                  noValueColour, min, max);
+                  maxColour, noValueColour, min, max);
           if (setting.getAttributeName().size() > 0)
           {
             gc.setAttributeName(setting.getAttributeName().toArray(
@@ -5121,8 +5120,7 @@ public class Jalview2XML
         }
         else
         {
-          featureColours.put(featureType,
-                  new FeatureColour(maxColour));
+          featureColours.put(featureType, new FeatureColour(maxColour));
         }
         renderOrder[fs] = featureType;
         if (setting.getOrder() != null)
@@ -5595,6 +5593,7 @@ public class Jalview2XML
       }
     }
   }
+
   /**
    * 
    * @param vamsasSeq
@@ -6341,8 +6340,8 @@ public class Jalview2XML
    * @param fcol
    * @return
    */
-  public static Colour marshalColour(
-          String featureType, FeatureColourI fcol)
+  public static Colour marshalColour(String featureType,
+          FeatureColourI fcol)
   {
     Colour col = new Colour();
     if (fcol.isSimpleColour())
@@ -6403,7 +6402,7 @@ public class Jalview2XML
           boolean and)
   {
     jalview.xml.binding.jalview.FeatureMatcherSet result = new jalview.xml.binding.jalview.FeatureMatcherSet();
-  
+
     if (filters.hasNext())
     {
       /*
@@ -6453,7 +6452,7 @@ public class Jalview2XML
       }
       result.setMatchCondition(matcherModel);
     }
-  
+
     return result;
   }
 
@@ -6464,8 +6463,7 @@ public class Jalview2XML
    * @param matcherSetModel
    * @return
    */
-  public static FeatureMatcherSetI parseFilter(
-          String featureType,
+  public static FeatureMatcherSetI parseFilter(String featureType,
           jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel)
   {
     FeatureMatcherSetI result = new FeatureMatcherSet();
@@ -6480,7 +6478,7 @@ public class Jalview2XML
                       featureType, e.getMessage()));
       // return as much as was parsed up to the error
     }
-  
+
     return result;
   }
 
@@ -6495,8 +6493,7 @@ public class Jalview2XML
    * @throws IllegalStateException
    *           if AND and OR conditions are mixed
    */
-  protected static void parseFilterConditions(
-          FeatureMatcherSetI matcherSet,
+  protected static void parseFilterConditions(FeatureMatcherSetI matcherSet,
           jalview.xml.binding.jalview.FeatureMatcherSet matcherSetModel,
           boolean and)
   {
@@ -6518,7 +6515,7 @@ public class Jalview2XML
       else if (filterBy == FilterBy.BY_SCORE)
       {
         matchCondition = FeatureMatcher.byScore(cond, pattern);
-  
+
       }
       else if (filterBy == FilterBy.BY_ATTRIBUTE)
       {
@@ -6528,7 +6525,7 @@ public class Jalview2XML
         matchCondition = FeatureMatcher.byAttribute(cond, pattern,
                 attNames);
       }
-  
+
       /*
        * note this throws IllegalStateException if AND-ing to a 
        * previously OR-ed compound condition, or vice versa
@@ -6571,13 +6568,13 @@ public class Jalview2XML
   public static FeatureColourI parseColour(Colour colourModel)
   {
     FeatureColourI colour = null;
-  
+
     if (colourModel.getMax() != null)
     {
       Color mincol = null;
       Color maxcol = null;
       Color noValueColour = null;
-  
+
       try
       {
         mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
@@ -6586,7 +6583,7 @@ public class Jalview2XML
       {
         Cache.log.warn("Couldn't parse out graduated feature color.", e);
       }
-  
+
       NoValueColour noCol = colourModel.getNoValueColour();
       if (noCol == NoValueColour.MIN)
       {
@@ -6596,7 +6593,7 @@ public class Jalview2XML
       {
         noValueColour = maxcol;
       }
-  
+
       colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour,
               safeFloat(colourModel.getMin()),
               safeFloat(colourModel.getMax()));
@@ -6635,7 +6632,7 @@ public class Jalview2XML
       Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
       colour = new FeatureColour(color);
     }
-  
+
     return colour;
   }
 }
index a5a9460..74f77a2 100644 (file)
@@ -64,4 +64,9 @@ public class HttpUtils
     return false;
   }
 
+  public static boolean startsWithHttpOrHttps(String file)
+  {
+    return file.startsWith("http://") || file.startsWith("https://");
+  }
+
 }
index b5f9653..9790f79 100644 (file)
  */
 package jalview.ws.sifts;
 
-import jalview.analysis.AlignSeq;
-import jalview.analysis.scoremodels.ScoreMatrix;
-import jalview.analysis.scoremodels.ScoreModels;
-import jalview.api.DBRefEntryI;
-import jalview.api.SiftsClientI;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.DBRefSource;
-import jalview.datamodel.SequenceI;
-import jalview.io.StructureFile;
-import jalview.schemes.ResidueProperties;
-import jalview.structure.StructureMapping;
-import jalview.util.Comparison;
-import jalview.util.DBRefUtils;
-import jalview.util.Format;
-import jalview.xml.binding.sifts.Entry;
-import jalview.xml.binding.sifts.Entry.Entity;
-import jalview.xml.binding.sifts.Entry.Entity.Segment;
-import jalview.xml.binding.sifts.Entry.Entity.Segment.ListMapRegion.MapRegion;
-import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue;
-import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.CrossRefDb;
-import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.ResidueDetail;
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -73,6 +51,28 @@ import javax.xml.stream.XMLStreamReader;
 
 import MCview.Atom;
 import MCview.PDBChain;
+import jalview.analysis.AlignSeq;
+import jalview.analysis.scoremodels.ScoreMatrix;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.api.DBRefEntryI;
+import jalview.api.SiftsClientI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.SequenceI;
+import jalview.io.BackupFiles;
+import jalview.io.StructureFile;
+import jalview.schemes.ResidueProperties;
+import jalview.structure.StructureMapping;
+import jalview.util.Comparison;
+import jalview.util.DBRefUtils;
+import jalview.util.Format;
+import jalview.xml.binding.sifts.Entry;
+import jalview.xml.binding.sifts.Entry.Entity;
+import jalview.xml.binding.sifts.Entry.Entity.Segment;
+import jalview.xml.binding.sifts.Entry.Entity.Segment.ListMapRegion.MapRegion;
+import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue;
+import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.CrossRefDb;
+import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.ResidueDetail;
 
 public class SiftsClient implements SiftsClientI
 {
@@ -123,6 +123,7 @@ public class SiftsClient implements SiftsClientI
   private enum CoordinateSys
   {
     UNIPROT("UniProt"), PDB("PDBresnum"), PDBe("PDBe");
+
     private String name;
 
     private CoordinateSys(String name)
@@ -140,6 +141,7 @@ public class SiftsClient implements SiftsClientI
   {
     NAME_SEC_STRUCTURE("nameSecondaryStructure"),
     CODE_SEC_STRUCTURE("codeSecondaryStructure"), ANNOTATION("Annotation");
+
     private String code;
 
     private ResidueDetailType(String code)
@@ -225,7 +227,7 @@ public class SiftsClient implements SiftsClientI
               SiftsSettings.getCacheThresholdInDays()))
       {
         File oldSiftsFile = new File(siftsFileName + "_old");
-        siftsFile.renameTo(oldSiftsFile);
+        BackupFiles.moveFileToFile(siftsFile, oldSiftsFile);
         try
         {
           siftsFile = downloadSiftsFile(pdbId.toLowerCase());
@@ -234,7 +236,7 @@ public class SiftsClient implements SiftsClientI
         } catch (IOException e)
         {
           e.printStackTrace();
-          oldSiftsFile.renameTo(siftsFile);
+          BackupFiles.moveFileToFile(oldSiftsFile, siftsFile);
           return new File(siftsFileName);
         }
       }
@@ -461,7 +463,7 @@ public class SiftsClient implements SiftsClientI
           SequenceI seq, java.io.PrintStream os) throws SiftsException
   {
     List<Integer> omitNonObserved = new ArrayList<>();
-    int nonObservedShiftIndex = 0,pdbeNonObserved=0;
+    int nonObservedShiftIndex = 0, pdbeNonObserved = 0;
     // System.out.println("Generating mappings for : " + entityId);
     Entity entity = null;
     entity = getEntityById(entityId);
@@ -492,7 +494,7 @@ public class SiftsClient implements SiftsClientI
     TreeMap<Integer, String> resNumMap = new TreeMap<Integer, String>();
     List<Segment> segments = entity.getSegment();
     SegmentHelperPojo shp = new SegmentHelperPojo(seq, mapping, resNumMap,
-            omitNonObserved, nonObservedShiftIndex,pdbeNonObserved);
+            omitNonObserved, nonObservedShiftIndex, pdbeNonObserved);
     processSegments(segments, shp);
     try
     {
@@ -514,18 +516,20 @@ public class SiftsClient implements SiftsClientI
     {
       throw new SiftsException("SIFTS mapping failed");
     }
-    // also construct a mapping object between the seq-coord sys and the PDB seq's coord sys
+    // also construct a mapping object between the seq-coord sys and the PDB
+    // seq's coord sys
 
     Integer[] keys = mapping.keySet().toArray(new Integer[0]);
     Arrays.sort(keys);
     seqStart = keys[0];
     seqEnd = keys[keys.length - 1];
-    List<int[]> from=new ArrayList<>(),to=new ArrayList<>();
-    int[]_cfrom=null,_cto=null;
+    List<int[]> from = new ArrayList<>(), to = new ArrayList<>();
+    int[] _cfrom = null, _cto = null;
     String matchedSeq = originalSeq;
-    if (seqStart != UNASSIGNED) // fixme! seqStart can map to -1 for a pdb sequence that starts <-1
+    if (seqStart != UNASSIGNED) // fixme! seqStart can map to -1 for a pdb
+                                // sequence that starts <-1
     {
-      for (int seqps:keys)
+      for (int seqps : keys)
       {
         int pdbpos = mapping.get(seqps)[PDBE_POS];
         if (pdbpos == UNASSIGNED)
@@ -533,19 +537,23 @@ public class SiftsClient implements SiftsClientI
           // not correct - pdbpos might be -1, but leave it for now
           continue;
         }
-        if (_cfrom==null || seqps!=_cfrom[1]+1)
+        if (_cfrom == null || seqps != _cfrom[1] + 1)
         {
-          _cfrom = new int[] { seqps,seqps};
+          _cfrom = new int[] { seqps, seqps };
           from.add(_cfrom);
           _cto = null; // discontinuity
-        } else {
-          _cfrom[1]= seqps;
         }
-        if (_cto==null || pdbpos!=1+_cto[1])
+        else
+        {
+          _cfrom[1] = seqps;
+        }
+        if (_cto == null || pdbpos != 1 + _cto[1])
         {
-          _cto = new int[] { pdbpos,pdbpos};
+          _cto = new int[] { pdbpos, pdbpos };
           to.add(_cto);
-        } else {
+        }
+        else
+        {
           _cto[1] = pdbpos;
         }
       }
@@ -567,8 +575,7 @@ public class SiftsClient implements SiftsClientI
       ;
 
       seqFromPdbMapping = new jalview.datamodel.Mapping(null, _cto, _cfrom,
-              1,
-              1);
+              1, 1);
       pdbStart = mapping.get(seqStart)[PDB_RES_POS];
       pdbEnd = mapping.get(seqEnd)[PDB_RES_POS];
       int orignalSeqStart = seq.getStart();
@@ -699,12 +706,12 @@ public class SiftsClient implements SiftsClientI
         }
         // if (currSeqIndex >= seq.getStart() && currSeqIndex <= seqlength) //
         // true
-                                                                         // numbering
-                                                                         // is
-                                                                         // not
-                                                                         // up
-                                                                         // to
-                                                                         // seq.getEnd()
+        // numbering
+        // is
+        // not
+        // up
+        // to
+        // seq.getEnd()
         {
 
           int resNum = (pdbRefDb == null)
@@ -1044,6 +1051,7 @@ public class SiftsClient implements SiftsClientI
     {
       return pdbeNonObserved;
     }
+
     public SequenceI getSeq()
     {
       return seq;
diff --git a/utils/clover/lib/clover-ant-4.4.1.jar b/utils/clover/lib/clover-ant-4.4.1.jar
new file mode 100644 (file)
index 0000000..4f92395
Binary files /dev/null and b/utils/clover/lib/clover-ant-4.4.1.jar differ
diff --git a/utils/cmd-nox.sh b/utils/cmd-nox.sh
new file mode 100755 (executable)
index 0000000..bd615bd
--- /dev/null
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+CMD=$(basename $0)
+CMD=${CMD%-nox.sh}
+
+echo "Running '$CMD' headlessly"
+
+xvfb-run -s "-screen 0 1280x800x16" -e /dev/stdout -a $CMD ${@}
diff --git a/utils/gradle-nox.sh b/utils/gradle-nox.sh
new file mode 120000 (symlink)
index 0000000..4abb9a2
--- /dev/null
@@ -0,0 +1 @@
+cmd-nox.sh
\ No newline at end of file