Merge branch 'develop' into trialMerge
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 24 May 2019 10:31:34 +0000 (11:31 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 24 May 2019 10:31:34 +0000 (11:31 +0100)
Conflicts:
.classpath
.project
.settings/org.eclipse.jdt.core.prefs
.settings/org.eclipse.jdt.groovy.core.prefs
.settings/org.eclipse.jdt.ui.prefs
build.xml
src/MCview/AppletPDBCanvas.java
src/MCview/Atom.java
src/MCview/PDBCanvas.java
src/jalview/appletgui/EmbmenuFrame.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/SeqPanel.java
src/jalview/bin/Jalview.java
src/jalview/ext/paradise/Annotate3D.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/FeatureTypeSettings.java
src/jalview/io/FileLoader.java
src/jalview/jbgui/GDesktop.java
src/jalview/util/ImageMaker.java
src/jalview/util/Platform.java

50 files changed:
1  2 
.classpath
.project
.settings/org.eclipse.jdt.core.prefs
.settings/org.eclipse.jdt.ui.prefs
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/MCview/AppletPDBCanvas.java
src/MCview/Atom.java
src/MCview/PDBCanvas.java
src/jalview/analysis/AlignmentSorter.java
src/jalview/analysis/Conservation.java
src/jalview/analysis/StructureFrequency.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/EmbmenuFrame.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/SeqPanel.java
src/jalview/bin/Jalview.java
src/jalview/bin/JalviewLite.java
src/jalview/controller/AlignViewController.java
src/jalview/datamodel/Alignment.java
src/jalview/ext/ensembl/EnsemblMap.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/paradise/Annotate3D.java
src/jalview/gui/APQHandlers.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AppJmol.java
src/jalview/gui/BlogReader.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/FeatureTypeSettings.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/SplitFrame.java
src/jalview/io/AnnotationFile.java
src/jalview/io/FeaturesFile.java
src/jalview/io/JPredFile.java
src/jalview/io/ModellerDescription.java
src/jalview/io/NewickFile.java
src/jalview/io/vamsas/Tree.java
src/jalview/io/vcf/VCFLoader.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GDesktop.java
src/jalview/project/Jalview2XML.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/util/Platform.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
src/org/jibble/epsgraphics/EpsGraphics2D.java
test/jalview/io/vcf/VCFLoaderTest.java

diff --combined .classpath
index 004d432,0000000..430d9e6
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,183 @@@
 +<?xml version="1.0" encoding="UTF-8"?>
 +<classpath>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="src" path="src2"/>
-       <classpathentry kind="src" path="test"/>
-       <classpathentry kind="src" path="utils"/>
-       <classpathentry kind="lib" path="lib/activation.jar"/>
-       <classpathentry kind="lib" path="lib/axis.jar" sourcepath="D:/axis-1_2RC2-src/axis-1_2RC2"/>
-       <classpathentry kind="lib" path="lib/commons-discovery.jar"/>
-       <classpathentry kind="lib" path="lib/jaxrpc.jar"/>
-       <classpathentry kind="lib" path="lib/jhall.jar"/>
-       <classpathentry kind="lib" path="lib/mail.jar"/>
-       <classpathentry kind="lib" path="lib/regex.jar"/>
-       <classpathentry kind="lib" path="lib/saaj.jar"/>
-       <classpathentry kind="lib" path="lib/wsdl4j.jar"/>
-       <classpathentry kind="lib" path="lib/xercesImpl.jar"/>
-       <classpathentry kind="lib" path="lib/JGoogleAnalytics_0.3.jar" sourcepath="/JGoogleAnalytics/src/main/java"/>
-       <classpathentry kind="lib" path="lib/vamsas-client.jar"/>
-       <classpathentry kind="lib" path="lib/commons-logging-1.1.1.jar"/>
-       <classpathentry kind="lib" path="lib/apache-mime4j-0.6.jar" sourcepath="G:/InstallsDir/Sources for Development/apache-mime4j-0.6-src.zip"/>
-       <classpathentry kind="lib" path="lib/httpclient-4.0.3.jar">
-               <attributes>
-                       <attribute name="javadoc_location" value="file:/D:/InstallsDir/Sources for Development/httpconnect/httpcomponents-client-4.0.3/javadoc/"/>
-               </attributes>
-       </classpathentry>
-       <classpathentry kind="lib" path="lib/httpcore-4.0.1.jar">
-               <attributes>
-                       <attribute name="javadoc_location" value="file:/D:/InstallsDir/Sources for Development/httpconnect/httpcomponents-client-4.0.3/javadoc/"/>
-               </attributes>
-       </classpathentry>
-       <classpathentry kind="lib" path="lib/httpmime-4.0.3.jar">
-               <attributes>
-                       <attribute name="javadoc_location" value="file:/D:/InstallsDir/Sources for Development/httpconnect/httpcomponents-client-4.0.3/javadoc/"/>
-               </attributes>
-       </classpathentry>
-       <classpathentry kind="lib" path="lib/miglayout-4.0-swing.jar"/>
-       <classpathentry kind="lib" path="lib/jswingreader-0.3.jar" sourcepath="/jswingreader"/>
-       <classpathentry kind="lib" path="lib/commons-codec-1.3.jar"/>
-       <classpathentry kind="lib" path="lib/jabaws-min-client-2.2.0.jar" sourcepath="/clustengine"/>
-       <classpathentry kind="lib" path="lib/json_simple-1.1.jar" sourcepath="/Users/jimp/Downloads/json_simple-1.1-all.zip"/>
-       <classpathentry kind="lib" path="lib/slf4j-api-1.7.7.jar"/>
-       <classpathentry kind="lib" path="lib/jsoup-1.8.1.jar"/>
-       <classpathentry kind="lib" path="lib/log4j-to-slf4j-2.0-rc2.jar"/>
-       <classpathentry kind="lib" path="lib/slf4j-log4j12-1.7.7.jar"/>
-       <classpathentry kind="lib" path="lib/VARNAv3-93.jar"/>
-       <classpathentry kind="lib" path="lib/jfreesvg-2.1.jar"/>
-       <classpathentry kind="lib" path="lib/quaqua-filechooser-only-8.0.jar"/>
-       <classpathentry kind="lib" path="lib/VAqua5-patch.jar"/>
-       <classpathentry kind="lib" path="utils/classgraph-4.1.6.jar"/>
-       <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/plugin"/>
-       <classpathentry kind="lib" path="lib/xml-apis.jar"/>
-       <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
-       <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Plugin.jar"/>
-       <classpathentry kind="lib" path="lib/jersey-client-1.19.jar"/>
-       <classpathentry kind="lib" path="lib/jersey-core-1.19.jar"/>
-       <classpathentry kind="lib" path="lib/jsr311-api-1.1.1.jar"/>
-       <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/plugin.jar"/>
-       <classpathentry kind="lib" path="lib/jetty-server-9.2.10.v20150310.jar"/>
-       <classpathentry kind="lib" path="lib/servlet-api-3.1.jar"/>
-       <classpathentry kind="lib" path="lib/jetty-util-9.2.10.v20150310.jar"/>
-       <classpathentry kind="lib" path="lib/jetty-http-9.2.10.v20150310.jar"/>
-       <classpathentry kind="lib" path="lib/jetty-io-9.2.10.v20150310.jar"/>
-       <classpathentry kind="lib" path="lib/java-json.jar"/>
-       <classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
-       <classpathentry kind="lib" path="lib/biojava-core-4.1.0.jar"/>
-       <classpathentry kind="lib" path="lib/biojava-ontology-4.1.0.jar"/>
-       <classpathentry kind="lib" path="lib/htsjdk-2.12.0.jar"/>
-       <classpathentry kind="lib" path="lib/groovy-all-2.4.12-indy.jar"/>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
-       <classpathentry exported="true" kind="con" path="GROOVY_DSL_SUPPORT"/>
++      <classpathentry kind="src" output="bin/main" path="src">
++              <attributes>
++                      <attribute name="gradle_scope" value="main"/>
++                      <attribute name="gradle_used_by_scope" value=""/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="src" output="bin/test" path="test">
++              <attributes>
++                      <attribute name="test" value="true"/>
++                      <attribute name="gradle_scope" value="test"/>
++                      <attribute name="gradle_used_by_scope" value=""/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
++              <attributes>
++                      <attribute name="module" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
++      <classpathentry kind="lib" path="help"/>
++      <classpathentry kind="lib" path="resources"/>
++      <classpathentry kind="lib" path="j11lib/apache-mime4j-0.6.jar"/>
++      <classpathentry kind="lib" path="j11lib/axis.jar"/>
++      <classpathentry kind="lib" path="j11lib/biojava-core-4.1.0.jar"/>
++      <classpathentry kind="lib" path="j11lib/biojava-ontology-4.1.0.jar"/>
++      <classpathentry kind="lib" path="j11lib/commons-codec-1.3.jar"/>
++      <classpathentry kind="lib" path="j11lib/commons-compress-1.18.jar"/>
++      <classpathentry kind="lib" path="j11lib/commons-discovery.jar"/>
++      <classpathentry kind="lib" path="j11lib/commons-logging-1.1.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/FastInfoset.jar"/>
++      <classpathentry kind="lib" path="j11lib/getdown-core.jar"/>
++      <classpathentry kind="lib" path="j11lib/gmbal-api-only-MODULE.jar"/>
++      <classpathentry kind="lib" path="j11lib/groovy-2.5.6.jar"/>
++      <classpathentry kind="lib" path="j11lib/groovy-console-2.5.6.jar"/>
++      <classpathentry kind="lib" path="j11lib/htsjdk-2.12.0.jar"/>
++      <classpathentry kind="lib" path="j11lib/httpclient-4.0.3.jar"/>
++      <classpathentry kind="lib" path="j11lib/httpcore-4.0.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/httpmime-4.0.3.jar"/>
++      <classpathentry kind="lib" path="j11lib/i4jruntime.jar"/>
++      <classpathentry kind="lib" path="j11lib/intervalstore-v1.0.jar"/>
++      <classpathentry kind="lib" path="j11lib/istack-commons-runtime.jar"/>
++      <classpathentry kind="lib" path="j11lib/jabaws-min-client-2.2.0.jar"/>
++      <classpathentry kind="lib" path="j11lib/java-json.jar"/>
++      <classpathentry kind="lib" path="j11lib/javax.activation-MODULE.jar"/>
++      <classpathentry kind="lib" path="j11lib/javax.annotation-api-MODULE.jar"/>
++      <classpathentry kind="lib" path="j11lib/javax.jws-api-1.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/javax.servlet-api-MODULE.jar"/>
++      <classpathentry kind="lib" path="j11lib/javax.xml.rpc-api-1.1.2.jar"/>
++      <classpathentry kind="lib" path="j11lib/javax.xml.soap-api.jar"/>
++      <classpathentry kind="lib" path="j11lib/jaxb-api-java9.jar"/>
++      <classpathentry kind="lib" path="j11lib/jaxb-runtime.jar"/>
++      <classpathentry kind="lib" path="j11lib/jaxws-api.jar"/>
++      <classpathentry kind="lib" path="j11lib/jaxws-rt-java9.jar"/>
++      <classpathentry kind="lib" path="j11lib/jersey-client-1.19.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/jersey-core-1.19.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/jersey-json-1.19.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/jetty-http-9.2.10.v20150310.jar"/>
++      <classpathentry kind="lib" path="j11lib/jetty-io-9.2.10.v20150310.jar"/>
++      <classpathentry kind="lib" path="j11lib/jetty-server-9.2.10.v20150310.jar"/>
++      <classpathentry kind="lib" path="j11lib/jetty-util-9.2.10.v20150310.jar"/>
++      <classpathentry kind="lib" path="j11lib/jfreesvg-2.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/JGoogleAnalytics_0.3.jar"/>
++      <classpathentry kind="lib" path="j11lib/jhall.jar"/>
++      <classpathentry kind="lib" path="j11lib/json_simple-1.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/jsoup-1.8.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/jsr311-api-1.1.1.jar"/>
++      <classpathentry kind="lib" path="j11lib/jswingreader-0.3.jar"/>
++      <classpathentry kind="lib" path="j11lib/libquaqua-8.0.jnilib.jar"/>
++      <classpathentry kind="lib" path="j11lib/libquaqua64-8.0.jnilib.jar"/>
++      <classpathentry kind="lib" path="j11lib/log4j-to-slf4j-2.0-rc2.jar"/>
++      <classpathentry kind="lib" path="j11lib/mail-MODULE.jar"/>
++      <classpathentry kind="lib" path="j11lib/miglayout-4.0-swing.jar"/>
++      <classpathentry kind="lib" path="j11lib/mimepull.jar"/>
++      <classpathentry kind="lib" path="j11lib/policy.jar"/>
++      <classpathentry kind="lib" path="j11lib/quaqua-filechooser-only-8.0.jar"/>
++      <classpathentry kind="lib" path="j11lib/regex.jar"/>
++      <classpathentry kind="lib" path="j11lib/saaj-impl.jar"/>
++      <classpathentry kind="lib" path="j11lib/slf4j-api-1.7.7.jar"/>
++      <classpathentry kind="lib" path="j11lib/slf4j-log4j12-1.7.7.jar"/>
++      <classpathentry kind="lib" path="j11lib/stax-ex.jar"/>
++      <classpathentry kind="lib" path="j11lib/stax2-api-MODULE.jar"/>
++      <classpathentry kind="lib" path="j11lib/streambuffer.jar"/>
++      <classpathentry kind="lib" path="j11lib/txw2.jar"/>
++      <classpathentry kind="lib" path="j11lib/vamsas-client.jar"/>
++      <classpathentry kind="lib" path="j11lib/VAqua5-patch.jar"/>
++      <classpathentry kind="lib" path="j11lib/VARNAv3-93.jar"/>
++      <classpathentry kind="lib" path="j11lib/wsdl4j-MODULE.jar"/>
++      <classpathentry kind="lib" path="j11lib/xercesImpl.jar"/>
++      <classpathentry kind="lib" path="utils/ant-contrib-1.0b3.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/axis-ant.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/classgraph-4.1.6.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/hamcrest-core-1.3.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/jhall.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/jhindexer.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/junit-4.12.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/proguard_5.3.3.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/roxes-ant-tasks-1.2-2004-01-30.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/testnglibs/bsh-2.0b4.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/testnglibs/guava-base-r03.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/testnglibs/guava-collections-r03.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/testnglibs/jcommander.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/testnglibs/junit-4.12.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/testnglibs/snakeyaml.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/testnglibs/testng-sources.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/testnglibs/testng.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
++      <classpathentry kind="lib" path="utils/wsdl4j.jar">
++              <attributes>
++                      <attribute name="test" value="true"/>
++              </attributes>
++      </classpathentry>
 +      <classpathentry kind="lib" path="lib/Jmol-14.29.17.jar"/>
-       <classpathentry kind="lib" path="lib/intervalstore-v1.0.jar"/>
-       <classpathentry kind="output" path="classes"/>
++      <classpathentry kind="output" path="bin/main"/>
 +</classpath>
diff --combined .project
index 6c40472,0000000..d4d0c20
mode 100644,000000..100644
--- /dev/null
+++ b/.project
@@@ -1,37 -1,0 +1,23 @@@
 +<?xml version="1.0" encoding="UTF-8"?>
 +<projectDescription>
-       <name>Jalview Release 2.7-old</name>
++      <name>Jalview with gradle build</name>
 +      <comment></comment>
-       <projects>
-       </projects>
++      <projects/>
++      <natures>
++              <nature>org.eclipse.jdt.core.javanature</nature>
++              <nature>org.eclipse.jdt.groovy.core.groovyNature</nature>
++              <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
++      </natures>
 +      <buildSpec>
 +              <buildCommand>
 +                      <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.wst.common.project.facet.core.builder</name>
-                       <arguments>
-                       </arguments>
++                      <arguments/>
 +              </buildCommand>
 +              <buildCommand>
-                       <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
-                       <triggers>full,incremental,</triggers>
-                       <arguments>
-                               <dictionary>
-                                       <key>LaunchConfigHandle</key>
-                                       <value>&lt;project&gt;/.externalToolBuilders/Jalview Release indices [Builder].launch</value>
-                               </dictionary>
-                       </arguments>
++                      <name>org.eclipse.buildship.core.gradleprojectbuilder</name>
++                      <arguments/>
 +              </buildCommand>
 +      </buildSpec>
-       <natures>
-               <nature>org.eclipse.jdt.groovy.core.groovyNature</nature>
-               <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-               <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
-               <nature>de.tud.st.ispace.builder.ISpaceNature</nature>
-               <nature>org.eclipse.jem.beaninfo.BeanInfoNature</nature>
-       </natures>
++      <linkedResources/>
++      <filteredResources/>
 +</projectDescription>
index 32ad05c,0000000..604d902
mode 100644,000000..100644
--- /dev/null
@@@ -1,421 -1,0 +1,298 @@@
 +eclipse.preferences.version=1
- org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
- org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
- org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
- org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
- org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
- org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
- org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
- org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
- org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 +org.eclipse.jdt.core.compiler.compliance=1.8
 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 +org.eclipse.jdt.core.compiler.debug.localVariable=generate
 +org.eclipse.jdt.core.compiler.debug.sourceFile=generate
- org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
- org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
- org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
- org.eclipse.jdt.core.compiler.problem.deadCode=warning
- org.eclipse.jdt.core.compiler.problem.deprecation=warning
- org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
- org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
 +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
- org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
 +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
- org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
- org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
- org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
- org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
- org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
- org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
- org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
- org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
- org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
- org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
- org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
- org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
- org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
- org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
- org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
- org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
- org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
- org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
- org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
- org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
- org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
- org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
- org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
- org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
- org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
- org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
- org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
- org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
- org.eclipse.jdt.core.compiler.problem.nullReference=warning
- org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
- org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
- org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
- org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
- org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
- org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
- org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
- org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
- org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
- org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
- org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
- org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
- org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
- org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
- org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
- org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
- org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
- org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
- org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
- org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
- org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
- org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
- org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
- org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
- org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
- org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
- org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
- org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
- org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
- org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
- org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
- org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
- org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
- org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
- org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
- org.eclipse.jdt.core.compiler.problem.unusedImport=warning
- org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
- org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
- org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
- org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
- org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
- org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
- org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
- org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
- org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
- org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
- org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
 +org.eclipse.jdt.core.compiler.release=disabled
 +org.eclipse.jdt.core.compiler.source=1.8
- org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
- org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
- org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
- org.eclipse.jdt.core.formatter.align_with_spaces=false
 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=52
 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0
 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
- org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
- org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
- org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
- org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
- org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
- org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1
 +org.eclipse.jdt.core.formatter.blank_lines_before_field=1
 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1
 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0
 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line
 +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=next_line
 +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=next_line_on_wrap
 +org.eclipse.jdt.core.formatter.brace_position_for_block=next_line
 +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line
 +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line
 +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line
 +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line
 +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
 +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line
 +org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line
 +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
- org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false
- org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
 +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
 +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
- org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false
 +org.eclipse.jdt.core.formatter.comment.format_block_comments=false
 +org.eclipse.jdt.core.formatter.comment.format_header=false
 +org.eclipse.jdt.core.formatter.comment.format_html=true
 +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
 +org.eclipse.jdt.core.formatter.comment.format_line_comments=true
 +org.eclipse.jdt.core.formatter.comment.format_source_code=true
 +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
 +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
 +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
 +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
 +org.eclipse.jdt.core.formatter.comment.line_length=80
 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
 +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
 +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
 +org.eclipse.jdt.core.formatter.compact_else_if=true
 +org.eclipse.jdt.core.formatter.continuation_indentation=4
 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
 +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
 +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
 +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
 +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
 +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
 +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
 +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
 +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
 +org.eclipse.jdt.core.formatter.indent_empty_lines=false
 +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
 +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
 +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
 +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
- org.eclipse.jdt.core.formatter.indentation.size=2
- org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
++org.eclipse.jdt.core.formatter.indentation.size=8
 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
 +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
 +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
 +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
 +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
 +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
 +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
 +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
 +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
 +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
 +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
 +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
 +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
 +org.eclipse.jdt.core.formatter.join_lines_in_comments=true
 +org.eclipse.jdt.core.formatter.join_wrapped_lines=true
 +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
 +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=true
 +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
- org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
- org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
- org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
 +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
 +org.eclipse.jdt.core.formatter.lineSplit=76
 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
 +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
- org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
- org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
- org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
- org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
- org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
- org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
- org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
- org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
- org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
- org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
 +org.eclipse.jdt.core.formatter.tabulation.char=space
 +org.eclipse.jdt.core.formatter.tabulation.size=2
 +org.eclipse.jdt.core.formatter.use_on_off_tags=true
 +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
- org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
 +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
- org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
 +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
 +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
- org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
@@@ -1,7 -1,7 +1,7 @@@
  eclipse.preferences.version=1
  editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
  formatter_profile=_Jalview
- formatter_settings_version=14
+ formatter_settings_version=16
  org.eclipse.jdt.ui.ignorelowercasenames=true
  org.eclipse.jdt.ui.importorder=jalview;java;javax;org;com;
  org.eclipse.jdt.ui.ondemandthreshold=99
@@@ -41,7 -41,6 +41,7 @@@ sp_cleanup.qualify_static_member_access
  sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
  sp_cleanup.remove_private_constructors=true
  sp_cleanup.remove_redundant_modifiers=false
 +sp_cleanup.remove_redundant_semicolons=true
  sp_cleanup.remove_redundant_type_arguments=true
  sp_cleanup.remove_trailing_whitespaces=false
  sp_cleanup.remove_trailing_whitespaces_all=true
@@@ -32,6 -32,7 +32,7 @@@ action.load_project = Load Projec
  action.save_project = Save Project
  action.save_project_as = Save Project as...
  action.quit = Quit
+ label.quit_jalview = Quit Jalview?
  action.expand_views = Expand Views
  action.gather_views = Gather Views
  action.page_setup = Page Setup...
@@@ -359,8 -360,7 +360,8 @@@ label.open_saved_vamsas_session = Open 
  label.groovy_console = Groovy Console...
  label.lineart = Lineart
  label.dont_ask_me_again = Don't ask me again
 -label.select_eps_character_rendering_style = Select EPS character rendering style
 +label.select_character_rendering_style = {0} character rendering style
 +label.select_character_style_title = {0} Rendering options
  label.invert_selection = Invert Selection
  label.optimise_order = Optimise Order
  label.seq_sort_by_score = Sequence sort by Score
@@@ -409,7 -409,7 +410,7 @@@ label.input_alignment_from_url = Input 
  label.input_alignment = Input Alignment
  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.couldnt_locate = Couldn''t locate {0}
  label.url_not_found = URL not found
  label.new_sequence_url_link = New sequence URL link
  label.cannot_edit_annotations_in_wrapped_view = Cannot edit annotations in wrapped view
@@@ -595,7 -595,7 +596,7 @@@ label.check_for_questionnaires = Check 
  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.eps_rendering_style = EPS rendering style
 +label.rendering_style = {0} rendering style
  label.append_start_end = Append /start-end (/15-380)
  label.full_sequence_id = Full Sequence Id
  label.smooth_font = Smooth Font
@@@ -676,7 -676,7 +677,7 @@@ label.sequence_details_for = Sequence D
  label.sequence_name = Sequence Name
  label.sequence_description = Sequence Description
  label.edit_sequence_name_description = Edit Sequence Name/Description
 -label.spaces_converted_to_backslashes = Spaces have been converted to _
 +label.spaces_converted_to_underscores = Spaces have been converted to _
  label.no_spaces_allowed_sequence_name = No spaces allowed in Sequence Name
  label.select_outline_colour = Select Outline Colour
  label.web_browser_not_found_unix = Unixers\: Couldn't find default web browser.\nAdd the full path to your browser in Preferences."
@@@ -878,6 -878,8 +879,6 @@@ label.save_feature_colours = Save Featu
  label.select_startup_file = Select startup file
  label.select_default_browser = Select default web browser
  label.save_tree_as_newick = Save tree as newick file
 -label.create_eps_from_tree = Create EPS file from tree
 -label.create_png_from_tree = Create PNG image from tree
  label.save_colour_scheme = Save colour scheme
  label.edit_params_for = Edit parameters for {0}
  label.choose_filename_for_param_file = Choose a filename for this parameter file
@@@ -933,6 -935,8 +934,6 @@@ error.call_setprogressbar_before_regist
  label.cancelled_params = Cancelled {0}
  error.implementation_error_cannot_show_view_alignment_frame = Implementation error: cannot show a view from another alignment in an AlignFrame.
  error.implementation_error_dont_know_about_threshold_setting = Implementation error: don't know about threshold setting for current AnnotationColourGradient.
 -error.eps_generation_not_implemented = EPS Generation not yet implemented
 -error.png_generation_not_implemented = PNG Generation not yet implemented
  error.try_join_vamsas_session_another = Trying to join a vamsas session when another is already connected
  error.invalid_vamsas_session_id = Invalid vamsas session id
  label.groovy_support_failed = Jalview Groovy Support Failed
@@@ -994,7 -998,8 +995,8 @@@ label.toggled = Toggle
  label.marked = Marked
  label.containing = containing
  label.not_containing = not containing
- label.no_feature_of_type_found = No features of type {0} found.
+ label.no_feature_of_type_found = No features of type {0} found
+ label.no_feature_found_selection = No features of type {0} found in selection
  label.submission_params = Submission {0}
  label.empty_alignment_job = Empty Alignment Job
  label.add_new_sbrs_service = Add a new Simple Bioinformatics Rest Service
@@@ -1003,7 -1008,7 +1005,7 @@@ label.pca_recalculating = Recalculatin
  label.pca_calculating = Calculating PCA
  label.select_foreground_colour = Choose foreground colour
  label.select_colour_for_text = Select Colour for Text
 -label.adjunst_foreground_text_colour_threshold = Adjust Foreground Text Colour Threshold
 +label.adjust_foreground_text_colour_threshold = Adjust Foreground Text Colour Threshold
  label.select_subtree_colour = Select Sub-Tree Colour
  label.create_new_sequence_features = Create New Sequence Feature(s)
  label.amend_delete_features = Amend/Delete Features for {0}
@@@ -1075,6 -1080,7 +1077,6 @@@ error.implementation_error_cannot_find_
  exception.jobsubmission_invalid_params_set = Invalid parameter set. Check Jalview implementation
  exception.notvaliddata_group_contains_less_than_min_seqs = Group contains less than {0} sequences.
  exception.outofmemory_loading_pdb_file = Out of memory loading PDB File
 -exception.eps_coudnt_write_output_file = Could not write to the output file: {0}
  exception.eps_method_not_supported = Method not currently supported by EpsGraphics2D version {0}
  exception.eps_unable_to_get_inverse_matrix = Unable to get inverse of matrix: {0}
  warn.job_cannot_be_cancelled_close_window = This job cannot be cancelled.\nJust close the window.
@@@ -1099,7 -1105,8 +1101,7 @@@ status.searching_for_sequences_from = S
  status.finished_searching_for_sequences_from = Finished searching for sequences from {0}
  label.eps_file = EPS file
  label.png_image = PNG image
 -status.saving_file = Saving {0}
 -status.export_complete = {0} Export completed.
 +status.export_complete = {0} Export completed
  status.fetching_pdb = Fetching PDB {0}
  status.refreshing_news = Refreshing news
  status.importing_vamsas_session_from = Importing VAMSAS session from {0}
@@@ -1226,6 -1233,7 +1228,6 @@@ exception.fts_server_unreachable = Jalv
  label.nw_mapping = Needleman & Wunsch Alignment
  label.sifts_mapping = SIFTs Mapping
  label.mapping_method = Sequence \u27f7 Structure mapping method
 -status.waiting_for_user_to_select_output_file = Waiting for user to select {0} file
  status.cancelled_image_export_operation = Cancelled {0} export operation
  info.error_creating_file = Error creating {0} file
  exception.outofmemory_loading_mmcif_file = Out of memory loading mmCIF File
@@@ -1306,10 -1314,11 +1308,11 @@@ label.numeric_required = The value shou
  label.filter = Filter
  label.filters = Filters
  label.join_conditions = Join conditions with
+ label.delete_condition = Delete this condition
  label.score = Score
  label.colour_by_label = Colour by label
  label.variable_colour = Variable colour...
 -label.select_colour = Select colour
 +label.select_colour_for = Select colour for {0}
  option.enable_disable_autosearch = When ticked, search is performed automatically
  option.autosearch = Autosearch
  label.retrieve_ids = Retrieve IDs
@@@ -1330,13 -1339,6 +1333,13 @@@ label.most_bound_molecules = Most Boun
  label.most_polymer_residues = Most Polymer Residues
  label.cached_structures = Cached Structures
  label.free_text_search = Free Text Search
 +label.annotation_name = Annotation Name
 +label.annotation_description = Annotation Description 
 +label.edit_annotation_name_description = Edit Annotation Name/Description
 +label.alignment = alignment
 +label.pca = PCA
 +label.create_image_of = Create {0} image of {1}
 +label.click_to_edit = Click to edit, right-click for menu
  label.backupfiles_confirm_delete = Confirm delete
  label.backupfiles_confirm_delete_old_files = Delete the following older backup files? (see the Backups tab in Preferences for more options)
  label.backupfiles_confirm_save_file = Confirm save file
@@@ -32,6 -32,7 +32,7 @@@ action.load_project = Cargar proyect
  action.save_project = Guardar proyecto
  action.save_project_as = Guardar proyecto como...
  action.quit = Salir
+ label.quit_jalview = Salir Javliew?
  action.expand_views = Expandir vistas
  action.gather_views = Capturar vistas
  action.page_setup = Configuración de la página
@@@ -327,8 -328,7 +328,8 @@@ label.open_saved_vamsas_session = Abri
  label.groovy_console = Consola Groovy 
  label.lineart = Lineart
  label.dont_ask_me_again = No volver a preguntar
 -label.select_eps_character_rendering_style = Seleccionar el carácter EPS como estilo de visualización 
 +label.select_character_rendering_style = Estilo de visualización para carácter {0} 
 +label.select_character_style_title = Opciones de visualización {0}
  label.invert_selection = Invertir selección
  label.optimise_order = Optimizar orden
  label.seq_sort_by_score = Ordenar las secuencias por puntuación
@@@ -550,7 -550,7 +551,7 @@@ label.check_for_questionnaires = Compro
  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.eps_rendering_style = Estilo de visualización EPS
 +label.rendering_style = Estilo de visualización {0}
  label.append_start_end = Añadir /inicio-fin (/15-380)
  label.full_sequence_id = ID de la secuencia completo
  label.smooth_font = Fuente alargada
@@@ -626,7 -626,7 +627,7 @@@ label.sequence_details_for = Detalles d
  label.sequence_name = Nombre de la secuencia
  label.sequence_description = Descripción de la secuencia
  label.edit_sequence_name_description = Editar el nombre/descripción de la secuencia
 -label.spaces_converted_to_backslashes = Los espacios se han convertido en _
 +label.spaces_converted_to_underscores = Los espacios se han convertido en _
  label.no_spaces_allowed_sequence_name = No se permiten espacios en el nombre de la secuencia
  label.select_outline_colour = Seleccionar el color del límite
  label.web_browser_not_found_unix = Unixers\: No es posible encontrar el navegador web por defecto.\nA\u00F1ada la ruta completa de su navegador en la pesta\u00F1a de Preferencias.
@@@ -803,6 -803,8 +804,6 @@@ label.save_feature_colours = Guardar es
  label.select_startup_file = Seleccionar fichero de arranque
  label.select_default_browser = Seleccionar navegador web por defecto
  label.save_tree_as_newick = Guardar Ã¡rbol como fichero newick
 -label.create_eps_from_tree = Crear un fichero EPS a partir de un Ã¡rbol
 -label.create_png_from_tree = Crear una imagen PNG a partir de un Ã¡rbol
  label.save_colour_scheme = Guardar esquema cromático
  label.edit_params_for = Editar los parámetros de {0}
  label.choose_filename_for_param_file = Escoja un nombre de fichero para este fichero de parámetros
@@@ -858,6 -860,8 +859,6 @@@ error.call_setprogressbar_before_regist
  label.cancelled_params = {0} cancelado
  error.implementation_error_cannot_show_view_alignment_frame = Error de implementación: no es posible mostrar una vista de otro alineamiento en un AlignFrame.
  error.implementation_error_dont_know_about_threshold_setting = Error de implementación: no se conoce la configuración del umbral para el AnnotationColourGradient actual.
 -error.eps_generation_not_implemented = La generación de EPS no se ha implementado todavía
 -error.png_generation_not_implemented = La generación de PNG no se ha implementado todavía
  error.try_join_vamsas_session_another = Tratando de establecer una sesión VAMSAS cuando ya había otra conectada
  error.invalid_vamsas_session_id = Identificador de sesión VAMSAS no válido
  label.groovy_support_failed = El soporte Groovy de Jalview ha fallado
@@@ -919,7 -923,8 +920,8 @@@ label.toggled = Invertid
  label.marked = Marcada
  label.containing = conteniendo
  label.not_containing = no conteniendo
- label.no_feature_of_type_found = No se han encontrado características del tipo {0}.
+ label.no_feature_of_type_found = No se han encontrado características del tipo {0}
+ label.no_feature_found_selection = No se han encontrado características del tipo {0} en la región seleccionada
  label.submission_params = Envío {0}
  label.empty_alignment_job = Trabajo de alineamiento vacío
  label.add_new_sbrs_service = Añadir un nuevo SBRS
@@@ -928,7 -933,7 +930,7 @@@ label.pca_recalculating = Recalculando 
  label.pca_calculating = Calculando ACP
  label.select_foreground_colour = Escoger color del primer plano
  label.select_colour_for_text = Seleccione el color del texto
 -label.adjunst_foreground_text_colour_threshold = Ajustar el umbral del color del texto en primer plano
 +label.adjust_foreground_text_colour_threshold = Ajustar el umbral del color del texto en primer plano
  label.select_subtree_colour = Seleccioanr el color del sub-árbol
  label.create_new_sequence_features = Crear nueva(s) característica(s) de secuencia
  label.amend_delete_features = Arrelgar/Borrar características de {0}
@@@ -1000,6 -1005,7 +1002,6 @@@ error.implementation_error_cannot_find_
  exception.jobsubmission_invalid_params_set = Conjunto de parámetros no válido. Comprueba la implementación de Jalview
  exception.notvaliddata_group_contains_less_than_min_seqs = El grupo contiene menos de {0} secuencias.
  exception.outofmemory_loading_pdb_file = Sin memoria al cargar el fichero PDB
 -exception.eps_coudnt_write_output_file = No es posible escribir el fichero de salida: {0}
  exception.eps_method_not_supported = Método actualmente no suportado por la versión {0} de EpsGraphics2D
  exception.eps_unable_to_get_inverse_matrix = Imposible obtener la inversa de la matrix: {0}
  warn.job_cannot_be_cancelled_close_window = Este trabajo no se puede cancelar.\nSimplemente, cierre la ventana.
@@@ -1021,7 -1027,8 +1023,7 @@@ status.searching_for_sequences_from = B
  status.finished_searching_for_sequences_from = Finalizada la búsqueda de secuencias en {0}
  label.eps_file = Fichero EPS
  label.png_image = Imagen PNG
 -status.saving_file = Guardando {0}
 -status.export_complete = Exportación completada.
 +status.export_complete = Exportación completada
  status.fetching_pdb = Recuperando PDB {0}
  status.refreshing_news = Refrescando noticias
  status.importing_vamsas_session_from = Importando sesión VAMSAS de {0}
@@@ -1220,6 -1227,7 +1222,6 @@@ label.hide_columns_not_containing=Ocult
  label.pdb_sequence_fetcher=Recuperador de secuencias PDB
  exception.fts_server_error=Parece que hay un error desde el servidor {0}
  exception.service_not_available=Servicio no disponible. El servidor se está actualizando, vuelva a intentarlo más tarde.
 -status.waiting_for_user_to_select_output_file=Esperando que el usuario seleccione el fichero {0}
  action.prev_page=<< 
  status.cancelled_image_export_operation=Operación de exportación {0} cancelada
  label.couldnt_run_groovy_script=No se ha podido ejecutar el script Groovy
@@@ -1306,11 -1314,12 +1308,12 @@@ label.matchCondition_ge = >
  label.numeric_required = Valor numérico requerido
  label.filter = Filtro
  label.filters = Filtros
+ label.delete_condition = Borrar esta condición
  label.join_conditions = Combinar condiciones con
  label.score = Puntuación
  label.colour_by_label = Colorear por texto
  label.variable_colour = Color variable...
 -label.select_colour = Seleccionar color
 +label.select_colour_for = Seleccionar color para {0}
  option.enable_disable_autosearch = Marcar para buscar automáticamente
  option.autosearch = Auto búsqueda
  label.retrieve_ids = Recuperar IDs
@@@ -1331,13 -1340,6 +1334,13 @@@ label.most_bound_molecules = Más Molécu
  label.most_polymer_residues = Más Residuos de Polímeros
  label.cached_structures = Estructuras en Caché
  label.free_text_search = Búsqueda de texto libre
 +label.annotation_name = Nombre de la anotación
 +label.annotation_description = Descripción de la anotación 
 +label.edit_annotation_name_description = Editar el nombre/descripción de la anotación
 +label.alignment = alineamiento
 +label.pca = ACP
 +label.create_image_of = Crear imagen {0} de {1}
 +label.click_to_edit = Haga clic para editar, clic en el botón derecho para ver el menú  
  label.backupfiles_confirm_delete = Confirmar borrar
  label.backupfiles_confirm_delete_old_files = Â¿Borrar los siguientes archivos? (ver la pestaña 'Copias' de la ventana de Preferencias para más opciones)
  label.backupfiles_confirm_save_file = Confirmar guardar archivo
index 0000000,c6553f8..bc36d9e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1264 +1,6 @@@
 -/*
 - * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
 - * Copyright (C) $$Year-Rel$$ The Jalview Authors
 - * 
 - * This file is part of Jalview.
 - * 
 - * Jalview is free software: you can redistribute it and/or
 - * modify it under the terms of the GNU General Public License 
 - * as published by the Free Software Foundation, either version 3
 - * of the License, or (at your option) any later version.
 - *  
 - * Jalview is distributed in the hope that it will be useful, but 
 - * WITHOUT ANY WARRANTY; without even the implied warranty 
 - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
 - * PURPOSE.  See the GNU General Public License for more details.
 - * 
 - * You should have received a copy of the GNU General Public License
 - * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
 - * The Jalview Authors are detailed in the 'AUTHORS' file.
 - */
+ package MCview;
 -import jalview.analysis.AlignSeq;
 -import jalview.appletgui.AlignmentPanel;
 -import jalview.appletgui.FeatureRenderer;
 -import jalview.appletgui.SequenceRenderer;
 -import jalview.datamodel.PDBEntry;
 -import jalview.datamodel.SequenceI;
 -import jalview.io.DataSourceType;
 -import jalview.io.StructureFile;
 -import jalview.renderer.seqfeatures.FeatureColourFinder;
 -import jalview.structure.AtomSpec;
 -import jalview.structure.StructureListener;
 -import jalview.structure.StructureMapping;
 -import jalview.structure.StructureSelectionManager;
 -import jalview.util.MessageManager;
 -
 -import java.awt.Color;
 -import java.awt.Dimension;
 -import java.awt.event.InputEvent;import java.awt.Font;
 -import java.awt.Graphics;
 -import java.awt.Image;
 -// JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
 -import java.awt.Panel;
 -import java.awt.event.KeyAdapter;
 -import java.awt.event.KeyEvent;
 -import java.awt.event.MouseEvent;
 -import java.awt.event.MouseListener;
 -import java.awt.event.MouseMotionListener;
 -import java.io.PrintStream;
 -import java.util.List;
 -import java.util.Vector;
 -
 -public class AppletPDBCanvas extends Panel
 -        implements MouseListener, MouseMotionListener, StructureListener
++public class AppletPDBCanvas
+ {
 -  MCMatrix idmat = new MCMatrix(3, 3);
 -
 -  MCMatrix objmat = new MCMatrix(3, 3);
 -
 -  boolean redrawneeded = true;
 -
 -  int omx = 0;
 -
 -  int mx = 0;
 -
 -  int omy = 0;
 -
 -  int my = 0;
 -
 -  public StructureFile pdb;
 -
 -  PDBEntry pdbentry;
 -
 -  int bsize;
 -
 -  Image img;
 -
 -  Graphics ig;
 -
 -  Dimension prefsize;
 -
 -  float[] centre = new float[3];
 -
 -  float[] width = new float[3];
 -
 -  float maxwidth;
 -
 -  float scale;
 -
 -  String inStr;
 -
 -  String inType;
 -
 -  boolean bysequence = true;
 -
 -  boolean depthcue = true;
 -
 -  boolean wire = false;
 -
 -  boolean bymolecule = false;
 -
 -  boolean zbuffer = true;
 -
 -  boolean dragging;
 -
 -  int xstart;
 -
 -  int xend;
 -
 -  int ystart;
 -
 -  int yend;
 -
 -  int xmid;
 -
 -  int ymid;
 -
 -  Font font = new Font("Helvetica", Font.PLAIN, 10);
 -
 -  public SequenceI[] sequence;
 -
 -  final StringBuffer mappingDetails = new StringBuffer();
 -
 -  String appletToolTip = null;
 -
 -  int toolx, tooly;
 -
 -  PDBChain mainchain;
 -
 -  Vector<String> highlightRes;
 -
 -  boolean pdbAction = false;
 -
 -  Bond highlightBond1, highlightBond2;
 -
 -  boolean errorLoading = false;
 -
 -  boolean seqColoursReady = false;
 -
 -  FeatureRenderer fr;
 -
 -  AlignmentPanel ap;
 -
 -  StructureSelectionManager ssm;
 -
 -  public AppletPDBCanvas(PDBEntry pdbentry, SequenceI[] seq,
 -          String[] chains, AlignmentPanel ap, DataSourceType protocol)
 -
 -  {
 -    this.ap = ap;
 -    this.pdbentry = pdbentry;
 -    this.sequence = seq;
 -
 -    ssm = StructureSelectionManager
 -            .getStructureSelectionManager(ap.av.applet);
 -
 -    try
 -    {
 -      pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol, null);
 -
 -      if (protocol == DataSourceType.PASTE)
 -      {
 -        pdbentry.setFile("INLINE" + pdb.getId());
 -      }
 -
 -    } catch (Exception ex)
 -    {
 -      ex.printStackTrace();
 -      return;
 -    }
 -
 -    pdbentry.setId(pdb.getId());
 -
 -    ssm.addStructureViewerListener(this);
 -
 -    colourBySequence();
 -
 -    float max = -10;
 -    int maxchain = -1;
 -    int pdbstart = 0;
 -    int pdbend = 0;
 -    int seqstart = 0;
 -    int seqend = 0;
 -
 -    // JUST DEAL WITH ONE SEQUENCE FOR NOW
 -    SequenceI sequence = seq[0];
 -
 -    for (int i = 0; i < pdb.getChains().size(); i++)
 -    {
 -
 -      mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
 -              + pdb.getChains().elementAt(i).sequence
 -                      .getSequenceAsString());
 -      mappingDetails.append("\nNo of residues = "
 -              + pdb.getChains().elementAt(i).residues.size() + "\n\n");
 -
 -      // Now lets compare the sequences to get
 -      // the start and end points.
 -      // Align the sequence to the pdb
 -      // TODO: DNa/Pep switch
 -      AlignSeq as = new AlignSeq(sequence,
 -              pdb.getChains().elementAt(i).sequence,
 -              pdb.getChains().elementAt(i).isNa ? AlignSeq.DNA
 -                      : AlignSeq.PEP);
 -      as.calcScoreMatrix();
 -      as.traceAlignment();
 -      PrintStream ps = new PrintStream(System.out)
 -      {
 -        @Override
 -        public void print(String x)
 -        {
 -          mappingDetails.append(x);
 -        }
 -
 -        @Override
 -        public void println()
 -        {
 -          mappingDetails.append("\n");
 -        }
 -      };
 -
 -      as.printAlignment(ps);
 -
 -      if (as.maxscore > max)
 -      {
 -        max = as.maxscore;
 -        maxchain = i;
 -
 -        pdbstart = as.seq2start;
 -        pdbend = as.seq2end;
 -        seqstart = as.seq1start + sequence.getStart() - 1;
 -        seqend = as.seq1end + sequence.getEnd() - 1;
 -      }
 -
 -      mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
 -      mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
 -    }
 -
 -    mainchain = pdb.getChains().elementAt(maxchain);
 -
 -    mainchain.pdbstart = pdbstart;
 -    mainchain.pdbend = pdbend;
 -    mainchain.seqstart = seqstart;
 -    mainchain.seqend = seqend;
 -    mainchain.isVisible = true;
 -    // mainchain.makeExactMapping(maxAlignseq, sequence);
 -    // mainchain.transferRESNUMFeatures(sequence, null);
 -    this.pdb = pdb;
 -    this.prefsize = new Dimension(getSize().width, getSize().height);
 -
 -    // Initialize the matrices to identity
 -    for (int i = 0; i < 3; i++)
 -    {
 -      for (int j = 0; j < 3; j++)
 -      {
 -        if (i != j)
 -        {
 -          idmat.addElement(i, j, 0);
 -          objmat.addElement(i, j, 0);
 -        }
 -        else
 -        {
 -          idmat.addElement(i, j, 1);
 -          objmat.addElement(i, j, 1);
 -        }
 -      }
 -    }
 -
 -    addMouseMotionListener(this);
 -    addMouseListener(this);
 -
 -    addKeyListener(new KeyAdapter()
 -    {
 -      @Override
 -      public void keyPressed(KeyEvent evt)
 -      {
 -        doKeyPressed(evt);
 -      }
 -    });
 -
 -    findCentre();
 -    findWidth();
 -
 -    setupBonds();
 -
 -    scale = findScale();
 -  }
 -
 -  Vector<Bond> visiblebonds;
 -
 -  void setupBonds()
 -  {
 -    seqColoursReady = false;
 -    // Sort the bonds by z coord
 -    visiblebonds = new Vector<Bond>();
 -
 -    for (int ii = 0; ii < pdb.getChains().size(); ii++)
 -    {
 -      if (pdb.getChains().elementAt(ii).isVisible)
 -      {
 -        Vector<Bond> tmp = pdb.getChains().elementAt(ii).bonds;
 -
 -        for (int i = 0; i < tmp.size(); i++)
 -        {
 -          visiblebonds.addElement(tmp.elementAt(i));
 -        }
 -      }
 -    }
 -    seqColoursReady = true;
 -    colourBySequence();
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  public void findWidth()
 -  {
 -    float[] max = new float[3];
 -    float[] min = new float[3];
 -
 -    max[0] = (float) -1e30;
 -    max[1] = (float) -1e30;
 -    max[2] = (float) -1e30;
 -
 -    min[0] = (float) 1e30;
 -    min[1] = (float) 1e30;
 -    min[2] = (float) 1e30;
 -
 -    for (int ii = 0; ii < pdb.getChains().size(); ii++)
 -    {
 -      if (pdb.getChains().elementAt(ii).isVisible)
 -      {
 -        Vector<Bond> bonds = pdb.getChains().elementAt(ii).bonds;
 -
 -        for (Bond tmp : bonds)
 -        {
 -          if (tmp.start[0] >= max[0])
 -          {
 -            max[0] = tmp.start[0];
 -          }
 -
 -          if (tmp.start[1] >= max[1])
 -          {
 -            max[1] = tmp.start[1];
 -          }
 -
 -          if (tmp.start[2] >= max[2])
 -          {
 -            max[2] = tmp.start[2];
 -          }
 -
 -          if (tmp.start[0] <= min[0])
 -          {
 -            min[0] = tmp.start[0];
 -          }
 -
 -          if (tmp.start[1] <= min[1])
 -          {
 -            min[1] = tmp.start[1];
 -          }
 -
 -          if (tmp.start[2] <= min[2])
 -          {
 -            min[2] = tmp.start[2];
 -          }
 -
 -          if (tmp.end[0] >= max[0])
 -          {
 -            max[0] = tmp.end[0];
 -          }
 -
 -          if (tmp.end[1] >= max[1])
 -          {
 -            max[1] = tmp.end[1];
 -          }
 -
 -          if (tmp.end[2] >= max[2])
 -          {
 -            max[2] = tmp.end[2];
 -          }
 -
 -          if (tmp.end[0] <= min[0])
 -          {
 -            min[0] = tmp.end[0];
 -          }
 -
 -          if (tmp.end[1] <= min[1])
 -          {
 -            min[1] = tmp.end[1];
 -          }
 -
 -          if (tmp.end[2] <= min[2])
 -          {
 -            min[2] = tmp.end[2];
 -          }
 -        }
 -      }
 -    }
 -
 -    width[0] = Math.abs(max[0] - min[0]);
 -    width[1] = Math.abs(max[1] - min[1]);
 -    width[2] = Math.abs(max[2] - min[2]);
 -
 -    maxwidth = width[0];
 -
 -    if (width[1] > width[0])
 -    {
 -      maxwidth = width[1];
 -    }
 -
 -    if (width[2] > width[1])
 -    {
 -      maxwidth = width[2];
 -    }
 -
 -    // System.out.println("Maxwidth = " + maxwidth);
 -  }
 -
 -  public float findScale()
 -  {
 -    int dim;
 -    int width;
 -    int height;
 -
 -    if (getSize().width != 0)
 -    {
 -      width = getSize().width;
 -      height = getSize().height;
 -    }
 -    else
 -    {
 -      width = prefsize.width;
 -      height = prefsize.height;
 -    }
 -
 -    if (width < height)
 -    {
 -      dim = width;
 -    }
 -    else
 -    {
 -      dim = height;
 -    }
 -
 -    return (float) (dim / (1.5d * maxwidth));
 -  }
 -
 -  public void findCentre()
 -  {
 -    float xtot = 0;
 -    float ytot = 0;
 -    float ztot = 0;
 -
 -    int bsize = 0;
 -
 -    // Find centre coordinate
 -    for (int ii = 0; ii < pdb.getChains().size(); ii++)
 -    {
 -      if (pdb.getChains().elementAt(ii).isVisible)
 -      {
 -        Vector<Bond> bonds = pdb.getChains().elementAt(ii).bonds;
 -
 -        bsize += bonds.size();
 -
 -        for (Bond b : bonds)
 -        {
 -          xtot = xtot + b.start[0] + b.end[0];
 -          ytot = ytot + b.start[1] + b.end[1];
 -          ztot = ztot + b.start[2] + b.end[2];
 -        }
 -      }
 -    }
 -
 -    centre[0] = xtot / (2 * (float) bsize);
 -    centre[1] = ytot / (2 * (float) bsize);
 -    centre[2] = ztot / (2 * (float) bsize);
 -  }
 -
 -  @Override
 -  public void paint(Graphics g)
 -  {
 -
 -    if (errorLoading)
 -    {
 -      g.setColor(Color.white);
 -      g.fillRect(0, 0, getSize().width, getSize().height);
 -      g.setColor(Color.black);
 -      g.setFont(new Font("Verdana", Font.BOLD, 14));
 -      g.drawString(MessageManager.getString("label.error_loading_pdb_data"),
 -              50, getSize().height / 2);
 -      return;
 -    }
 -
 -    if (!seqColoursReady)
 -    {
 -      g.setColor(Color.black);
 -      g.setFont(new Font("Verdana", Font.BOLD, 14));
 -      g.drawString(MessageManager.getString("label.fetching_pdb_data"), 50,
 -              getSize().height / 2);
 -      return;
 -    }
 -
 -    // Only create the image at the beginning -
 -    // this saves much memory usage
 -    if ((img == null) || (prefsize.width != getSize().width)
 -            || (prefsize.height != getSize().height))
 -    {
 -
 -      try
 -      {
 -        prefsize.width = getSize().width;
 -        prefsize.height = getSize().height;
 -
 -        scale = findScale();
 -        img = createImage(prefsize.width, prefsize.height);
 -        ig = img.getGraphics();
 -
 -        redrawneeded = true;
 -      } catch (Exception ex)
 -      {
 -        ex.printStackTrace();
 -      }
 -    }
 -
 -    if (redrawneeded)
 -    {
 -      drawAll(ig, prefsize.width, prefsize.height);
 -      redrawneeded = false;
 -    }
 -    if (appletToolTip != null)
 -    {
 -      ig.setColor(Color.red);
 -      ig.drawString(appletToolTip, toolx, tooly);
 -    }
 -
 -    g.drawImage(img, 0, 0, this);
 -
 -    pdbAction = false;
 -  }
 -
 -  public void drawAll(Graphics g, int width, int height)
 -  {
 -    ig.setColor(Color.black);
 -    ig.fillRect(0, 0, width, height);
 -    drawScene(ig);
 -    drawLabels(ig);
 -  }
 -
 -  public void setColours(jalview.schemes.ColourSchemeI cs)
 -  {
 -    bysequence = false;
 -    pdb.setColours(cs);
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  // This method has been taken out of PDBChain to allow
 -  // Applet and Application specific sequence renderers to be used
 -  void colourBySequence()
 -  {
 -    SequenceRenderer sr = new SequenceRenderer(ap.av);
 -
 -    StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
 -
 -    boolean showFeatures = false;
 -    if (ap.av.isShowSequenceFeatures())
 -    {
 -      if (fr == null)
 -      {
 -        fr = new jalview.appletgui.FeatureRenderer(ap.av);
 -      }
 -
 -      fr.transferSettings(ap.getFeatureRenderer());
 -
 -      showFeatures = true;
 -    }
 -
 -    FeatureColourFinder finder = new FeatureColourFinder(fr);
 -
 -    PDBChain chain;
 -    if (bysequence && pdb != null)
 -    {
 -      for (int ii = 0; ii < pdb.getChains().size(); ii++)
 -      {
 -        chain = pdb.getChains().elementAt(ii);
 -
 -        for (int i = 0; i < chain.bonds.size(); i++)
 -        {
 -          Bond tmp = chain.bonds.elementAt(i);
 -          tmp.startCol = Color.lightGray;
 -          tmp.endCol = Color.lightGray;
 -          if (chain != mainchain)
 -          {
 -            continue;
 -          }
 -
 -          for (int s = 0; s < sequence.length; s++)
 -          {
 -            for (int m = 0; m < mapping.length; m++)
 -            {
 -              if (mapping[m].getSequence() == sequence[s])
 -              {
 -                int pos = mapping[m].getSeqPos(tmp.at1.resNumber) - 1;
 -                if (pos > 0)
 -                {
 -                  pos = sequence[s].findIndex(pos);
 -                  tmp.startCol = sr.getResidueColour(sequence[s], pos,
 -                          finder);
 -                }
 -                pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
 -                if (pos > 0)
 -                {
 -                  pos = sequence[s].findIndex(pos);
 -                  tmp.endCol = sr.getResidueColour(sequence[s], pos,
 -                          finder);
 -                }
 -              }
 -            }
 -          }
 -        }
 -      }
 -    }
 -  }
 -
 -  Zsort zsort;
 -
 -  public void drawScene(Graphics g)
 -  {
 -    if (zbuffer)
 -    {
 -      if (zsort == null)
 -      {
 -        zsort = new Zsort();
 -      }
 -
 -      zsort.sort(visiblebonds);
 -    }
 -
 -    Bond tmpBond = null;
 -    for (int i = 0; i < visiblebonds.size(); i++)
 -    {
 -      tmpBond = visiblebonds.elementAt(i);
 -
 -      xstart = (int) (((tmpBond.start[0] - centre[0]) * scale)
 -              + (getSize().width / 2));
 -      ystart = (int) (((centre[1] - tmpBond.start[1]) * scale)
 -              + (getSize().height / 2));
 -
 -      xend = (int) (((tmpBond.end[0] - centre[0]) * scale)
 -              + (getSize().width / 2));
 -      yend = (int) (((centre[1] - tmpBond.end[1]) * scale)
 -              + (getSize().height / 2));
 -
 -      xmid = (xend + xstart) / 2;
 -      ymid = (yend + ystart) / 2;
 -
 -      if (depthcue && !bymolecule)
 -      {
 -        if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
 -        {
 -          g.setColor(tmpBond.startCol.darker().darker());
 -          drawLine(g, xstart, ystart, xmid, ymid);
 -
 -          g.setColor(tmpBond.endCol.darker().darker());
 -          drawLine(g, xmid, ymid, xend, yend);
 -        }
 -        else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
 -        {
 -          g.setColor(tmpBond.startCol.darker());
 -          drawLine(g, xstart, ystart, xmid, ymid);
 -
 -          g.setColor(tmpBond.endCol.darker());
 -          drawLine(g, xmid, ymid, xend, yend);
 -        }
 -        else
 -        {
 -          g.setColor(tmpBond.startCol);
 -          drawLine(g, xstart, ystart, xmid, ymid);
 -
 -          g.setColor(tmpBond.endCol);
 -          drawLine(g, xmid, ymid, xend, yend);
 -        }
 -
 -      }
 -      else if (depthcue && bymolecule)
 -      {
 -        if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
 -        {
 -          g.setColor(Color.green.darker().darker());
 -          drawLine(g, xstart, ystart, xend, yend);
 -        }
 -        else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
 -        {
 -          g.setColor(Color.green.darker());
 -          drawLine(g, xstart, ystart, xend, yend);
 -        }
 -        else
 -        {
 -          g.setColor(Color.green);
 -          drawLine(g, xstart, ystart, xend, yend);
 -        }
 -      }
 -      else if (!depthcue && !bymolecule)
 -      {
 -        g.setColor(tmpBond.startCol);
 -        drawLine(g, xstart, ystart, xmid, ymid);
 -        g.setColor(tmpBond.endCol);
 -        drawLine(g, xmid, ymid, xend, yend);
 -      }
 -      else
 -      {
 -        drawLine(g, xstart, ystart, xend, yend);
 -      }
 -
 -      if (highlightBond1 != null && highlightBond1 == tmpBond)
 -      {
 -        g.setColor(Color.white);
 -        drawLine(g, xmid, ymid, xend, yend);
 -      }
 -
 -      if (highlightBond2 != null && highlightBond2 == tmpBond)
 -      {
 -        g.setColor(Color.white);
 -        drawLine(g, xstart, ystart, xmid, ymid);
 -      }
 -
 -    }
 -  }
 -
 -  public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
 -  {
 -    if (!wire)
 -    {
 -      if (((float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
 -      {
 -        g.drawLine(x1, y1, x2, y2);
 -        g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
 -        g.drawLine(x1, y1 - 1, x2, y2 - 1);
 -      }
 -      else
 -      {
 -        g.setColor(g.getColor().brighter());
 -        g.drawLine(x1, y1, x2, y2);
 -        g.drawLine(x1 + 1, y1, x2 + 1, y2);
 -        g.drawLine(x1 - 1, y1, x2 - 1, y2);
 -      }
 -    }
 -    else
 -    {
 -      g.drawLine(x1, y1, x2, y2);
 -    }
 -  }
 -
 -  public Dimension minimumsize()
 -  {
 -    return prefsize;
 -  }
 -
 -  public Dimension preferredsize()
 -  {
 -    return prefsize;
 -  }
 -
 -  public void doKeyPressed(KeyEvent evt)
 -  {
 -    if (evt.getKeyCode() == KeyEvent.VK_UP)
 -    {
 -      scale = (float) (scale * 1.1);
 -      redrawneeded = true;
 -      repaint();
 -    }
 -    else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
 -    {
 -      scale = (float) (scale * 0.9);
 -      redrawneeded = true;
 -      repaint();
 -    }
 -  }
 -
 -  @Override
 -  public void mousePressed(MouseEvent e)
 -  {
 -    pdbAction = true;
 -    Atom fatom = findAtom(e.getX(), e.getY());
 -    if (fatom != null)
 -    {
 -      fatom.isSelected = !fatom.isSelected;
 -
 -      redrawneeded = true;
 -      repaint();
 -      if (foundchain != -1)
 -      {
 -        PDBChain chain = pdb.getChains().elementAt(foundchain);
 -        if (chain == mainchain)
 -        {
 -          if (fatom.alignmentMapping != -1)
 -          {
 -            if (highlightRes == null)
 -            {
 -              highlightRes = new Vector<String>();
 -            }
 -
 -            final String atomString = Integer
 -                    .toString(fatom.alignmentMapping);
 -            if (highlightRes.contains(atomString))
 -            {
 -              highlightRes.removeElement(atomString);
 -            }
 -            else
 -            {
 -              highlightRes.addElement(atomString);
 -            }
 -          }
 -        }
 -      }
 -
 -    }
 -    mx = e.getX();
 -    my = e.getY();
 -    omx = mx;
 -    omy = my;
 -    dragging = false;
 -  }
 -
 -  @Override
 -  public void mouseMoved(MouseEvent e)
 -  {
 -    pdbAction = true;
 -    if (highlightBond1 != null)
 -    {
 -      highlightBond1.at2.isSelected = false;
 -      highlightBond2.at1.isSelected = false;
 -      highlightBond1 = null;
 -      highlightBond2 = null;
 -    }
 -
 -    Atom fatom = findAtom(e.getX(), e.getY());
 -
 -    PDBChain chain = null;
 -    if (foundchain != -1)
 -    {
 -      chain = pdb.getChains().elementAt(foundchain);
 -      if (chain == mainchain)
 -      {
 -        mouseOverStructure(fatom.resNumber, chain.id);
 -      }
 -    }
 -
 -    if (fatom != null)
 -    {
 -      toolx = e.getX();
 -      tooly = e.getY();
 -
 -      appletToolTip = chain.id + ":" + fatom.resNumber + " "
 -              + fatom.resName;
 -      redrawneeded = true;
 -      repaint();
 -    }
 -    else
 -    {
 -      mouseOverStructure(-1, chain != null ? chain.id : null);
 -      appletToolTip = null;
 -      redrawneeded = true;
 -      repaint();
 -    }
 -  }
 -
 -  @Override
 -  public void mouseClicked(MouseEvent e)
 -  {
 -  }
 -
 -  @Override
 -  public void mouseEntered(MouseEvent e)
 -  {
 -  }
 -
 -  @Override
 -  public void mouseExited(MouseEvent e)
 -  {
 -  }
 -
 -  @Override
 -  public void mouseDragged(MouseEvent evt)
 -  {
 -    int x = evt.getX();
 -    int y = evt.getY();
 -    mx = x;
 -    my = y;
 -
 -    MCMatrix objmat = new MCMatrix(3, 3);
 -    objmat.setIdentity();
 -
 -    if ((evt.getModifiersEx() & InputEvent.META_DOWN_MASK) != 0)
 -    {
 -      objmat.rotatez(((mx - omx)));
 -    }
 -    else
 -    {
 -      objmat.rotatex(((omy - my)));
 -      objmat.rotatey(((omx - mx)));
 -    }
 -
 -    // Alter the bonds
 -    for (PDBChain chain : pdb.getChains())
 -    {
 -      for (Bond tmpBond : chain.bonds)
 -      {
 -        // Translate the bond so the centre is 0,0,0
 -        tmpBond.translate(-centre[0], -centre[1], -centre[2]);
 -
 -        // Now apply the rotation matrix
 -        tmpBond.start = objmat.vectorMultiply(tmpBond.start);
 -        tmpBond.end = objmat.vectorMultiply(tmpBond.end);
 -
 -        // Now translate back again
 -        tmpBond.translate(centre[0], centre[1], centre[2]);
 -      }
 -    }
 -
 -    objmat = null;
 -
 -    omx = mx;
 -    omy = my;
 -
 -    dragging = true;
 -
 -    redrawneeded = true;
 -
 -    repaint();
 -  }
 -
 -  @Override
 -  public void mouseReleased(MouseEvent evt)
 -  {
 -    dragging = false;
 -    return;
 -  }
 -
 -  void drawLabels(Graphics g)
 -  {
 -
 -    for (PDBChain chain : pdb.getChains())
 -    {
 -      if (chain.isVisible)
 -      {
 -        for (Bond tmpBond : chain.bonds)
 -        {
 -          if (tmpBond.at1.isSelected)
 -          {
 -            labelAtom(g, tmpBond, 1);
 -          }
 -
 -          if (tmpBond.at2.isSelected)
 -          {
 -            labelAtom(g, tmpBond, 2);
 -          }
 -        }
 -      }
 -    }
 -  }
 -
 -  public void labelAtom(Graphics g, Bond b, int n)
 -  {
 -    g.setFont(font);
 -
 -    if (n == 1)
 -    {
 -      int xstart = (int) (((b.start[0] - centre[0]) * scale)
 -              + (getSize().width / 2));
 -      int ystart = (int) (((centre[1] - b.start[1]) * scale)
 -              + (getSize().height / 2));
 -
 -      g.setColor(Color.red);
 -      g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
 -    }
 -
 -    if (n == 2)
 -    {
 -      int xstart = (int) (((b.end[0] - centre[0]) * scale)
 -              + (getSize().width / 2));
 -      int ystart = (int) (((centre[1] - b.end[1]) * scale)
 -              + (getSize().height / 2));
 -
 -      g.setColor(Color.red);
 -      g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
 -    }
 -  }
 -
 -  int foundchain = -1;
 -
 -  public Atom findAtom(int x, int y)
 -  {
 -    Atom fatom = null;
 -
 -    foundchain = -1;
 -
 -    for (int ii = 0; ii < pdb.getChains().size(); ii++)
 -    {
 -      PDBChain chain = pdb.getChains().elementAt(ii);
 -      int truex;
 -      Bond tmpBond = null;
 -
 -      if (chain.isVisible)
 -      {
 -        Vector<Bond> bonds = pdb.getChains().elementAt(ii).bonds;
 -
 -        for (int i = 0; i < bonds.size(); i++)
 -        {
 -          tmpBond = bonds.elementAt(i);
 -
 -          truex = (int) (((tmpBond.start[0] - centre[0]) * scale)
 -                  + (getSize().width / 2));
 -
 -          if (Math.abs(truex - x) <= 2)
 -          {
 -            int truey = (int) (((centre[1] - tmpBond.start[1]) * scale)
 -                    + (getSize().height / 2));
 -
 -            if (Math.abs(truey - y) <= 2)
 -            {
 -              fatom = tmpBond.at1;
 -              foundchain = ii;
 -              break;
 -            }
 -          }
 -        }
 -
 -        // Still here? Maybe its the last bond
 -
 -        truex = (int) (((tmpBond.end[0] - centre[0]) * scale)
 -                + (getSize().width / 2));
 -
 -        if (Math.abs(truex - x) <= 2)
 -        {
 -          int truey = (int) (((tmpBond.end[1] - centre[1]) * scale)
 -                  + (getSize().height / 2));
 -
 -          if (Math.abs(truey - y) <= 2)
 -          {
 -            fatom = tmpBond.at2;
 -            foundchain = ii;
 -            break;
 -          }
 -        }
 -
 -      }
 -
 -      if (fatom != null) // )&& chain.ds != null)
 -      {
 -        chain = pdb.getChains().elementAt(foundchain);
 -      }
 -    }
 -
 -    return fatom;
 -  }
 -
 -  @Override
 -  public void update(Graphics g)
 -  {
 -    paint(g);
 -  }
 -
 -  public void highlightRes(int ii)
 -  {
 -    if (!seqColoursReady)
 -    {
 -      return;
 -    }
 -
 -    if (highlightRes != null && highlightRes.contains((ii - 1) + ""))
 -    {
 -      return;
 -    }
 -
 -    int index = -1;
 -    Bond tmpBond;
 -    for (index = 0; index < mainchain.bonds.size(); index++)
 -    {
 -      tmpBond = mainchain.bonds.elementAt(index);
 -      if (tmpBond.at1.alignmentMapping == ii - 1)
 -      {
 -        if (highlightBond1 != null)
 -        {
 -          highlightBond1.at2.isSelected = false;
 -        }
 -
 -        if (highlightBond2 != null)
 -        {
 -          highlightBond2.at1.isSelected = false;
 -        }
 -
 -        highlightBond1 = null;
 -        highlightBond2 = null;
 -
 -        if (index > 0)
 -        {
 -          highlightBond1 = mainchain.bonds.elementAt(index - 1);
 -          highlightBond1.at2.isSelected = true;
 -        }
 -
 -        if (index != mainchain.bonds.size())
 -        {
 -          highlightBond2 = mainchain.bonds.elementAt(index);
 -          highlightBond2.at1.isSelected = true;
 -        }
 -
 -        break;
 -      }
 -    }
 -
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  public void setAllchainsVisible(boolean b)
 -  {
 -    for (int ii = 0; ii < pdb.getChains().size(); ii++)
 -    {
 -      PDBChain chain = pdb.getChains().elementAt(ii);
 -      chain.isVisible = b;
 -    }
 -    mainchain.isVisible = true;
 -    findCentre();
 -    setupBonds();
 -  }
 -
 -  // ////////////////////////////////
 -  // /StructureListener
 -  @Override
 -  public String[] getStructureFiles()
 -  {
 -    return new String[] { pdbentry.getFile() };
 -  }
 -
 -  String lastMessage;
 -
 -  public void mouseOverStructure(int pdbResNum, String chain)
 -  {
 -    if (lastMessage == null || !lastMessage.equals(pdbResNum + chain))
 -    {
 -      ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
 -    }
 -
 -    lastMessage = pdbResNum + chain;
 -  }
 -
 -  StringBuffer resetLastRes = new StringBuffer();
 -
 -  StringBuffer eval = new StringBuffer();
 -
 -  /**
 -   * Highlight the specified atoms in the structure.
 -   * 
 -   * @param atoms
 -   */
 -  @Override
 -  public void highlightAtoms(List<AtomSpec> atoms)
 -  {
 -    if (!seqColoursReady)
 -    {
 -      return;
 -    }
 -    for (AtomSpec atom : atoms)
 -    {
 -      int atomIndex = atom.getAtomIndex();
 -
 -      if (highlightRes != null
 -              && highlightRes.contains((atomIndex - 1) + ""))
 -      {
 -        continue;
 -      }
 -
 -      highlightAtom(atomIndex);
 -    }
 -
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  /**
 -   * @param atomIndex
 -   */
 -  protected void highlightAtom(int atomIndex)
 -  {
 -    int index = -1;
 -    Bond tmpBond;
 -    for (index = 0; index < mainchain.bonds.size(); index++)
 -    {
 -      tmpBond = mainchain.bonds.elementAt(index);
 -      if (tmpBond.at1.atomIndex == atomIndex)
 -      {
 -        if (highlightBond1 != null)
 -        {
 -          highlightBond1.at2.isSelected = false;
 -        }
 -
 -        if (highlightBond2 != null)
 -        {
 -          highlightBond2.at1.isSelected = false;
 -        }
 -
 -        highlightBond1 = null;
 -        highlightBond2 = null;
 -
 -        if (index > 0)
 -        {
 -          highlightBond1 = mainchain.bonds.elementAt(index - 1);
 -          highlightBond1.at2.isSelected = true;
 -        }
 -
 -        if (index != mainchain.bonds.size())
 -        {
 -          highlightBond2 = mainchain.bonds.elementAt(index);
 -          highlightBond2.at1.isSelected = true;
 -        }
 -
 -        break;
 -      }
 -    }
 -  }
 -
 -  public Color getColour(int atomIndex, int pdbResNum, String chain,
 -          String pdbfile)
 -  {
 -    return Color.white;
 -    // if (!pdbfile.equals(pdbentry.getFile()))
 -    // return null;
 -
 -    // return new Color(viewer.getAtomArgb(atomIndex));
 -  }
 -
 -  @Override
 -  public void updateColours(Object source)
 -  {
 -    colourBySequence();
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  @Override
 -  public void releaseReferences(Object svl)
 -  {
 -    // TODO Auto-generated method stub
 -
 -  }
 -
 -  @Override
 -  public boolean isListeningFor(SequenceI seq)
 -  {
 -    if (sequence != null)
 -    {
 -      for (SequenceI s : sequence)
 -      {
 -        if (s == seq)
 -        {
 -          return true;
 -        }
 -      }
 -    }
 -    return false;
 -  }
+ }
diff --combined src/MCview/Atom.java
index 0000000,a2ce2ae..eb91e4e
mode 000000,100755..100644
--- /dev/null
@@@ -1,0 -1,136 +1,6 @@@
 -/*
 - * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
 - * Copyright (C) $$Year-Rel$$ The Jalview Authors
 - * 
 - * This file is part of Jalview.
 - * 
 - * Jalview is free software: you can redistribute it and/or
 - * modify it under the terms of the GNU General Public License 
 - * as published by the Free Software Foundation, either version 3
 - * of the License, or (at your option) any later version.
 - *  
 - * Jalview is distributed in the hope that it will be useful, but 
 - * WITHOUT ANY WARRANTY; without even the implied warranty 
 - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
 - * PURPOSE.  See the GNU General Public License for more details.
 - * 
 - * You should have received a copy of the GNU General Public License
 - * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
 - * The Jalview Authors are detailed in the 'AUTHORS' file.
 - */
+ package MCview;
 -import jalview.schemes.ResidueProperties;
 -
 -import java.awt.Color;
 -
+ public class Atom
+ {
 -  public float x;
 -
 -  public float y;
 -
 -  public float z;
 -
 -  public int number;
 -
 -  public String name;
 -
 -  public String resName;
 -
 -  public int resNumber;
 -
 -  public char insCode = ' ';
 -
 -  public String resNumIns = null;
 -
 -  public int type;
 -
 -  Color color = Color.lightGray;
 -
 -  public String chain;
 -
 -  /**
 -   * this is a temporary value - designed to store the position in sequence that
 -   * this atom corresponds to after aligning the chain to a SequenceI object. Do
 -   * not rely on its value being correct when visualizing sequence colourings on
 -   * the structure - use the StructureSelectionManager's mapping instead.
 -   */
 -  public int alignmentMapping = -1;
 -
 -  public int atomIndex;
 -
 -  public float occupancy = 0;
 -
 -  public float tfactor = 0;
 -
 -  // need these if we ever want to export Atom data
 -  // public boolean tfacset=true,occset=true;
 -  public boolean isSelected = false;
 -
 -  public Atom(String str)
 -  {
 -    atomIndex = Integer.parseInt(str.substring(6, 11).trim());
 -
 -    name = str.substring(12, 15).trim();
 -
 -    resName = str.substring(17, 20);
 -    // JAL-1828 treat MSE Selenomethionine as MET (etc)
 -    resName = ResidueProperties.getCanonicalAminoAcid(resName);
 -
 -    chain = str.substring(21, 22);
 -
 -    resNumber = Integer.parseInt(str.substring(22, 26).trim());
 -    resNumIns = str.substring(22, 27).trim();
 -    insCode = str.substring(26, 27).charAt(0);
 -    this.x = (Float.valueOf(str.substring(30, 38).trim()).floatValue());
 -    this.y = (Float.valueOf(str.substring(38, 46).trim()).floatValue());
 -    this.z = (Float.valueOf(str.substring(47, 55).trim()).floatValue());
 -    // optional entries - see JAL-730
 -    String tm = str.substring(54, 60).trim();
 -    if (tm.length() > 0)
 -    {
 -      occupancy = (Float.valueOf(tm)).floatValue();
 -    }
 -    else
 -    {
 -      occupancy = 1f; // default occupancy
 -      // see note above: occset=false;
 -    }
 -    tm = str.substring(60, 66).trim();
 -    if (tm.length() > 0)
 -    {
 -      tfactor = (Float.valueOf(tm).floatValue());
 -    }
 -    else
 -    {
 -      tfactor = 1f;
 -      // see note above: tfacset=false;
 -    }
 -  }
 -
 -  @Override
 -  public boolean equals(Object that)
 -  {
 -    if (this == that || that == null)
 -    {
 -      return true;
 -    }
 -    if (that instanceof Atom)
 -    {
 -      Atom other = (Atom) that;
 -      return other.resName.equals(this.resName)
 -              && other.resNumber == this.resNumber
 -              && other.resNumIns.equals(this.resNumIns)
 -              && other.chain.equals(this.chain);
 -    }
 -    return false;
 -  }
 -  public Atom(float x, float y, float z)
 -  {
 -    this.x = x;
 -    this.y = y;
 -    this.z = z;
 -  }
+ }
index 0000000,a34e574..c49ab09
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1223 +1,6 @@@
 -/*
 - * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
 - * Copyright (C) $$Year-Rel$$ The Jalview Authors
 - * 
 - * This file is part of Jalview.
 - * 
 - * Jalview is free software: you can redistribute it and/or
 - * modify it under the terms of the GNU General Public License 
 - * as published by the Free Software Foundation, either version 3
 - * of the License, or (at your option) any later version.
 - *  
 - * Jalview is distributed in the hope that it will be useful, but 
 - * WITHOUT ANY WARRANTY; without even the implied warranty 
 - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
 - * PURPOSE.  See the GNU General Public License for more details.
 - * 
 - * You should have received a copy of the GNU General Public License
 - * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
 - * The Jalview Authors are detailed in the 'AUTHORS' file.
 - */
+ package MCview;
 -import jalview.analysis.AlignSeq;
 -import jalview.datamodel.PDBEntry;
 -import jalview.datamodel.SequenceI;
 -import jalview.gui.AlignmentPanel;
 -import jalview.gui.FeatureRenderer;
 -import jalview.gui.SequenceRenderer;
 -import jalview.io.DataSourceType;
 -import jalview.io.StructureFile;
 -import jalview.renderer.seqfeatures.FeatureColourFinder;
 -import jalview.structure.AtomSpec;
 -import jalview.structure.StructureListener;
 -import jalview.structure.StructureMapping;
 -import jalview.structure.StructureSelectionManager;
 -
 -import java.awt.Color;
 -import java.awt.Dimension;
 -import java.awt.event.InputEvent;import java.awt.Font;
 -import java.awt.Graphics;
 -import java.awt.Graphics2D;
 -// JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
 -import java.awt.Image;
 -import java.awt.RenderingHints;
 -import java.awt.event.KeyAdapter;
 -import java.awt.event.KeyEvent;
 -import java.awt.event.MouseEvent;
 -import java.awt.event.MouseListener;
 -import java.awt.event.MouseMotionListener;
 -import java.io.PrintStream;
 -import java.util.List;
 -import java.util.Vector;
 -
 -import javax.swing.JPanel;
 -import javax.swing.ToolTipManager;
 -
 -public class PDBCanvas extends JPanel
 -        implements MouseListener, MouseMotionListener, StructureListener
++public class PDBCanvas
+ {
 -  boolean redrawneeded = true;
 -
 -  int omx = 0;
 -
 -  int mx = 0;
 -
 -  int omy = 0;
 -
 -  int my = 0;
 -
 -  public StructureFile pdb;
 -
 -  PDBEntry pdbentry;
 -
 -  int bsize;
 -
 -  Image img;
 -
 -  Graphics ig;
 -
 -  Dimension prefsize;
 -
 -  float[] centre = new float[3];
 -
 -  float[] width = new float[3];
 -
 -  float maxwidth;
 -
 -  float scale;
 -
 -  String inStr;
 -
 -  String inType;
 -
 -  boolean bysequence = true;
 -
 -  boolean depthcue = true;
 -
 -  boolean wire = false;
 -
 -  boolean bymolecule = false;
 -
 -  boolean zbuffer = true;
 -
 -  boolean dragging;
 -
 -  int xstart;
 -
 -  int xend;
 -
 -  int ystart;
 -
 -  int yend;
 -
 -  int xmid;
 -
 -  int ymid;
 -
 -  Font font = new Font("Helvetica", Font.PLAIN, 10);
 -
 -  jalview.gui.SeqCanvas seqcanvas;
 -
 -  public SequenceI[] sequence;
 -
 -  final StringBuffer mappingDetails = new StringBuffer();
 -
 -  PDBChain mainchain;
 -
 -  Vector<String> highlightRes;
 -
 -  boolean pdbAction = false;
 -
 -  boolean seqColoursReady = false;
 -
 -  jalview.renderer.seqfeatures.FeatureRenderer fr;
 -
 -  Color backgroundColour = Color.black;
 -
 -  AlignmentPanel ap;
 -
 -  StructureSelectionManager ssm;
 -
 -  String errorMessage;
 -
 -  void init(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
 -          AlignmentPanel ap, DataSourceType protocol)
 -  {
 -    this.ap = ap;
 -    this.pdbentry = pdbentry;
 -    this.sequence = seq;
 -
 -    ssm = ap.av.getStructureSelectionManager();
 -
 -    try
 -    {
 -      pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol,
 -              ap.alignFrame);
 -
 -      if (protocol.equals(jalview.io.DataSourceType.PASTE))
 -      {
 -        pdbentry.setFile("INLINE" + pdb.getId());
 -      }
 -
 -    } catch (Exception ex)
 -    {
 -      ex.printStackTrace();
 -      return;
 -    }
 -
 -    if (pdb == null)
 -    {
 -      errorMessage = "Error loading file: " + pdbentry.getId();
 -      return;
 -    }
 -    pdbentry.setId(pdb.getId());
 -
 -    ssm.addStructureViewerListener(this);
 -
 -    colourBySequence();
 -
 -    float max = -10;
 -    int maxchain = -1;
 -    int pdbstart = 0;
 -    int pdbend = 0;
 -    int seqstart = 0;
 -    int seqend = 0;
 -
 -    // JUST DEAL WITH ONE SEQUENCE FOR NOW
 -    SequenceI sequence = seq[0];
 -
 -    for (int i = 0; i < pdb.getChains().size(); i++)
 -    {
 -
 -      mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
 -              + pdb.getChains().elementAt(i).sequence
 -                      .getSequenceAsString());
 -      mappingDetails.append("\nNo of residues = "
 -              + pdb.getChains().elementAt(i).residues.size() + "\n\n");
 -
 -      // Now lets compare the sequences to get
 -      // the start and end points.
 -      // Align the sequence to the pdb
 -      AlignSeq as = new AlignSeq(sequence,
 -              pdb.getChains().elementAt(i).sequence, "pep");
 -      as.calcScoreMatrix();
 -      as.traceAlignment();
 -      PrintStream ps = new PrintStream(System.out)
 -      {
 -        @Override
 -        public void print(String x)
 -        {
 -          mappingDetails.append(x);
 -        }
 -
 -        @Override
 -        public void println()
 -        {
 -          mappingDetails.append("\n");
 -        }
 -      };
 -
 -      as.printAlignment(ps);
 -
 -      if (as.maxscore > max)
 -      {
 -        max = as.maxscore;
 -        maxchain = i;
 -
 -        pdbstart = as.seq2start;
 -        pdbend = as.seq2end;
 -        seqstart = as.seq1start + sequence.getStart() - 1;
 -        seqend = as.seq1end + sequence.getEnd() - 1;
 -      }
 -
 -      mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
 -      mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
 -    }
 -
 -    mainchain = pdb.getChains().elementAt(maxchain);
 -
 -    mainchain.pdbstart = pdbstart;
 -    mainchain.pdbend = pdbend;
 -    mainchain.seqstart = seqstart;
 -    mainchain.seqend = seqend;
 -    mainchain.isVisible = true;
 -
 -    this.pdb = pdb;
 -    this.prefsize = new Dimension(getSize().width, getSize().height);
 -
 -    addMouseMotionListener(this);
 -    addMouseListener(this);
 -
 -    addKeyListener(new KeyAdapter()
 -    {
 -      @Override
 -      public void keyPressed(KeyEvent evt)
 -      {
 -        keyPressed(evt);
 -      }
 -    });
 -
 -    findCentre();
 -    findWidth();
 -
 -    setupBonds();
 -
 -    scale = findScale();
 -
 -    ToolTipManager.sharedInstance().registerComponent(this);
 -    ToolTipManager.sharedInstance().setInitialDelay(0);
 -    ToolTipManager.sharedInstance().setDismissDelay(10000);
 -  }
 -
 -  Vector<Bond> visiblebonds;
 -
 -  void setupBonds()
 -  {
 -    seqColoursReady = false;
 -    // Sort the bonds by z coord
 -    visiblebonds = new Vector<Bond>();
 -
 -    for (PDBChain chain : pdb.getChains())
 -    {
 -      if (chain.isVisible)
 -      {
 -        for (Bond bond : chain.bonds)
 -        {
 -          visiblebonds.addElement(bond);
 -        }
 -      }
 -    }
 -
 -    updateSeqColours();
 -    seqColoursReady = true;
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  public void findWidth()
 -  {
 -    float[] max = new float[3];
 -    float[] min = new float[3];
 -
 -    max[0] = (float) -1e30;
 -    max[1] = (float) -1e30;
 -    max[2] = (float) -1e30;
 -
 -    min[0] = (float) 1e30;
 -    min[1] = (float) 1e30;
 -    min[2] = (float) 1e30;
 -
 -    for (PDBChain chain : pdb.getChains())
 -    {
 -      if (chain.isVisible)
 -      {
 -        for (Bond tmp : chain.bonds)
 -        {
 -          if (tmp.start[0] >= max[0])
 -          {
 -            max[0] = tmp.start[0];
 -          }
 -
 -          if (tmp.start[1] >= max[1])
 -          {
 -            max[1] = tmp.start[1];
 -          }
 -
 -          if (tmp.start[2] >= max[2])
 -          {
 -            max[2] = tmp.start[2];
 -          }
 -
 -          if (tmp.start[0] <= min[0])
 -          {
 -            min[0] = tmp.start[0];
 -          }
 -
 -          if (tmp.start[1] <= min[1])
 -          {
 -            min[1] = tmp.start[1];
 -          }
 -
 -          if (tmp.start[2] <= min[2])
 -          {
 -            min[2] = tmp.start[2];
 -          }
 -
 -          if (tmp.end[0] >= max[0])
 -          {
 -            max[0] = tmp.end[0];
 -          }
 -
 -          if (tmp.end[1] >= max[1])
 -          {
 -            max[1] = tmp.end[1];
 -          }
 -
 -          if (tmp.end[2] >= max[2])
 -          {
 -            max[2] = tmp.end[2];
 -          }
 -
 -          if (tmp.end[0] <= min[0])
 -          {
 -            min[0] = tmp.end[0];
 -          }
 -
 -          if (tmp.end[1] <= min[1])
 -          {
 -            min[1] = tmp.end[1];
 -          }
 -
 -          if (tmp.end[2] <= min[2])
 -          {
 -            min[2] = tmp.end[2];
 -          }
 -        }
 -      }
 -    }
 -    /*
 -     * System.out.println("xmax " + max[0] + " min " + min[0]);
 -     * System.out.println("ymax " + max[1] + " min " + min[1]);
 -     * System.out.println("zmax " + max[2] + " min " + min[2]);
 -     */
 -
 -    width[0] = Math.abs(max[0] - min[0]);
 -    width[1] = Math.abs(max[1] - min[1]);
 -    width[2] = Math.abs(max[2] - min[2]);
 -
 -    maxwidth = width[0];
 -
 -    if (width[1] > width[0])
 -    {
 -      maxwidth = width[1];
 -    }
 -
 -    if (width[2] > width[1])
 -    {
 -      maxwidth = width[2];
 -    }
 -
 -    // System.out.println("Maxwidth = " + maxwidth);
 -  }
 -
 -  public float findScale()
 -  {
 -    int dim;
 -    int width;
 -    int height;
 -
 -    if (getWidth() != 0)
 -    {
 -      width = getWidth();
 -      height = getHeight();
 -    }
 -    else
 -    {
 -      width = prefsize.width;
 -      height = prefsize.height;
 -    }
 -
 -    if (width < height)
 -    {
 -      dim = width;
 -    }
 -    else
 -    {
 -      dim = height;
 -    }
 -
 -    return (float) (dim / (1.5d * maxwidth));
 -  }
 -
 -  public void findCentre()
 -  {
 -    float xtot = 0;
 -    float ytot = 0;
 -    float ztot = 0;
 -
 -    int bsize = 0;
 -
 -    // Find centre coordinate
 -    for (PDBChain chain : pdb.getChains())
 -    {
 -      if (chain.isVisible)
 -      {
 -        bsize += chain.bonds.size();
 -
 -        for (Bond bond : chain.bonds)
 -        {
 -          xtot = xtot + bond.start[0] + bond.end[0];
 -          ytot = ytot + bond.start[1] + bond.end[1];
 -          ztot = ztot + bond.start[2] + bond.end[2];
 -        }
 -      }
 -    }
 -
 -    centre[0] = xtot / (2 * (float) bsize);
 -    centre[1] = ytot / (2 * (float) bsize);
 -    centre[2] = ztot / (2 * (float) bsize);
 -  }
 -
 -  @Override
 -  public void paintComponent(Graphics g)
 -  {
 -    super.paintComponent(g);
 -
 -    if (!seqColoursReady || errorMessage != null)
 -    {
 -      g.setColor(Color.black);
 -      g.setFont(new Font("Verdana", Font.BOLD, 14));
 -      g.drawString(errorMessage == null ? "Retrieving PDB data...."
 -              : errorMessage, 20, getHeight() / 2);
 -      return;
 -    }
 -
 -    // Only create the image at the beginning -
 -    // this saves much memory usage
 -    if ((img == null) || (prefsize.width != getWidth())
 -            || (prefsize.height != getHeight()))
 -
 -    {
 -      prefsize.width = getWidth();
 -      prefsize.height = getHeight();
 -
 -      scale = findScale();
 -      img = createImage(prefsize.width, prefsize.height);
 -      ig = img.getGraphics();
 -      Graphics2D ig2 = (Graphics2D) ig;
 -
 -      ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 -              RenderingHints.VALUE_ANTIALIAS_ON);
 -
 -      redrawneeded = true;
 -    }
 -
 -    if (redrawneeded)
 -    {
 -      drawAll(ig, prefsize.width, prefsize.height);
 -      redrawneeded = false;
 -    }
 -
 -    g.drawImage(img, 0, 0, this);
 -
 -    pdbAction = false;
 -  }
 -
 -  public void drawAll(Graphics g, int width, int height)
 -  {
 -    g.setColor(backgroundColour);
 -    g.fillRect(0, 0, width, height);
 -    drawScene(g);
 -    drawLabels(g);
 -  }
 -
 -  public void updateSeqColours()
 -  {
 -    if (pdbAction)
 -    {
 -      return;
 -    }
 -
 -    colourBySequence();
 -
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  // This method has been taken out of PDBChain to allow
 -  // Applet and Application specific sequence renderers to be used
 -  void colourBySequence()
 -  {
 -    SequenceRenderer sr = new SequenceRenderer(ap.av);
 -
 -    StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
 -
 -    boolean showFeatures = false;
 -    if (ap.av.isShowSequenceFeatures())
 -    {
 -      if (fr == null)
 -      {
 -        fr = new FeatureRenderer(ap);
 -      }
 -
 -      fr.transferSettings(ap.alignFrame.getFeatureRenderer());
 -
 -      showFeatures = true;
 -    }
 -
 -    FeatureColourFinder finder = new FeatureColourFinder(fr);
 -    PDBChain chain;
 -    if (bysequence && pdb != null)
 -    {
 -      for (int ii = 0; ii < pdb.getChains().size(); ii++)
 -      {
 -        chain = pdb.getChains().elementAt(ii);
 -
 -        for (int i = 0; i < chain.bonds.size(); i++)
 -        {
 -          Bond tmp = chain.bonds.elementAt(i);
 -          tmp.startCol = Color.lightGray;
 -          tmp.endCol = Color.lightGray;
 -          if (chain != mainchain)
 -          {
 -            continue;
 -          }
 -
 -          for (int s = 0; s < sequence.length; s++)
 -          {
 -            for (int m = 0; m < mapping.length; m++)
 -            {
 -              if (mapping[m].getSequence() == sequence[s])
 -              {
 -                int pos = mapping[m].getSeqPos(tmp.at1.resNumber) - 1;
 -                if (pos > 0)
 -                {
 -                  pos = sequence[s].findIndex(pos);
 -                  tmp.startCol = sr.getResidueColour(sequence[s], pos,
 -                          finder);
 -                }
 -                pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
 -                if (pos > 0)
 -                {
 -                  pos = sequence[s].findIndex(pos);
 -                  tmp.endCol = sr.getResidueColour(sequence[s], pos,
 -                          finder);
 -                }
 -
 -              }
 -            }
 -          }
 -        }
 -      }
 -    }
 -  }
 -
 -  Zsort zsort;
 -
 -  public void drawScene(Graphics g)
 -  {
 -    if (zbuffer)
 -    {
 -      if (zsort == null)
 -      {
 -        zsort = new Zsort();
 -      }
 -
 -      zsort.sort(visiblebonds);
 -    }
 -
 -    Bond tmpBond = null;
 -    for (int i = 0; i < visiblebonds.size(); i++)
 -    {
 -      tmpBond = visiblebonds.elementAt(i);
 -
 -      xstart = (int) (((tmpBond.start[0] - centre[0]) * scale)
 -              + (getWidth() / 2));
 -      ystart = (int) (((centre[1] - tmpBond.start[1]) * scale)
 -              + (getHeight() / 2));
 -
 -      xend = (int) (((tmpBond.end[0] - centre[0]) * scale)
 -              + (getWidth() / 2));
 -      yend = (int) (((centre[1] - tmpBond.end[1]) * scale)
 -              + (getHeight() / 2));
 -
 -      xmid = (xend + xstart) / 2;
 -      ymid = (yend + ystart) / 2;
 -      if (depthcue && !bymolecule)
 -      {
 -        if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
 -        {
 -
 -          g.setColor(tmpBond.startCol.darker().darker());
 -          drawLine(g, xstart, ystart, xmid, ymid);
 -          g.setColor(tmpBond.endCol.darker().darker());
 -          drawLine(g, xmid, ymid, xend, yend);
 -
 -        }
 -        else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
 -        {
 -          g.setColor(tmpBond.startCol.darker());
 -          drawLine(g, xstart, ystart, xmid, ymid);
 -
 -          g.setColor(tmpBond.endCol.darker());
 -          drawLine(g, xmid, ymid, xend, yend);
 -        }
 -        else
 -        {
 -          g.setColor(tmpBond.startCol);
 -          drawLine(g, xstart, ystart, xmid, ymid);
 -
 -          g.setColor(tmpBond.endCol);
 -          drawLine(g, xmid, ymid, xend, yend);
 -        }
 -      }
 -      else if (depthcue && bymolecule)
 -      {
 -        if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
 -        {
 -          g.setColor(Color.green.darker().darker());
 -          drawLine(g, xstart, ystart, xend, yend);
 -        }
 -        else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
 -        {
 -          g.setColor(Color.green.darker());
 -          drawLine(g, xstart, ystart, xend, yend);
 -        }
 -        else
 -        {
 -          g.setColor(Color.green);
 -          drawLine(g, xstart, ystart, xend, yend);
 -        }
 -      }
 -      else if (!depthcue && !bymolecule)
 -      {
 -        g.setColor(tmpBond.startCol);
 -        drawLine(g, xstart, ystart, xmid, ymid);
 -        g.setColor(tmpBond.endCol);
 -        drawLine(g, xmid, ymid, xend, yend);
 -      }
 -      else
 -      {
 -        drawLine(g, xstart, ystart, xend, yend);
 -      }
 -
 -      if (highlightBond1 != null && highlightBond1 == tmpBond)
 -      {
 -        g.setColor(
 -                tmpBond.endCol.brighter().brighter().brighter().brighter());
 -        drawLine(g, xmid, ymid, xend, yend);
 -      }
 -
 -      if (highlightBond2 != null && highlightBond2 == tmpBond)
 -      {
 -        g.setColor(tmpBond.startCol.brighter().brighter().brighter()
 -                .brighter());
 -        drawLine(g, xstart, ystart, xmid, ymid);
 -      }
 -
 -    }
 -
 -  }
 -
 -  public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
 -  {
 -    if (!wire)
 -    {
 -      if (((float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
 -      {
 -        g.drawLine(x1, y1, x2, y2);
 -        g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
 -        g.drawLine(x1, y1 - 1, x2, y2 - 1);
 -      }
 -      else
 -      {
 -        g.setColor(g.getColor().brighter());
 -        g.drawLine(x1, y1, x2, y2);
 -        g.drawLine(x1 + 1, y1, x2 + 1, y2);
 -        g.drawLine(x1 - 1, y1, x2 - 1, y2);
 -      }
 -    }
 -    else
 -    {
 -      g.drawLine(x1, y1, x2, y2);
 -    }
 -  }
 -
 -  public Dimension minimumsize()
 -  {
 -    return prefsize;
 -  }
 -
 -  public Dimension preferredsize()
 -  {
 -    return prefsize;
 -  }
 -
 -  public void keyPressed(KeyEvent evt)
 -  {
 -    if (evt.getKeyCode() == KeyEvent.VK_UP)
 -    {
 -      scale = (float) (scale * 1.1);
 -      redrawneeded = true;
 -      repaint();
 -    }
 -    else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
 -    {
 -      scale = (float) (scale * 0.9);
 -      redrawneeded = true;
 -      repaint();
 -    }
 -  }
 -
 -  @Override
 -  public void mousePressed(MouseEvent e)
 -  {
 -    pdbAction = true;
 -    Atom fatom = findAtom(e.getX(), e.getY());
 -    if (fatom != null)
 -    {
 -      fatom.isSelected = !fatom.isSelected;
 -
 -      redrawneeded = true;
 -      repaint();
 -      if (foundchain != -1)
 -      {
 -        PDBChain chain = pdb.getChains().elementAt(foundchain);
 -        if (chain == mainchain)
 -        {
 -          if (fatom.alignmentMapping != -1)
 -          {
 -            if (highlightRes == null)
 -            {
 -              highlightRes = new Vector<String>();
 -            }
 -
 -            final String atomString = Integer
 -                    .toString(fatom.alignmentMapping);
 -            if (highlightRes.contains(atomString))
 -            {
 -              highlightRes.remove(atomString);
 -            }
 -            else
 -            {
 -              highlightRes.add(atomString);
 -            }
 -          }
 -        }
 -      }
 -
 -    }
 -    mx = e.getX();
 -    my = e.getY();
 -    omx = mx;
 -    omy = my;
 -    dragging = false;
 -  }
 -
 -  @Override
 -  public void mouseMoved(MouseEvent e)
 -  {
 -    pdbAction = true;
 -    if (highlightBond1 != null)
 -    {
 -      highlightBond1.at2.isSelected = false;
 -      highlightBond2.at1.isSelected = false;
 -      highlightBond1 = null;
 -      highlightBond2 = null;
 -    }
 -
 -    Atom fatom = findAtom(e.getX(), e.getY());
 -
 -    PDBChain chain = null;
 -    if (foundchain != -1)
 -    {
 -      chain = pdb.getChains().elementAt(foundchain);
 -      if (chain == mainchain)
 -      {
 -        mouseOverStructure(fatom.resNumber, chain.id);
 -      }
 -    }
 -
 -    if (fatom != null)
 -    {
 -      this.setToolTipText(
 -              chain.id + ":" + fatom.resNumber + " " + fatom.resName);
 -    }
 -    else
 -    {
 -      mouseOverStructure(-1, chain != null ? chain.id : null);
 -      this.setToolTipText(null);
 -    }
 -  }
 -
 -  @Override
 -  public void mouseClicked(MouseEvent e)
 -  {
 -  }
 -
 -  @Override
 -  public void mouseEntered(MouseEvent e)
 -  {
 -  }
 -
 -  @Override
 -  public void mouseExited(MouseEvent e)
 -  {
 -  }
 -
 -  @Override
 -  public void mouseDragged(MouseEvent evt)
 -  {
 -    int x = evt.getX();
 -    int y = evt.getY();
 -    mx = x;
 -    my = y;
 -
 -    MCMatrix objmat = new MCMatrix(3, 3);
 -    objmat.setIdentity();
 -
 -    if ((evt.getModifiersEx() & InputEvent.META_DOWN_MASK) != 0)
 -    {
 -      objmat.rotatez(((mx - omx)));
 -    }
 -    else
 -    {
 -      objmat.rotatex(((my - omy)));
 -      objmat.rotatey(((omx - mx)));
 -    }
 -
 -    // Alter the bonds
 -    for (PDBChain chain : pdb.getChains())
 -    {
 -      for (Bond tmpBond : chain.bonds)
 -      {
 -        // Translate the bond so the centre is 0,0,0
 -        tmpBond.translate(-centre[0], -centre[1], -centre[2]);
 -
 -        // Now apply the rotation matrix
 -        tmpBond.start = objmat.vectorMultiply(tmpBond.start);
 -        tmpBond.end = objmat.vectorMultiply(tmpBond.end);
 -
 -        // Now translate back again
 -        tmpBond.translate(centre[0], centre[1], centre[2]);
 -      }
 -    }
 -
 -    objmat = null;
 -
 -    omx = mx;
 -    omy = my;
 -
 -    dragging = true;
 -
 -    redrawneeded = true;
 -
 -    repaint();
 -  }
 -
 -  @Override
 -  public void mouseReleased(MouseEvent evt)
 -  {
 -    dragging = false;
 -    return;
 -  }
 -
 -  void drawLabels(Graphics g)
 -  {
 -
 -    for (PDBChain chain : pdb.getChains())
 -    {
 -      if (chain.isVisible)
 -      {
 -        for (Bond tmpBond : chain.bonds)
 -        {
 -          if (tmpBond.at1.isSelected)
 -          {
 -            labelAtom(g, tmpBond, 1);
 -          }
 -
 -          if (tmpBond.at2.isSelected)
 -          {
 -            labelAtom(g, tmpBond, 2);
 -          }
 -        }
 -      }
 -    }
 -  }
 -
 -  public void labelAtom(Graphics g, Bond b, int n)
 -  {
 -    g.setFont(font);
 -    g.setColor(Color.red);
 -    if (n == 1)
 -    {
 -      int xstart = (int) (((b.start[0] - centre[0]) * scale)
 -              + (getWidth() / 2));
 -      int ystart = (int) (((centre[1] - b.start[1]) * scale)
 -              + (getHeight() / 2));
 -
 -      g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
 -    }
 -
 -    if (n == 2)
 -    {
 -      int xstart = (int) (((b.end[0] - centre[0]) * scale)
 -              + (getWidth() / 2));
 -      int ystart = (int) (((centre[1] - b.end[1]) * scale)
 -              + (getHeight() / 2));
 -
 -      g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
 -    }
 -  }
 -
 -  int foundchain = -1;
 -
 -  public Atom findAtom(int x, int y)
 -  {
 -    Atom fatom = null;
 -
 -    foundchain = -1;
 -
 -    for (int ii = 0; ii < pdb.getChains().size(); ii++)
 -    {
 -      PDBChain chain = pdb.getChains().elementAt(ii);
 -      int truex;
 -      Bond tmpBond = null;
 -
 -      if (chain.isVisible)
 -      {
 -        for (Bond bond : chain.bonds)
 -        {
 -          tmpBond = bond;
 -
 -          truex = (int) (((tmpBond.start[0] - centre[0]) * scale)
 -                  + (getWidth() / 2));
 -
 -          if (Math.abs(truex - x) <= 2)
 -          {
 -            int truey = (int) (((centre[1] - tmpBond.start[1]) * scale)
 -                    + (getHeight() / 2));
 -
 -            if (Math.abs(truey - y) <= 2)
 -            {
 -              fatom = tmpBond.at1;
 -              foundchain = ii;
 -              break;
 -            }
 -          }
 -        }
 -
 -        // Still here? Maybe its the last bond
 -
 -        truex = (int) (((tmpBond.end[0] - centre[0]) * scale)
 -                + (getWidth() / 2));
 -
 -        if (Math.abs(truex - x) <= 2)
 -        {
 -          int truey = (int) (((tmpBond.end[1] - centre[1]) * scale)
 -                  + (getHeight() / 2));
 -
 -          if (Math.abs(truey - y) <= 2)
 -          {
 -            fatom = tmpBond.at2;
 -            foundchain = ii;
 -            break;
 -          }
 -        }
 -
 -      }
 -
 -      if (fatom != null) // )&& chain.ds != null)
 -      { // dead code? value of chain is either overwritten or discarded
 -        chain = pdb.getChains().elementAt(foundchain);
 -      }
 -    }
 -
 -    return fatom;
 -  }
 -
 -  Bond highlightBond1, highlightBond2;
 -
 -  public void highlightRes(int ii)
 -  {
 -    if (!seqColoursReady)
 -    {
 -      return;
 -    }
 -
 -    if (highlightRes != null && highlightRes.contains((ii - 1) + ""))
 -    {
 -      return;
 -    }
 -
 -    int index = -1;
 -    Bond tmpBond;
 -    for (index = 0; index < mainchain.bonds.size(); index++)
 -    {
 -      tmpBond = mainchain.bonds.elementAt(index);
 -      if (tmpBond.at1.alignmentMapping == ii - 1)
 -      {
 -        if (highlightBond1 != null)
 -        {
 -          highlightBond1.at2.isSelected = false;
 -        }
 -
 -        if (highlightBond2 != null)
 -        {
 -          highlightBond2.at1.isSelected = false;
 -        }
 -
 -        highlightBond1 = null;
 -        highlightBond2 = null;
 -
 -        if (index > 0)
 -        {
 -          highlightBond1 = mainchain.bonds.elementAt(index - 1);
 -          highlightBond1.at2.isSelected = true;
 -        }
 -
 -        if (index != mainchain.bonds.size())
 -        {
 -          highlightBond2 = mainchain.bonds.elementAt(index);
 -          highlightBond2.at1.isSelected = true;
 -        }
 -
 -        break;
 -      }
 -    }
 -
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  public void setAllchainsVisible(boolean b)
 -  {
 -    for (int ii = 0; ii < pdb.getChains().size(); ii++)
 -    {
 -      PDBChain chain = pdb.getChains().elementAt(ii);
 -      chain.isVisible = b;
 -    }
 -    mainchain.isVisible = true;
 -    findCentre();
 -    setupBonds();
 -  }
 -
 -  // ////////////////////////////////
 -  // /StructureListener
 -  @Override
 -  public String[] getStructureFiles()
 -  {
 -    return new String[] { pdbentry.getFile() };
 -  }
 -
 -  String lastMessage;
 -
 -  public void mouseOverStructure(int pdbResNum, String chain)
 -  {
 -    if (lastMessage == null || !lastMessage.equals(pdbResNum + chain))
 -    {
 -      ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
 -    }
 -
 -    lastMessage = pdbResNum + chain;
 -  }
 -
 -  StringBuffer resetLastRes = new StringBuffer();
 -
 -  StringBuffer eval = new StringBuffer();
 -
 -  /**
 -   * Highlight the specified atoms in the structure.
 -   * 
 -   * @param atoms
 -   */
 -  @Override
 -  public void highlightAtoms(List<AtomSpec> atoms)
 -  {
 -    if (!seqColoursReady)
 -    {
 -      return;
 -    }
 -
 -    for (AtomSpec atom : atoms)
 -    {
 -      int atomIndex = atom.getAtomIndex();
 -      if (highlightRes != null
 -              && highlightRes.contains((atomIndex - 1) + ""))
 -      {
 -        continue;
 -      }
 -
 -      highlightAtom(atomIndex);
 -    }
 -
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  /**
 -   * Highlight the atom at the specified index.
 -   * 
 -   * @param atomIndex
 -   */
 -  protected void highlightAtom(int atomIndex)
 -  {
 -    int index = -1;
 -    Bond tmpBond;
 -    for (index = 0; index < mainchain.bonds.size(); index++)
 -    {
 -      tmpBond = mainchain.bonds.elementAt(index);
 -      if (tmpBond.at1.atomIndex == atomIndex)
 -      {
 -        if (highlightBond1 != null)
 -        {
 -          highlightBond1.at2.isSelected = false;
 -        }
 -
 -        if (highlightBond2 != null)
 -        {
 -          highlightBond2.at1.isSelected = false;
 -        }
 -
 -        highlightBond1 = null;
 -        highlightBond2 = null;
 -
 -        if (index > 0)
 -        {
 -          highlightBond1 = mainchain.bonds.elementAt(index - 1);
 -          highlightBond1.at2.isSelected = true;
 -        }
 -
 -        if (index != mainchain.bonds.size())
 -        {
 -          highlightBond2 = mainchain.bonds.elementAt(index);
 -          highlightBond2.at1.isSelected = true;
 -        }
 -
 -        break;
 -      }
 -    }
 -  }
 -
 -  public Color getColour(int atomIndex, int pdbResNum, String chain,
 -          String pdbfile)
 -  {
 -    return Color.white;
 -    // if (!pdbfile.equals(pdbentry.getFile()))
 -    // return null;
 -
 -    // return new Color(viewer.getAtomArgb(atomIndex));
 -  }
 -
 -  @Override
 -  public void updateColours(Object source)
 -  {
 -    colourBySequence();
 -    redrawneeded = true;
 -    repaint();
 -  }
 -
 -  @Override
 -  public void releaseReferences(Object svl)
 -  {
 -    // TODO Auto-generated method stub
 -
 -  }
 -  @Override
 -  public boolean isListeningFor(SequenceI seq)
 -  {
 -    if (sequence != null)
 -    {
 -      for (SequenceI s : sequence)
 -      {
 -        if (s == seq)
 -        {
 -          return true;
 -        }
 -      }
 -    }
 -    return false;
 -  }
+ }
@@@ -143,8 -143,8 +143,8 @@@ public class AlignmentSorte
      }
  
      // NOTE: DO NOT USE align.setSequenceAt() here - it will NOT work
 -    List<SequenceI> asq;
 -    synchronized (asq = align.getSequences())
 +    List<SequenceI> asq = align.getSequences();
 +    synchronized (asq)
      {
        for (int i = 0; i < len; i++)
        {
    public static void setOrder(AlignmentI align, SequenceI[] seqs)
    {
      // NOTE: DO NOT USE align.setSequenceAt() here - it will NOT work
 -    List<SequenceI> algn;
 -    synchronized (algn = align.getSequences())
 +    List<SequenceI> algn = align.getSequences();
 +    synchronized (algn)
      {
 -      List<SequenceI> tmp = new ArrayList<SequenceI>();
 +      List<SequenceI> tmp = new ArrayList<>();
  
        for (int i = 0; i < seqs.length; i++)
        {
    {
      // MAINTAINS ORIGNAL SEQUENCE ORDER,
      // ORDERS BY GROUP SIZE
 -    List<SequenceGroup> groups = new ArrayList<SequenceGroup>();
 +    List<SequenceGroup> groups = new ArrayList<>();
  
      if (groups.hashCode() != lastGroupHash)
      {
  
      // NOW ADD SEQUENCES MAINTAINING ALIGNMENT ORDER
      // /////////////////////////////////////////////
 -    List<SequenceI> seqs = new ArrayList<SequenceI>();
 +    List<SequenceI> seqs = new ArrayList<>();
  
      for (int i = 0; i < groups.size(); i++)
      {
      // tmp2 = tmp.retainAll(mask);
      // return tmp2.addAll(mask.removeAll(tmp2))
  
 -    ArrayList<SequenceI> seqs = new ArrayList<SequenceI>();
 +    ArrayList<SequenceI> seqs = new ArrayList<>();
      int i, idx;
      boolean[] tmask = new boolean[mask.size()];
  
    {
      int nSeq = align.getHeight();
  
 -    List<SequenceI> tmp = new ArrayList<SequenceI>();
 +    List<SequenceI> tmp = new ArrayList<>();
  
      tmp = _sortByTree(tree.getTopNode(), tmp, align.getSequences());
  
  
      for (int i = 0; i < alignment.length; i++)
      {
-       ids[i] = (new Float(alignment[i].getName().substring(8)))
+       ids[i] = (Float.valueOf(alignment[i].getName().substring(8)))
                .floatValue();
      }
  
@@@ -30,7 -30,6 +30,7 @@@ import jalview.datamodel.Sequence
  import jalview.datamodel.SequenceI;
  import jalview.schemes.ResidueProperties;
  import jalview.util.Comparison;
 +import jalview.util.Format;
  
  import java.awt.Color;
  import java.util.List;
@@@ -55,8 -54,6 +55,8 @@@ public class Conservatio
  
    private static final int GAP_INDEX = -1;
  
 +  private static final Format FORMAT_3DP = new Format("%2.5f");
 +
    SequenceI[] sequences;
  
    int start;
  
        max = Math.max(max, bigtot);
  
-       quality.addElement(new Double(bigtot));
+       quality.addElement(Double.valueOf(bigtot));
      }
  
      double newmax = -Double.MAX_VALUE;
        tmp = ((max - tmp) * (size - cons2GapCounts[j])) / size;
  
        // System.out.println(tmp+ " " + j);
-       quality.setElementAt(new Double(tmp), j);
+       quality.setElementAt(Double.valueOf(tmp), j);
  
        if (tmp > newmax)
        {
          value = quality.elementAt(i).floatValue();
          float vprop = value - qmin;
          vprop /= qmax;
 -        quality2.annotations[i] = new Annotation(" ", String.valueOf(value),
 +        String description = FORMAT_3DP.form(value);
 +        quality2.annotations[i] = new Annotation(" ", description,
                  ' ', value, new Color(minR + (maxR * vprop),
                          minG + (maxG * vprop), minB + (maxB * vprop)));
        }
@@@ -27,6 -27,7 +27,6 @@@ import jalview.datamodel.SequenceI
  import jalview.util.Comparison;
  import jalview.util.Format;
  
 -import java.util.ArrayList;
  import java.util.Hashtable;
  
  /**
@@@ -93,11 -94,11 +93,11 @@@ public class StructureFrequenc
     * @param rnaStruc
     */
    public static final void calculate(SequenceI[] sequences, int start,
 -          int end, Hashtable[] result, boolean profile,
 +          int end, Hashtable<String, Object>[] result, boolean profile,
            AlignmentAnnotation rnaStruc)
    {
  
 -    Hashtable residueHash;
 +    Hashtable<String, Object> residueHash;
      String maxResidue;
      char[] struc = rnaStruc.getRNAStruc().toCharArray();
  
          }
        }
  
 -      residueHash = new Hashtable();
 +      residueHash = new Hashtable<>();
        if (profile)
        {
          // TODO 1-dim array with jsize in [0], nongapped in [1]; or Pojo
            maxResidue = "{";
          }
        }
-       residueHash.put(MAXCOUNT, new Integer(count));
+       residueHash.put(MAXCOUNT, Integer.valueOf(count));
        residueHash.put(MAXRESIDUE, maxResidue);
  
        percentage = ((float) count * 100) / jSize;
-       residueHash.put(PID_GAPS, new Float(percentage));
+       residueHash.put(PID_GAPS, Float.valueOf(percentage));
  
        percentage = ((float) count * 100) / nongap;
-       residueHash.put(PID_NOGAPS, new Float(percentage));
+       residueHash.put(PID_NOGAPS, Float.valueOf(percentage));
  
        if (result[i] == null)
        {
          maxResidue = maxResidue.equals("(") ? ")"
                  : maxResidue.equals("[") ? "]" : "}";
  
 -        residueHash = new Hashtable();
 +        residueHash = new Hashtable<>();
          if (profile)
          {
            residueHash.put(PROFILE,
            residueHash.put(PAIRPROFILE, pairs);
          }
  
-         residueHash.put(MAXCOUNT, new Integer(count));
+         residueHash.put(MAXCOUNT, Integer.valueOf(count));
          residueHash.put(MAXRESIDUE, maxResidue);
  
          percentage = ((float) count * 100) / jSize;
-         residueHash.put(PID_GAPS, new Float(percentage));
+         residueHash.put(PID_GAPS, Float.valueOf(percentage));
  
          percentage = ((float) count * 100) / nongap;
-         residueHash.put(PID_NOGAPS, new Float(percentage));
+         residueHash.put(PID_NOGAPS, Float.valueOf(percentage));
  
          result[bpEnd] = residueHash;
        }
     * @param includeAllConsSymbols
     */
    public static void completeConsensus(AlignmentAnnotation consensus,
 -          Hashtable[] hconsensus, int iStart, int width,
 +          Hashtable<String, Object>[] hconsensus, int iStart, int width,
            boolean ignoreGapsInConsensusCalculation,
            boolean includeAllConsSymbols, long nseq)
    {
  
      for (int i = iStart; i < width; i++)
      {
 -      Hashtable hci;
 +      Hashtable<String, Object> hci;
        if (i >= hconsensus.length || ((hci = hconsensus[i]) == null))
        {
          // happens if sequences calculated over were shorter than alignment
     * @param hconsensus
     * @return profile of the given column
     */
 -  public static int[] extractProfile(Hashtable hconsensus,
 +  public static int[] extractProfile(Hashtable<String, Object> hconsensus,
            boolean ignoreGapsInConsensusCalculation)
    {
      int[] rtnval = new int[STRUCTURE_PROFILE_LENGTH]; // 2*(5*5)+2
      System.arraycopy(rtnval, 0, result, 1, rtnval.length);
      return result;
    }
 -
 -  public static void main(String args[])
 -  {
 -    // Short test to see if checkBpType works
 -    ArrayList<String> test = new ArrayList<String>();
 -    test.add("A");
 -    test.add("c");
 -    test.add("g");
 -    test.add("T");
 -    test.add("U");
 -    for (String i : test)
 -    {
 -      for (String j : test)
 -      {
 -        System.out.println(i + "-" + j + ": "
 -                + Rna.isCanonicalOrWobblePair(i.charAt(0), j.charAt(0)));
 -      }
 -    }
 -  }
  }
@@@ -106,6 -106,7 +106,7 @@@ import java.awt.event.KeyListener
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
  import java.io.IOException;
+ import java.io.UnsupportedEncodingException;
  import java.net.URL;
  import java.net.URLEncoder;
  import java.util.Arrays;
@@@ -416,7 -417,7 +417,7 @@@ public class AlignFrame extends Embmenu
          viewport.featureSettings.refreshTable();
        }
        alignPanel.paintAlignment(true, true);
 -      statusBar.setText(MessageManager
 +      setStatus(MessageManager
                .getString("label.successfully_added_features_alignment"));
      }
      return featuresFile;
  
      case KeyEvent.VK_F2:
        viewport.cursorMode = !viewport.cursorMode;
 -      statusBar.setText(MessageManager
 +      setStatus(MessageManager
                .formatMessage("label.keyboard_editing_mode", new String[]
                { (viewport.cursorMode ? "on" : "off") }));
        if (viewport.cursorMode)
      try
      {
        new URL(url);
-       url = URLEncoder.encode(url);
+       url = URLEncoder.encode(url, "UTF-8");
      }
      /*
       * When we finally deprecate 1.1 compatibility, we can start to use
      {
        url = viewport.applet.getCodeBase() + url;
      }
+     catch (UnsupportedEncodingException ex)
+     {
+       System.err.println(
+               "WARNING = IMPLEMENTATION ERROR - UNSUPPORTED ENCODING EXCEPTION FOR "
+                       + url);
+       ex.printStackTrace();
+     }
      return url;
    }
  
              seqs, 0, viewport.getAlignment().getWidth(),
              viewport.getAlignment()));
  
 -    viewport.getRanges().setEndSeq(viewport.getAlignment().getHeight());
 +    viewport.getRanges().setEndSeq(viewport.getAlignment().getHeight() - 1); // BH
 +                                                                             // 2019.04.18
      viewport.getAlignment().getWidth();
      viewport.firePropertyChange("alignment", null,
              viewport.getAlignment().getSequences());
                  column, al);
        }
  
 -      statusBar.setText(MessageManager
 +      setStatus(MessageManager
                .formatMessage("label.removed_columns", new String[]
                { Integer.valueOf(trimRegion.getSize()).toString() }));
        addHistoryItem(trimRegion);
  
      addHistoryItem(removeGapCols);
  
 -    statusBar.setText(MessageManager
 +    setStatus(MessageManager
              .formatMessage("label.removed_empty_columns", new String[]
              { Integer.valueOf(removeGapCols.getSize()).toString() }));
  
       */
      statusBar.setBackground(Color.white);
      statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
 -    statusBar.setText(MessageManager.getString("label.status_bar"));
 +    setStatus(MessageManager.getString("label.status_bar"));
      this.add(statusBar, BorderLayout.SOUTH);
    }
  
      }
      else
      {
 -      new MCview.AppletPDBViewer(pdb, seqs, chains, alignPanel, protocol);
 +      new mc_view.AppletPDBViewer(pdb, seqs, chains, alignPanel, protocol);
      }
  
    }
@@@ -52,6 -52,8 +52,6 @@@ public class AlignViewport extends Alig
  
    public jalview.bin.JalviewLite applet;
  
 -  boolean MAC = false;
 -
    private AnnotationColumnChooser annotationColumnSelectionState;
  
    public AlignViewport(AlignmentI al, JalviewLite applet)
@@@ -71,7 -73,7 +71,7 @@@
        {
          try
          {
-           widthScale = new Float(param).floatValue();
+           widthScale = Float.valueOf(param).floatValue();
          } catch (Exception e)
          {
          }
@@@ -94,7 -96,7 +94,7 @@@
        {
          try
          {
-           heightScale = new Float(param).floatValue();
+           heightScale = Float.valueOf(param).floatValue();
          } catch (Exception e)
          {
          }
      }
      setFont(font, true);
  
 -    MAC = new jalview.util.Platform().isAMac();
 -
      if (applet != null)
      {
        setShowJVSuffix(
  
    public void resetSeqLimits(int height)
    {
 -    ranges.setEndSeq(height / getCharHeight());
 +    ranges.setEndSeq(height / getCharHeight() - 1); // BH 2019.04.18
    }
  
    boolean centreColumnLabels;
@@@ -99,14 -99,14 +99,14 @@@ public class AnnotationPanel extends Pa
  
    public static int GRAPH_HEIGHT = 40;
  
 -  boolean MAC = false;
 +//  boolean MAC = false;
  
    public final AnnotationRenderer renderer;
  
    public AnnotationPanel(AlignmentPanel ap)
    {
      new jalview.util.Platform();
 -    MAC = Platform.isAMac();
 +//    MAC = Platform.isAMac();
      this.ap = ap;
      av = ap.av;
      setLayout(null);
        }
      }
  
-     if ((evt.getModifiers()
-             & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK
+     if ((evt.getModifiersEx()
+             & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK
              && activeRow != -1)
      {
        if (av.getColumnSelection() == null
@@@ -20,8 -20,6 +20,8 @@@
   */
  package jalview.appletgui;
  
 +import jalview.util.Platform;
 +
  import java.awt.BorderLayout;
  import java.awt.Color;
  import java.awt.FlowLayout;
@@@ -51,8 -49,8 +51,9 @@@ import java.util.Map
   * @author Jim Procter and Andrew Waterhouse
   * 
   */
 +@SuppressWarnings("serial")
- public class EmbmenuFrame extends Frame implements MouseListener
+ public class EmbmenuFrame extends Frame
+         implements MouseListener, AutoCloseable
  {
    protected static final Font FONT_ARIAL_PLAIN_11 = new Font("Arial",
            Font.PLAIN, 11);
@@@ -62,7 -60,7 +63,7 @@@
    /**
     * map from labels to popup menus for the embedded menubar
     */
-   protected Map<Label, PopupMenu> embeddedPopup = new HashMap<Label, PopupMenu>();
+   protected Map<Label, PopupMenu> embeddedPopup = new HashMap<>();
  
    /**
     * the embedded menu is built on this and should be added to the frame at the
@@@ -98,7 -96,7 +99,7 @@@
        return false;
      }
      // DEBUG Hint: can test embedded menus by inserting true here.
 -    if (new jalview.util.Platform().isAMac())
 +    if (Platform.isAMacAndNotJS())
      {
        // Build the embedded menu panel, allowing override with system font
        embeddedMenu = makeEmbeddedPopupMenu(topMenuBar, true, false);
      return embeddedMenu;
    }
  
+   @Override
    public void mousePressed(MouseEvent evt)
    {
      PopupMenu popup = null;
      return embeddedPopup.get(source);
    }
  
+   @Override
    public void mouseClicked(MouseEvent evt)
    {
    }
  
+   @Override
    public void mouseReleased(MouseEvent evt)
    {
    }
  
+   @Override
    public void mouseEntered(MouseEvent evt)
    {
    }
  
+   @Override
    public void mouseExited(MouseEvent evt)
    {
    }
    /**
     * calls destroyMenus()
     */
-   public void finalize() throws Throwable
+   @Override
+   public void close()
    {
      destroyMenus();
      embeddedPopup = null;
      embeddedMenu = null;
-     super.finalize();
+     // no close for Frame
+     // super.finalize();
    }
  }
@@@ -44,8 -44,6 +44,8 @@@ import java.awt.event.MouseListener
  import java.awt.event.MouseMotionListener;
  import java.beans.PropertyChangeEvent;
  
 +import javax.swing.SwingUtilities;
 +
  public class OverviewPanel extends Panel implements Runnable,
          MouseMotionListener, MouseListener, ViewportListenerI
  {
    @Override
    public void mouseClicked(MouseEvent evt)
    {
-     if ((evt.getModifiers()
-             & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+     if ((evt.getModifiersEx()
+             & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
      {
        showPopupMenu(evt);
      }
    @Override
    public void mousePressed(MouseEvent evt)
    {
-     if ((evt.getModifiers()
-             & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+     if ((evt.getModifiersEx()
+             & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
      {
 -      if (!Platform.isAMac())
 +      if (!Platform.isMac()) // BH was excluding JavaScript
        {
          showPopupMenu(evt);
        }
    @Override
    public void mouseDragged(MouseEvent evt)
    {
-     if (Platform.isWinRightButton(evt)) 
 -    if ((evt.getModifiersEx()
 -            & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
++    if (Platform.isWinRightButton(evt))
      {
-       showPopupMenu(evt);
-       return;
 -      if (!Platform.isAMac())
++      if ((evt.getModifiersEx()
++              & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
+       {
 -        showPopupMenu(evt);
++              showPopupMenu(evt);
++              return;
+       }
      }
 -    else
 -    {
 -      if (draggingBox)
 -      {
 -        // set the mouse position as a fixed point in the box
 -        // and drag relative to that position
 -        od.adjustViewportFromMouse(evt.getX(), evt.getY(),
 -                av.getAlignment().getHiddenSequences(),
 -                av.getAlignment().getHiddenColumns());
 -      }
 -      else
 -      {
 -        od.updateViewportFromMouse(evt.getX(), evt.getY(),
 -                av.getAlignment().getHiddenSequences(),
 -                av.getAlignment().getHiddenColumns());
 -      }
 -      ap.paintAlignment(false, false);
 +
 +    if (SwingUtilities.isRightMouseButton(evt))
 +    { 
 +      return;
      }
 +    
 +        if (draggingBox)
 +        {
 +          // set the mouse position as a fixed point in the box
 +          // and drag relative to that position
 +          od.adjustViewportFromMouse(evt.getX(), evt.getY(),
 +                  av.getAlignment().getHiddenSequences(),
 +                  av.getAlignment().getHiddenColumns());
 +        }
 +        else
 +        {
 +          od.updateViewportFromMouse(evt.getX(), evt.getY(),
 +                  av.getAlignment().getHiddenSequences(),
 +                  av.getAlignment().getHiddenColumns());
 +        }
 +        ap.paintAlignment(false, false);
    }
  
    /**
@@@ -42,7 -42,6 +42,7 @@@ import jalview.structure.VamsasSource
  import jalview.util.Comparison;
  import jalview.util.MappingUtils;
  import jalview.util.MessageManager;
 +import jalview.util.Platform;
  import jalview.viewmodel.AlignmentViewport;
  
  import java.awt.BorderLayout;
@@@ -500,8 -499,9 +500,7 @@@ public class SeqPanel extends Panel imp
  
      // For now, ignore the mouseWheel font resizing on Macs
      // As the Button2_mask always seems to be true
-     
 -    if ((evt.getModifiersEx()
 -            & InputEvent.BUTTON2_DOWN_MASK) == InputEvent.BUTTON2_DOWN_MASK
 -            && !av.MAC)
 +    if (Platform.isWinMiddleButton(evt))
      {
        mouseWheelPressed = true;
        return;
      }
  
      // DETECT RIGHT MOUSE BUTTON IN AWT
-     if ((evt.getModifiers()
-             & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+     if ((evt.getModifiersEx()
+             & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
      {
        List<SequenceFeature> allFeatures = findFeaturesAtColumn(sequence,
                sequence.findPosition(column + 1));
@@@ -60,13 -60,12 +60,15 @@@ import java.security.Policy
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Vector;
 +import java.util.logging.ConsoleHandler;
 +import java.util.logging.Level;
 +import java.util.logging.Logger;
  
  import javax.swing.LookAndFeel;
  import javax.swing.UIManager;
  
+ import com.threerings.getdown.util.LaunchUtil;
  import groovy.lang.Binding;
  import groovy.util.GroovyScriptEngine;
  
   */
  public class Jalview
  {
 -  /*
 -   * singleton instance of this class
 -   */
 +  static
 +  {
 +    Platform.getURLCommandArguments();
 +  }
 +
 +  // singleton instance of this class
 +
    private static Jalview instance;
  
    private Desktop desktop;
  
    static
    {
 -    // grab all the rights we can the JVM
 -    Policy.setPolicy(new Policy()
 +    if (!Platform.isJS())
 +    /**
 +     * Java only
 +     * 
 +     * @j2sIgnore
 +     */
      {
 -      @Override
 -      public PermissionCollection getPermissions(CodeSource codesource)
 -      {
 -        Permissions perms = new Permissions();
 -        perms.add(new AllPermission());
 -        return (perms);
 -      }
 -    
 -      @Override
 -      public void refresh()
 -      {
 -      }
 -    });
 +      // grab all the rights we can for the JVM
 +          Policy.setPolicy(new Policy()
 +          {
 +            @Override
 +            public PermissionCollection getPermissions(CodeSource codesource)
 +            {
 +              Permissions perms = new Permissions();
 +              perms.add(new AllPermission());
 +              return (perms);
 +            }
 +      
 +            @Override
 +            public void refresh()
 +            {
 +            }
 +          });
 +    }
    }
  
    /**
     */
    public static void main(String[] args)
    {
 +//    setLogging(); // BH - for event debugging in JavaScript
      instance = new Jalview();
      instance.doMain(args);
 +}
 +
 +  private static void logClass(String name) 
 +  {   
 +        // BH - for event debugging in JavaScript
 +      ConsoleHandler consoleHandler = new ConsoleHandler();
 +      consoleHandler.setLevel(Level.ALL);
 +      Logger logger = Logger.getLogger(name);
 +      logger.setLevel(Level.ALL);
 +      logger.addHandler(consoleHandler);
 +  }
 +
 +  @SuppressWarnings("unused")
 +  private static void setLogging() 
 +  {
 +
 +    /**
 +     * @j2sIgnore
 +     * 
 +     */
 +    {
 +      System.out.println("not in js");
 +    }
 +
 +        // BH - for event debugging in JavaScript (Java mode only)
 +    if (!Platform.isJS())
 +    /**
 +     * Java only
 +     * 
 +     * @j2sIgnore
 +     */
 +      {
 +              Logger.getLogger("").setLevel(Level.ALL);
 +        logClass("java.awt.EventDispatchThread");
 +        logClass("java.awt.EventQueue");
 +        logClass("java.awt.Component");
 +        logClass("java.awt.focus.Component");
 +        logClass("java.awt.focus.DefaultKeyboardFocusManager"); 
 +      }       
 +
    }
 +  
 +
 +  
  
    /**
     * @param args
     */
    void doMain(String[] args)
    {
 -    System.setSecurityManager(null);
 +
 +    if (!Platform.isJS())
 +    {
 +      System.setSecurityManager(null);
 +    }
 +
      System.out
              .println("Java version: " + System.getProperty("java.version"));
      System.out.println(System.getProperty("os.arch") + " "
              + System.getProperty("os.name") + " "
              + System.getProperty("os.version"));
  
+     String appdirString = System.getProperty("getdownappdir");
+     if (appdirString != null && appdirString.length() > 0)
+     {
+       final File appdir = new File(appdirString);
+       new Thread()
+       {
+         @Override
+         public void run()
+         {
+           LaunchUtil.upgradeGetdown(
+                   new File(appdir, "getdown-launcher-old.jar"),
+                   new File(appdir, "getdown-launcher.jar"),
+                   new File(appdir, "getdown-launcher-new.jar"));
+         }
+       }.start();
+     }
      ArgsParser aparser = new ArgsParser(args);
      boolean headless = false;
  
 -    if (aparser.contains("help") || aparser.contains("h"))
 -    {
 -      showUsage();
 -      System.exit(0);
 -    }
 -    if (aparser.contains("nodisplay") || aparser.contains("nogui")
 -            || aparser.contains("headless"))
 -    {
 -      System.setProperty("java.awt.headless", "true");
 -      headless = true;
 -    }
      String usrPropsFile = aparser.getValue("props");
      Cache.loadProperties(usrPropsFile); // must do this before
      if (usrPropsFile != null)
                "CMD [-props " + usrPropsFile + "] executed successfully!");
      }
  
 -    // anything else!
 -
 -    final String jabawsUrl = aparser.getValue("jabaws");
 -    if (jabawsUrl != null)
 +    if (!Platform.isJS())
 +    /**
 +     * Java only
 +     * 
 +     * @j2sIgnore
 +     */
      {
 -      try
 +      if (aparser.contains("help") || aparser.contains("h"))
        {
 -        Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
 -        System.out.println(
 -                "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
 -      } catch (MalformedURLException e)
 +        showUsage();
 +        System.exit(0);
 +      }
 +      if (aparser.contains("nodisplay") || aparser.contains("nogui")
 +              || aparser.contains("headless"))
        {
 -        System.err.println(
 -                "Invalid jabaws parameter: " + jabawsUrl + " ignored");
 +        System.setProperty("java.awt.headless", "true");
 +        headless = true;
 +      }
 +      // anything else!
 +
 +      final String jabawsUrl = aparser.getValue("jabaws");
 +      if (jabawsUrl != null)
 +      {
 +        try
 +        {
 +          Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
 +          System.out.println(
 +                  "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
 +        } catch (MalformedURLException e)
 +        {
 +          System.err.println(
 +                  "Invalid jabaws parameter: " + jabawsUrl + " ignored");
 +        }
        }
 -    }
  
 +    }
      String defs = aparser.getValue("setprop");
      while (defs != null)
      {
        else
        {
          System.out.println("Executing setprop argument: " + defs);
 -        // DISABLED FOR SECURITY REASONS
 -        // TODO: add a property to allow properties to be overriden by cli args
 -        // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
 +        if (Platform.isJS())
 +        {
 +          Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
 +        }
        }
        defs = aparser.getValue("setprop");
      }
        System.err.println("Unexpected Look and Feel Exception");
        ex.printStackTrace();
      }
 -    if (Platform.isAMac())
 +    if (Platform.isAMacAndNotJS())
      {
  
        LookAndFeel lookAndFeel = ch.randelshofer.quaqua.QuaquaManager
  
      if (!headless)
      {
 -      desktop = new Desktop();
 +      desktop = new Desktop() 
 +//      {
 +// // BH testing
 +//              @Override
 +//              protected void processEvent(AWTEvent e) {
 +//                      System.out.println("Jalview.java " + e);
 +//                      super.processEvent(e);
 +//              }
 +//       }
 +      ;
        desktop.setInBatchMode(true); // indicate we are starting up
+       try
+       {
+         JalviewTaskbar.setTaskbar(this);
+       } catch (Exception e)
+       {
+         e.printStackTrace();
+       } catch (Throwable t)
+       {
+         t.printStackTrace();
+       }
        desktop.setVisible(true);
 -      desktop.startServiceDiscovery();
 -      if (!aparser.contains("nousagestats"))
 -      {
 -        startUsageStats(desktop);
 -      }
 -      else
 -      {
 -        System.err.println("CMD [-nousagestats] executed successfully!");
 -      }
  
 -      if (!aparser.contains("noquestionnaire"))
 +      if (!Platform.isJS())
 +      /**
 +       * Java only
 +       * 
 +       * @j2sIgnore
 +       */
        {
 -        String url = aparser.getValue("questionnaire");
 -        if (url != null)
 +        desktop.startServiceDiscovery();
 +        if (!aparser.contains("nousagestats"))
          {
 -          // Start the desktop questionnaire prompter with the specified
 -          // questionnaire
 -          Cache.log.debug("Starting questionnaire url at " + url);
 -          desktop.checkForQuestionnaire(url);
 -          System.out.println(
 -                  "CMD questionnaire[-" + url + "] executed successfully!");
 +          startUsageStats(desktop);
          }
          else
          {
 -          if (Cache.getProperty("NOQUESTIONNAIRES") == null)
 +          System.err.println("CMD [-nousagestats] executed successfully!");
 +        }
 +
 +        if (!aparser.contains("noquestionnaire"))
 +        {
 +          String url = aparser.getValue("questionnaire");
 +          if (url != null)
            {
              // Start the desktop questionnaire prompter with the specified
              // questionnaire
 -            // String defurl =
 -            // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
 -            // //
 -            String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
 -            Cache.log.debug(
 -                    "Starting questionnaire with default url: " + defurl);
 -            desktop.checkForQuestionnaire(defurl);
 +            Cache.log.debug("Starting questionnaire url at " + url);
 +            desktop.checkForQuestionnaire(url);
 +            System.out.println("CMD questionnaire[-" + url
 +                    + "] executed successfully!");
 +          }
 +          else
 +          {
 +            if (Cache.getProperty("NOQUESTIONNAIRES") == null)
 +            {
 +              // Start the desktop questionnaire prompter with the specified
 +              // questionnaire
 +              // String defurl =
 +              // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
 +              // //
 +              String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
 +              Cache.log.debug(
 +                      "Starting questionnaire with default url: " + defurl);
 +              desktop.checkForQuestionnaire(defurl);
 +            }
            }
          }
 -      }
 -      else
 -      {
 -        System.err.println("CMD [-noquestionnaire] executed successfully!");
 -      }
 +        else
 +        {
 +          System.err
 +                  .println("CMD [-noquestionnaire] executed successfully!");
 +        }
  
 -      if (!aparser.contains("nonews"))
 -      {
 -        desktop.checkForNews();
 -      }
 +        if (!aparser.contains("nonews"))
 +        {
 +          desktop.checkForNews();
 +        }
  
 -      BioJsHTMLOutput.updateBioJS();
 +        BioJsHTMLOutput.updateBioJS();
 +      }
      }
  
      String file = null, data = null;
        }
        System.out.println("CMD [-open " + file + "] executed successfully!");
  
 -      if (!file.startsWith("http://"))
 +      if (!Platform.isJS())
 +        /**
 +         * ignore in JavaScript -- can't just file existence - could load it?
 +         * 
 +         * @j2sIgnore
 +         */
        {
 -        if (!(new File(file)).exists())
 +        if (!file.startsWith("http://") && !file.startsWith("https://"))
 +        // BH 2019 added https check for Java
          {
 -          System.out.println("Can't find " + file);
 -          if (headless)
 +          if (!(new File(file)).exists())
            {
 -            System.exit(1);
 +            System.out.println("Can't find " + file);
 +            if (headless)
 +            {
 +              System.exit(1);
 +            }
            }
          }
        }
  
 -      protocol = AppletFormatAdapter.checkProtocol(file);
 +        protocol = AppletFormatAdapter.checkProtocol(file);
  
        try
        {
              continue;
            }
  
 -          if (af.saveAlignment(file, format))
 +          af.saveAlignment(file, format);
 +          if (af.isSaveAlignmentSuccessful())
            {
              System.out.println("Written alignment in " + format
                      + " format to " + file);
      // And the user
      // ////////////////////
  
 -    if (!headless && file == null && vamsasImport == null
 +    if (!Platform.isJS() && !headless && file == null
 +            && vamsasImport == null
              && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
 +    /**
 +     * Java only
 +     * 
 +     * @j2sIgnore
 +     */
      {
        file = jalview.bin.Cache.getDefault("STARTUP_FILE",
                jalview.bin.Cache.getDefault("www.jalview.org",
      }
      try
      {
-       Map<String, Object> vbinding = new HashMap<>();
+       Map<String, java.lang.Object> vbinding = new HashMap<>();
        vbinding.put("Jalview", this);
        if (af != null)
        {
@@@ -198,7 -198,7 +198,7 @@@ public class JalviewLite extends Apple
        int apos = -1;
        try
        {
-         apos = new Integer(position).intValue();
+         apos = Integer.valueOf(position).intValue();
          apos--;
        } catch (NumberFormatException ex)
        {
            int from = -1, to = -1;
            try
            {
-             from = new Integer(cl.substring(0, p)).intValue();
+             from = Integer.valueOf(cl.substring(0, p)).intValue();
              from--;
            } catch (NumberFormatException ex)
            {
            }
            try
            {
-             to = new Integer(cl.substring(p + 1)).intValue();
+             to = Integer.valueOf(cl.substring(p + 1)).intValue();
              to--;
            } catch (NumberFormatException ex)
            {
            int r = -1;
            try
            {
-             r = new Integer(cl).intValue();
+             r = Integer.valueOf(cl).intValue();
              r--;
            } catch (NumberFormatException ex)
            {
          try
          {
            StructureSelectionManager.getStructureSelectionManager(me)
-                   .mouseOverStructure(new Integer(pdbResNum).intValue(),
+                   .mouseOverStructure(Integer.valueOf(pdbResNum).intValue(),
                            chain, pdbfile);
            if (debug)
            {
        {
          try
          {
-           alf.scrollTo(new Integer(topRow).intValue(),
-                   new Integer(leftHandColumn).intValue());
+           alf.scrollTo(Integer.valueOf(topRow).intValue(),
+                   Integer.valueOf(leftHandColumn).intValue());
  
          } catch (Exception ex)
          {
        {
          try
          {
-           alf.scrollToRow(new Integer(topRow).intValue());
+           alf.scrollToRow(Integer.valueOf(topRow).intValue());
  
          } catch (Exception ex)
          {
        {
          try
          {
-           alf.scrollToColumn(new Integer(leftHandColumn).intValue());
+           alf.scrollToColumn(Integer.valueOf(leftHandColumn).intValue());
  
          } catch (Exception ex)
          {
    private boolean alignPdbStructures = false;
  
    /**
 -   * use an external structure viewer exclusively (no jmols or MCViews will be
 +   * use an external structure viewer exclusively (no jmols or mc_views will be
     * opened by JalviewLite itself)
     */
    public boolean useXtrnalSviewer = false;
            if (!jmolAvailable)
            {
              System.out.println(
 -                    "Jmol not available - Using MCview for structures");
 +                    "Jmol not available - Using mc_view for structures");
            }
          } catch (java.lang.ClassNotFoundException ex)
          {
          if (debug)
          {
            System.err.println(
 -                  "Skipping Jmol check. Will use MCView (probably)");
 +                  "Skipping Jmol check. Will use mc_view (probably)");
          }
        }
        checkedForJmol = true;
@@@ -166,9 -166,10 +166,10 @@@ public class AlignViewController implem
      // JBPNote this routine could also mark rows, not just columns.
      // need a decent query structure to allow all types of feature searches
      BitSet bs = new BitSet();
-     SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null
-             || extendCurrent) ? viewport.getAlignment()
-                     : viewport.getSelectionGroup();
+     boolean searchSelection = viewport.getSelectionGroup() != null
+             && !extendCurrent;
+     SequenceCollectionI sqcol = searchSelection ? viewport
+             .getSelectionGroup() : viewport.getAlignment();
  
      int nseq = findColumnsWithFeature(featureType, sqcol, bs);
  
      }
      else
      {
-       avcg.setStatus(MessageManager
-               .formatMessage("label.no_feature_of_type_found", new String[]
-               { featureType }));
+       String key = searchSelection ? "label.no_feature_found_selection"
+               : "label.no_feature_of_type_found";
+       avcg.setStatus(MessageManager.formatMessage(key,
+               new String[] { featureType }));
        if (!extendCurrent)
        {
          cs.clear();
    }
  
    @Override
 -  public boolean parseFeaturesFile(String file, DataSourceType protocol,
 +  public boolean parseFeaturesFile(Object file, DataSourceType protocol,
            boolean relaxedIdMatching)
    {
      boolean featuresAdded = false;
@@@ -47,7 -47,7 +47,7 @@@ import java.util.Vector
   * @author JimP
   * 
   */
- public class Alignment implements AlignmentI
+ public class Alignment implements AlignmentI, AutoCloseable
  {
    private Alignment dataset;
  
    {
      synchronized (sequences)
      {
 +    
        if (i > -1 && i < sequences.size())
        {
          return sequences.get(i);
    }
  
    @Override
-   public void finalize() throws Throwable
+   public void close()
    {
      if (getDataset() != null)
      {
-       getDataset().removeAlignmentRef();
+       try
+       {
+         getDataset().removeAlignmentRef();
+       } catch (Throwable e)
+       {
+         e.printStackTrace();
+       }
      }
  
      nullReferences();
-     super.finalize();
    }
  
    /**
      int i = 0;
      SequenceI sq = null;
      String sqname = null;
 +    int nseq = sequences.size();
      if (startAfter != null)
      {
        // try to find the sequence in the alignment
        boolean matched = false;
 -      while (i < sequences.size())
 +      while (i < nseq)
        {
          if (getSequenceAt(i++) == startAfter)
          {
          i = 0;
        }
      }
 -    while (i < sequences.size())
 +    while (i < nseq)
      {
        sq = getSequenceAt(i);
        sqname = sq.getName();
      int maxLength = -1;
  
      SequenceI current;
 -    for (int i = 0; i < sequences.size(); i++)
 +    int nseq = sequences.size();
 +    for (int i = 0; i < nseq; i++)
      {
        current = getSequenceAt(i);
        for (int j = current.getLength(); j > maxLength; j--)
      maxLength++;
  
      int cLength;
 -    for (int i = 0; i < sequences.size(); i++)
 +    for (int i = 0; i < nseq; i++)
      {
        current = getSequenceAt(i);
        cLength = current.getLength();
@@@ -3,7 -3,6 +3,7 @@@ package jalview.ext.ensembl
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.DBRefSource;
  import jalview.datamodel.GeneLociI;
 +import jalview.util.JSONUtils;
  import jalview.util.MapList;
  
  import java.io.BufferedReader;
@@@ -14,10 -13,24 +14,22 @@@ import java.util.ArrayList
  import java.util.Collections;
  import java.util.Iterator;
  import java.util.List;
 +import java.util.Map;
  
 -import org.json.simple.JSONArray;
 -import org.json.simple.JSONObject;
 -import org.json.simple.parser.JSONParser;
  import org.json.simple.parser.ParseException;
  
+ /**
+  * A client for the Ensembl REST service /map endpoint, to convert from
+  * coordinates of one genome assembly to another.
+  * <p>
+  * Note that species and assembly identifiers passed to this class must be valid
+  * in Ensembl. They are not case sensitive.
+  * 
+  * @author gmcarstairs
+  * @see https://rest.ensembl.org/documentation/info/assembly_map
+  * @see https://rest.ensembl.org/info/assembly/human?content-type=text/xml
+  * @see https://rest.ensembl.org/info/species?content-type=text/xml
+  */
  public class EnsemblMap extends EnsemblRestClient
  {
    private static final String MAPPED = "mapped";
            String fromRef, String toRef, int[] queryRange)
    {
      URL url = null;
 -    BufferedReader br = null;
 -
      try
      {
        url = getAssemblyMapUrl(species, chromosome, fromRef, toRef, queryRange[0],
                queryRange[1]);
 -      br = getHttpResponse(url, null);
 -      return (parseAssemblyMappingResponse(br));
 +      return (parseAssemblyMappingResponse(url));
      } catch (Throwable t)
      {
        System.out.println("Error calling " + url + ": " + t.getMessage());
        return null;
 -    } finally
 -    {
 -      if (br != null)
 -      {
 -        try
 -        {
 -          br.close();
 -        } catch (IOException e)
 -        {
 -          // ignore
 -        }
 -      }
      }
    }
  
     * @param br
     * @return
     */
 -  protected int[] parseAssemblyMappingResponse(BufferedReader br)
 +  @SuppressWarnings("unchecked")
 +  protected int[] parseAssemblyMappingResponse(URL url)
    {
      int[] result = null;
  
      try
      {
 -      JSONObject parsed = (JSONObject) jp.parse(br);
 -      JSONArray mappings = (JSONArray) parsed.get(MAPPINGS);
 -
 -      Iterator rvals = mappings.iterator();
 +      Iterator<Object> rvals = (Iterator<Object>) getJSON(url, null, -1, MODE_ITERATOR, MAPPINGS);
 +      if (rvals == null)
 +        return null;
        while (rvals.hasNext())
        {
          // todo check for "mapped"
 -        JSONObject val = (JSONObject) rvals.next();
 -        JSONObject mapped = (JSONObject) val.get(MAPPED);
 +        Map<String, Object> val = (Map<String, Object>) rvals.next();
 +        Map<String, Object> mapped = (Map<String, Object>) val.get(MAPPED);
          int start = Integer.parseInt(mapped.get("start").toString());
          int end = Integer.parseInt(mapped.get("end").toString());
          String strand = mapped.get("strand").toString();
            int end, String cdsOrCdna)
    {
      URL url = null;
 -    BufferedReader br = null;
 -
      try
      {
        String domain = new EnsemblInfo().getDomain(division);
        if (domain != null)
        {
          url = getIdMapUrl(domain, accession, start, end, cdsOrCdna);
 -        br = getHttpResponse(url, null);
 -        if (br != null)
 -        {
 -          return (parseIdMappingResponse(br, accession, domain));
 -        }
 +        return (parseIdMappingResponse(url, accession, domain));
        }
        return null;
      } catch (Throwable t)
      {
        System.out.println("Error calling " + url + ": " + t.getMessage());
        return null;
 -    } finally
 -    {
 -      if (br != null)
 -      {
 -        try
 -        {
 -          br.close();
 -        } catch (IOException e)
 -        {
 -          // ignore
 -        }
 -      }
      }
    }
  
     * @param domain
     * @return
     */
 -  GeneLociI parseIdMappingResponse(BufferedReader br, String accession,
 +  @SuppressWarnings("unchecked")
 +GeneLociI parseIdMappingResponse(URL url, String accession,
            String domain)
    {
  
      try
      {
 -      JSONObject parsed = (JSONObject) jp.parse(br);
 -      JSONArray mappings = (JSONArray) parsed.get(MAPPINGS);
 -
 -      Iterator rvals = mappings.iterator();
 +      Iterator<Object> rvals = (Iterator<Object>) getJSON(url, null, -1, MODE_ITERATOR, MAPPINGS);
 +      if (rvals == null)
 +        return null;
        String assembly = null;
        String chromosome = null;
        int fromEnd = 0;
  
        while (rvals.hasNext())
        {
 -        JSONObject val = (JSONObject) rvals.next();
 -        JSONObject original = (JSONObject) val.get("original");
 +        Map<String, Object> val = (Map<String, Object>) rvals.next();
 +        Map<String, Object> original = (Map<String, Object>) val.get("original");
          fromEnd = Integer.parseInt(original.get("end").toString());
  
 -        JSONObject mapped = (JSONObject) val.get(MAPPED);
 +        Map<String, Object> mapped = (Map<String, Object>) val.get(MAPPED);
          int start = Integer.parseInt(mapped.get("start").toString());
          int end = Integer.parseInt(mapped.get("end").toString());
          String ass = mapped.get("assembly_name").toString();
@@@ -44,7 -44,6 +44,6 @@@ import java.awt.event.ComponentEvent
  import java.awt.event.ComponentListener;
  import java.io.File;
  import java.net.URL;
- import java.security.AccessControlException;
  import java.util.ArrayList;
  import java.util.BitSet;
  import java.util.Hashtable;
@@@ -166,10 -165,7 +165,10 @@@ public abstract class JalviewJmolBindin
    {
      // remove listeners for all structures in viewer
      getSsm().removeStructureViewerListener(this, this.getStructureFiles());
 -    viewer.dispose();
 +    if (viewer != null)
 +    {
 +      viewer.dispose();
 +    }
      lastCommand = null;
      viewer = null;
      releaseUIResources();
      jmolHistory(false);
      if (lastCommand == null || !lastCommand.equals(command))
      {
 -      viewer.evalStringQuiet(command + "\n");
 +      jmolScript(command + "\n");
      }
      jmolHistory(true);
      lastCommand = command;
    }
  
    Thread colourby = null;
 +
    /**
     * Sends a set of colour commands to the structure viewer
     * 
        colourby.interrupt();
        colourby = null;
      }
 -    colourby = new Thread(new Runnable()
 +    Thread colourby = new Thread(new Runnable()
      {
        @Override
        public void run()
        }
      });
      colourby.start();
 +    this.colourby = colourby;
    }
  
    /**
     */
    private int _modelFileNameMap[];
  
-   // ////////////////////////////////
-   // /StructureListener
-   // @Override
-   public synchronized String[] getPdbFilex()
-   {
-     if (viewer == null)
-     {
-       return new String[0];
-     }
-     if (modelFileNames == null)
-     {
-       List<String> mset = new ArrayList<>();
-       _modelFileNameMap = new int[viewer.ms.mc];
-       String m = viewer.ms.getModelFileName(0);
-       if (m != null)
-       {
-         String filePath = m;
-         try
-         {
-           filePath = new File(m).getAbsolutePath();
-         } catch (AccessControlException x)
-         {
-           // usually not allowed to do this in applet
-           System.err.println(
-                   "jmolBinding: Using local file string from Jmol: " + m);
-         }
-         if (filePath.indexOf("/file:") != -1)
-         {
-           // applet path with docroot - discard as format won't match pdbfile
-           filePath = m;
-         }
-         mset.add(filePath);
-         _modelFileNameMap[0] = 0; // filename index for first model is always 0.
-       }
-       int j = 1;
-       for (int i = 1; i < viewer.ms.mc; i++)
-       {
-         m = viewer.ms.getModelFileName(i);
-         String filePath = m;
-         if (m != null)
-         {
-           try
-           {
-             filePath = new File(m).getAbsolutePath();
-           } catch (AccessControlException x)
-           {
-             // usually not allowed to do this in applet, so keep raw handle
-             // System.err.println("jmolBinding: Using local file string from
-             // Jmol: "+m);
-           }
-         }
-         /*
-          * add this model unless it is read from a structure file we have
-          * already seen (example: 2MJW is an NMR structure with 10 models)
-          */
-         if (!mset.contains(filePath))
-         {
-           mset.add(filePath);
-           _modelFileNameMap[j] = i; // record the model index for the filename
-           j++;
-         }
-       }
-       modelFileNames = mset.toArray(new String[mset.size()]);
-     }
-     return modelFileNames;
-   }
    @Override
    public synchronized String[] getStructureFiles()
    {
      {
        if (resetLastRes.length() > 0)
        {
 -        viewer.evalStringQuiet(resetLastRes.toString());
 +        jmolScript(resetLastRes.toString());
          resetLastRes.setLength(0);
        }
        for (AtomSpec atom : atoms)
  
      cmd.append("spacefill 200;select none");
  
 -    viewer.evalStringQuiet(cmd.toString());
 +    jmolScript(cmd.toString());
      jmolHistory(true);
  
    }
  
    private void jmolHistory(boolean enable)
    {
 -    viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
 +    jmolScript("History " + ((debug || enable) ? "on" : "off"));
    }
  
    public void loadInline(String string)
        try
        {
          // recover PDB filename for the model hovered over.
-         int mnumber = new Integer(mdlId).intValue() - 1;
+         int mnumber = Integer.valueOf(mdlId).intValue() - 1;
          if (_modelFileNameMap != null)
          {
            int _mp = _modelFileNameMap.length - 1;
    {
      /**
       * this implements the toggle label behaviour copied from the original
 -     * structure viewer, MCView
 +     * structure viewer, mc_view
       */
      if (strData != null)
      {
  
      if (!atomsPicked.contains(picked))
      {
 -      viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
 +      jmolScript("select " + picked + ";label %n %r:%c");
        atomsPicked.addElement(picked);
      }
      else
            // see JAL-623 - need method of matching pasted data up
            {
              pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
 -                    pdbfile, DataSourceType.PASTE,
 -                    getIProgressIndicator());
 +                    pdbfile, DataSourceType.PASTE, getIProgressIndicator());
              getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
              matches = true;
              foundEntry = true;
      // }
      if (!isLoadingFromArchive())
      {
 -      viewer.evalStringQuiet(
 +      jmolScript(
                "model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
      }
      // register ourselves as a listener and notify the gui that it needs to
  
    public void showHelp()
    {
 -    showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
 +    showUrl("http://wiki.jmol.org"
 +    // BH 2018 "http://jmol.sourceforge.net/docs/JmolUserGuide/"
 +            , "jmolHelp");
    }
  
    /**
     */
    public abstract void showConsole(boolean show);
  
 +  public static Viewer getJmolData(JmolParser jmolParser)
 +  {
 +    return (Viewer) JmolViewer.allocateViewer(null, null, null, null, null,
 +            "-x -o -n", jmolParser);
 +  }
 +
    /**
 +   * 
 +   * 
 +   * 
     * @param renderPanel
     * @param jmolfileio
     *          - when true will initialise jmol's file IO system (should be false
     * @param consolePanel
     *          - panel to contain Jmol console
     * @param buttonsToShow
 -   *          - buttons to show on the console, in ordr
 +   *          - buttons to show on the console, in order
     */
    public void allocateViewer(Container renderPanel, boolean jmolfileio,
            String htmlName, URL documentBase, URL codeBase,
            String commandOptions, final Container consolePanel,
            String buttonsToShow)
    {
 +
 +    System.err.println("Allocating Jmol Viewer: " + commandOptions);
 +
      if (commandOptions == null)
      {
        commandOptions = "";
  
      viewer.setJmolStatusListener(this); // extends JmolCallbackListener
  
 -    console = createJmolConsole(consolePanel, buttonsToShow);
 +    try
 +    {
 +      console = createJmolConsole(consolePanel, buttonsToShow);
 +    } catch (Throwable e)
 +    {
 +      System.err.println("Could not create Jmol application console. "
 +              + e.getMessage());
 +      e.printStackTrace();
 +    }
      if (consolePanel != null)
      {
        consolePanel.addComponentListener(this);
    protected abstract JmolAppConsoleInterface createJmolConsole(
            Container consolePanel, String buttonsToShow);
  
 +  // BH 2018 -- Jmol console is not working due to problems with styled
 +  // documents.
 +
    protected org.jmol.api.JmolAppConsoleInterface console = null;
  
    @Override
    public void setBackgroundColour(java.awt.Color col)
    {
      jmolHistory(false);
 -    viewer.evalStringQuiet("background [" + col.getRed() + ","
 -            + col.getGreen() + "," + col.getBlue() + "];");
 +    jmolScript("background [" + col.getRed() + "," + col.getGreen() + ","
 +            + col.getBlue() + "];");
      jmolHistory(true);
    }
  
 +  private String jmolScript(String script)
 +  {
 +
 +    System.err.println(">>Jmol>> " + script);
 +
 +    String s = viewer.scriptWait(script);
 +
 +    System.err.println("<<Jmol<< " + s);
 +
 +    return s;
 +  }
 +
    @Override
    public int[] resizeInnerPanel(String data)
    {
    {
      showConsole(false);
    }
 +
  }
@@@ -20,7 -20,6 +20,7 @@@
   */
  package jalview.ext.paradise;
  
 +import jalview.util.JSONUtils;
  import jalview.util.MessageManager;
  import jalview.ws.HttpClientUtils;
  
@@@ -33,10 -32,11 +33,10 @@@ import java.net.URL
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
 +import java.util.Map;
  
  import org.apache.http.NameValuePair;
  import org.apache.http.message.BasicNameValuePair;
 -import org.json.simple.JSONArray;
 -import org.json.simple.JSONObject;
  import org.json.simple.parser.ContentHandler;
  import org.json.simple.parser.ParseException;
  
@@@ -137,13 -137,13 +137,13 @@@ public class Annotate3
    public static Iterator<Reader> getRNAMLForPDBFileAsString(String pdbfile)
            throws Exception
    {
-     List<NameValuePair> vals = new ArrayList<NameValuePair>();
+     List<NameValuePair> vals = new ArrayList<>();
      vals.add(new BasicNameValuePair("tool", "rnaview"));
      vals.add(new BasicNameValuePair("data", pdbfile));
      vals.add(new BasicNameValuePair("output", "rnaml"));
      // return processJsonResponseFor(HttpClientUtils.doHttpUrlPost(twoDtoolsURL,
      // vals));
-     ArrayList<Reader> readers = new ArrayList<Reader>();
+     ArrayList<Reader> readers = new ArrayList<>();
      final BufferedReader postResponse = HttpClientUtils
              .doHttpUrlPost(twoDtoolsURL, vals, 0, 0);
      readers.add(postResponse);
  
    }
  
 +  /**
 +   * @param respons
 +   * @return
 +   * @throws Exception
 +   */
    public static Iterator<Reader> processJsonResponseFor(Reader respons)
            throws Exception
    {
-         // BH 2019 never called?
 -    org.json.simple.parser.JSONParser jp = new org.json.simple.parser.JSONParser();
      try
      {
 -      final JSONArray responses = (JSONArray) jp.parse(respons);
 -      final RvalsIterator rvals = new RvalsIterator(responses);
 -      return rvals;
 +      @SuppressWarnings("unchecked")
-       final Iterator<Object> rvals = ((List<Object>) JSONUtils.parse(respons)).iterator();
-       return new Iterator<Reader>()
-       {
-         @Override
-         public boolean hasNext()
-         {
-           return rvals.hasNext();
-         }
-         @SuppressWarnings("unchecked")
-               @Override
-         public Reader next()
-         {
-           Map<String, Object> val = (Map<String, Object>) rvals.next();
-           Object sval = null;
-           try
-           {
-             sval = val.get("2D");
-           } catch (Exception x)
-           {
-             x.printStackTrace();
-           }
-           ;
-           if (sval == null)
-           {
-             System.err.println(
-                     "DEVELOPER WARNING: Annotate3d didn't return a '2D' tag in its response. Consider checking output of server. Response was :"
-                             + val.toString());
-             sval = "";
-           }
-           return new StringReader(sval.toString());
-         }
-         @Override
-         public void remove()
-         {
-           throw new Error(
-                   MessageManager.getString("error.not_implemented_remove"));
-         }
-         @Override
-         protected Object clone() throws CloneNotSupportedException
-         {
-           throw new CloneNotSupportedException(
-                   MessageManager.getString("error.not_implemented_clone"));
-         }
-         @Override
-         public boolean equals(Object obj)
-         {
-           return super.equals(obj);
-         }
-         @Override
-         protected void finalize() throws Throwable
-         {
-           while (rvals.hasNext())
-           {
-             rvals.next();
-           }
-           super.finalize();
-         }
-       };
++      List<Object> responses = (List<Object>) JSONUtils.parse(respons);
++      return new RvalsIterator(responses);
      } catch (Exception foo)
      {
        throw new Exception(MessageManager.getString(
                "exception.couldnt_parse_responde_from_annotated3d_server"),
                foo);
      }
--
    }
  
    public static Iterator<Reader> getRNAMLForPDBId(String pdbid)
            throws Exception
    {
-     List<NameValuePair> vals = new ArrayList<NameValuePair>();
+     List<NameValuePair> vals = new ArrayList<>();
      vals.add(new BasicNameValuePair("tool", "rnaview"));
      vals.add(new BasicNameValuePair("pdbid", pdbid));
      vals.add(new BasicNameValuePair("output", "rnaml"));
              + pdbid + "&output=rnaml");
      // return processJsonResponseFor(new
      // InputStreamReader(geturl.openStream()));
-     ArrayList<Reader> readers = new ArrayList<Reader>();
+     ArrayList<Reader> readers = new ArrayList<>();
      readers.add(new InputStreamReader(geturl.openStream()));
      return readers.iterator();
    }
  
  }
 -class RvalsIterator implements Iterator, AutoCloseable
++class RvalsIterator implements Iterator<Reader>, AutoCloseable
+ {
 -  private Iterator rvals;
++  private Iterator<Object> rvals;
 -  protected RvalsIterator(JSONArray responses)
++  protected RvalsIterator(List<Object> responses)
+   {
+     this.rvals = responses.iterator();
+   }
+   @Override
+   public boolean hasNext()
+   {
+     return rvals.hasNext();
+   }
+   @Override
+   public Reader next()
+   {
 -    JSONObject val = (JSONObject) rvals.next();
++    Map<String, Object> val = (Map<String, Object>) rvals.next();
+     Object sval = null;
+     try
+     {
+       sval = val.get("2D");
+     } catch (Exception x)
+     {
+       x.printStackTrace();
+     }
 -    ;
+     if (sval == null)
+     {
+       System.err.println(
+               "DEVELOPER WARNING: Annotate3d didn't return a '2D' tag in its response. Consider checking output of server. Response was :"
+                       + val.toString());
+       sval = "";
+     }
 -    return new StringReader(
 -            (sval instanceof JSONObject) ? ((JSONObject) sval).toString()
 -                    : sval.toString());
 -
++    return new StringReader(sval.toString());
+   }
+   @Override
+   public void remove()
+   {
 -    throw new Error(
 -            MessageManager.getString("error.not_implemented_remove"));
 -
++    throw new UnsupportedOperationException();
+   }
+   @Override
+   protected Object clone() throws CloneNotSupportedException
+   {
 -    throw new CloneNotSupportedException(
 -            MessageManager.getString("error.not_implemented_clone"));
 -  }
 -
 -  @Override
 -  public boolean equals(Object obj)
 -  {
 -    return super.equals(obj);
++    throw new UnsupportedOperationException();
+   }
+   @Override
+   public void close()
+   {
+     while (rvals.hasNext())
+     {
+       rvals.next();
+     }
+   }
+ }
index 0000000,31f7a6d..3706cba
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,150 +1,150 @@@
+ package jalview.gui;
+ import jalview.util.MessageManager;
+ import jalview.util.Platform;
+ import java.awt.Desktop;
+ import java.awt.desktop.AboutEvent;
+ import java.awt.desktop.AboutHandler;
+ import java.awt.desktop.PreferencesEvent;
+ import java.awt.desktop.PreferencesHandler;
+ import java.awt.desktop.QuitEvent;
+ import java.awt.desktop.QuitHandler;
+ import java.awt.desktop.QuitResponse;
+ import java.awt.desktop.QuitStrategy;
+ import javax.swing.JOptionPane;
+ public class APQHandlers
+ {
+   private static boolean setAPQHandlers = false;
+   public APQHandlers() {
+   }
+   protected static boolean setAPQHandlers(jalview.gui.Desktop jalviewDesktop)
+   {
+     // flagging this test to avoid unnecessary reflection
+     if (!setAPQHandlers)
+     {
+       // see if the Quit, About and Preferences handlers are available
+       Class desktopClass = Desktop.class;
+       Desktop hdesktop = Desktop.getDesktop();
+       try
+       {
+         Float specversion = Float.parseFloat(
+                 System.getProperty("java.specification.version"));
+         if (specversion >= 9)
+         {
 -          if (Platform.isAMac())
++          if (Platform.isMac())
+           {
+             if (desktopClass.getDeclaredMethod("setAboutHandler",
+                     new Class[]
+                     { AboutHandler.class }) != null)
+             {
+               hdesktop.setAboutHandler(new AboutHandler()
+               {
+                 @Override
+                 public void handleAbout(AboutEvent e)
+                 {
+                   jalviewDesktop.aboutMenuItem_actionPerformed(null);
+                 }
+               });
+             }
+             if (desktopClass.getDeclaredMethod("setPreferencesHandler",
+                     new Class[]
+                     { PreferencesHandler.class }) != null)
+             {
+               hdesktop.setPreferencesHandler(
+                       new PreferencesHandler()
+               {
+                         @Override
+                         public void handlePreferences(
+                                 PreferencesEvent e)
+                         {
+                           jalviewDesktop.preferences_actionPerformed(null);
+                         }
+                       });
+             }
+             if (desktopClass.getDeclaredMethod("setQuitHandler",
+                     new Class[]
+                     { QuitHandler.class }) != null)
+             {
+               hdesktop.setQuitHandler(new QuitHandler()
+               {
+                 @Override
+                 public void handleQuitRequestWith(
+                         QuitEvent e, QuitResponse r)
+                 {
+                   boolean confirmQuit = jalview.bin.Cache
+                           .getDefault(jalviewDesktop.CONFIRM_KEYBOARD_QUIT,
+                                   true);
+                   int n;
+                   if (confirmQuit)
+                   {
+                     n = JOptionPane.showConfirmDialog(null,
+                             MessageManager.getString("label.quit_jalview"),
+                             MessageManager.getString("action.quit"),
+                             JOptionPane.OK_CANCEL_OPTION,
+                             JOptionPane.PLAIN_MESSAGE, null);
+                   }
+                   else
+                   {
+                     n = JOptionPane.OK_OPTION;
+                   }
+                   if (n == JOptionPane.OK_OPTION)
+                   {
+                     System.out.println("Shortcut Quit confirmed by user");
+                     jalviewDesktop.quit();
+                     r.performQuit(); // probably won't reach this line, but just
+                                      // in
+                                      // case
+                   }
+                   else
+                   {
+                     r.cancelQuit();
+                     System.out.println("Shortcut Quit cancelled by user");
+                   }
+                 }
+               });
+               hdesktop.setQuitStrategy(
+                       QuitStrategy.CLOSE_ALL_WINDOWS);
+             }
+           }
+           setAPQHandlers = true;
+         }
+         else
+         {
+           System.out.println(
+                   "Not going to try setting APQ Handlers as java.spec.version is "
+                           + specversion);
+         }
+       } catch (Exception e)
+       {
+         System.out.println(
+                 "Exception when looking for About, Preferences, Quit Handlers");
+         e.printStackTrace();
+       } catch (Throwable t)
+       {
+         System.out.println(
+                 "Throwable when looking for About, Preferences, Quit Handlers");
+         t.printStackTrace();
+       }
+     }
+     
+     return setAPQHandlers;
+   }
+ }
@@@ -27,7 -27,7 +27,7 @@@ import jalview.analysis.Dna
  import jalview.analysis.GeneticCodeI;
  import jalview.analysis.ParseProperties;
  import jalview.analysis.SequenceIdMatcher;
 -import jalview.api.AlignExportSettingI;
 +import jalview.api.AlignExportSettingsI;
  import jalview.api.AlignViewControllerGuiI;
  import jalview.api.AlignViewControllerI;
  import jalview.api.AlignViewportI;
@@@ -46,7 -46,6 +46,7 @@@ import jalview.commands.RemoveGapColCom
  import jalview.commands.RemoveGapsCommand;
  import jalview.commands.SlideSequencesCommand;
  import jalview.commands.TrimRegionCommand;
 +import jalview.datamodel.AlignExportSettingsAdapter;
  import jalview.datamodel.AlignedCodonFrame;
  import jalview.datamodel.Alignment;
  import jalview.datamodel.AlignmentAnnotation;
@@@ -56,6 -55,7 +56,6 @@@ import jalview.datamodel.AlignmentOrder
  import jalview.datamodel.AlignmentView;
  import jalview.datamodel.ColumnSelection;
  import jalview.datamodel.HiddenColumns;
 -import jalview.datamodel.HiddenSequences;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SeqCigar;
  import jalview.datamodel.Sequence;
@@@ -85,14 -85,11 +85,14 @@@ import jalview.io.ScoreMatrixFile
  import jalview.io.TCoffeeScoreFile;
  import jalview.io.vcf.VCFLoader;
  import jalview.jbgui.GAlignFrame;
 +import jalview.project.Jalview2XML;
  import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ColourSchemes;
  import jalview.schemes.ResidueColourScheme;
  import jalview.schemes.TCoffeeColourScheme;
 +import jalview.util.ImageMaker.TYPE;
  import jalview.util.MessageManager;
 +import jalview.util.Platform;
  import jalview.viewmodel.AlignmentViewport;
  import jalview.viewmodel.ViewportRanges;
  import jalview.ws.DBRefFetcher;
@@@ -103,7 -100,6 +103,7 @@@ import jalview.ws.jws2.jabaws2.Jws2Inst
  import jalview.ws.seqfetcher.DbSourceProxy;
  
  import java.awt.BorderLayout;
 +import java.awt.Color;
  import java.awt.Component;
  import java.awt.Rectangle;
  import java.awt.Toolkit;
@@@ -142,26 -138,20 +142,26 @@@ import java.util.Vector
  
  import javax.swing.ButtonGroup;
  import javax.swing.JCheckBoxMenuItem;
 +import javax.swing.JComponent;
  import javax.swing.JEditorPane;
  import javax.swing.JInternalFrame;
 +import javax.swing.JLabel;
  import javax.swing.JLayeredPane;
  import javax.swing.JMenu;
  import javax.swing.JMenuItem;
 +import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.SwingUtilities;
  
 +import ext.vamsas.ServiceHandle;
 +
  /**
   * DOCUMENT ME!
   * 
   * @author $author$
   * @version $Revision$
   */
 +@SuppressWarnings("serial")
  public class AlignFrame extends GAlignFrame implements DropTargetListener,
          IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener
  {
     */
    String fileName = null;
  
 +  File fileObject;
 +
    /**
     * Creates a new AlignFrame object with specific width and height.
     * 
     */
    void init()
    {
 +//      setBackground(Color.white); // BH 2019
 +                
      if (!Jalview.isHeadlessMode())
      {
        progressBar = new ProgressBar(this.statusPanel, this.statusBar);
      if (Desktop.desktop != null)
      {
        this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
 -      addServiceListeners();
 +      if (!Platform.isJS())
 +      {
 +        addServiceListeners();
 +      }
        setGUINucleotide();
      }
  
    }
  
    /**
 +   * JavaScript will have this, maybe others. More dependable than a file name
 +   * and maintains a reference to the actual bytes loaded.
 +   * 
 +   * @param file
 +   */
 +  public void setFileObject(File file)
 +  {
 +    this.fileObject = file;
 +  }
 +
 +  /**
     * Add a KeyListener with handlers for various KeyPressed and KeyReleased
     * events
     */
          case KeyEvent.VK_BACK_SPACE:
            if (!viewport.cursorMode)
            {
 -            cut_actionPerformed(null);
 +            cut_actionPerformed();
            }
            else
            {
  
          case KeyEvent.VK_F2:
            viewport.cursorMode = !viewport.cursorMode;
 -          statusBar.setText(MessageManager
 +          setStatus(MessageManager
                    .formatMessage("label.keyboard_editing_mode", new String[]
                    { (viewport.cursorMode ? "on" : "off") }));
            if (viewport.cursorMode)
          Desktop.instance.removeJalviewPropertyChangeListener("services",
                  thisListener);
          closeMenuItem_actionPerformed(true);
 -      };
 +      }
      });
      // Finally, build the menu once to get current service state
      new Thread(new Runnable()
    }
  
    @Override
 -  public void fetchSequence_actionPerformed(ActionEvent e)
 +  public void fetchSequence_actionPerformed()
    {
 -    new jalview.gui.SequenceFetcher(this);
 +    new SequenceFetcher(this);
    }
  
    @Override
          Rectangle bounds = this.getBounds();
  
          FileLoader loader = new FileLoader();
 -        DataSourceType protocol = fileName.startsWith("http:")
 -                ? DataSourceType.URL
 -                : DataSourceType.FILE;
 -        AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName,
 -                protocol, currentFileFormat);
 +
 +        AlignFrame newframe = null;
 +
 +        if (fileObject == null)
 +        {
 +
 +          DataSourceType protocol = (fileName.startsWith("http:")
 +                  ? DataSourceType.URL
 +                  : DataSourceType.FILE);
 +          newframe = loader.LoadFileWaitTillLoaded(fileName, protocol,
 +                  currentFileFormat);
 +        }
 +        else
 +        {
 +          newframe = loader.LoadFileWaitTillLoaded(fileObject,
 +                  DataSourceType.FILE, currentFileFormat);
 +        }
  
          newframe.setBounds(bounds);
          if (featureSettings != null && featureSettings.isShowing())
      if (fileName == null || (currentFileFormat == null)
              || fileName.startsWith("http"))
      {
 -      saveAs_actionPerformed(null);
 +      saveAs_actionPerformed();
      }
      else
      {
    }
  
    /**
 -   * DOCUMENT ME!
 -   * 
 -   * @param e
 -   *          DOCUMENT ME!
 +   * Saves the alignment to a file with a name chosen by the user, if necessary
 +   * warning if a file would be overwritten
     */
    @Override
 -  public void saveAs_actionPerformed(ActionEvent e)
 +  public void saveAs_actionPerformed()
    {
      String format = currentFileFormat == null ? null
              : currentFileFormat.getName();
  
      int value = chooser.showSaveDialog(this);
  
 -    if (value == JalviewFileChooser.APPROVE_OPTION)
 +    if (value != JalviewFileChooser.APPROVE_OPTION)
      {
 +      return;
 +    }
 +    currentFileFormat = chooser.getSelectedFormat();
 +    // todo is this (2005) test now obsolete - value is never null?
 +    while (currentFileFormat == null)
 +    {
 +      JvOptionPane.showInternalMessageDialog(Desktop.desktop,
 +              MessageManager
 +                      .getString("label.select_file_format_before_saving"),
 +              MessageManager.getString("label.file_format_not_specified"),
 +              JvOptionPane.WARNING_MESSAGE);
        currentFileFormat = chooser.getSelectedFormat();
 -      while (currentFileFormat == null)
 +      value = chooser.showSaveDialog(this);
 +      if (value != JalviewFileChooser.APPROVE_OPTION)
        {
 -        JvOptionPane.showInternalMessageDialog(Desktop.desktop,
 -                MessageManager.getString(
 -                        "label.select_file_format_before_saving"),
 -                MessageManager.getString("label.file_format_not_specified"),
 -                JvOptionPane.WARNING_MESSAGE);
 -        currentFileFormat = chooser.getSelectedFormat();
 -        value = chooser.showSaveDialog(this);
 -        if (value != JalviewFileChooser.APPROVE_OPTION)
 -        {
 -          return;
 -        }
 +        return;
        }
 +    }
  
 -      fileName = chooser.getSelectedFile().getPath();
 +    fileName = chooser.getSelectedFile().getPath();
  
 -      Cache.setProperty("DEFAULT_FILE_FORMAT", currentFileFormat.getName());
 +    Cache.setProperty("DEFAULT_FILE_FORMAT", currentFileFormat.getName());
 +    Cache.setProperty("LAST_DIRECTORY", fileName);
 +    saveAlignment(fileName, currentFileFormat);
 +  }
  
 -      Cache.setProperty("LAST_DIRECTORY", fileName);
 -      saveAlignment(fileName, currentFileFormat);
 +  boolean lastSaveSuccessful = false;
 +
 +  FileFormatI lastFormatSaved;
 +
 +  String lastFilenameSaved;
 +
 +  /**
 +   * Raise a dialog or status message for the last call to saveAlignment.
 +   *
 +   * @return true if last call to saveAlignment(file, format) was successful.
 +   */
 +  public boolean isSaveAlignmentSuccessful()
 +  {
 +
 +    if (!lastSaveSuccessful)
 +    {
 +      JvOptionPane.showInternalMessageDialog(this, MessageManager
 +              .formatMessage("label.couldnt_save_file", new Object[]
 +              { lastFilenameSaved }),
 +              MessageManager.getString("label.error_saving_file"),
 +              JvOptionPane.WARNING_MESSAGE);
      }
 +    else
 +    {
 +
 +      setStatus(MessageManager.formatMessage(
 +              "label.successfully_saved_to_file_in_format", new Object[]
 +              { lastFilenameSaved, lastFormatSaved }));
 +
 +    }
 +    return lastSaveSuccessful;
    }
  
 -  public boolean saveAlignment(String file, FileFormatI format)
 +  /**
 +   * Saves the alignment to the specified file path, in the specified format,
 +   * which may be an alignment format, or Jalview project format. If the
 +   * alignment has hidden regions, or the format is one capable of including
 +   * non-sequence data (features, annotations, groups), then the user may be
 +   * prompted to specify what to include in the output.
 +   * 
 +   * @param file
 +   * @param format
 +   */
 +  public void saveAlignment(String file, FileFormatI format)
    {
 -    boolean success = true;
 +    lastSaveSuccessful = true;
 +    lastFilenameSaved = file;
 +    lastFormatSaved = format;
  
      if (FileFormat.Jalview.equals(format))
      {
        String shortName = title;
 -
 -      if (shortName.indexOf(java.io.File.separatorChar) > -1)
 +      if (shortName.indexOf(File.separatorChar) > -1)
        {
          shortName = shortName.substring(
 -                shortName.lastIndexOf(java.io.File.separatorChar) + 1);
 +                shortName.lastIndexOf(File.separatorChar) + 1);
        }
 -
 -      success = new jalview.project.Jalview2XML().saveAlignment(this, file,
 -              shortName);
 -
 +      lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, shortName);
 +      
        statusBar.setText(MessageManager.formatMessage(
                "label.successfully_saved_to_file_in_format", new Object[]
                { fileName, format }));
 -
 +      
 +      return;
      }
 -    else
 +
 +    AlignExportSettingsI options = new AlignExportSettingsAdapter(false);
 +    Runnable cancelAction = new Runnable()
      {
 -      AlignmentExportData exportData = getAlignmentForExport(format,
 -              viewport, null);
 -      if (exportData.getSettings().isCancelled())
 -      {
 -        return false;
 -      }
 -      FormatAdapter f = new FormatAdapter(alignPanel,
 -              exportData.getSettings());
 -      String output = f.formatSequences(format, exportData.getAlignment(), // class
 -                                                                           // cast
 -                                                                           // exceptions
 -                                                                           // will
 -              // occur in the distant future
 -              exportData.getOmitHidden(), exportData.getStartEndPostions(),
 -              f.getCacheSuffixDefault(format),
 -              viewport.getAlignment().getHiddenColumns());
 -
 -      if (output == null)
 +      @Override
 +      public void run()
        {
 -        success = false;
 +        lastSaveSuccessful = false;
        }
 -      else
 +    };
 +    Runnable outputAction = new Runnable()
 +    {
 +      @Override
 +      public void run()
        {
 -        // create backupfiles object and get new temp filename destination
 -        BackupFiles backupfiles = new BackupFiles(file);
 -
 -        try
 +        // todo defer this to inside formatSequences (or later)
 +        AlignmentExportData exportData = viewport
 +                .getAlignExportData(options);
 +        String output = new FormatAdapter(alignPanel, options)
 +                .formatSequences(format, exportData.getAlignment(),
 +                        exportData.getOmitHidden(),
 +                        exportData.getStartEndPostions(),
 +                        viewport.getAlignment().getHiddenColumns());
 +        if (output == null)
          {
 -          PrintWriter out = new PrintWriter(
 -                  new FileWriter(backupfiles.getTempFilePath()));
 -
 -          // TESTING code here
 -          boolean TESTING = true;
 -          if (TESTING)
 +          lastSaveSuccessful = false;
 +        }
 +        else
 +        {
 +          // create backupfiles object and get new temp filename destination
 +          boolean doBackup = BackupFiles.getEnabled();
 +          BackupFiles backupfiles = doBackup ? new BackupFiles(file) : null;
 +          try
            {
 -            out.print("; TESTSTART\n");
 -            int count = 20;
 -            for (int i = 0; i < count; i++)
 -            {
 -              // Thread.sleep(1000);
 -              out.println("; TEST: " + (count - 1 - i));
 -            }
 +            String tempFilePath = doBackup ? backupfiles.getTempFilePath() : file;
 +                      PrintWriter out = new PrintWriter(
 +                    new FileWriter(tempFilePath));
 +            out.print(output);
 +            out.close();
 +            AlignFrame.this.setTitle(file);
 +            statusBar.setText(MessageManager.formatMessage(
 +                  "label.successfully_saved_to_file_in_format", new Object[]
 +                  { fileName, format.getName() }));
 +            lastSaveSuccessful = true;
 +          } catch (Exception ex)
 +          {
 +            lastSaveSuccessful = false;
 +            ex.printStackTrace();
            }
 -          out.print(output);
 -          if (TESTING)
 +
 +          if (doBackup)
            {
 -            out.print("; TESTEND\n");
 +            backupfiles.setWriteSuccess(lastSaveSuccessful);
 +            // do the backup file roll and rename the temp file to actual file
 +            lastSaveSuccessful = backupfiles.rollBackupsAndRenameTempFile();
            }
 -          out.close();
 -          this.setTitle(file);
 -          statusBar.setText(MessageManager.formatMessage(
 -                  "label.successfully_saved_to_file_in_format", new Object[]
 -                  { fileName, format.getName() }));
 -        } catch (Exception ex)
 -        {
 -          success = false;
 -          ex.printStackTrace();
          }
 -
 -        backupfiles.setWriteSuccess(success);
 -        // do the backup file roll and rename the temp file to actual file
 -        success = backupfiles.rollBackupsAndRenameTempFile();
 -
        }
 -    }
 -
 -    if (!success)
 -    {
 -      JvOptionPane.showInternalMessageDialog(this, MessageManager
 -              .formatMessage("label.couldnt_save_file", new Object[]
 -              { fileName }),
 -              MessageManager.getString("label.error_saving_file"),
 -              JvOptionPane.WARNING_MESSAGE);
 -    }
 +    };
  
 -    return success;
 -  }
 -
 -  private void warningMessage(String warning, String title)
 -  {
 -    if (new jalview.util.Platform().isHeadless())
 +    /*
 +     * show dialog with export options if applicable; else just do it
 +     */
 +    if (AlignExportOptions.isNeeded(viewport, format))
      {
 -      System.err.println("Warning: " + title + "\nWarning: " + warning);
 -
 +      AlignExportOptions choices = new AlignExportOptions(
 +              alignPanel.getAlignViewport(), format, options);
 +      choices.setResponseAction(0, outputAction);
 +      choices.setResponseAction(1, cancelAction);
 +      choices.showDialog();
      }
      else
      {
 -      JvOptionPane.showInternalMessageDialog(this, warning, title,
 -              JvOptionPane.WARNING_MESSAGE);
 +      outputAction.run();
      }
    }
  
    /**
 -   * DOCUMENT ME!
 +   * Outputs the alignment to textbox in the requested format, if necessary
 +   * first prompting the user for whether to include hidden regions or
 +   * non-sequence data
     * 
 -   * @param e
 -   *          DOCUMENT ME!
 +   * @param fileFormatName
     */
    @Override
 -  protected void outputText_actionPerformed(ActionEvent e)
 +  protected void outputText_actionPerformed(String fileFormatName)
    {
      FileFormatI fileFormat = FileFormats.getInstance()
 -            .forName(e.getActionCommand());
 -    AlignmentExportData exportData = getAlignmentForExport(fileFormat,
 -            viewport, null);
 -    if (exportData.getSettings().isCancelled())
 -    {
 -      return;
 -    }
 -    CutAndPasteTransfer cap = new CutAndPasteTransfer();
 -    cap.setForInput(null);
 -    try
 -    {
 -      FileFormatI format = fileFormat;
 -      cap.setText(new FormatAdapter(alignPanel, exportData.getSettings())
 -              .formatSequences(format, exportData.getAlignment(),
 -                      exportData.getOmitHidden(),
 -                      exportData.getStartEndPostions(),
 -                      viewport.getAlignment().getHiddenColumns()));
 -      Desktop.addInternalFrame(cap, MessageManager
 -              .formatMessage("label.alignment_output_command", new Object[]
 -              { e.getActionCommand() }), 600, 500);
 -    } catch (OutOfMemoryError oom)
 -    {
 -      new OOMWarning("Outputting alignment as " + e.getActionCommand(),
 -              oom);
 -      cap.dispose();
 -    }
 -
 -  }
 -
 -  public static AlignmentExportData getAlignmentForExport(
 -          FileFormatI format, AlignViewportI viewport,
 -          AlignExportSettingI exportSettings)
 -  {
 -    AlignmentI alignmentToExport = null;
 -    AlignExportSettingI settings = exportSettings;
 -    String[] omitHidden = null;
 -
 -    HiddenSequences hiddenSeqs = viewport.getAlignment()
 -            .getHiddenSequences();
 -
 -    alignmentToExport = viewport.getAlignment();
 -
 -    boolean hasHiddenSeqs = hiddenSeqs.getSize() > 0;
 -    if (settings == null)
 -    {
 -      settings = new AlignExportSettings(hasHiddenSeqs,
 -              viewport.hasHiddenColumns(), format);
 -    }
 -    // settings.isExportAnnotations();
 -
 -    if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns())
 +            .forName(fileFormatName);
 +    AlignExportSettingsI options = new AlignExportSettingsAdapter(false);
 +    Runnable outputAction = new Runnable()
      {
 -      omitHidden = viewport.getViewAsString(false,
 -              settings.isExportHiddenSequences());
 -    }
 +      @Override
 +      public void run()
 +      {
 +        // todo defer this to inside formatSequences (or later)
 +        AlignmentExportData exportData = viewport
 +                .getAlignExportData(options);
 +        CutAndPasteTransfer cap = new CutAndPasteTransfer();
 +        cap.setForInput(null);
 +        try
 +        {
 +          FileFormatI format = fileFormat;
 +          cap.setText(new FormatAdapter(alignPanel, options)
 +                  .formatSequences(format, exportData.getAlignment(),
 +                          exportData.getOmitHidden(),
 +                          exportData.getStartEndPostions(),
 +                          viewport.getAlignment().getHiddenColumns()));
 +          Desktop.addInternalFrame(cap, MessageManager.formatMessage(
 +                  "label.alignment_output_command", new Object[]
 +                  { fileFormat.getName() }), 600, 500);
 +        } catch (OutOfMemoryError oom)
 +        {
 +          new OOMWarning("Outputting alignment as " + fileFormat.getName(),
 +                  oom);
 +          cap.dispose();
 +        }
 +      }
 +    };
  
 -    int[] alignmentStartEnd = new int[2];
 -    if (hasHiddenSeqs && settings.isExportHiddenSequences())
 +    /*
 +     * show dialog with export options if applicable; else just do it
 +     */
 +    if (AlignExportOptions.isNeeded(viewport, fileFormat))
      {
 -      alignmentToExport = hiddenSeqs.getFullAlignment();
 +      AlignExportOptions choices = new AlignExportOptions(
 +              alignPanel.getAlignViewport(), fileFormat, options);
 +      choices.setResponseAction(0, outputAction);
 +      choices.showDialog();
      }
      else
      {
 -      alignmentToExport = viewport.getAlignment();
 +      outputAction.run();
      }
 -    alignmentStartEnd = viewport.getAlignment().getHiddenColumns()
 -            .getVisibleStartAndEndIndex(alignmentToExport.getWidth());
 -    AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
 -            omitHidden, alignmentStartEnd, settings);
 -    return ed;
    }
  
    /**
    }
  
    /**
 -   * DOCUMENT ME!
 +   * Creates a PNG image of the alignment and writes it to the given file. If
 +   * the file is null, the user is prompted to choose a file.
     * 
 -   * @param e
 -   *          DOCUMENT ME!
 +   * @param f
     */
    @Override
    public void createPNG(File f)
    {
 -    alignPanel.makePNG(f);
 +    alignPanel.makeAlignmentImage(TYPE.PNG, f);
    }
  
    /**
 -   * DOCUMENT ME!
 +   * Creates an EPS image of the alignment and writes it to the given file. If
 +   * the file is null, the user is prompted to choose a file.
     * 
 -   * @param e
 -   *          DOCUMENT ME!
 +   * @param f
     */
    @Override
    public void createEPS(File f)
    {
 -    alignPanel.makeEPS(f);
 +    alignPanel.makeAlignmentImage(TYPE.EPS, f);
    }
  
 +  /**
 +   * Creates an SVG image of the alignment and writes it to the given file. If
 +   * the file is null, the user is prompted to choose a file.
 +   * 
 +   * @param f
 +   */
    @Override
    public void createSVG(File f)
    {
 -    alignPanel.makeSVG(f);
 +    alignPanel.makeAlignmentImage(TYPE.SVG, f);
    }
  
    @Override
    @Override
    public void associatedData_actionPerformed(ActionEvent e)
    {
 -    // Pick the tree file
 -    JalviewFileChooser chooser = new JalviewFileChooser(
 +    final JalviewFileChooser chooser = new JalviewFileChooser(
              jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(
              MessageManager.getString("label.load_jalview_annotations"));
      chooser.setToolTipText(
              MessageManager.getString("label.load_jalview_annotations"));
 -
 -    int value = chooser.showOpenDialog(null);
 -
 -    if (value == JalviewFileChooser.APPROVE_OPTION)
 +    chooser.setResponseHandler(0, new Runnable()
      {
 -      String choice = chooser.getSelectedFile().getPath();
 -      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
 -      loadJalviewDataFile(choice, null, null, null);
 -    }
 +      @Override
 +      public void run()
 +      {
 +        String choice = chooser.getSelectedFile().getPath();
 +        jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
 +        loadJalviewDataFile(chooser.getSelectedFile(), null, null, null);
 +      }
 +    });
  
 +    chooser.showOpenDialog(this);
    }
  
    /**
     *          DOCUMENT ME!
     */
    @Override
 -  protected void copy_actionPerformed(ActionEvent e)
 +  protected void copy_actionPerformed()
    {
      if (viewport.getSelectionGroup() == null)
      {
  
      Desktop.jalviewClipboard = new Object[] { seqs,
          viewport.getAlignment().getDataset(), hiddenColumns };
 -    statusBar.setText(MessageManager.formatMessage(
 +    setStatus(MessageManager.formatMessage(
              "label.copied_sequences_to_clipboard", new Object[]
              { Integer.valueOf(seqs.length).toString() }));
    }
                  && Desktop.jalviewClipboard[1] != alignment.getDataset();
          // importDs==true instructs us to copy over new dataset sequences from
          // an existing alignment
 -        Vector newDs = (importDs) ? new Vector() : null; // used to create
 +        Vector<SequenceI> newDs = (importDs) ? new Vector<>() : null; // used to
 +                                                                      // create
          // minimum dataset set
  
          for (int i = 0; i < sequences.length; i++)
                      newGraphGroups.add(q, null);
                    }
                    newGraphGroups.set(newann.graphGroup,
-                           new Integer(++fgroup));
+                           Integer.valueOf(++fgroup));
                  }
                  newann.graphGroup = newGraphGroups.get(newann.graphGroup)
                          .intValue();
                      newGraphGroups.add(q, null);
                    }
                    newGraphGroups.set(newann.graphGroup,
-                           new Integer(++fgroup));
+                           Integer.valueOf(++fgroup));
                  }
                  newann.graphGroup = newGraphGroups.get(newann.graphGroup)
                          .intValue();
        {
  
          // propagate alignment changed.
 -        viewport.getRanges().setEndSeq(alignment.getHeight());
 +        viewport.getRanges().setEndSeq(alignment.getHeight() - 1);
          if (annotationAdded)
          {
            // Duplicate sequence annotation in all views.
    }
  
    /**
 -   * DOCUMENT ME!
 -   * 
 -   * @param e
 -   *          DOCUMENT ME!
 +   * Action Cut (delete and copy) the selected region
     */
    @Override
 -  protected void cut_actionPerformed(ActionEvent e)
 +  protected void cut_actionPerformed()
    {
 -    copy_actionPerformed(null);
 -    delete_actionPerformed(null);
 +    copy_actionPerformed();
 +    delete_actionPerformed();
    }
  
    /**
 -   * DOCUMENT ME!
 -   * 
 -   * @param e
 -   *          DOCUMENT ME!
 +   * Performs menu option to Delete the currently selected region
     */
    @Override
 -  protected void delete_actionPerformed(ActionEvent evt)
 +  protected void delete_actionPerformed()
    {
  
      SequenceGroup sg = viewport.getSelectionGroup();
        return;
      }
  
 +    Runnable okAction = new Runnable() 
 +    {
 +              @Override
 +              public void run() 
 +              {
 +                  SequenceI[] cut = sg.getSequences()
 +                          .toArray(new SequenceI[sg.getSize()]);
 +
 +                  addHistoryItem(new EditCommand(
 +                          MessageManager.getString("label.cut_sequences"), Action.CUT,
 +                          cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
 +                          viewport.getAlignment()));
 +
 +                  viewport.setSelectionGroup(null);
 +                  viewport.sendSelection();
 +                  viewport.getAlignment().deleteGroup(sg);
 +
 +                  viewport.firePropertyChange("alignment", null,
 +                          viewport.getAlignment().getSequences());
 +                  if (viewport.getAlignment().getHeight() < 1)
 +                  {
 +                    try
 +                    {
 +                      AlignFrame.this.setClosed(true);
 +                    } catch (Exception ex)
 +                    {
 +                    }
 +                  }
 +              }};
 +
      /*
 -     * If the cut affects all sequences, warn, remove highlighted columns
 +     * If the cut affects all sequences, prompt for confirmation
       */
 -    if (sg.getSize() == viewport.getAlignment().getHeight())
 -    {
 -      boolean isEntireAlignWidth = (((sg.getEndRes() - sg.getStartRes())
 -              + 1) == viewport.getAlignment().getWidth()) ? true : false;
 -      if (isEntireAlignWidth)
 -      {
 -        int confirm = JvOptionPane.showConfirmDialog(this,
 -                MessageManager.getString("warn.delete_all"), // $NON-NLS-1$
 -                MessageManager.getString("label.delete_all"), // $NON-NLS-1$
 -                JvOptionPane.OK_CANCEL_OPTION);
 -
 -        if (confirm == JvOptionPane.CANCEL_OPTION
 -                || confirm == JvOptionPane.CLOSED_OPTION)
 -        {
 -          return;
 -        }
 -      }
 -      viewport.getColumnSelection().removeElements(sg.getStartRes(),
 -              sg.getEndRes() + 1);
 -    }
 -    SequenceI[] cut = sg.getSequences()
 -            .toArray(new SequenceI[sg.getSize()]);
 -
 -    addHistoryItem(new EditCommand(
 -            MessageManager.getString("label.cut_sequences"), Action.CUT,
 -            cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
 -            viewport.getAlignment()));
 -
 -    viewport.setSelectionGroup(null);
 -    viewport.sendSelection();
 -    viewport.getAlignment().deleteGroup(sg);
 -
 -    viewport.firePropertyChange("alignment", null,
 -            viewport.getAlignment().getSequences());
 -    if (viewport.getAlignment().getHeight() < 1)
 -    {
 -      try
 -      {
 -        this.setClosed(true);
 -      } catch (Exception ex)
 -      {
 -      }
 -    }
 +    boolean wholeHeight = sg.getSize() == viewport.getAlignment().getHeight();
 +    boolean wholeWidth = (((sg.getEndRes() - sg.getStartRes())
 +            + 1) == viewport.getAlignment().getWidth()) ? true : false;
 +      if (wholeHeight && wholeWidth)
 +      {
 +          JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop);
 +              dialog.setResponseHandler(0, okAction); // 0 = OK_OPTION
 +          Object[] options = new Object[] { MessageManager.getString("action.ok"),
 +                  MessageManager.getString("action.cancel") };
 +              dialog.showDialog(MessageManager.getString("warn.delete_all"),
 +                  MessageManager.getString("label.delete_all"),
 +                  JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null,
 +                  options, options[0]);
 +      } else 
 +      {
 +              okAction.run();
 +      }
    }
  
    /**
                  column, viewport.getAlignment());
        }
  
 -      statusBar.setText(MessageManager
 +      setStatus(MessageManager
                .formatMessage("label.removed_columns", new String[]
                { Integer.valueOf(trimRegion.getSize()).toString() }));
  
  
      addHistoryItem(removeGapCols);
  
 -    statusBar.setText(MessageManager
 +    setStatus(MessageManager
              .formatMessage("label.removed_empty_columns", new Object[]
              { Integer.valueOf(removeGapCols.getSize()).toString() }));
  
     * @param toggleSeqs
     * @param toggleCols
     */
 -  private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
 +  protected void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
    {
  
      boolean hide = false;
    @Override
    public void alignmentProperties()
    {
 -    JEditorPane editPane = new JEditorPane("text/html", "");
 -    editPane.setEditable(false);
 +    JComponent pane;
      StringBuffer contents = new AlignmentProperties(viewport.getAlignment())
 +
              .formatAsHtml();
 -    editPane.setText(
 -            MessageManager.formatMessage("label.html_content", new Object[]
 -            { contents.toString() }));
 +    String content = MessageManager.formatMessage("label.html_content",
 +            new Object[]
 +            { contents.toString() });
 +    contents = null;
 +
 +    if (Platform.isJS())
 +    {
 +      JLabel textLabel = new JLabel();
 +      textLabel.setText(content);
 +      textLabel.setBackground(Color.WHITE);
 +      
 +      pane = new JPanel(new BorderLayout());
 +      ((JPanel) pane).setOpaque(true);
 +      pane.setBackground(Color.WHITE);
 +      ((JPanel) pane).add(textLabel, BorderLayout.NORTH);
 +    }
 +    else
 +    /**
 +     * Java only
 +     * 
 +     * @j2sIgnore
 +     */
 +    {
 +      JEditorPane editPane = new JEditorPane("text/html", "");
 +      editPane.setEditable(false);
 +      editPane.setText(content);
 +      pane = editPane;
 +    }
 +
      JInternalFrame frame = new JInternalFrame();
 -    frame.getContentPane().add(new JScrollPane(editPane));
 +
 +    frame.getContentPane().add(new JScrollPane(pane));
  
      Desktop.addInternalFrame(frame, MessageManager
              .formatMessage("label.alignment_properties", new Object[]
                {
                  overview.dispose();
                  alignPanel.setOverviewPanel(null);
 -              };
 +              }
              });
      if (getKeyListeners().length > 0)
      {
      {
        sortByAnnotScore.removeAll();
        // almost certainly a quicker way to do this - but we keep it simple
 -      Hashtable scoreSorts = new Hashtable();
 +      Hashtable<String, String> scoreSorts = new Hashtable<>();
        AlignmentAnnotation aann[];
        for (SequenceI sqa : viewport.getAlignment().getSequences())
        {
            }
          }
        }
 -      Enumeration labels = scoreSorts.keys();
 +      Enumeration<String> labels = scoreSorts.keys();
        while (labels.hasMoreElements())
        {
          addSortByAnnotScoreMenuItem(sortByAnnotScore,
 -                (String) labels.nextElement());
 +                labels.nextElement());
        }
        sortByAnnotScore.setVisible(scoreSorts.size() > 0);
        scoreSorts.clear();
      chooser.setToolTipText(
              MessageManager.getString("label.load_tree_file"));
  
 -    int value = chooser.showOpenDialog(null);
 -
 -    if (value == JalviewFileChooser.APPROVE_OPTION)
 +    chooser.setResponseHandler(0,new Runnable()
      {
 -      String filePath = chooser.getSelectedFile().getPath();
 -      Cache.setProperty("LAST_DIRECTORY", filePath);
 -      NewickFile fin = null;
 -      try
 -      {
 -        fin = new NewickFile(filePath, DataSourceType.FILE);
 -        viewport.setCurrentTree(showNewickTree(fin, filePath).getTree());
 -      } catch (Exception ex)
 -      {
 -        JvOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
 -                MessageManager.getString("label.problem_reading_tree_file"),
 -                JvOptionPane.WARNING_MESSAGE);
 -        ex.printStackTrace();
 -      }
 -      if (fin != null && fin.hasWarningMessage())
 +      @Override
 +      public void run()
        {
 -        JvOptionPane.showMessageDialog(Desktop.desktop,
 -                fin.getWarningMessage(),
 -                MessageManager
 -                        .getString("label.possible_problem_with_tree_file"),
 -                JvOptionPane.WARNING_MESSAGE);
 +        String filePath = chooser.getSelectedFile().getPath();
 +        Cache.setProperty("LAST_DIRECTORY", filePath);
 +        NewickFile fin = null;
 +        try
 +        {
 +          fin = new NewickFile(new FileParse(chooser.getSelectedFile(),
 +                  DataSourceType.FILE));
 +          viewport.setCurrentTree(showNewickTree(fin, filePath).getTree());
 +        } catch (Exception ex)
 +        {
 +          JvOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
 +                  MessageManager
 +                          .getString("label.problem_reading_tree_file"),
 +                  JvOptionPane.WARNING_MESSAGE);
 +          ex.printStackTrace();
 +        }
 +        if (fin != null && fin.hasWarningMessage())
 +        {
 +          JvOptionPane.showMessageDialog(Desktop.desktop,
 +                  fin.getWarningMessage(),
 +                  MessageManager.getString(
 +                          "label.possible_problem_with_tree_file"),
 +                  JvOptionPane.WARNING_MESSAGE);
 +        }
        }
 -    }
 +    });
 +    chooser.showOpenDialog(this);
    }
  
    public TreePanel showNewickTree(NewickFile nf, String treeTitle)
              // No MSAWS used any more:
              // Vector msaws = null; // (Vector)
              // Discoverer.services.get("MsaWS");
 -            Vector secstrpr = (Vector) Discoverer.services
 +            Vector<ServiceHandle> secstrpr = Discoverer.services
                      .get("SecStrPred");
              if (secstrpr != null)
              {
                // Add any secondary structure prediction services
                for (int i = 0, j = secstrpr.size(); i < j; i++)
                {
 -                final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
 +                final ext.vamsas.ServiceHandle sh = secstrpr
                          .get(i);
                  jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
                          .getServiceClient(sh);
     * 
     * @param webService
     */
 -  private void build_urlServiceMenu(JMenu webService)
 +  protected void build_urlServiceMenu(JMenu webService)
    {
      // TODO: remove this code when 2.7 is released
      // DEBUG - alignmentView
     * Try to load a features file onto the alignment.
     * 
     * @param file
 -   *          contents or path to retrieve file
 +   *          contents or path to retrieve file or a File object
     * @param sourceType
     *          access mode of file (see jalview.io.AlignFile)
     * @return true if features file was parsed correctly.
     */
 -  public boolean parseFeaturesFile(String file, DataSourceType sourceType)
 +  public boolean parseFeaturesFile(Object file, DataSourceType sourceType)
    {
 +    // BH 2018
      return avc.parseFeaturesFile(file, sourceType,
              Cache.getDefault("RELAXEDSEQIDMATCHING", false));
  
      // Java's Transferable for native dnd
      evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
      Transferable t = evt.getTransferable();
 +
      final AlignFrame thisaf = this;
 -    final List<String> files = new ArrayList<>();
 +    final List<Object> files = new ArrayList<>();
      List<DataSourceType> protocols = new ArrayList<>();
  
      try
               * Object[] { String,SequenceI}
               */
              ArrayList<Object[]> filesmatched = new ArrayList<>();
 -            ArrayList<String> filesnotmatched = new ArrayList<>();
 +            ArrayList<Object> filesnotmatched = new ArrayList<>();
              for (int i = 0; i < files.size(); i++)
              {
 -              String file = files.get(i).toString();
 +              // BH 2018
 +              Object file = files.get(i);
 +              String fileName = file.toString();
                String pdbfn = "";
 -              DataSourceType protocol = FormatAdapter.checkProtocol(file);
 +              DataSourceType protocol = (file instanceof File
 +                      ? DataSourceType.FILE
 +                      : FormatAdapter.checkProtocol(fileName));
                if (protocol == DataSourceType.FILE)
                {
 -                File fl = new File(file);
 +                File fl;
 +                if (file instanceof File) {
 +                  fl = (File) file;
 +                  Platform.cacheFileData(fl);
 +                } else {
 +                  fl = new File(fileName);
 +                }
                  pdbfn = fl.getName();
                }
                else if (protocol == DataSourceType.URL)
                {
 -                URL url = new URL(file);
 +                URL url = new URL(fileName);
                  pdbfn = url.getFile();
                }
                if (pdbfn.length() > 0)
                  }
                  if (mtch != null)
                  {
 -                  FileFormatI type = null;
 +                  FileFormatI type;
                    try
                    {
                      type = new IdentifyFile().identify(file, protocol);
                    for (SequenceI toassoc : (SequenceI[]) fm[2])
                    {
                      PDBEntry pe = new AssociatePdbFileWithSeq()
 -                            .associatePdbWithSeq((String) fm[0],
 +                            .associatePdbWithSeq(fm[0].toString(),
                                      (DataSourceType) fm[1], toassoc, false,
                                      Desktop.instance);
                      if (pe != null)
                      {
                        System.err.println("Associated file : "
 -                              + ((String) fm[0]) + " with "
 +                              + (fm[0].toString()) + " with "
                                + toassoc.getDisplayId(true));
                        assocfiles++;
                      }
                   */
                  for (Object[] o : filesmatched)
                  {
 -                  filesnotmatched.add((String) o[0]);
 +                  filesnotmatched.add(o[0]);
                  }
                }
              }
                {
                  return;
                }
 -              for (String fn : filesnotmatched)
 +              for (Object fn : filesnotmatched)
                {
                  loadJalviewDataFile(fn, null, null, null);
                }
     * @param file
     *          either a filename or a URL string.
     */
 -  public void loadJalviewDataFile(String file, DataSourceType sourceType,
 +  public void loadJalviewDataFile(Object file, DataSourceType sourceType,
            FileFormatI format, SequenceI assocSeq)
    {
 +    // BH 2018 was String file
      try
      {
        if (sourceType == null)
                changeColour(
                        new TCoffeeColourScheme(viewport.getAlignment()));
                isAnnotation = true;
 -              statusBar.setText(MessageManager.getString(
 +              setStatus(MessageManager.getString(
                        "label.successfully_pasted_tcoffee_scores_to_alignment"));
              }
              else
                      new FileParse(file, sourceType));
              sm.parse();
              // todo: i18n this message
 -            statusBar.setText(MessageManager.formatMessage(
 +            setStatus(MessageManager.formatMessage(
                      "label.successfully_loaded_matrix",
                      sm.getMatrixName()));
            }
      if (e.isPopupTrigger())
      {
        String msg = MessageManager.getString("label.enter_view_name");
 -      String reply = JvOptionPane.showInternalInputDialog(this, msg, msg,
 -              JvOptionPane.QUESTION_MESSAGE);
 +      String ttl = tabbedPane.getTitleAt(tabbedPane.getSelectedIndex());
 +      String reply = JvOptionPane.showInputDialog(msg, ttl);
  
        if (reply != null)
        {
          trimrs.setSelected(trimrs.isSelected());
          Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES,
                  Boolean.valueOf(trimrs.isSelected()).toString());
 -      };
 +      }
      });
      rfetch.add(trimrs);
      JMenuItem fetchr = new JMenuItem(
  
      });
      rfetch.add(fetchr);
 -    final AlignFrame me = this;
      new Thread(new Runnable()
      {
        @Override
        public void run()
        {
          final jalview.ws.SequenceFetcher sf = jalview.gui.SequenceFetcher
 -                .getSequenceFetcherSingleton(me);
 +                .getSequenceFetcherSingleton();
          javax.swing.SwingUtilities.invokeLater(new Runnable()
          {
            @Override
            public void run()
            {
 -            String[] dbclasses = sf.getOrderedSupportedSources();
 -            // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
 -            // jalview.util.QuickSort.sort(otherdb, otherdb);
 +            String[] dbclasses = sf.getNonAlignmentSources();
              List<DbSourceProxy> otherdb;
              JMenu dfetch = new JMenu();
              JMenu ifetch = new JMenu();
                {
                  continue;
                }
 -              // List<DbSourceProxy> dbs=otherdb;
 -              // otherdb=new ArrayList<DbSourceProxy>();
 -              // for (DbSourceProxy db:dbs)
 -              // {
 -              // if (!db.isA(DBRefSource.ALIGNMENTDB)
 -              // }
                if (mname == null)
                {
                  mname = "From " + dbclass;
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(MessageManager.getString("label.load_vcf_file"));
      chooser.setToolTipText(MessageManager.getString("label.load_vcf_file"));
 -
 -    int value = chooser.showOpenDialog(null);
 -
 -    if (value == JalviewFileChooser.APPROVE_OPTION)
 +    final AlignFrame us = this;
 +    chooser.setResponseHandler(0, new Runnable()
      {
 -      String choice = chooser.getSelectedFile().getPath();
 -      Cache.setProperty("LAST_DIRECTORY", choice);
 -      SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
 -      new VCFLoader(choice).loadVCF(seqs, this);
 -    }
 +      @Override
 +      public void run()
 +      {
 +        String choice = chooser.getSelectedFile().getPath();
 +        Cache.setProperty("LAST_DIRECTORY", choice);
 +        SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
 +        new VCFLoader(choice).loadVCF(seqs, us);
 +      }
 +    });
 +    chooser.showOpenDialog(null);
  
    }
 +
  }
  
  class PrintThread extends Thread
@@@ -24,11 -24,9 +24,11 @@@ import jalview.bin.Cache
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SequenceI;
 +import jalview.gui.ImageExporter.ImageWriterI;
  import jalview.gui.StructureViewer.ViewerType;
  import jalview.structures.models.AAStructureBindingModel;
  import jalview.util.BrowserLauncher;
 +import jalview.util.ImageMaker;
  import jalview.util.MessageManager;
  import jalview.util.Platform;
  import jalview.ws.dbsources.Pdb;
@@@ -328,7 -326,7 +328,7 @@@ public class AppJmol extends StructureV
      for (String s : files)
      {
        fileList.append(SPACE).append(QUOTE)
-               .append(Platform.escapeString(s)).append(QUOTE);
+               .append(Platform.escapeBackslashes(s)).append(QUOTE);
      }
      String filesString = fileList.toString();
  
        } catch (Exception ex)
        {
          Cache.log.error("Couldn't open Jmol viewer!", ex);
 +        ex.printStackTrace();
 +        return;
        }
      }
      else
          new OOMWarning("When trying to add structures to the Jmol viewer!",
                  oomerror);
          Cache.log.debug("File locations are " + filesString);
 +        return;
        } catch (Exception ex)
        {
          Cache.log.error("Couldn't add files to Jmol viewer!", ex);
 +        ex.printStackTrace();
 +        return;
        }
      }
  
              addingStructures = true; // already files loaded.
              for (int c = 0; c < filesInViewer.length; c++)
              {
-               if (filesInViewer[c].equals(file))
+               if (Platform.pathEquals(filesInViewer[c], file))
                {
                  file = null;
                  break;
      return files;
    }
  
 -  @Override
 -  public void eps_actionPerformed(ActionEvent e)
 -  {
 -    makePDBImage(jalview.util.ImageMaker.TYPE.EPS);
 -  }
 -
 -  @Override
 -  public void png_actionPerformed(ActionEvent e)
 -  {
 -    makePDBImage(jalview.util.ImageMaker.TYPE.PNG);
 -  }
 -
 -  void makePDBImage(jalview.util.ImageMaker.TYPE type)
 +  /**
 +   * Outputs the Jmol viewer image as an image file, after prompting the user to
 +   * choose a file and (for EPS) choice of Text or Lineart character rendering
 +   * (unless a preference for this is set)
 +   * 
 +   * @param type
 +   */
 +  public void makePDBImage(ImageMaker.TYPE type)
    {
      int width = getWidth();
      int height = getHeight();
 -
 -    jalview.util.ImageMaker im;
 -
 -    if (type == jalview.util.ImageMaker.TYPE.PNG)
 +    ImageWriterI writer = new ImageWriterI()
      {
 -      im = new jalview.util.ImageMaker(this,
 -              jalview.util.ImageMaker.TYPE.PNG, "Make PNG image from view",
 -              width, height, null, null, null, 0, false);
 -    }
 -    else if (type == jalview.util.ImageMaker.TYPE.EPS)
 -    {
 -      im = new jalview.util.ImageMaker(this,
 -              jalview.util.ImageMaker.TYPE.EPS, "Make EPS file from view",
 -              width, height, null, this.getTitle(), null, 0, false);
 -    }
 -    else
 -    {
 -
 -      im = new jalview.util.ImageMaker(this,
 -              jalview.util.ImageMaker.TYPE.SVG, "Make SVG file from PCA",
 -              width, height, null, this.getTitle(), null, 0, false);
 -    }
 -
 -    if (im.getGraphics() != null)
 -    {
 -      jmb.viewer.renderScreenImage(im.getGraphics(), width, height);
 -      im.writeImage();
 -    }
 +      @Override
 +      public void exportImage(Graphics g) throws Exception
 +      {
 +        jmb.viewer.renderScreenImage(g, width, height);
 +      }
 +    };
 +    String view = MessageManager.getString("action.view").toLowerCase();
 +    ImageExporter exporter = new ImageExporter(writer,
 +            jmb.getIProgressIndicator(), type, getTitle());
 +    exporter.doExport(null, this, width, height, view);
    }
  
    @Override
    {
      try
      {
 -      BrowserLauncher
 -              .openURL("http://jmol.sourceforge.net/docs/JmolUserGuide/");
 +      BrowserLauncher // BH 2018
 +              .openURL("http://wiki.jmol.org");//http://jmol.sourceforge.net/docs/JmolUserGuide/");
      } catch (Exception ex)
      {
      }
@@@ -219,7 -219,7 +219,7 @@@ public class BlogReader extends JPane
  
        }
      };
 -  };
 +  }
  
    private JLabel lblChannels = new JLabel();
  
      } catch (Exception x)
      {
      }
 -    ;
      if (chan != null && chan.getItems() != null)
      {
        Cache.log.debug("Scanning news items: newsnew=" + newsnew
      public LaunchJvBrowserOnItem(JList listItems)
      {
        super("Open in Browser");
-       this.putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_O));
+       this.putValue(MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_O));
        this.putValue(Action.LONG_DESCRIPTION, "Open in Browser");
        _listItems = listItems;
      }
      }
    }
  
 +  /**
 +   * @j2sIgnore
 +   * @param args
 +   */
    public static void main(String args[])
    {
      // this tests the detection of new news based on the last read date stored
          } catch (InterruptedException x)
          {
          }
 -        ;
        } while (me.isVisible());
  
        if (me.isNewsNew())
@@@ -32,7 -32,6 +32,7 @@@ import jalview.io.DataSourceType
  import jalview.io.StructureFile;
  import jalview.structures.models.AAStructureBindingModel;
  import jalview.util.BrowserLauncher;
 +import jalview.util.ImageMaker.TYPE;
  import jalview.util.MessageManager;
  import jalview.util.Platform;
  import jalview.ws.dbsources.Pdb;
@@@ -481,7 -480,7 +481,7 @@@ public class ChimeraViewFrame extends S
          {
            filePDB.add(thePdbEntry);
            filePDBpos.add(Integer.valueOf(pi));
-           files.append(" \"" + Platform.escapeString(file) + "\"");
+           files.append(" \"" + Platform.escapeBackslashes(file) + "\"");
          }
        }
      } catch (OutOfMemoryError oomerror)
    }
  
    @Override
 -  public void eps_actionPerformed(ActionEvent e)
 +  public void makePDBImage(TYPE imageType)
    {
 -    throw new Error(MessageManager
 -            .getString("error.eps_generation_not_implemented"));
 -  }
 -
 -  @Override
 -  public void png_actionPerformed(ActionEvent e)
 -  {
 -    throw new Error(MessageManager
 -            .getString("error.png_generation_not_implemented"));
 +    throw new UnsupportedOperationException(
 +            "Image export for Chimera is not implemented");
    }
  
    @Override
   */
  package jalview.gui;
  
- import static jalview.util.UrlConstants.SEQUENCE_ID;
  import jalview.api.AlignViewportI;
  import jalview.api.AlignmentViewPanel;
  import jalview.bin.Cache;
  import jalview.bin.Jalview;
 +import jalview.gui.ImageExporter.ImageWriterI;
  import jalview.io.BackupFiles;
  import jalview.io.DataSourceType;
  import jalview.io.FileFormat;
@@@ -43,8 -40,7 +41,8 @@@ import jalview.jbgui.GStructureViewer
  import jalview.project.Jalview2XML;
  import jalview.structure.StructureSelectionManager;
  import jalview.urls.IdOrgSettings;
 -import jalview.util.ImageMaker;
 +import jalview.util.BrowserLauncher;
 +import jalview.util.ImageMaker.TYPE;
  import jalview.util.MessageManager;
  import jalview.util.Platform;
  import jalview.util.UrlConstants;
@@@ -84,12 -80,15 +82,14 @@@ import java.beans.PropertyChangeListene
  import java.io.BufferedInputStream;
  import java.io.File;
  import java.io.FileOutputStream;
+ import java.io.FileWriter;
  import java.io.IOException;
  import java.net.URL;
  import java.util.ArrayList;
+ import java.util.HashMap;
  import java.util.Hashtable;
  import java.util.List;
  import java.util.ListIterator;
 -import java.util.StringTokenizer;
  import java.util.Vector;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
@@@ -108,14 -107,12 +108,13 @@@ import javax.swing.JCheckBox
  import javax.swing.JComboBox;
  import javax.swing.JComponent;
  import javax.swing.JDesktopPane;
- import javax.swing.JFrame;
  import javax.swing.JInternalFrame;
  import javax.swing.JLabel;
  import javax.swing.JMenuItem;
  import javax.swing.JPanel;
  import javax.swing.JPopupMenu;
  import javax.swing.JProgressBar;
 +import javax.swing.JTextField;
  import javax.swing.KeyStroke;
  import javax.swing.SwingUtilities;
  import javax.swing.event.HyperlinkEvent;
@@@ -148,6 -145,10 +147,10 @@@ public class Desktop extends jalview.jb
  
    private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
  
+   protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
+   public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
    private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
  
    /**
  
    public static MyDesktopPane desktop;
  
 +  public static MyDesktopPane getDesktop()
 +  {
 +    // BH 2018 could use currentThread() here as a reference to a
 +    // Hashtable<Thread, MyDesktopPane> in JavaScript
 +    return desktop;
 +  }
 +
    static int openFrameCount = 0;
  
    static final int xOffset = 30;
     */
    public Desktop()
    {
 +    super();
      /**
       * A note to implementors. It is ESSENTIAL that any activities that might
       * block are spawned off as threads rather than waited for during this
       * constructor.
       */
      instance = this;
 -    doVamsasClientCheck();
 +    if (!Platform.isJS())
 +    {
 +      doVamsasClientCheck();
 +    }
  
      doConfigureStructurePrefs();
      setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
-     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+     /*
+     if (!Platform.isAMac())
+     {
+       // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+     }
+     else
+     {
+      this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+     }
+     */
+     try
+     {
+       APQHandlers.setAPQHandlers(this);
+     } catch (Exception e)
+     {
+       System.out.println("Exception when trying to set APQHandlers");
+       e.printStackTrace();
+     } catch (Throwable t)
+     {
+       System.out.println("Throwable when trying to set APQHandlers");
+       t.printStackTrace();
+     }
+     addWindowListener(new WindowAdapter()
+     {
+       @Override
+       public void windowClosing(WindowEvent ev)
+       {
+         quit();
+       }
+     });
      boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
              false);
      boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
              false);
      desktop = new MyDesktopPane(selmemusage);
 +
      showMemusage.setSelected(selmemusage);
      desktop.setBackground(Color.white);
      getContentPane().setLayout(new BorderLayout());
      // alternate config - have scrollbars - see notes in JAL-153
      // JScrollPane sp = new JScrollPane();
      // sp.getViewport().setView(desktop);
      // getContentPane().add(sp, BorderLayout.CENTER);
 +
 +    // BH 2018 - just an experiment to try unclipped JInternalFrames.
 +    if (Platform.isJS())
 +    {
 +      getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
 +    }
 +
      getContentPane().add(desktop, BorderLayout.CENTER);
      desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
  
      // This line prevents Windows Look&Feel resizing all new windows to maximum
      // if previous window was maximised
      desktop.setDesktopManager(new MyDesktopManager(
 -            (Platform.isWindows() ? new DefaultDesktopManager()
 -                    : Platform.isAMac()
 +            (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
 +                    : Platform.isAMacAndNotJS()
                              ? new AquaInternalFrameManager(
                                      desktop.getDesktopManager())
                              : desktop.getDesktopManager())));
      else
      {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
 -      setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
 -              900, 650);
 -    }
 -    jconsole = new Console(this, showjconsole);
 -    // add essential build information
 -    jconsole.setHeader(
 -            "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
 -                    + "\n" + "Jalview Installation: "
 -                    + jalview.bin.Cache.getDefault("INSTALLATION",
 -                            "unknown")
 -                    + "\n" + "Build Date: "
 -                    + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
 -                    + "\n" + "Java version: "
 -                    + System.getProperty("java.version") + "\n"
 -                    + System.getProperty("os.arch") + " "
 -                    + System.getProperty("os.name") + " "
 -                    + System.getProperty("os.version")
 -                    + (jalview.bin.Cache.getProperty("VERSION").equals("DEVELOPMENT")
 -                                    ? "\nJava path:"
 -                                            + System.getProperty(
 -                                                    "java.home")
 -                                            + File.separator + "bin"
 -                                            + File.separator + "java"
 -                                    : "")
 -            );
 -
 -    showConsole(showjconsole);
 -
 -    showNews.setVisible(false);
 -
 -    experimentalFeatures.setSelected(showExperimental());
 -
 -    getIdentifiersOrgData();
 -
 -    checkURLLinks();
 +      int xPos = Math.max(5, (screenSize.width - 900) / 2);
 +      int yPos = Math.max(5, (screenSize.height - 650) / 2);
 +      setBounds(xPos, yPos, 900, 650);
 +    }
 +
 +    if (!Platform.isJS())
 +    /**
 +     * Java only
 +     * 
 +     * @j2sIgnore
 +     */
 +    {
 +
 +      jconsole = new Console(this, showjconsole);
 +      // add essential build information
 +      jconsole.setHeader("Jalview Version: "
 +              + jalview.bin.Cache.getProperty("VERSION") + "\n"
 +              + "Jalview Installation: "
 +              + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
 +              + "\n" + "Build Date: "
 +              + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
 +              + "Java version: " + System.getProperty("java.version") + "\n"
 +              + System.getProperty("os.arch") + " "
 +              + System.getProperty("os.name") + " "
-               + System.getProperty("os.version"));
++              + System.getProperty("os.version")
++              + (jalview.bin.Cache.getProperty("VERSION").equals("DEVELOPMENT")
++                              ? "\nJava path:"
++                                      + System.getProperty(
++                                              "java.home")
++                                      + File.separator + "bin"
++                                      + File.separator + "java"
++                              : ""));
 +
 +      showConsole(showjconsole);
 +
 +      showNews.setVisible(false);
 +
 +      experimentalFeatures.setSelected(showExperimental());
 +
 +      getIdentifiersOrgData();
 +
 +      checkURLLinks();
 +
 +      // Spawn a thread that shows the splashscreen
 +
 +      SwingUtilities.invokeLater(new Runnable()
 +      {
 +        @Override
 +        public void run()
 +        {
 +          new SplashScreen();
 +        }
 +      });
 +
 +      // Thread off a new instance of the file chooser - this reduces the time
-       // it
-       // takes to open it later on.
++      // it takes to open it later on.
 +      new Thread(new Runnable()
 +      {
 +        @Override
 +        public void run()
 +        {
 +          Cache.log.debug("Filechooser init thread started.");
 +          String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
 +          JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
 +                  fileFormat);
 +          Cache.log.debug("Filechooser init thread finished.");
 +        }
 +      }).start();
 +      // Add the service change listener
 +      changeSupport.addJalviewPropertyChangeListener("services",
 +              new PropertyChangeListener()
 +              {
 +
 +                @Override
 +                public void propertyChange(PropertyChangeEvent evt)
 +                {
 +                  Cache.log.debug("Firing service changed event for "
 +                          + evt.getNewValue());
 +                  JalviewServicesChanged(evt);
 +                }
 +
 +              });
 +
 +    }
 +
 +    this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
  
      this.addWindowListener(new WindowAdapter()
      {
      });
      desktop.addMouseListener(ma);
  
 -    this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
 -    // Spawn a thread that shows the splashscreen
 -    SwingUtilities.invokeLater(new Runnable()
 -    {
 -      @Override
 -      public void run()
 -      {
 -        new SplashScreen();
 -      }
 -    });
 -
 -    // Thread off a new instance of the file chooser - this reduces the time it
 -    // takes to open it later on.
 -    new Thread(new Runnable()
 -    {
 -      @Override
 -      public void run()
 -      {
 -        Cache.log.debug("Filechooser init thread started.");
 -        String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
 -        JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
 -                fileFormat);
 -        Cache.log.debug("Filechooser init thread finished.");
 -      }
 -    }).start();
 -    // Add the service change listener
 -    changeSupport.addJalviewPropertyChangeListener("services",
 -            new PropertyChangeListener()
 -            {
 -
 -              @Override
 -              public void propertyChange(PropertyChangeEvent evt)
 -              {
 -                Cache.log.debug("Firing service changed event for "
 -                        + evt.getNewValue());
 -                JalviewServicesChanged(evt);
 -              }
 -
 -            });
    }
  
    /**
        public void run()
        {
          Cache.log.debug("Starting news thread.");
 -
          jvnews = new BlogReader(me);
          showNews.setVisible(true);
          Cache.log.debug("Completed news thread.");
          }
        }
      }).start();
--    ;
++    
    }
  
    @Override
  
    void showNews(boolean visible)
    {
 +    Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
 +    showNews.setSelected(visible);
 +    if (visible && !jvnews.isVisible())
      {
 -      Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
 -      showNews.setSelected(visible);
 -      if (visible && !jvnews.isVisible())
 +      new Thread(new Runnable()
        {
 -        new Thread(new Runnable()
 +        @Override
 +        public void run()
          {
 -          @Override
 -          public void run()
 -          {
 -            long now = System.currentTimeMillis();
 -            Desktop.instance.setProgressBar(
 -                    MessageManager.getString("status.refreshing_news"),
 -                    now);
 -            jvnews.refreshNews();
 -            Desktop.instance.setProgressBar(null, now);
 -            jvnews.showNews();
 -          }
 -        }).start();
 -      }
 +          long now = System.currentTimeMillis();
 +          Desktop.instance.setProgressBar(
 +                  MessageManager.getString("status.refreshing_news"), now);
 +          jvnews.refreshNews();
 +          Desktop.instance.setProgressBar(null, now);
 +          jvnews.showNews();
 +        }
 +      }).start();
      }
    }
  
  
    private void doVamsasClientCheck()
    {
 -    if (jalview.bin.Cache.vamsasJarsPresent())
 +    if (Cache.vamsasJarsPresent())
      {
        setupVamsasDisconnectedGui();
        VamsasMenu.setVisible(true);
      frame.setResizable(resizable);
      frame.setMaximizable(resizable);
      frame.setIconifiable(resizable);
 -    frame.setOpaque(false);
 +    frame.setOpaque(Platform.isJS());
  
      if (frame.getX() < 1 && frame.getY() < 1)
      {
            menuItem.removeActionListener(menuItem.getActionListeners()[0]);
          }
          windowMenu.remove(menuItem);
--      };
++      }
      });
  
      menuItem.addActionListener(new ActionListener()
            frame.setIcon(false);
          } catch (java.beans.PropertyVetoException ex)
          {
 -
 +          // System.err.println(ex.toString());
          }
        }
      });
    }
  
    /**
 -   * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
 -   * the window
 +   * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
 +   * window
     * 
     * @param frame
     */
      KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
              InputEvent.CTRL_DOWN_MASK);
      KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
  
      InputMap inputMap = frame
              .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
      // Java's Transferable for native dnd
      evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
      Transferable t = evt.getTransferable();
 -    List<String> files = new ArrayList<>();
 +    List<Object> files = new ArrayList<>();
      List<DataSourceType> protocols = new ArrayList<>();
  
      try
        {
          for (int i = 0; i < files.size(); i++)
          {
 -          String file = files.get(i).toString();
 +          // BH 2018 File or String
 +          Object file = files.get(i);
 +          String fileName = file.toString();
            DataSourceType protocol = (protocols == null)
                    ? DataSourceType.FILE
                    : protocols.get(i);
            FileFormatI format = null;
  
 -          if (file.endsWith(".jar"))
 +          if (fileName.endsWith(".jar"))
            {
              format = FileFormat.Jalview;
  
            {
              format = new IdentifyFile().identify(file, protocol);
            }
 -
 -          new FileLoader().LoadFile(file, protocol, format);
 +          if (file instanceof File)
 +          {
 +            Platform.cacheFileData((File) file);
 +          }
 +          new FileLoader().LoadFile(null, file, protocol, format);
  
          }
        } catch (Exception ex)
              MessageManager.getString("label.open_local_file"));
      chooser.setToolTipText(MessageManager.getString("action.open"));
  
 -    int value = chooser.showOpenDialog(this);
 -
 -    if (value == JalviewFileChooser.APPROVE_OPTION)
 +    chooser.setResponseHandler(0, new Runnable()
      {
 -      String choice = chooser.getSelectedFile().getPath();
 -      Cache.setProperty("LAST_DIRECTORY",
 -              chooser.getSelectedFile().getParent());
 +      @Override
 +      public void run()
 +      {
 +        File selectedFile = chooser.getSelectedFile();
 +        Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
  
 -      FileFormatI format = chooser.getSelectedFormat();
 +        FileFormatI format = chooser.getSelectedFormat();
  
 -      /*
 -       * Call IdentifyFile to verify the file contains what its extension implies.
 -       * Skip this step for dynamically added file formats, because
 -       * IdentifyFile does not know how to recognise them.
 -       */
 -      if (FileFormats.getInstance().isIdentifiable(format))
 -      {
 -        try
 -        {
 -          format = new IdentifyFile().identify(choice, DataSourceType.FILE);
 -        } catch (FileFormatException e)
 +        /*
 +         * Call IdentifyFile to verify the file contains what its extension implies.
 +         * Skip this step for dynamically added file formats, because
 +         * IdentifyFile does not know how to recognise them.
 +         */
 +        if (FileFormats.getInstance().isIdentifiable(format))
          {
 -          // format = null; //??
 +          try
 +          {
 +            format = new IdentifyFile().identify(selectedFile,
 +                    DataSourceType.FILE);
 +          } catch (FileFormatException e)
 +          {
 +            // format = null; //??
 +          }
          }
 -      }
  
 -      if (viewport != null)
 -      {
 -        new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
 -                format);
 -      }
 -      else
 -      {
 -        new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
 +        new FileLoader().LoadFile(viewport, selectedFile,
 +                DataSourceType.FILE, format);
        }
 -    }
 +    });
 +    chooser.showOpenDialog(this);
    }
  
    /**
 -   * DOCUMENT ME!
 +   * Shows a dialog for input of a URL at which to retrieve alignment data
     * 
 -   * @param e
 -   *          DOCUMENT ME!
 +   * @param viewport
     */
    @Override
    public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
      // for viewing
      JLabel label = new JLabel(
              MessageManager.getString("label.input_file_url"));
  
      JPanel panel = new JPanel(new GridLayout(2, 1));
      panel.add(label);
 -    panel.add(history);
 -    history.setPreferredSize(new Dimension(400, 20));
 -    history.setEditable(true);
 -    history.addItem("http://www.");
 -
 -    String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
 -
 -    StringTokenizer st;
 -
 -    if (historyItems != null)
 -    {
 -      st = new StringTokenizer(historyItems, "\t");
 -
 -      while (st.hasMoreTokens())
 -      {
 -        history.addItem(st.nextElement());
 -      }
 -    }
  
 -    int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
 -            MessageManager.getString("label.input_alignment_from_url"),
 -            JvOptionPane.OK_CANCEL_OPTION);
 -
 -    if (reply != JvOptionPane.OK_OPTION)
 +    /*
 +     * the URL to fetch is
 +     * Java: an editable combobox with history
 +     * JS: (pending JAL-3038) a plain text field
 +     */
 +    JComponent history;
 +    String urlBase = "http://www.";
 +    if (Platform.isJS())
      {
 -      return;
 +      history = new JTextField(urlBase, 35);
      }
 -
 -    String url = history.getSelectedItem().toString();
 -
 -    if (url.toLowerCase().endsWith(".jar"))
 +    else
 +    /**
 +     * Java only
 +     * 
 +     * @j2sIgnore
 +     */
      {
 -      if (viewport != null)
 -      {
 -        new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
 -                FileFormat.Jalview);
 -      }
 -      else
 +      JComboBox<String> asCombo = new JComboBox<>();
 +      asCombo.setPreferredSize(new Dimension(400, 20));
 +      asCombo.setEditable(true);
 +      asCombo.addItem(urlBase);
 +      String historyItems = Cache.getProperty("RECENT_URL");
 +      if (historyItems != null)
        {
 -        new FileLoader().LoadFile(url, DataSourceType.URL,
 -                FileFormat.Jalview);
 +        for (String token : historyItems.split("\\t"))
 +        {
 +          asCombo.addItem(token);
 +        }
        }
 +      history = asCombo;
      }
 -    else
 +    panel.add(history);
 +
 +    Object[] options = new Object[] { MessageManager.getString("action.ok"),
 +        MessageManager.getString("action.cancel") };
 +    Runnable action = new Runnable()
      {
 -      FileFormatI format = null;
 -      try
 -      {
 -        format = new IdentifyFile().identify(url, DataSourceType.URL);
 -      } catch (FileFormatException e)
 +      @Override
 +      public void run()
        {
 -        // TODO revise error handling, distinguish between
 -        // URL not found and response not valid
 -      }
 +        @SuppressWarnings("unchecked")
 +        String url = (history instanceof JTextField
 +                ? ((JTextField) history).getText()
 +                : ((JComboBox<String>) history).getSelectedItem()
 +                        .toString());
  
 -      if (format == null)
 -      {
 -        JvOptionPane.showInternalMessageDialog(Desktop.desktop,
 -                MessageManager.formatMessage("label.couldnt_locate",
 -                        new Object[]
 -                        { url }),
 -                MessageManager.getString("label.url_not_found"),
 -                JvOptionPane.WARNING_MESSAGE);
 +        if (url.toLowerCase().endsWith(".jar"))
 +        {
 +          if (viewport != null)
 +          {
 +            new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
 +                    FileFormat.Jalview);
 +          }
 +          else
 +          {
 +            new FileLoader().LoadFile(url, DataSourceType.URL,
 +                    FileFormat.Jalview);
 +          }
 +        }
 +        else
 +        {
 +          FileFormatI format = null;
 +          try
 +          {
 +            format = new IdentifyFile().identify(url, DataSourceType.URL);
 +          } catch (FileFormatException e)
 +          {
 +            // TODO revise error handling, distinguish between
 +            // URL not found and response not valid
 +          }
  
 -        return;
 -      }
 +          if (format == null)
 +          {
 +            String msg = MessageManager
 +                    .formatMessage("label.couldnt_locate", url);
 +            JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
 +                    MessageManager.getString("label.url_not_found"),
 +                    JvOptionPane.WARNING_MESSAGE);
  
 -      if (viewport != null)
 -      {
 -        new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
 -                format);
 -      }
 -      else
 -      {
 -        new FileLoader().LoadFile(url, DataSourceType.URL, format);
 +            return;
 +          }
 +
 +          if (viewport != null)
 +          {
 +            new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
 +                    format);
 +          }
 +          else
 +          {
 +            new FileLoader().LoadFile(url, DataSourceType.URL, format);
 +          }
 +        }
        }
 -    }
 +    };
 +    String dialogOption = MessageManager
 +            .getString("label.input_alignment_from_url");
 +    JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action)
 +            .showInternalDialog(panel, dialogOption,
 +                    JvOptionPane.YES_NO_CANCEL_OPTION,
 +                    JvOptionPane.PLAIN_MESSAGE, null, options,
 +                    MessageManager.getString("action.ok"));
    }
  
    /**
    @Override
    public void quit()
    {
+     //System.out.println("********** Desktop.quit()");
+     //System.out.println(savingFiles.toString());
      Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
      jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
              screen.width + "");
    }
  
    /**
 -   * DOCUMENT ME!
 -   * 
 -   * @param e
 -   *          DOCUMENT ME!
 +   * Action on requesting Help documentation
     */
    @Override
 -  public void documentationMenuItem_actionPerformed(ActionEvent e)
 +  public void documentationMenuItem_actionPerformed()
    {
      try
      {
 -      Help.showHelpWindow();
 +      if (Platform.isJS())
 +      {
 +        BrowserLauncher.openURL("http://www.jalview.org/help.html");
 +      }
 +      else
 +      /**
 +       * Java only
 +       * 
 +       * @j2sIgnore
 +       */
 +      {
 +        Help.showHelpWindow();
 +      }
      } catch (Exception ex)
      {
 +      System.err.println("Error opening help: " + ex.getMessage());
      }
    }
  
     */
    void showConsole(boolean selected)
    {
 -    showConsole.setSelected(selected);
      // TODO: decide if we should update properties file
 -    Cache.setProperty("SHOW_JAVA_CONSOLE",
 -            Boolean.valueOf(selected).toString());
 -    jconsole.setVisible(selected);
 +    if (jconsole != null) // BH 2018
 +    {
 +      showConsole.setSelected(selected);
 +      Cache.setProperty("SHOW_JAVA_CONSOLE",
 +              Boolean.valueOf(selected).toString());
 +      jconsole.setVisible(selected);
 +    }
    }
  
    void reorderAssociatedWindows(boolean minimize, boolean close)
    }
  
    /**
 -   * Shows a file chooser dialog and writes out the current session as a Jalview
 -   * project file
 +   * Prompts the user to choose a file and then saves the Jalview state as a
 +   * Jalview project file
     */
    @Override
    public void saveState_actionPerformed()
            // TODO prevent user from messing with the Desktop whilst we're saving
            try
            {
 -            BackupFiles backupfiles = new BackupFiles(chosenFile);
 +              boolean doBackup = BackupFiles.getEnabled();
 +            BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile) : null;
  
 -            new Jalview2XML().saveState(backupfiles.getTempFile());
 +            new Jalview2XML().saveState(doBackup ? backupfiles.getTempFile() : chosenFile);
  
 -            backupfiles.setWriteSuccess(true);
 -            backupfiles.rollBackupsAndRenameTempFile();
 +            if (doBackup)
 +            {
 +              backupfiles.setWriteSuccess(true);
 +              backupfiles.rollBackupsAndRenameTempFile();
 +            }
            } catch (OutOfMemoryError oom)
            {
              new OOMWarning("Whilst saving current state to "
            setProgressBar(null, chosenFile.hashCode());
          }
        }).start();
 -    }
 +      }
    }
  
    @Override
                                              // allowBackupFiles
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
 -
 -    int value = chooser.showOpenDialog(this);
 -
 -    if (value == JalviewFileChooser.APPROVE_OPTION)
 +    chooser.setResponseHandler(0, new Runnable()
      {
 -      final File selectedFile = chooser.getSelectedFile();
 -      setProjectFile(selectedFile);
 -      final String choice = selectedFile.getAbsolutePath();
 -      Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
 -      new Thread(new Runnable()
 +      @Override
 +      public void run()
        {
 -        @Override
 -        public void run()
 +        File selectedFile = chooser.getSelectedFile();
 +        setProjectFile(selectedFile);
 +        String choice = selectedFile.getAbsolutePath();
 +        Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
 +        new Thread(new Runnable()
          {
 -          setProgressBar(MessageManager.formatMessage(
 -                  "label.loading_jalview_project", new Object[]
 -                  { choice }), choice.hashCode());
 -          try
 -          {
 -            new Jalview2XML().loadJalviewAlign(choice);
 -          } catch (OutOfMemoryError oom)
 -          {
 -            new OOMWarning("Whilst loading project from " + choice, oom);
 -          } catch (Exception ex)
 +          @Override
 +          public void run()
            {
 -            Cache.log.error(
 -                    "Problems whilst loading project from " + choice, ex);
 -            JvOptionPane.showMessageDialog(Desktop.desktop,
 -                    MessageManager.formatMessage(
 -                            "label.error_whilst_loading_project_from",
 -                            new Object[]
 -                            { choice }),
 -                    MessageManager.getString("label.couldnt_load_project"),
 -                    JvOptionPane.WARNING_MESSAGE);
 +              try 
 +            {
 +              new Jalview2XML().loadJalviewAlign(choice);
 +            } catch (OutOfMemoryError oom)
 +              {
 +                new OOMWarning("Whilst loading project from " + choice, oom);
 +              } catch (Exception ex)
 +              {
 +                Cache.log.error(
 +                        "Problems whilst loading project from " + choice, ex);
 +                JvOptionPane.showMessageDialog(Desktop.desktop,
 +                        MessageManager.formatMessage(
 +                                "label.error_whilst_loading_project_from",
 +                              new Object[]
 +                                  { choice }),
 +                        MessageManager.getString("label.couldnt_load_project"),
 +                        JvOptionPane.WARNING_MESSAGE);
 +              }
            }
 -          setProgressBar(null, choice.hashCode());
 -        }
 -      }).start();
 -    }
 +        }).start();
 +      }
 +    });
 +    
 +    chooser.showOpenDialog(this);
    }
  
    @Override
  
    ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
  
 -  public void startLoading(final String fileName)
 +  public void startLoading(final Object fileName)
    {
      if (fileLoadingCount == 0)
      {
  
    /**
     * Gather expanded views (separate AlignFrame's) with the same sequence set
 -   * identifier back in to this frame as additional views, and close the
 -   * expanded views. Note the expanded frames may themselves have multiple
 -   * views. We take the lot.
 +   * identifier back in to this frame as additional views, and close the expanded
 +   * views. Note the expanded frames may themselves have multiple views. We take
 +   * the lot.
     * 
     * @param source
     */
    @Override
    public void vamsasImport_actionPerformed(ActionEvent e)
    {
 +    // TODO: JAL-3048 not needed for Jalview-JS
 +
      if (v_client == null)
      {
        // Load and try to start a session.
                  });
                  rthr.start();
                }
--            };
++            }
            });
            VamsasStMenu.add(sessit);
          }
    @Override
    public void vamsasSave_actionPerformed(ActionEvent e)
    {
 +    // TODO: JAL-3048 not needed for Jalview-JS
 +
      if (v_client != null)
      {
        // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
            while (li.hasNext())
            {
              String link = li.next();
-             if (link.contains(SEQUENCE_ID)
+             if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
                      && !UrlConstants.isDefaultString(link))
              {
                check = true;
  
    /**
     * Proxy class for JDesktopPane which optionally displays the current memory
 -   * usage and highlights the desktop area with a red bar if free memory runs
 -   * low.
 +   * usage and highlights the desktop area with a red bar if free memory runs low.
     * 
     * @author AMW
     */
 -  public class MyDesktopPane extends JDesktopPane implements Runnable
 +  public class MyDesktopPane extends JDesktopPane
 +          implements Runnable
    {
 -
      private static final float ONE_MB = 1048576f;
  
      boolean showMemoryUsage = false;
    }
  
    /**
 -   * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
 -   * binding when opened
 +   * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
 +   * when opened
     */
    protected void addQuitHandler()
    {
      getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
              .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
-                     Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+                     jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
                      "Quit");
      getRootPane().getActionMap().put("Quit", new AbstractAction()
      {
    @Override
    public void setProgressBar(String message, long id)
    {
 +          Platform.timeCheck("Desktop " + message, Platform.TIME_MARK);     
 +
      if (progressBars == null)
      {
        progressBars = new Hashtable<>();
        progressBarHandlers = new Hashtable<>();
      }
  
-     if (progressBars.get(new Long(id)) != null)
+     if (progressBars.get(Long.valueOf(id)) != null)
      {
-       JPanel panel = progressBars.remove(new Long(id));
-       if (progressBarHandlers.contains(new Long(id)))
+       JPanel panel = progressBars.remove(Long.valueOf(id));
+       if (progressBarHandlers.contains(Long.valueOf(id)))
        {
-         progressBarHandlers.remove(new Long(id));
+         progressBarHandlers.remove(Long.valueOf(id));
        }
        removeProgressPanel(panel);
      }
      else
      {
-       progressBars.put(new Long(id), addProgressPanel(message));
+       progressBars.put(Long.valueOf(id), addProgressPanel(message));
      }
    }
  
            final IProgressIndicatorHandler handler)
    {
      if (progressBarHandlers == null
-             || !progressBars.containsKey(new Long(id)))
+             || !progressBars.containsKey(Long.valueOf(id)))
      {
        throw new Error(MessageManager.getString(
                "error.call_setprogressbar_before_registering_handler"));
      }
-     progressBarHandlers.put(new Long(id), handler);
-     final JPanel progressPanel = progressBars.get(new Long(id));
+     progressBarHandlers.put(Long.valueOf(id), handler);
+     final JPanel progressPanel = progressBars.get(Long.valueOf(id));
      if (handler.canCancel())
      {
        JButton cancel = new JButton(
    }
  
    /**
 -   * This will return the first AlignFrame holding the given viewport instance.
 -   * It will break if there are more than one AlignFrames viewing a particular
 -   * av.
 +   * This will return the first AlignFrame holding the given viewport instance. It
 +   * will break if there are more than one AlignFrames viewing a particular av.
     * 
     * @param viewport
     * @return alignFrame for viewport
            } catch (InterruptedException x)
            {
            }
--          ;
          }
          if (instance == null)
          {
      block.release();
    }
  
 +  /**
 +   * Outputs an image of the desktop to file in EPS format, after prompting the
 +   * user for choice of Text or Lineart character rendering (unless a preference
 +   * has been set). The file name is generated as
 +   * 
 +   * <pre>
 +   * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
 +   * </pre>
 +   */
    @Override
    protected void snapShotWindow_actionPerformed(ActionEvent e)
    {
 +    // currently the menu option to do this is not shown
      invalidate();
 -    File of;
 -    ImageMaker im = new jalview.util.ImageMaker(
 -            this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
 -            getHeight(), of = new File("Jalview_snapshot"
 -                    + System.currentTimeMillis() + ".eps"),
 -            "View of desktop", null, 0, false);
 -    try
 -    {
 -      paintAll(im.getGraphics());
 -      im.writeImage();
 -    } catch (Exception q)
 +
 +    int width = getWidth();
 +    int height = getHeight();
 +    File of = new File(
 +            "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
 +    ImageWriterI writer = new ImageWriterI()
      {
 -      Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
 -              q);
 -      return;
 -    }
 -    Cache.log.info("Successfully written snapshot to file "
 -            + of.getAbsolutePath());
 +      @Override
 +      public void exportImage(Graphics g) throws Exception
 +      {
 +        paintAll(g);
 +        Cache.log.info("Successfully written snapshot to file "
 +                + of.getAbsolutePath());
 +      }
 +    };
 +    String title = "View of desktop";
 +    ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
 +            title);
 +    exporter.doExport(of, this, width, height, title);
    }
  
    /**
     * Explode the views in the given SplitFrame into separate SplitFrame windows.
 -   * This respects (remembers) any previous 'exploded geometry' i.e. the size
 -   * and location last time the view was expanded (if any). However it does not
 +   * This respects (remembers) any previous 'exploded geometry' i.e. the size and
 +   * location last time the view was expanded (if any). However it does not
     * remember the split pane divider location - this is set to match the
     * 'exploding' frame.
     * 
     *          - the payload from the drop event
     * @throws Exception
     */
 -  public static void transferFromDropTarget(List<String> files,
 +  public static void transferFromDropTarget(List<Object> files,
            List<DataSourceType> protocols, DropTargetDropEvent evt,
            Transferable t) throws Exception
    {
  
 +    // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
 +
 +    // DataFlavor[] flavors = t.getTransferDataFlavors();
 +    // for (int i = 0; i < flavors.length; i++) {
 +    // if (flavors[i].isFlavorJavaFileListType()) {
 +    // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
 +    // List<File> list = (List<File>) t.getTransferData(flavors[i]);
 +    // for (int j = 0; j < list.size(); j++) {
 +    // File file = (File) list.get(j);
 +    // byte[] data = getDroppedFileBytes(file);
 +    // fileName.setText(file.getName() + " - " + data.length + " " +
 +    // evt.getLocation());
 +    // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
 +    // target.setText(new String(data));
 +    // }
 +    // dtde.dropComplete(true);
 +    // return;
 +    // }
 +    //
 +
      DataFlavor uriListFlavor = new DataFlavor(
              "text/uri-list;class=java.lang.String"), urlFlavour = null;
      try
          }
          else
          {
 -          if (Platform.isAMac())
 +          if (Platform.isAMacAndNotJS())
            {
              System.err.println(
                      "Please ignore plist error - occurs due to problem with java 8 on OSX");
            }
--          ;
          }
        } catch (Throwable ex)
        {
        for (Object file : (List) t
                .getTransferData(DataFlavor.javaFileListFlavor))
        {
 -        files.add(((File) file).toString());
 +        files.add(file);
          protocols.add(DataSourceType.FILE);
        }
      }
          }
        }
      }
 -    if (Platform.isWindows())
 -
 +    if (Platform.isWindowsAndNotJS())
      {
        Cache.log.debug("Scanning dropped content for Windows Link Files");
  
        // resolve any .lnk files in the file drop
        for (int f = 0; f < files.size(); f++)
        {
 -        String source = files.get(f).toLowerCase();
 +        String source = files.get(f).toString().toLowerCase();
          if (protocols.get(f).equals(DataSourceType.FILE)
                  && (source.endsWith(".lnk") || source.endsWith(".url")
                          || source.endsWith(".site")))
          {
            try
            {
 -            File lf = new File(files.get(f));
 +            Object obj = files.get(f);
 +            File lf = (obj instanceof File ? (File) obj
 +                    : new File((String) obj));
              // process link file to get a URL
              Cache.log.debug("Found potential link file: " + lf);
              WindowsShortcut wscfile = new WindowsShortcut(lf);
    }
  
    /**
 -   * Answers a (possibly empty) list of any structure viewer frames (currently
 -   * for either Jmol or Chimera) which are currently open. This may optionally
 -   * be restricted to viewers of a specified class, or viewers linked to a
 -   * specified alignment panel.
 +   * Answers a (possibly empty) list of any structure viewer frames (currently for
 +   * either Jmol or Chimera) which are currently open. This may optionally be
 +   * restricted to viewers of a specified class, or viewers linked to a specified
 +   * alignment panel.
     * 
     * @param apanel
     *          if not null, only return viewers linked to this panel
@@@ -29,7 -29,6 +29,7 @@@ import jalview.datamodel.features.Featu
  import jalview.datamodel.features.FeatureMatcherSet;
  import jalview.datamodel.features.FeatureMatcherSetI;
  import jalview.gui.Help.HelpId;
 +import jalview.gui.JalviewColourChooser.ColourChooserListener;
  import jalview.io.JalviewFileChooser;
  import jalview.io.JalviewFileView;
  import jalview.schemes.FeatureColour;
@@@ -81,7 -80,8 +81,7 @@@ import javax.swing.BorderFactory
  import javax.swing.Icon;
  import javax.swing.JButton;
  import javax.swing.JCheckBox;
 -import javax.swing.JColorChooser;
 -import javax.swing.JDialog;
 +import javax.swing.JCheckBoxMenuItem;
  import javax.swing.JInternalFrame;
  import javax.swing.JLabel;
  import javax.swing.JLayeredPane;
@@@ -93,7 -93,6 +93,7 @@@ import javax.swing.JSlider
  import javax.swing.JTable;
  import javax.swing.ListSelectionModel;
  import javax.swing.SwingConstants;
 +import javax.swing.ToolTipManager;
  import javax.swing.border.Border;
  import javax.swing.event.ChangeEvent;
  import javax.swing.event.ChangeListener;
@@@ -131,8 -130,7 +131,8 @@@ public class FeatureSettings extends JP
  
    private static final int MIN_HEIGHT = 400;
  
 -  private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit");
 +  private final static String BASE_TOOLTIP = MessageManager
 +          .getString("label.click_to_edit");
  
    final FeatureRenderer fr;
  
     */
    Object[][] originalData;
  
 -  private float originalTransparency;
 +  float originalTransparency;
  
 -  private Map<String, FeatureMatcherSetI> originalFilters;
 +  Map<String, FeatureMatcherSetI> originalFilters;
  
    final JInternalFrame frame;
  
    /*
     * true when Feature Settings are updating from feature renderer
     */
 -  private boolean handlingUpdate = false;
 +  boolean handlingUpdate = false;
  
    /*
     * holds {featureCount, totalExtent} for each feature type
          default:
            break;
          }
 -        
 +
          return tip;
        }
  
      tableHeader.setFont(new Font("Verdana", Font.PLAIN, 12));
      tableHeader.setReorderingAllowed(false);
      table.setFont(new Font("Verdana", Font.PLAIN, 12));
 -
 -    table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
 +    ToolTipManager.sharedInstance().registerComponent(table);
 +    table.setDefaultEditor(FeatureColour.class, new ColorEditor());
      table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
  
 -    table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
 +    table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor());
      table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
  
      TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
 -            new ColorRenderer(), new ColorEditor(this));
 +            new ColorRenderer(), new ColorEditor());
      table.addColumn(colourColumn);
  
      TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
 -            new FilterRenderer(), new FilterEditor(this));
 +            new FilterRenderer(), new FilterEditor());
      table.addColumn(filterColumn);
  
      table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
          if (evt.isPopupTrigger())
          {
            Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
 -          popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
 -                  evt.getY());
 +          showPopupMenu(selectedRow, type, colour, evt.getPoint());
          }
          else if (evt.getClickCount() == 2)
          {
          {
            String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
            Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
 -          popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
 -                  evt.getY());
 +          showPopupMenu(selectedRow, type, colour, evt.getPoint());
          }
        }
      });
  
      frame = new JInternalFrame();
      frame.setContentPane(this);
 -    if (Platform.isAMac())
 -    {
 -      Desktop.addInternalFrame(frame,
 -              MessageManager.getString("label.sequence_feature_settings"),
 -              600, 480);
 -    }
 -    else
 -    {
 -      Desktop.addInternalFrame(frame,
 -              MessageManager.getString("label.sequence_feature_settings"),
 -              600, 450);
 -    }
 +    Desktop.addInternalFrame(frame,
 +            MessageManager.getString("label.sequence_feature_settings"),
 +            600, Platform.isAMacAndNotJS() ? 480 : 450);
      frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
  
      frame.addInternalFrameListener(
      inConstruction = false;
    }
  
 -  protected void popupSort(final int rowSelected, final String type,
 -          final Object typeCol, final Map<String, float[][]> minmax, int x,
 -          int y)
 +  /**
 +   * Constructs and shows a popup menu of possible actions on the selected row
 +   * and feature type
 +   * 
 +   * @param rowSelected
 +   * @param type
 +   * @param typeCol
 +   * @param pt
 +   */
 +  protected void showPopupMenu(final int rowSelected, final String type,
 +          final Object typeCol, final Point pt)
    {
      JPopupMenu men = new JPopupMenu(MessageManager
              .formatMessage("label.settings_for_param", new String[]
              { type }));
 +    final FeatureColourI featureColour = (FeatureColourI) typeCol;
 +
 +    /*
 +     * menu option to select (or deselect) variable colour
 +     */
 +    final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
 +            MessageManager.getString("label.variable_colour"));
 +    variableColourCB.setSelected(!featureColour.isSimpleColour());
 +    men.add(variableColourCB);
 +
 +    /*
 +     * checkbox action listener doubles up as listener to OK
 +     * from the variable colour / filters dialog
 +     */
 +    variableColourCB.addActionListener(new ActionListener()
 +    {
 +      @Override
 +      public void actionPerformed(ActionEvent e)
 +      {
 +        if (e.getSource() == variableColourCB)
 +        {
 +          men.setVisible(true); // BH 2018 for JavaScript because this is a
 +                                // checkbox
 +          men.setVisible(false); // BH 2018 for JavaScript because this is a
 +                                 // checkbox
 +          if (featureColour.isSimpleColour())
 +          {
 +            /*
 +             * toggle simple colour to variable colour - show dialog
 +             */
 +            FeatureTypeSettings fc = new FeatureTypeSettings(fr, type);
 +            fc.addActionListener(this);
 +          }
 +          else
 +          {
 +            /*
 +             * toggle variable to simple colour - show colour chooser
 +             */
 +            String title = MessageManager
 +                    .formatMessage("label.select_colour_for", type);
 +            ColourChooserListener listener = new ColourChooserListener()
 +            {
 +              @Override
 +              public void colourSelected(Color c)
 +              {
 +                table.setValueAt(new FeatureColour(c), rowSelected,
 +                        COLOUR_COLUMN);
 +                table.validate();
 +                updateFeatureRenderer(
 +                        ((FeatureTableModel) table.getModel()).getData(),
 +                        false);
 +              }
 +            };
 +            JalviewColourChooser.showColourChooser(FeatureSettings.this,
 +                    title, featureColour.getMaxColour(), listener);
 +          }
 +        }
 +        else
 +        {
 +          if (e.getSource() instanceof FeatureTypeSettings)
 +          {
 +            /*
 +             * update after OK in feature colour dialog; the updated
 +             * colour will have already been set in the FeatureRenderer
 +             */
 +            FeatureColourI fci = fr.getFeatureColours().get(type);
 +            table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
 +            // BH 2018 setting a table value does not invalidate it.
 +            // System.out.println("FeatureSettings is valied" +
 +            // table.validate();
 +          }
 +        }
 +      }
 +    });
 +
 +    men.addSeparator();
 +
      JMenuItem scr = new JMenuItem(
              MessageManager.getString("label.sort_by_score"));
      men.add(scr);
 -    final FeatureSettings me = this;
      scr.addActionListener(new ActionListener()
      {
  
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        me.af.avc
 -                .sortAlignmentByFeatureScore(Arrays.asList(new String[]
 +        af.avc.sortAlignmentByFeatureScore(Arrays.asList(new String[]
                  { type }));
        }
 -
      });
      JMenuItem dens = new JMenuItem(
              MessageManager.getString("label.sort_by_density"));
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        me.af.avc
 -                .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
 +        af.avc.sortAlignmentByFeatureDensity(Arrays.asList(new String[]
                  { type }));
        }
 -
      });
      men.add(dens);
  
      men.add(clearCols);
      men.add(hideCols);
      men.add(hideOtherCols);
 -    men.show(table, x, y);
 +    men.show(table, pt.x, pt.y);
    }
  
    @Override
          data[dataIndex][FILTER_COLUMN] = featureFilter == null
                  ? new FeatureMatcherSet()
                  : featureFilter;
-         data[dataIndex][SHOW_COLUMN] = new Boolean(
+         data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(
                  af.getViewport().getFeaturesDisplayed().isVisible(type));
          dataIndex++;
          displayableTypes.remove(type);
        data[dataIndex][FILTER_COLUMN] = featureFilter == null
                ? new FeatureMatcherSet()
                : featureFilter;
-       data[dataIndex][SHOW_COLUMN] = new Boolean(true);
+       data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(true);
        dataIndex++;
        displayableTypes.remove(type);
      }
    }
  
    /**
 -   * Updates 'originalData' (used for restore on Cancel) if we detect that changes
 -   * have been made outwith this dialog
 +   * Updates 'originalData' (used for restore on Cancel) if we detect that
 +   * changes have been made outwith this dialog
     * <ul>
     * <li>a new feature type added (and made visible)</li>
     * <li>a feature colour changed (in the Amend Features dialog)</li>
  
    /**
     * Remove from the groups panel any checkboxes for groups that are not in the
 -   * foundGroups set. This enables removing a group from the display when the last
 -   * feature in that group is deleted.
 +   * foundGroups set. This enables removing a group from the display when the
 +   * last feature in that group is deleted.
     * 
     * @param foundGroups
     */
      chooser.setDialogTitle(
              MessageManager.getString("label.load_feature_colours"));
      chooser.setToolTipText(MessageManager.getString("action.load"));
 -
 -    int value = chooser.showOpenDialog(this);
 -
 -    if (value == JalviewFileChooser.APPROVE_OPTION)
 +    chooser.setResponseHandler(0, new Runnable()
      {
 -      File file = chooser.getSelectedFile();
 -      load(file);
 -    }
 +      @Override
 +      public void run()
 +      {
 +        File file = chooser.getSelectedFile();
 +        load(file);
 +      }
 +    });
 +    chooser.showOpenDialog(this);
    }
  
    /**
        if (table != null)
        {
          resetTable(null);
 -        Object[][] data = ((FeatureTableModel) table.getModel())
 -                .getData();
 +        Object[][] data = ((FeatureTableModel) table.getModel()).getData();
          ensureOrder(data);
          updateFeatureRenderer(data, false);
          table.repaint();
      chooser.setDialogTitle(
              MessageManager.getString("label.save_feature_colours"));
      chooser.setToolTipText(MessageManager.getString("action.save"));
 -
 -    int value = chooser.showSaveDialog(this);
 -
 -    if (value == JalviewFileChooser.APPROVE_OPTION)
 +    int option = chooser.showSaveDialog(this);
 +    if (option == JalviewFileChooser.APPROVE_OPTION)
      {
 -      save(chooser.getSelectedFile());
 +      File file = chooser.getSelectedFile();
 +      save(file);
      }
    }
  
      ucs.setSchemeName("Sequence Features");
      try
      {
 -      PrintWriter out = new PrintWriter(new OutputStreamWriter(
 -              new FileOutputStream(file), "UTF-8"));
 +      PrintWriter out = new PrintWriter(
 +              new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
  
        /*
         * sort feature types by colour order, from 0 (highest)
          FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
          if (filter != null && !filter.isEmpty())
          {
 -          Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
 +          Iterator<FeatureMatcherI> iterator = filter.getMatchers()
 +                  .iterator();
            FeatureMatcherI firstMatcher = iterator.next();
            jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
 -                  .marshalFilter(firstMatcher, iterator,
 -                  filter.isAnded());
 +                  .marshalFilter(firstMatcher, iterator, filter.isAnded());
            Filter filterModel = new Filter();
            filterModel.setFeatureType(featureType);
            filterModel.setMatcherSet(ms);
        else
        {
          width[i] /= max; // normalize
 -        fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
 +        fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for
 +                                                                // later
        }
        if (i > 0)
        {
    }
  
    /**
 -   * Update the priority order of features; only repaint if this changed the order
 -   * of visible features
 +   * Update the priority order of features; only repaint if this changed the
 +   * order of visible features
     * 
     * @param data
     * @param visibleNew
     */
 -  private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
 +  void updateFeatureRenderer(Object[][] data, boolean visibleNew)
    {
      FeatureSettingsBean[] rowData = getTableAsBeans(data);
  
    {
      boolean thr = false;
      StringBuilder tx = new StringBuilder();
 -  
 +
      if (gcol.isColourByAttribute())
      {
        tx.append(FeatureMatcher
      renderGraduatedColor(comp, gcol, w, h);
    }
  
 +  @SuppressWarnings("serial")
    class ColorEditor extends AbstractCellEditor
            implements TableCellEditor, ActionListener
    {
 -    FeatureSettings me;
 -
      FeatureColourI currentColor;
  
      FeatureTypeSettings chooser;
  
      JButton button;
  
 -    JColorChooser colorChooser;
 -
 -    JDialog dialog;
 -
      protected static final String EDIT = "edit";
  
      int rowSelected = 0;
  
 -    public ColorEditor(FeatureSettings me)
 +    public ColorEditor()
      {
 -      this.me = me;
        // Set up the editor (from the table's point of view),
        // which is a button.
        // This button brings up the color chooser dialog,
        button.setActionCommand(EDIT);
        button.addActionListener(this);
        button.setBorderPainted(false);
      }
  
      /**
 -     * Handles events from the editor button and from the dialog's OK button.
 +     * Handles events from the editor button, and from the colour/filters
 +     * dialog's OK button
       */
      @Override
      public void actionPerformed(ActionEvent e)
      {
 -      // todo test e.getSource() instead here
 -      if (EDIT.equals(e.getActionCommand()))
 +      if (button == e.getSource())
        {
 -        // The user has clicked the cell, so
 -        // bring up the dialog.
          if (currentColor.isSimpleColour())
          {
 -          // bring up simple color chooser
 -          button.setBackground(currentColor.getColour());
 -          colorChooser.setColor(currentColor.getColour());
 -          dialog.setVisible(true);
 +          /*
 +           * simple colour chooser
 +           */
 +          String ttl = MessageManager
 +                  .formatMessage("label.select_colour_for", type);
 +          ColourChooserListener listener = new ColourChooserListener()
 +          {
 +            @Override
 +            public void colourSelected(Color c)
 +            {
 +              currentColor = new FeatureColour(c);
 +              table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
 +              fireEditingStopped();
 +            }
 +
 +            @Override
 +            public void cancel()
 +            {
 +              fireEditingStopped();
 +            }
 +          };
 +          JalviewColourChooser.showColourChooser(button, ttl,
 +                  currentColor.getColour(), listener);
          }
          else
          {
 -          // bring up graduated chooser.
 -          chooser = new FeatureTypeSettings(me.fr, type);
 +          /*
 +           * variable colour and filters dialog
 +           */
 +          chooser = new FeatureTypeSettings(fr, type);
 +          if (!Platform.isJS())
            /**
 -           * @j2sNative
 +           * Java only
 +           * 
 +           * @j2sIgnore
             */
            {
              chooser.setRequestFocusEnabled(true);
              chooser.requestFocus();
            }
            chooser.addActionListener(this);
 -          // Make the renderer reappear.
            fireEditingStopped();
          }
        }
        else
        {
 -        if (currentColor.isSimpleColour())
 -        {
 -          /*
 -           * read off colour picked in colour chooser after OK pressed
 -           */
 -          currentColor = new FeatureColour(colorChooser.getColor());
 -          me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
 -        }
 -        else
 +        /*
 +         * after OK in variable colour dialog, any changes to colour 
 +         * (or filters!) are already set in FeatureRenderer, so just
 +         * update table data without triggering updateFeatureRenderer
 +         */
 +        currentColor = fr.getFeatureColours().get(type);
 +        FeatureMatcherSetI currentFilter = fr.getFeatureFilter(type);
 +        if (currentFilter == null)
          {
 -          /*
 -           * after OK in variable colour dialog, any changes to colour 
 -           * (or filters!) are already set in FeatureRenderer, so just
 -           * update table data without triggering updateFeatureRenderer
 -           */
 -          currentColor = fr.getFeatureColours().get(type);
 -          FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
 -          if (currentFilter == null)
 -          {
 -            currentFilter = new FeatureMatcherSet();
 -          }
 -          Object[] data = ((FeatureTableModel) table.getModel())
 -                  .getData()[rowSelected];
 -          data[COLOUR_COLUMN] = currentColor;
 -          data[FILTER_COLUMN] = currentFilter;
 +          currentFilter = new FeatureMatcherSet();
          }
 +        Object[] data = ((FeatureTableModel) table.getModel())
 +                .getData()[rowSelected];
 +        data[COLOUR_COLUMN] = currentColor;
 +        data[FILTER_COLUMN] = currentFilter;
          fireEditingStopped();
 -        me.table.validate();
 +        // SwingJS needs an explicit repaint() here,
 +        // rather than relying upon no validation having
 +        // occurred since the stopEditing call was made.
 +        // Its laying out has not been stopped by the modal frame
 +        table.validate();
 +        table.repaint();
        }
      }
  
 +    /**
 +     * Override allows access to this method from anonymous inner classes
 +     */
 +    @Override
 +    protected void fireEditingStopped()
 +    {
 +      super.fireEditingStopped();
 +    }
 +
      // Implement the one CellEditor method that AbstractCellEditor doesn't.
      @Override
      public Object getCellEditorValue()
  
      // Implement the one method defined by TableCellEditor.
      @Override
 -    public Component getTableCellEditorComponent(JTable theTable, Object value,
 -            boolean isSelected, int row, int column)
 +    public Component getTableCellEditorComponent(JTable theTable,
 +            Object value, boolean isSelected, int row, int column)
      {
        currentColor = (FeatureColourI) value;
        this.rowSelected = row;
 -      type = me.table.getValueAt(row, TYPE_COLUMN).toString();
 +      type = table.getValueAt(row, TYPE_COLUMN).toString();
        button.setOpaque(true);
 -      button.setBackground(me.getBackground());
 +      button.setBackground(FeatureSettings.this.getBackground());
        if (!currentColor.isSimpleColour())
        {
          JLabel btn = new JLabel();
  
    /**
     * The cell editor for the Filter column. It displays the text of any filters
 -   * for the feature type in that row (in full as a tooltip, possible abbreviated
 -   * as display text). On click in the cell, opens the Feature Display Settings
 -   * dialog at the Filters tab.
 +   * for the feature type in that row (in full as a tooltip, possible
 +   * abbreviated as display text). On click in the cell, opens the Feature
 +   * Display Settings dialog at the Filters tab.
     */
 +  @SuppressWarnings("serial")
    class FilterEditor extends AbstractCellEditor
            implements TableCellEditor, ActionListener
    {
 -    FeatureSettings me;
  
      FeatureMatcherSetI currentFilter;
  
  
      int rowSelected = 0;
  
 -    public FilterEditor(FeatureSettings me)
 +    public FilterEditor()
      {
 -      this.me = me;
        button = new JButton();
        button.setActionCommand(EDIT);
        button.addActionListener(this);
      {
        if (button == e.getSource())
        {
 -        FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
 +        FeatureTypeSettings chooser = new FeatureTypeSettings(fr, type);
          chooser.addActionListener(this);
          chooser.setRequestFocusEnabled(true);
          chooser.requestFocus();
           * update table data without triggering updateFeatureRenderer
           */
          FeatureColourI currentColor = fr.getFeatureColours().get(type);
 -        currentFilter = me.fr.getFeatureFilter(type);
 +        currentFilter = fr.getFeatureFilter(type);
          if (currentFilter == null)
          {
            currentFilter = new FeatureMatcherSet();
          }
 +
          Object[] data = ((FeatureTableModel) table.getModel())
                  .getData()[rowSelected];
          data[COLOUR_COLUMN] = currentColor;
          data[FILTER_COLUMN] = currentFilter;
          fireEditingStopped();
 -        me.table.validate();
 +        // SwingJS needs an explicit repaint() here,
 +        // rather than relying upon no validation having
 +        // occurred since the stopEditing call was made.
 +        // Its laying out has not been stopped by the modal frame
 +        table.validate();
 +        table.repaint();
        }
      }
  
      }
  
      @Override
 -    public Component getTableCellEditorComponent(JTable theTable, Object value,
 -            boolean isSelected, int row, int column)
 +    public Component getTableCellEditorComponent(JTable theTable,
 +            Object value, boolean isSelected, int row, int column)
      {
        currentFilter = (FeatureMatcherSetI) value;
        this.rowSelected = row;
 -      type = me.table.getValueAt(row, TYPE_COLUMN).toString();
 +      type = table.getValueAt(row, TYPE_COLUMN).toString();
        button.setOpaque(true);
 -      button.setBackground(me.getBackground());
 +      button.setBackground(FeatureSettings.this.getBackground());
        button.setText(currentFilter.toString());
        button.setIcon(null);
        return button;
@@@ -1984,8 -1897,7 +1984,8 @@@ class FeatureIcon implements Ico
          g.fillRect(s1, 0, e1 - s1, height);
        }
        g.setColor(gcol.getMaxColour());
 -      g.fillRect(0, e1, width - e1, height);
 +      // g.fillRect(0, e1, width - e1, height); // BH 2018
 +      g.fillRect(e1, 0, width - e1, height);
      }
    }
  }
@@@ -29,7 -29,6 +29,7 @@@ import jalview.datamodel.features.Featu
  import jalview.datamodel.features.FeatureMatcherI;
  import jalview.datamodel.features.FeatureMatcherSet;
  import jalview.datamodel.features.FeatureMatcherSetI;
 +import jalview.gui.JalviewColourChooser.ColourChooserListener;
  import jalview.schemes.FeatureColour;
  import jalview.util.ColorUtils;
  import jalview.util.MessageManager;
@@@ -57,6 -56,7 +57,6 @@@ import javax.swing.BoxLayout
  import javax.swing.ButtonGroup;
  import javax.swing.JButton;
  import javax.swing.JCheckBox;
 -import javax.swing.JColorChooser;
  import javax.swing.JComboBox;
  import javax.swing.JLabel;
  import javax.swing.JPanel;
@@@ -111,9 -111,9 +111,9 @@@ public class FeatureTypeSettings extend
    /*
     * the view panel to update when settings change
     */
 -  private final AlignmentViewPanel ap;
 +  final AlignmentViewPanel ap;
  
 -  private final String featureType;
 +  final String featureType;
  
    /*
     * the colour and filters to reset to on Cancel
     * set flag to true when setting values programmatically,
     * to avoid invocation of action handlers
     */
 -  private boolean adjusting = false;
 +  boolean adjusting = false;
  
    /*
     * minimum of the value range for graduated colour
    /*
     * scale factor for conversion between absolute min-max and slider
     */
 -  private float scaleFactor;
 +  float scaleFactor;
  
    /*
     * radio button group, to select what to colour by:
     * simple colour, by category (text), or graduated
     */
 -  private JRadioButton simpleColour = new JRadioButton();
 +  JRadioButton simpleColour = new JRadioButton();
  
 -  private JRadioButton byCategory = new JRadioButton();
 +  JRadioButton byCategory = new JRadioButton();
  
 -  private JRadioButton graduatedColour = new JRadioButton();
 +  JRadioButton graduatedColour = new JRadioButton();
  
 -  /**
 -   * colours and filters are shown in tabbed view or single content pane
 -   */
 -  JPanel coloursPanel, filtersPanel;
 +  JPanel coloursPanel;
 +  
 +  JPanel filtersPanel;
  
    JPanel singleColour = new JPanel();
  
 -  private JPanel minColour = new JPanel();
 +  JPanel minColour = new JPanel();
  
 -  private JPanel maxColour = new JPanel();
 +  JPanel maxColour = new JPanel();
  
    private JComboBox<String> threshold = new JComboBox<>();
  
 -  private JSlider slider = new JSlider();
 +  JSlider slider = new JSlider();
  
 -  private JTextField thresholdValue = new JTextField(20);
 +  JTextField thresholdValue = new JTextField(20);
  
    private JCheckBox thresholdIsMin = new JCheckBox();
  
    /*
     * filters for the currently selected feature type
     */
 -  private List<FeatureMatcherI> filters;
 +  List<FeatureMatcherI> filters;
  
    private JPanel chooseFiltersPanel;
  
        return;
      }
      
 -    updateColoursTab();
 +    updateColoursPanel();
      
 -    updateFiltersTab();
 +    updateFiltersPanel();
      
      adjusting = false;
      
    }
  
    /**
 -   * Configures the widgets on the Colours tab according to the current feature
 +   * Configures the widgets on the Colours panel according to the current feature
     * colour scheme
     */
 -  private void updateColoursTab()
 +  private void updateColoursPanel()
    {
      FeatureColourI fc = fr.getFeatureColours().get(featureType);
  
      };
  
      /*
 -     * first panel/tab: colour options
 +     * first panel: colour options
       */
      JPanel coloursPanel = initialiseColoursPanel();
      this.add(coloursPanel, BorderLayout.NORTH);
  
      /*
 -     * second panel/tab: filter options
 +     * second panel: filter options
       */
      JPanel filtersPanel = initialiseFiltersPanel();
      this.add(filtersPanel, BorderLayout.CENTER);
      graduatedColour = new JRadioButton(
              MessageManager.getString("label.by_range_of") + COLON);
      graduatedColour.setPreferredSize(new Dimension(RADIO_WIDTH, 20));
 +    graduatedColour.setOpaque(false);
      graduatedColour.addItemListener(new ItemListener()
      {
        @Override
        {
          if (minColour.isEnabled())
          {
 -          showColourChooser(minColour, "label.select_colour_minimum_value");
 +          String ttl = MessageManager.getString("label.select_colour_minimum_value");
 +          showColourChooser(minColour, ttl);
          }
        }
      });
        {
          if (maxColour.isEnabled())
          {
 -          showColourChooser(maxColour, "label.select_colour_maximum_value");
 +          String ttl = MessageManager.getString("label.select_colour_maximum_value");
 +          showColourChooser(maxColour, ttl);
          }
        }
      });
      simpleColour = new JRadioButton(
              MessageManager.getString("label.simple_colour"));
      simpleColour.setPreferredSize(new Dimension(RADIO_WIDTH, 20));
 +    simpleColour.setOpaque(false);
      simpleColour.addItemListener(new ItemListener()
      {
        @Override
        {
          if (simpleColour.isSelected())
          {
 -          showColourChooser(singleColour, "label.select_colour");
 +          String ttl = MessageManager.formatMessage("label.select_colour_for",  featureType);
 +          showColourChooser(singleColour, ttl);
          }
        }
      });
      byCategory = new JRadioButton(
              MessageManager.getString("label.by_text_of") + COLON);
      byCategory.setPreferredSize(new Dimension(RADIO_WIDTH, 20));
 +    byCategory.setOpaque(false);
      byCategory.addItemListener(new ItemListener()
      {
        @Override
      return colourByPanel;
    }
  
 -  private void showColourChooser(JPanel colourPanel, String key)
 +  /**
 +   * Shows a colour chooser dialog, and if a selection is made, updates the
 +   * colour of the given panel
 +   * 
 +   * @param colourPanel
 +   *          the panel whose background colour is being picked
 +   * @param title
 +   */
 +  void showColourChooser(JPanel colourPanel, String title)
    {
 -    Color col = JColorChooser.showDialog(this,
 -            MessageManager.getString(key), colourPanel.getBackground());
 -    if (col != null)
 +    ColourChooserListener listener = new ColourChooserListener()
      {
 -      colourPanel.setBackground(col);
 -      colourPanel.setForeground(col);
 -    }
 -    colourPanel.repaint();
 -    colourChanged(true);
 +      @Override
 +      public void colourSelected(Color col)
 +      {
 +        colourPanel.setBackground(col);
 +        colourPanel.setForeground(col);
 +        colourPanel.repaint();
 +        colourChanged(true);
 +      }
 +    };
 +      JalviewColourChooser.showColourChooser(this, title, 
 +        colourPanel.getBackground(), listener);
    }
  
    /**
      fr.setColour(featureType, acg);
      ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview);
  
 -    updateColoursTab();
 +    updateColoursPanel();
    }
  
    /**
      }
      float minValue = min;
      float maxValue = max;
 -    final int thresholdOption = threshold.getSelectedIndex();
 +    int thresholdOption = threshold.getSelectedIndex();
      if (thresholdIsMin.isSelected()
              && thresholdOption == ABOVE_THRESHOLD_OPTION)
      {
      andOrPanel.setBackground(Color.white);
      andFilters = new JRadioButton(MessageManager.getString("label.and"));
      orFilters = new JRadioButton(MessageManager.getString("label.or"));
 +    andFilters.setOpaque(false);
 +    orFilters.setOpaque(false);
      ActionListener actionListener = new ActionListener()
      {
        @Override
     * for adding a condition. This should be called after a filter has been
     * removed, added or amended.
     */
 -  private void updateFiltersTab()
 +  private void updateFiltersPanel()
    {
      /*
       * clear the panel and list of filter conditions
        {
          orFilters.setSelected(true);
        }
 -      featureFilters.getMatchers().forEach(matcher -> filters.add(matcher));
 +      // avoid use of lambda expression to keep SwingJS happy
 +      // featureFilters.getMatchers().forEach(item -> filters.add(item));
 +      for (FeatureMatcherI matcher : featureFilters.getMatchers())
 +      {
 +        filters.add(matcher);
 +      }
      }
  
      /*
       * drop-down choice of attribute, with description as a tooltip 
       * if we can obtain it
       */
 -    final JComboBox<String> attCombo = populateAttributesDropdown(attNames,
 -            true, true);
 +    JComboBox<String> attCombo = populateAttributesDropdown(attNames, true,
 +            true);
      String filterBy = setSelectedAttribute(attCombo, filter);
  
      JComboBox<Condition> condCombo = new JComboBox<>();
              || (pattern != null && pattern.trim().length() > 0))
      {
        JButton removeCondition = new JButton("\u2717"); // Dingbats cursive x
 +      removeCondition.setBorder(new EmptyBorder(0, 0, 0, 0));
 +      removeCondition.setBackground(Color.WHITE);
 +      removeCondition.setPreferredSize(new Dimension(23, 17));
-       removeCondition
-               .setToolTipText(MessageManager.getString("label.delete_row"));
+       removeCondition.setToolTipText(
+               MessageManager.getString("label.delete_condition"));
+       removeCondition.setBorder(new EmptyBorder(0, 0, 0, 0));
        removeCondition.addActionListener(new ActionListener()
        {
          @Override
     * @param condCombo
     * @param patternField
     */
 -  private void populateConditions(String attName, Condition cond,
 +  void populateConditions(String attName, Condition cond,
            JComboBox<Condition> condCombo, JTextField patternField)
    {
      Datatype type = FeatureAttributes.getInstance().getDatatype(featureType,
      fr.setFeatureFilter(featureType, combined.isEmpty() ? null : combined);
      ap.paintAlignment(true, true);
  
 -    updateFiltersTab();
 +    updateFiltersPanel();
    }
  }
@@@ -30,8 -30,6 +30,8 @@@ import jalview.datamodel.AlignmentI
  import jalview.datamodel.AlignmentView;
  import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.SequenceI;
 +import jalview.gui.ImageExporter.ImageWriterI;
 +import jalview.gui.JalviewColourChooser.ColourChooserListener;
  import jalview.jbgui.GPCAPanel;
  import jalview.math.RotatableMatrix.Axis;
  import jalview.util.ImageMaker;
@@@ -51,6 -49,7 +51,6 @@@ import java.awt.print.PrinterException
  import java.awt.print.PrinterJob;
  
  import javax.swing.ButtonGroup;
 -import javax.swing.JColorChooser;
  import javax.swing.JMenuItem;
  import javax.swing.JRadioButtonMenuItem;
  import javax.swing.event.InternalFrameAdapter;
@@@ -131,6 -130,8 +131,6 @@@ public class PCAPanel extends GPCAPane
  
      addKeyListener(getRotatableCanvas());
      validate();
 -
 -    this.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
    }
  
    /**
    @Override
    protected void bgcolour_actionPerformed()
    {
 -    Color col = JColorChooser.showDialog(this,
 -            MessageManager.getString("label.select_background_colour"),
 -            getRotatableCanvas().getBgColour());
 -
 -    if (col != null)
 +    String ttl = MessageManager.getString("label.select_background_colour");
 +    ColourChooserListener listener = new ColourChooserListener()
      {
 -      getRotatableCanvas().setBgColour(col);
 -    }
 -    getRotatableCanvas().repaint();
 +      @Override
 +      public void colourSelected(Color c)
 +      {
 +        rc.setBgColour(c);
 +        rc.repaint();
 +      }
 +    };
 +    JalviewColourChooser.showColourChooser(this, ttl, rc.getBgColour(),
 +            listener);
    }
  
    /**
                MessageManager.formatMessage("label.calc_title", "PCA",
                        getPcaModel().getScoreModelName()),
                475, 450);
 +      this.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
      }
      working = false;
    }
      }
    }
  
 -  /**
 -   * Handler for 'Save as EPS' option
 -   */
 -  @Override
 -  protected void eps_actionPerformed()
 -  {
 -    makePCAImage(ImageMaker.TYPE.EPS);
 -  }
 -
 -  /**
 -   * Handler for 'Save as PNG' option
 -   */
 -  @Override
 -  protected void png_actionPerformed()
 -  {
 -    makePCAImage(ImageMaker.TYPE.PNG);
 -  }
 -
 -  void makePCAImage(ImageMaker.TYPE type)
 +  public void makePCAImage(ImageMaker.TYPE type)
    {
      int width = getRotatableCanvas().getWidth();
      int height = getRotatableCanvas().getHeight();
 -
 -    ImageMaker im;
 -
 -    switch (type)
 +    ImageWriterI writer = new ImageWriterI()
      {
 -    case PNG:
 -      im = new ImageMaker(this, ImageMaker.TYPE.PNG,
 -              "Make PNG image from PCA", width, height, null, null, null, 0,
 -              false);
 -      break;
 -    case EPS:
 -      im = new ImageMaker(this, ImageMaker.TYPE.EPS,
 -              "Make EPS file from PCA", width, height, null,
 -              this.getTitle(), null, 0, false);
 -      break;
 -    default:
 -      im = new ImageMaker(this, ImageMaker.TYPE.SVG,
 -              "Make SVG file from PCA", width, height, null,
 -              this.getTitle(), null, 0, false);
 -    }
 -
 -    if (im.getGraphics() != null)
 -    {
 -      getRotatableCanvas().drawBackground(im.getGraphics());
 -      getRotatableCanvas().drawScene(im.getGraphics());
 -      if (getRotatableCanvas().drawAxes)
 +      @Override
 +      public void exportImage(Graphics g) throws Exception
        {
 -        getRotatableCanvas().drawAxes(im.getGraphics());
 +      RotatableCanvas canvas = getRotatableCanvas();
 +      canvas.drawBackground(g);
 +      canvas.drawScene(g);
 +        if (canvas.drawAxes)
 +        {
 +          canvas.drawAxes(g);
 +        }
        }
 -      im.writeImage();
 -    }
 +    };
 +    String pca = MessageManager.getString("label.pca");
 +    ImageExporter exporter = new ImageExporter(writer, null, type, pca);
 +    exporter.doExport(null, this, width, height, pca);
    }
  
    @Override
      // }
      //
      // JPanel progressPanel;
-     // Long lId = new Long(id);
+     // Long lId = Long.valueOf(id);
      // GridLayout layout = (GridLayout) statusPanel.getLayout();
      // if (progressBars.get(lId) != null)
      // {
-     // progressPanel = (JPanel) progressBars.get(new Long(id));
+     // progressPanel = (JPanel) progressBars.get(Long.valueOf(id));
      // statusPanel.remove(progressPanel);
      // progressBars.remove(lId);
      // progressPanel = null;
            final IProgressIndicatorHandler handler)
    {
      progressBar.registerHandler(id, handler);
-     // if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
+     // if (progressBarHandlers == null || !progressBars.contains(Long.valueOf(id)))
      // {
      // throw new
      // Error(MessageManager.getString("error.call_setprogressbar_before_registering_handler"));
      // }
-     // progressBarHandlers.put(new Long(id), handler);
-     // final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
+     // progressBarHandlers.put(Long.valueOf(id), handler);
+     // final JPanel progressPanel = (JPanel) progressBars.get(Long.valueOf(id));
      // if (handler.canCancel())
      // {
      // JButton cancel = new JButton(
@@@ -97,9 -97,9 +97,9 @@@ public class SplitFrame extends GSplitF
       * estimate width and height of SplitFrame; this.getInsets() doesn't seem to
       * give the full additional size (a few pixels short)
       */
 -    int widthFudge = Platform.isAMac() ? MAC_INSETS_WIDTH
 +    int widthFudge = Platform.isAMacAndNotJS() ? MAC_INSETS_WIDTH
              : WINDOWS_INSETS_WIDTH;
 -    int heightFudge = Platform.isAMac() ? MAC_INSETS_HEIGHT
 +    int heightFudge = Platform.isAMacAndNotJS() ? MAC_INSETS_HEIGHT
              : WINDOWS_INSETS_HEIGHT;
      int width = ((AlignFrame) getTopFrame()).getWidth() + widthFudge;
      int height = ((AlignFrame) getTopFrame()).getHeight()
      /*
       * estimate ratio of (topFrameContent / bottomFrameContent)
       */
 -    int insets = Platform.isAMac() ? MAC_INSETS_HEIGHT
 +    int insets = Platform.isAMacAndNotJS() ? MAC_INSETS_HEIGHT
              : WINDOWS_INSETS_HEIGHT;
      // allow 3 'rows' for scale, scrollbar, status bar
      int topHeight = insets + (3 + topCount) * topCharHeight
       * Ctrl-W / Cmd-W - close view or window
       */
      KeyStroke key_cmdW = KeyStroke.getKeyStroke(KeyEvent.VK_W,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      action = new AbstractAction()
      {
        @Override
       * Ctrl-T / Cmd-T open new view
       */
      KeyStroke key_cmdT = KeyStroke.getKeyStroke(KeyEvent.VK_T,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      AbstractAction action = new AbstractAction()
      {
        @Override
       * Ctrl-F / Cmd-F open Finder dialog, 'focused' on the right alignment
       */
      KeyStroke key_cmdF = KeyStroke.getKeyStroke(KeyEvent.VK_F,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      AbstractAction action = new AbstractAction()
      {
        @Override
@@@ -274,7 -274,7 +274,7 @@@ public class AnnotationFil
            if (row.graphGroup > -1)
            {
              graphGroupSeen.set(row.graphGroup);
-             Integer key = new Integer(row.graphGroup);
+             Integer key = Integer.valueOf(row.graphGroup);
              if (graphGroup.containsKey(key))
              {
                graphGroup.put(key, graphGroup.get(key) + "\t" + row.label);
  
    String refSeqId = null;
  
 -  public boolean annotateAlignmentView(AlignViewportI viewport, String file,
 +  public boolean annotateAlignmentView(AlignViewportI viewport, Object file,
            DataSourceType protocol)
    {
      ColumnSelection colSel = viewport.getColumnSelection();
    }
  
    public boolean readAnnotationFile(AlignmentI al, HiddenColumns hidden,
 -          String file, DataSourceType sourceType)
 +          Object file, DataSourceType sourceType)
    {
      BufferedReader in = null;
      try
      {
        if (sourceType == DataSourceType.FILE)
        {
 -        in = new BufferedReader(new FileReader(file));
 +        in = FileLoader.getBufferedReader(file);
        }
        else if (sourceType == DataSourceType.URL)
        {
 -        URL url = new URL(file);
 +        URL url = new URL(file.toString());
          in = new BufferedReader(new InputStreamReader(url.openStream()));
        }
        else if (sourceType == DataSourceType.PASTE)
        {
 -        in = new BufferedReader(new StringReader(file));
 +        in = new BufferedReader(new StringReader(file.toString()));
        }
        else if (sourceType == DataSourceType.CLASSLOADER)
        {
                        autoAnnotsKey(aa[aai], aa[aai].sequenceRef,
                                (aa[aai].groupRef == null ? null
                                        : aa[aai].groupRef.getName())),
-                       new Integer(1));
+                       Integer.valueOf(1));
              }
            }
          }
          {
            displayChar = token;
            // foo
-           value = new Float(token).floatValue();
+           value = Float.valueOf(token).floatValue();
            parsedValue = true;
            continue;
          } catch (NumberFormatException ex)
@@@ -105,11 -105,11 +105,11 @@@ public class FeaturesFile extends Align
    /**
     * Constructor which does not parse the file immediately
     * 
 -   * @param file
 +   * @param file File or String filename
     * @param paste
     * @throws IOException
     */
 -  public FeaturesFile(String file, DataSourceType paste)
 +  public FeaturesFile(Object file, DataSourceType paste)
            throws IOException
    {
      super(false, file, paste);
     * @param type
     * @throws IOException
     */
 -  public FeaturesFile(boolean parseImmediately, String file,
 +  public FeaturesFile(boolean parseImmediately, Object file,
            DataSourceType type) throws IOException
    {
      super(parseImmediately, file, type);
        float score = Float.NaN;
        try
        {
-         score = new Float(gffColumns[6]).floatValue();
+         score = Float.valueOf(gffColumns[6]).floatValue();
        } catch (NumberFormatException ex)
        {
          sf = new SequenceFeature(ft, desc, startPos, endPos, featureGroup);
@@@ -68,8 -68,6 +68,8 @@@ public class JPredFile extends AlignFil
    /**
     * Creates a new JPredFile object.
     * 
 +   * BH allows File or String
 +   * 
     * @param inFile
     *          DOCUMENT ME!
     * @param sourceType
@@@ -78,7 -76,7 +78,7 @@@
     * @throws IOException
     *           DOCUMENT ME!
     */
 -  public JPredFile(String inFile, DataSourceType sourceType)
 +  public JPredFile(Object inFile, DataSourceType sourceType)
            throws IOException
    {
      super(inFile, sourceType);
            {
              ascore = symbols.nextToken();
  
-             Float score = new Float(ascore);
+             Float score = Float.valueOf(ascore);
              scores.addElement(score);
            }
  
  
            seq_entries.addElement(newseq.toString());
            ids.addElement(id);
-           Symscores.put(id, new Integer(ids.size() - 1));
+           Symscores.put(id, Integer.valueOf(ids.size() - 1));
          }
        }
      }
    }
  
    /**
 -   * DOCUMENT ME!
     * 
     * @param args
 -   *          DOCUMENT ME!
 +   * @j2sIgnore
     */
    public static void main(String[] args)
    {
   */
  package jalview.io;
  
 +import jalview.datamodel.DBRefEntry;
  import jalview.datamodel.SequenceI;
  
 +import java.util.List;
 +
 +import com.stevesoft.pat.Regex;
 +
  public class ModellerDescription
  {
    /**
@@@ -90,7 -85,7 +90,7 @@@
  
      resCode(int v)
      {
-       val = new Integer(v);
+       val = Integer.valueOf(v);
        field = val.toString();
      }
    };
@@@ -98,7 -93,7 +98,7 @@@
    private resCode validResidueCode(String field)
    {
      Integer val = null;
 -    com.stevesoft.pat.Regex r = new com.stevesoft.pat.Regex(
 +    Regex r = new Regex(
              "\\s*((([-0-9]+).?)|FIRST|LAST|@)");
  
      if (!r.search(field))
        if (seq.getDatasetSequence() != null
                && seq.getDatasetSequence().getDBRefs() != null)
        {
 -        jalview.datamodel.DBRefEntry[] dbr = seq.getDatasetSequence()
 -                .getDBRefs();
 -        int i, j;
 -        for (i = 0, j = dbr.length; i < j; i++)
 +        List<DBRefEntry> dbr = seq.getDatasetSequence().getDBRefs();
 +        for (int i = 0, ni = dbr.size(); i < ni; i++)
          {
 -          if (dbr[i] != null)
 +              DBRefEntry dbri = dbr.get(i);
 +          if (dbri != null)
            {
              // JBPNote PDB dbRefEntry needs properties to propagate onto
              // ModellerField
              // JBPNote Need to get info from the user about whether the sequence
              // is the one being modelled, or if it is a template.
 -            if (dbr[i].getSource()
 +            if (dbri.getSource()
                      .equals(jalview.datamodel.DBRefSource.PDB))
              {
 -              fields.put(Fields[LOCALID], dbr[i].getAccessionId());
 +              fields.put(Fields[LOCALID], dbri.getAccessionId());
                t = 2;
                break;
              }
@@@ -35,8 -35,6 +35,8 @@@ import java.io.FileReader
  import java.io.IOException;
  import java.util.StringTokenizer;
  
 +import com.stevesoft.pat.Regex;
 +
  /**
   * Parse a new hanpshire style tree Caveats: NHX files are NOT supported and the
   * tree distances and topology are unreliable when they are parsed. TODO: on
@@@ -89,13 -87,13 +89,13 @@@ public class NewickFile extends FilePar
  
    boolean printRootInfo = true;
  
 -  private com.stevesoft.pat.Regex[] NodeSafeName = new com.stevesoft.pat.Regex[] {
 -      new com.stevesoft.pat.Regex().perlCode("m/[\\[,:'()]/"), // test for
 +  private Regex[] NodeSafeName = new Regex[] {
 +      new Regex().perlCode("m/[\\[,:'()]/"), // test for
        // requiring
        // quotes
 -      new com.stevesoft.pat.Regex().perlCode("s/'/''/"), // escaping quote
 +      new Regex().perlCode("s/'/''/"), // escaping quote
        // characters
 -      new com.stevesoft.pat.Regex().perlCode("s/\\/w/_/") // unqoted whitespace
 +      new Regex().perlCode("s/\\/w/_/") // unqoted whitespace
        // transformation
    };
  
      boolean ascending = false; // flag indicating that we are leaving the
      // current node
  
 -    com.stevesoft.pat.Regex majorsyms = new com.stevesoft.pat.Regex(
 +    Regex majorsyms = new Regex(
              "[(\\['),;]");
  
      int nextcp = 0;
  
            continue;
          }
 -
 -        ;
          d++;
  
          if (c.right() == null)
        // Deal with quoted fields
        case '\'':
  
 -        com.stevesoft.pat.Regex qnodename = new com.stevesoft.pat.Regex(
 +        Regex qnodename = new Regex(
                  "'([^']|'')+'");
  
          if (qnodename.searchFrom(nf, fcp))
            nodename = new String(
                    qnodename.stringMatched().substring(1, nl - 1));
            // unpack any escaped colons
 -          com.stevesoft.pat.Regex xpandquotes = com.stevesoft.pat.Regex
 +          Regex xpandquotes = Regex
                    .perlCode("s/''/'/");
            String widernodename = xpandquotes.replaceAll(nodename);
            nodename = widernodename;
             * '"+nf.substring(cp,fcp)+"'"); }
             */
            // verify termination.
 -          com.stevesoft.pat.Regex comment = new com.stevesoft.pat.Regex(
 +          Regex comment = new Regex(
                    "]");
            if (comment.searchFrom(nf, fcp))
            {
              Error = ErrorStringrange(Error, "Unterminated comment", 3, fcp,
                      nf);
            }
 -
 -          ;
          }
          // Parse simpler field strings
          String fstring = nf.substring(ncp, fcp);
                    + fstring.substring(cend + 1);
  
          }
 -        com.stevesoft.pat.Regex uqnodename = new com.stevesoft.pat.Regex(
 +        Regex uqnodename = new Regex(
                  "\\b([^' :;\\](),]+)");
 -        com.stevesoft.pat.Regex nbootstrap = new com.stevesoft.pat.Regex(
 +        Regex nbootstrap = new Regex(
                  "\\s*([0-9+]+)\\s*:");
 -        com.stevesoft.pat.Regex ndist = new com.stevesoft.pat.Regex(
 +        Regex ndist = new Regex(
                  ":([-0-9Ee.+]+)");
  
          if (!parsednodename && uqnodename.search(fstring)
            {
              try
              {
-               bootstrap = (new Integer(nbootstrap.stringMatched(1)))
+               bootstrap = (Integer.valueOf(nbootstrap.stringMatched(1)))
                        .intValue();
                HasBootstrap = true;
              } catch (Exception e)
          {
            try
            {
-             distance = (new Float(ndist.stringMatched(1))).floatValue();
+             distance = (Float.valueOf(ndist.stringMatched(1))).floatValue();
              HasDistances = true;
              nodehasdistance = true;
            } catch (Exception e)
              if (code.toLowerCase().equals("b"))
              {
                int v = -1;
-               Float iv = new Float(value);
+               Float iv = Float.valueOf(value);
                v = iv.intValue(); // jalview only does integer bootstraps
                // currently
                c.setBootstrap(v);
      }
    }
  
 -  // Test
 +  /**
 +   * 
 +   * @param args
 +   * @j2sIgnore
 +   */
    public static void main(String[] args)
    {
      try
        trf.parse();
        System.out.println("Original file :\n");
  
 -      com.stevesoft.pat.Regex nonl = new com.stevesoft.pat.Regex("\n+", "");
 +      Regex nonl = new Regex("\n+", "");
        System.out.println(nonl.replaceAll(newickfile.toString()) + "\n");
  
        System.out.println("Parsed file.\n");
@@@ -271,14 -271,14 +271,14 @@@ public class Tree extends DatastoreIte
     * @return vector of alignment sequences in order of SeqCigar array (but
     *         missing unfound seqcigars)
     */
 -  private Vector findAlignmentSequences(AlignmentI jal,
 +  private Vector<SequenceI> findAlignmentSequences(AlignmentI jal,
            SeqCigar[] sequences)
    {
      SeqCigar[] tseqs = new SeqCigar[sequences.length];
      System.arraycopy(sequences, 0, tseqs, 0, sequences.length);
 -    Vector alsq = new Vector();
 -    List<SequenceI> jalsqs;
 -    synchronized (jalsqs = jal.getSequences())
 +    Vector<SequenceI> alsq = new Vector<>();
 +    List<SequenceI> jalsqs = jal.getSequences();
 +    synchronized (jalsqs)
      {
        for (SequenceI asq : jalsqs)
        {
      Integer nindx = (Integer) nodespecs.get(nname);
      if (nindx == null)
      {
-       nindx = new Integer(1);
+       nindx = Integer.valueOf(1);
      }
      nname = nindx.toString() + " " + nname;
      return nname;
      String oval = nodespec.substring(0, nodespec.indexOf(' '));
      try
      {
-       occurence = new Integer(oval).intValue();
+       occurence = Integer.valueOf(oval).intValue();
      } catch (Exception e)
      {
        System.err.println("Invalid nodespec '" + nodespec + "'");
@@@ -51,6 -51,8 +51,8 @@@ import htsjdk.variant.vcf.VCFInfoHeader
   */
  public class VCFLoader
  {
+   private static final String DEFAULT_SPECIES = "homo_sapiens";
    /**
     * A class to model the mapping from sequence to VCF coordinates. Cases include
     * <ul>
@@@ -82,7 -84,7 +84,7 @@@
  
    /*
     * Lookup keys, and default values, for Preference entries that describe
-    * patterns for VCF and VEP fields to capture 
+    * patterns for VCF and VEP fields to capture
     */
    private static final String VEP_FIELDS_PREF = "VEP_FIELDS";
  
    private static final String DEFAULT_VEP_FIELDS = ".*";// "Allele,Consequence,IMPACT,SWISSPROT,SIFT,PolyPhen,CLIN_SIG";
  
    /*
+    * Lookup keys, and default values, for Preference entries that give
+    * mappings from tokens in the 'reference' header to species or assembly
+    */
+   private static final String VCF_ASSEMBLY = "VCF_ASSEMBLY";
+   private static final String DEFAULT_VCF_ASSEMBLY = "assembly19=GRCh38,hs37=GRCh37,grch37=GRCh37,grch38=GRCh38";
+   private static final String VCF_SPECIES = "VCF_SPECIES"; // default is human
+   /*
     * keys to fields of VEP CSQ consequence data
     * see https://www.ensembl.org/info/docs/tools/vep/vep_formats.html
     */
    private static final String PIPE_REGEX = "\\|";
  
    /*
-    * key for Allele Frequency output by VEP
-    * see http://www.ensembl.org/info/docs/tools/vep/vep_formats.html
-    */
-   private static final String ALLELE_FREQUENCY_KEY = "AF";
-   /*
     * delimiter that separates multiple consequence data blocks
     */
    private static final String COMMA = ",";
    private VCFHeader header;
  
    /*
+    * species (as a valid Ensembl term) the VCF is for 
+    */
+   private String vcfSpecies;
+   /*
+    * genome assembly version (as a valid Ensembl identifier) the VCF is for 
+    */
+   private String vcfAssembly;
+   /*
     * a Dictionary of contigs (if present) referenced in the VCF file
     */
    private SAMSequenceDictionary dictionary;
     */
    public SequenceI loadVCFContig(String contig)
    {
-     String ref = header.getOtherHeaderLine(VCFHeader.REFERENCE_KEY)
-             .getValue();
+     VCFHeaderLine headerLine = header.getOtherHeaderLine(VCFHeader.REFERENCE_KEY);
+     String ref = headerLine == null ? null : headerLine.getValue();
      if (ref.startsWith("file://"))
      {
        ref = ref.substring(7);
      }
+     setSpeciesAndAssembly(ref);
  
      SequenceI seq = null;
      File dbFile = new File(ref);
      {
        HtsContigDb db = new HtsContigDb("", dbFile);
        seq = db.getSequenceProxy(contig);
-       loadSequenceVCF(seq, ref);
+       loadSequenceVCF(seq);
        db.close();
      }
      else
      {
        VCFHeaderLine ref = header
                .getOtherHeaderLine(VCFHeader.REFERENCE_KEY);
-       String vcfAssembly = ref.getValue();
+       String reference = ref.getValue();
+       setSpeciesAndAssembly(reference);
  
        int varCount = 0;
        int seqCount = 0;
         */
        for (SequenceI seq : seqs)
        {
-         int added = loadSequenceVCF(seq, vcfAssembly);
+         int added = loadSequenceVCF(seq);
          if (added > 0)
          {
            seqCount++;
    }
  
    /**
+    * Attempts to determine and save the species and genome assembly version to
+    * which the VCF data applies. This may be done by parsing the {@code reference}
+    * header line, configured in a property file, or (potentially) confirmed
+    * interactively by the user.
+    * <p>
+    * The saved values should be identifiers valid for Ensembl's REST service
+    * {@code map} endpoint, so they can be used (if necessary) to retrieve the
+    * mapping between VCF coordinates and sequence coordinates.
+    * 
+    * @param reference
+    * @see https://rest.ensembl.org/documentation/info/assembly_map
+    * @see https://rest.ensembl.org/info/assembly/human?content-type=text/xml
+    * @see https://rest.ensembl.org/info/species?content-type=text/xml
+    */
+   protected void setSpeciesAndAssembly(String reference)
+   {
+     reference = reference.toLowerCase();
+     vcfSpecies = DEFAULT_SPECIES;
+     /*
+      * for a non-human species, or other assembly identifier,
+      * specify as a Jalview property file entry e.g.
+      * VCF_ASSEMBLY = hs37=GRCh37,assembly19=GRCh37
+      * VCF_SPECIES = c_elegans=celegans
+      * to map a token in the reference header to a value
+      */
+     String prop = Cache.getDefault(VCF_ASSEMBLY, DEFAULT_VCF_ASSEMBLY);
+     for (String token : prop.split(","))
+     {
+       String[] tokens = token.split("=");
+       if (tokens.length == 2)
+       {
+         if (reference.contains(tokens[0].trim().toLowerCase()))
+         {
+           vcfAssembly = tokens[1].trim();
+           break;
+         }
+       }
+     }
+     prop = Cache.getProperty(VCF_SPECIES);
+     if (prop != null)
+     {
+       for (String token : prop.split(","))
+       {
+         String[] tokens = token.split("=");
+         if (tokens.length == 2)
+         {
+           if (reference.contains(tokens[0].trim().toLowerCase()))
+           {
+             vcfSpecies = tokens[1].trim();
+             break;
+           }
+         }
+       }
+     }
+   }
+   /**
     * Opens the VCF file and parses header data
     * 
     * @param filePath
     */
    protected void transferAddedFeatures(SequenceI seq)
    {
 -    DBRefEntry[] dbrefs = seq.getDBRefs();
 +    List<DBRefEntry> dbrefs = seq.getDBRefs();
      if (dbrefs == null)
      {
        return;
     * and returns the number of variant features added
     * 
     * @param seq
-    * @param vcfAssembly
     * @return
     */
-   protected int loadSequenceVCF(SequenceI seq, String vcfAssembly)
+   protected int loadSequenceVCF(SequenceI seq)
    {
-     VCFMap vcfMap = getVcfMap(seq, vcfAssembly);
+     VCFMap vcfMap = getVcfMap(seq);
      if (vcfMap == null)
      {
        return 0;
     * Answers a map from sequence coordinates to VCF chromosome ranges
     * 
     * @param seq
-    * @param vcfAssembly
     * @return
     */
-   private VCFMap getVcfMap(SequenceI seq, String vcfAssembly)
+   private VCFMap getVcfMap(SequenceI seq)
    {
      /*
       * simplest case: sequence has id and length matching a VCF contig
      String seqRef = seqCoords.getAssemblyId();
      MapList map = seqCoords.getMap();
  
-     if (!vcfSpeciesMatchesSequence(vcfAssembly, species))
+     // note this requires the configured species to match that
+     // returned with the Ensembl sequence; todo: support aliases?
+     if (!vcfSpecies.equalsIgnoreCase(species))
      {
+       Cache.log.warn("No VCF loaded to " + seq.getName()
+               + " as species not matched");
        return null;
      }
  
-     if (vcfAssemblyMatchesSequence(vcfAssembly, seqRef))
+     if (seqRef.equalsIgnoreCase(vcfAssembly))
      {
        return new VCFMap(chromosome, map);
      }
  
-     if (!"GRCh38".equalsIgnoreCase(seqRef) // Ensembl
-             || !vcfAssembly.contains("Homo_sapiens_assembly19")) // gnomAD
-     {
-       return null;
-     }
      /*
-      * map chromosomal coordinates from sequence to VCF if the VCF
-      * data has a different reference assembly to the sequence
+      * VCF data has a different reference assembly to the sequence:
+      * query Ensembl to map chromosomal coordinates from sequence to VCF
       */
-     // TODO generalise for cases other than GRCh38 -> GRCh37 !
-     // - or get the user to choose in a dialog
      List<int[]> toVcfRanges = new ArrayList<>();
      List<int[]> fromSequenceRanges = new ArrayList<>();
-     String toRef = "GRCh37";
  
      for (int[] range : map.getToRanges())
      {
        }
  
        int[] newRange = mapReferenceRange(range, chromosome, "human", seqRef,
-               toRef);
+               vcfAssembly);
        if (newRange == null)
        {
          Cache.log.error(
                  String.format("Failed to map %s:%s:%s:%d:%d to %s", species,
-                         chromosome, seqRef, range[0], range[1], toRef));
+                         chromosome, seqRef, range[0], range[1],
+                         vcfAssembly));
          continue;
        }
        else
    }
  
    /**
-    * Answers true if we determine that the VCF data uses the same reference
-    * assembly as the sequence, else false
-    * 
-    * @param vcfAssembly
-    * @param seqRef
-    * @return
-    */
-   private boolean vcfAssemblyMatchesSequence(String vcfAssembly,
-           String seqRef)
-   {
-     // TODO improve on this stub, which handles gnomAD and
-     // hopes for the best for other cases
-     if ("GRCh38".equalsIgnoreCase(seqRef) // Ensembl
-             && vcfAssembly.contains("Homo_sapiens_assembly19")) // gnomAD
-     {
-       return false;
-     }
-     return true;
-   }
-   /**
-    * Answers true if the species inferred from the VCF reference identifier
-    * matches that for the sequence
-    * 
-    * @param vcfAssembly
-    * @param speciesId
-    * @return
-    */
-   boolean vcfSpeciesMatchesSequence(String vcfAssembly, String speciesId)
-   {
-     // PROBLEM 1
-     // there are many aliases for species - how to equate one with another?
-     // PROBLEM 2
-     // VCF ##reference header is an unstructured URI - how to extract species?
-     // perhaps check if ref includes any (Ensembl) alias of speciesId??
-     // TODO ask the user to confirm this??
-     if (vcfAssembly.contains("Homo_sapiens") // gnomAD exome data example
-             && "HOMO_SAPIENS".equals(speciesId)) // Ensembl species id
-     {
-       return true;
-     }
-     if (vcfAssembly.contains("c_elegans") // VEP VCF response example
-             && "CAENORHABDITIS_ELEGANS".equals(speciesId)) // Ensembl
-     {
-       return true;
-     }
-     // this is not a sustainable solution...
-     return false;
-   }
-   /**
     * Queries the VCF reader for any variants that overlap the mapped chromosome
     * ranges of the sequence, and adds as variant features. Returns the number of
     * overlapping variants found.
@@@ -35,7 -35,6 +35,6 @@@ import jalview.util.Platform
  import java.awt.BorderLayout;
  import java.awt.Color;
  import java.awt.GridLayout;
- import java.awt.Toolkit;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.FocusAdapter;
@@@ -62,18 -61,15 +61,18 @@@ import javax.swing.event.ChangeEvent
  import javax.swing.event.MenuEvent;
  import javax.swing.event.MenuListener;
  
 +@SuppressWarnings("serial")
  public class GAlignFrame extends JInternalFrame
  {
    protected JMenuBar alignFrameMenuBar = new JMenuBar();
  
    protected JMenuItem closeMenuItem = new JMenuItem();
  
 -  protected JMenu webService = new JMenu();
 +  public JMenu webService = new JMenu();// BH 2019 was protected, but not
 +                                        // sufficient for AlignFrame thread run
  
 -  protected JMenuItem webServiceNoServices;
 +  public JMenuItem webServiceNoServices;// BH 2019 was protected, but not
 +                                        // sufficient for AlignFrame thread run
  
    protected JCheckBoxMenuItem viewBoxesMenuItem = new JCheckBoxMenuItem();
  
@@@ -81,9 -77,7 +80,9 @@@
  
    protected JMenu sortByAnnotScore = new JMenu();
  
 -  protected JLabel statusBar = new JLabel();
 +  public JLabel statusBar = new JLabel(); // BH 2019 was protected, but not
 +                                          // sufficient for
 +                                          // AlignFrame.printWriter
  
    protected JMenu outputTextboxMenu = new JMenu();
  
  
    protected JCheckBoxMenuItem applyAutoAnnotationSettings = new JCheckBoxMenuItem();
  
 +  protected JMenuItem openFeatureSettings;
 +
    private SequenceAnnotationOrder annotationSortOrder;
  
    private boolean showAutoCalculatedAbove = false;
    {
      try
      {
 +
 +      // for Web-page embedding using id=align-frame-div
 +      setName("jalview-alignment");
 +
        jbInit();
        setJMenuBar(alignFrameMenuBar);
  
            @Override
            public void actionPerformed(ActionEvent e)
            {
 -            outputText_actionPerformed(e);
 +            outputText_actionPerformed(e.getActionCommand());
            }
          });
  
        System.err.println(e.toString());
      }
  
 -    if (!Platform.isAMac())
 +    if (Platform.allowMnemonics()) // was "not mac and not JS"
      {
        closeMenuItem.setMnemonic('C');
        outputTextboxMenu.setMnemonic('T');
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        saveAs_actionPerformed(e);
 +        saveAs_actionPerformed();
        }
      };
  
      // FIXME getDefaultToolkit throws an exception in Headless mode
      KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
-                     | KeyEvent.SHIFT_MASK,
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+                     | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK,
              false);
      addMenuActionAndAccelerator(keyStroke, saveAs, al);
  
      closeMenuItem.setText(MessageManager.getString("action.close"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_W,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem selectAllSequenceMenuItem = new JMenuItem(
              MessageManager.getString("action.select_all"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem invertSequenceMenuItem = new JMenuItem(
              MessageManager.getString("action.invert_sequence_selection"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem remove2LeftMenuItem = new JMenuItem(
              MessageManager.getString("action.remove_left"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_L,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem remove2RightMenuItem = new JMenuItem(
              MessageManager.getString("action.remove_right"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem removeGappedColumnMenuItem = new JMenuItem(
              MessageManager.getString("action.remove_empty_columns"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem removeAllGapsMenuItem = new JMenuItem(
              MessageManager.getString("action.remove_all_gaps"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
-                     | KeyEvent.SHIFT_MASK,
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+                     | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK,
              false);
      al = new ActionListener()
      {
      JMenuItem removeRedundancyMenuItem = new JMenuItem(
              MessageManager.getString("action.remove_redundancy"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      undoMenuItem.setEnabled(false);
      undoMenuItem.setText(MessageManager.getString("action.undo"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      redoMenuItem.setEnabled(false);
      redoMenuItem.setText(MessageManager.getString("action.redo"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem printMenuItem = new JMenuItem(
              MessageManager.getString("action.print"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem findMenuItem = new JMenuItem(
              MessageManager.getString("action.find"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      findMenuItem.setToolTipText(JvSwingUtils.wrapTooltip(true,
              MessageManager.getString("label.find_tip")));
      al = new ActionListener()
      JMenuItem deleteGroups = new JMenuItem(
              MessageManager.getString("action.undefine_groups"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_U,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem createGroup = new JMenuItem(
              MessageManager.getString("action.create_group"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem unGroup = new JMenuItem(
              MessageManager.getString("action.remove_group"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
-                     | KeyEvent.SHIFT_MASK,
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+                     | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK,
              false);
      al = new ActionListener()
      {
  
      copy.setText(MessageManager.getString("action.copy"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_C,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
  
      al = new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        copy_actionPerformed(e);
 +        copy_actionPerformed();
        }
      };
      addMenuActionAndAccelerator(keyStroke, copy, al);
  
      cut.setText(MessageManager.getString("action.cut"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_X,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        cut_actionPerformed(e);
 +        cut_actionPerformed();
        }
      };
      addMenuActionAndAccelerator(keyStroke, cut, al);
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        delete_actionPerformed(e);
 +        delete_actionPerformed();
        }
      });
  
      JMenuItem pasteNew = new JMenuItem(
              MessageManager.getString("label.to_new_alignment"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
-                     | KeyEvent.SHIFT_MASK,
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+                     | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK,
              false);
      al = new ActionListener()
      {
      JMenuItem pasteThis = new JMenuItem(
              MessageManager.getString("label.to_this_alignment"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      /*
       * Translate as cDNA with sub-menu of translation tables
       */
 -    showTranslation.setText(MessageManager
 -            .getString("label.translate_cDNA"));
 +    showTranslation
 +            .setText(MessageManager.getString("label.translate_cDNA"));
      boolean first = true;
      for (final GeneticCodeI table : GeneticCodes.getInstance()
              .getCodeTables())
        }
      });
  
 -    JMenuItem openFeatureSettings = new JMenuItem(
 +    openFeatureSettings = new JMenuItem(
              MessageManager.getString("action.feature_settings"));
      openFeatureSettings.addActionListener(new ActionListener()
      {
          featureSettings_actionPerformed(e);
        }
      });
 +
 +    /*
 +     * add sub-menu of database we can fetch from
 +     */
      JMenuItem fetchSequence = new JMenuItem(
              MessageManager.getString("label.fetch_sequences"));
      fetchSequence.addActionListener(new ActionListener()
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        fetchSequence_actionPerformed(e);
 +        fetchSequence_actionPerformed();
        }
      });
  
          associatedData_actionPerformed(e);
        }
      });
 -    loadVcf = new JMenuItem(MessageManager.getString("label.load_vcf_file"));
 +    loadVcf = new JMenuItem(
 +            MessageManager.getString("label.load_vcf_file"));
      loadVcf.setToolTipText(MessageManager.getString("label.load_vcf"));
      loadVcf.addActionListener(new ActionListener()
      {
      JMenuItem invertColSel = new JMenuItem(
              MessageManager.getString("action.invert_column_selection"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
-                     | KeyEvent.ALT_MASK,
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+                     | jalview.util.ShortcutKeyMaskExWrapper.ALT_DOWN_MASK,
              false);
      al = new ActionListener()
      {
  
      JMenuItem save = new JMenuItem(MessageManager.getString("action.save"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      JMenuItem newView = new JMenuItem(
              MessageManager.getString("action.new_view"));
      keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_T,
-             Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+             jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
      al = new ActionListener()
      {
        @Override
      alignFrameMenuBar.add(formatMenu);
      alignFrameMenuBar.add(colourMenu);
      alignFrameMenuBar.add(calculateMenu);
 -    alignFrameMenuBar.add(webService);
 +    if (!Platform.isJS())
 +    {
 +      alignFrameMenuBar.add(webService);
 +    }
  
      fileMenu.add(fetchSequence);
      fileMenu.add(addSequenceMenu);
      fileMenu.add(exportAnnotations);
      fileMenu.add(loadTreeMenuItem);
      fileMenu.add(associatedData);
 -    fileMenu.add(loadVcf);
 +    if (!Platform.isJS())
 +    {
 +      fileMenu.add(loadVcf);
 +    }
      fileMenu.addSeparator();
      fileMenu.add(closeMenuItem);
  
      calculateMenu.addSeparator();
      calculateMenu.add(expandAlignment);
      calculateMenu.add(extractScores);
 -    calculateMenu.addSeparator();
 -    calculateMenu.add(runGroovy);
 +    if (!Platform.isJS())
 +    {
 +      calculateMenu.addSeparator();
 +      calculateMenu.add(runGroovy);
 +    }
  
      webServiceNoServices = new JMenuItem(
              MessageManager.getString("label.no_services"));
      webService.add(webServiceNoServices);
 -    exportImageMenu.add(htmlMenuItem);
 +    if (!Platform.isJS())
 +    {
 +      exportImageMenu.add(htmlMenuItem);
 +    }
      exportImageMenu.add(epsFile);
      exportImageMenu.add(createPNG);
 -    exportImageMenu.add(createBioJS);
 -    exportImageMenu.add(createSVG);
 +    if (!Platform.isJS())
 +    {
 +      exportImageMenu.add(createBioJS);
 +      exportImageMenu.add(createSVG);
 +    }
      addSequenceMenu.add(addFromFile);
      addSequenceMenu.add(addFromText);
      addSequenceMenu.add(addFromURL);
    {
    }
  
 -  protected void outputText_actionPerformed(ActionEvent e)
 +  protected void outputText_actionPerformed(String formatName)
    {
    }
  
    {
    }
  
 -  protected void copy_actionPerformed(ActionEvent e)
 +  protected void copy_actionPerformed()
    {
    }
  
 -  protected void cut_actionPerformed(ActionEvent e)
 +  protected void cut_actionPerformed()
    {
    }
  
 -  protected void delete_actionPerformed(ActionEvent e)
 +  protected void delete_actionPerformed()
    {
    }
  
    {
    }
  
 -  protected void saveAs_actionPerformed(ActionEvent e)
 +  protected void saveAs_actionPerformed()
    {
    }
  
  
    }
  
 -  public void fetchSequence_actionPerformed(ActionEvent e)
 +  public void fetchSequence_actionPerformed()
    {
  
    }
@@@ -26,7 -26,6 +26,6 @@@ import jalview.util.MessageManager
  import jalview.util.Platform;
  
  import java.awt.FlowLayout;
- import java.awt.Toolkit;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  
@@@ -42,10 -41,8 +41,10 @@@ import javax.swing.JMenuItem
   * @author $author$
   * @version $Revision$
   */
 +@SuppressWarnings("serial")
  public class GDesktop extends JFrame
  {
 +
    protected static JMenu windowMenu = new JMenu();
  
    JMenuBar desktopMenubar = new JMenuBar();
     */
    public GDesktop()
    {
 +    super();
      try
      {
        jbInit();
        e.printStackTrace();
      }
  
 -    if (!Platform.isAMac())
 +    if (Platform.allowMnemonics()) 
      {
 +      //BH was !Platform.isAMacAndNotJS()) i.e. "JS or not Mac"
 +      // but here we want just not a Mac, period, right?
        FileMenu.setMnemonic('F');
        inputLocalFileMenuItem.setMnemonic('L');
 -      VamsasMenu.setMnemonic('V');
 +      VamsasMenu.setMnemonic('V'); 
        inputURLMenuItem.setMnemonic('U');
        inputTextboxMenuItem.setMnemonic('C');
        quit.setMnemonic('Q');
     */
    private void jbInit() throws Exception
    {
 -
 +    setName("jalview-desktop");
      FileMenu.setText(MessageManager.getString("action.file"));
      HelpMenu.setText(MessageManager.getString("action.help"));
      VamsasMenu.setText("Vamsas");
              .setText(MessageManager.getString("label.load_tree_from_file"));
      inputLocalFileMenuItem.setAccelerator(
              javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O,
-                     Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(),
+                     jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(),
                      false));
      inputLocalFileMenuItem
              .addActionListener(new java.awt.event.ActionListener()
                @Override
                public void actionPerformed(ActionEvent e)
                {
 -                documentationMenuItem_actionPerformed(e);
 +                documentationMenuItem_actionPerformed();
                }
              });
      this.getContentPane().setLayout(flowLayout1);
        }
      });
  
+     Float specversion = Float.parseFloat(System.getProperty("java.specification.version"));
+     
      desktopMenubar.add(FileMenu);
      desktopMenubar.add(toolsMenu);
      VamsasMenu.setVisible(false);
      VamsasMenu.add(vamsasImport);
      VamsasMenu.add(vamsasSave);
      VamsasMenu.add(vamsasStop);
-     toolsMenu.add(preferences);
-     if (!Platform.isJS())
 -    if (!Platform.isAMac() || specversion < 11)
++    if (!Platform.isMac() || specversion < 11)
      {
-       toolsMenu.add(showMemusage);
-       toolsMenu.add(showConsole);
+       toolsMenu.add(preferences);
      }
 -    toolsMenu.add(showMemusage);
 -    toolsMenu.add(showConsole);
 -    toolsMenu.add(showNews);
 -    toolsMenu.add(garbageCollect);
 -    toolsMenu.add(groovyShell);
 +    if (!Platform.isJS())
 +    {
++      toolsMenu.add(showMemusage);
++      toolsMenu.add(showConsole);
 +      toolsMenu.add(showNews);
 +      toolsMenu.add(garbageCollect);
 +      toolsMenu.add(groovyShell);
 +    }
      toolsMenu.add(experimentalFeatures);
      // toolsMenu.add(snapShotWindow);
      inputMenu.add(inputLocalFileMenuItem);
     */
    protected void quit()
    {
+     //System.out.println("********** GDesktop.quit()");
    }
  
    /**
    {
    }
  
 -  /**
 -   * DOCUMENT ME!
 -   * 
 -   * @param e
 -   *          DOCUMENT ME!
 -   */
 -  protected void documentationMenuItem_actionPerformed(ActionEvent e)
 +  protected void documentationMenuItem_actionPerformed()
    {
    }
  
@@@ -38,7 -38,6 +38,7 @@@ import jalview.datamodel.AlignedCodonFr
  import jalview.datamodel.Alignment;
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.AlignmentI;
 +import jalview.datamodel.DBRefEntry;
  import jalview.datamodel.GraphLine;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.Point;
@@@ -153,7 -152,6 +153,7 @@@ import java.awt.Color
  import java.awt.Font;
  import java.awt.Rectangle;
  import java.io.BufferedReader;
 +import java.io.ByteArrayInputStream;
  import java.io.DataInputStream;
  import java.io.DataOutputStream;
  import java.io.File;
@@@ -210,15 -208,6 +210,15 @@@ import javax.xml.stream.XMLStreamReader
   */
  public class Jalview2XML
  {
 +
 +  // BH 2018 we add the .jvp binary extension to J2S so that
 +  // it will declare that binary when we do the file save from the browser
 +
 +  static
 +  {
 +    Platform.addJ2SBinaryType(".jvp?");
 +  }
 +
    private static final String VIEWER_PREFIX = "viewer_";
  
    private static final String RNA_PREFIX = "rna_";
        public boolean isResolvable()
        {
          return super.isResolvable() && mp.getTo() != null;
 -      };
 +      }
  
        @Override
        boolean resolve()
        } catch (Exception foo)
        {
        }
 -      ;
        jout.close();
      } catch (Exception ex)
      {
      try
      {
        // create backupfiles object and get new temp filename destination
 -      BackupFiles backupfiles = new BackupFiles(jarFile);
 -      FileOutputStream fos = new FileOutputStream(
 -              backupfiles.getTempFilePath());
 +      boolean doBackup = BackupFiles.getEnabled();
 +      BackupFiles backupfiles = doBackup ? new BackupFiles(jarFile) : null;
 +      FileOutputStream fos = new FileOutputStream(doBackup ? 
 +              backupfiles.getTempFilePath() : jarFile);
  
        JarOutputStream jout = new JarOutputStream(fos);
        List<AlignFrame> frames = new ArrayList<>();
        } catch (Exception foo)
        {
        }
        jout.close();
        boolean success = true;
  
 -      backupfiles.setWriteSuccess(success);
 -      success = backupfiles.rollBackupsAndRenameTempFile();
 +      if (doBackup)
 +      {
 +        backupfiles.setWriteSuccess(success);
 +        success = backupfiles.rollBackupsAndRenameTempFile();
 +      }
  
        return success;
      } catch (Exception ex)
        // using save and then load
        try
        {
-       fileName = fileName.replace('\\', '/');
++        fileName = fileName.replace('\\', '/');
          System.out.println("Writing jar entry " + fileName);
          JarEntry entry = new JarEntry(fileName);
          jout.putNextEntry(entry);
    {
      if (jout != null)
      {
 +      jarEntryName = jarEntryName.replace('\\','/');
        System.out.println("Writing jar entry " + jarEntryName);
        jout.putNextEntry(new JarEntry(jarEntryName));
        DataOutputStream dout = new DataOutputStream(jout);
      vamsasSeq.setName(jds.getName());
      vamsasSeq.setSequence(jds.getSequenceAsString());
      vamsasSeq.setDescription(jds.getDescription());
 -    jalview.datamodel.DBRefEntry[] dbrefs = null;
 +    List<DBRefEntry> dbrefs = null;
      if (jds.getDatasetSequence() != null)
      {
        vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
      }
      if (dbrefs != null)
      {
 -      for (int d = 0; d < dbrefs.length; d++)
 +      for (int d = 0, nd = dbrefs.size(); d < nd; d++)
        {
          DBRef dbref = new DBRef();
 -        dbref.setSource(dbrefs[d].getSource());
 -        dbref.setVersion(dbrefs[d].getVersion());
 -        dbref.setAccessionId(dbrefs[d].getAccessionId());
 -        if (dbrefs[d].hasMap())
 +        DBRefEntry ref = dbrefs.get(d);
 +        dbref.setSource(ref.getSource());
 +        dbref.setVersion(ref.getVersion());
 +        dbref.setAccessionId(ref.getAccessionId());
 +        if (ref.hasMap())
          {
 -          Mapping mp = createVamsasMapping(dbrefs[d].getMap(), parentseq,
 +          Mapping mp = createVamsasMapping(ref.getMap(), parentseq,
                    jds, recurse);
            dbref.setMapping(mp);
          }
     * @param file
     *          - HTTP URL or filename
     */
 -  public AlignFrame loadJalviewAlign(final String file)
 +  public AlignFrame loadJalviewAlign(final Object file)
    {
  
      jalview.gui.AlignFrame af = null;
            public void run()
            {
              setLoadingFinishedForNewStructureViewers();
 -          };
 +          }
          });
        } catch (Exception x)
        {
      return af;
    }
  
-       @SuppressWarnings("unused")
-       private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
 -  private jarInputStreamProvider createjarInputStreamProvider(
 -          final String file) throws MalformedURLException
 -  {
 -    URL url = null;
 -    errorMessage = null;
 -    uniqueSetSuffix = null;
 -    seqRefIds = null;
 -    viewportsAdded.clear();
 -    frefedSequence = null;
 -
 -    if (file.startsWith("http://"))
 -    {
 -      url = new URL(file);
 -    }
 -    final URL _url = url;
 -    return new jarInputStreamProvider()
 -    {
 -
 -      @Override
 -      public JarInputStream getJarInputStream() throws IOException
 -      {
 -        if (_url != null)
 -        {
 -          return new JarInputStream(_url.openStream());
 -        }
 -        else
 -        {
 -          return new JarInputStream(new FileInputStream(file));
++        @SuppressWarnings("unused")
++        private jarInputStreamProvider createjarInputStreamProvider(final Object ofile) throws MalformedURLException {
 +
-               // BH 2018 allow for bytes already attached to File object
-               try {
-                       String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
++                // BH 2018 allow for bytes already attached to File object
++                try {
++                        String file = (ofile instanceof File ? ((File) ofile).getCanonicalPath() : ofile.toString());
 +      byte[] bytes = Platform.isJS() ? Platform.getFileBytes((File) ofile)
 +              : null;
-                       URL url = null;
-                       errorMessage = null;
-                       uniqueSetSuffix = null;
-                       seqRefIds = null;
-                       viewportsAdded.clear();
-                       frefedSequence = null;
-                       if (file.startsWith("http://")) {
-                               url = new URL(file);
-                       }
-                       final URL _url = url;
-                       return new jarInputStreamProvider() {
-                               @Override
-                               public JarInputStream getJarInputStream() throws IOException {
-                                       if (bytes != null) {
- //                                            System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
-                                               return new JarInputStream(new ByteArrayInputStream(bytes));
-                                       }
-                                       if (_url != null) {
- //                                            System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
-                                               return new JarInputStream(_url.openStream());
-                                       } else {
- //                                            System.out.println("Jalview2XML: opening file jarInputStream for " + file);
-                                               return new JarInputStream(new FileInputStream(file));
-                                       }
-                               }
-                               @Override
-                               public String getFilename() {
-                                       return file;
-                               }
-                       };
-               } catch (IOException e) {
-                       e.printStackTrace();
-                       return null;
-               }
-       }
++                        URL url = null;
++                        errorMessage = null;
++                        uniqueSetSuffix = null;
++                        seqRefIds = null;
++                        viewportsAdded.clear();
++                        frefedSequence = null;
++
++                        if (file.startsWith("http://")) {
++                                url = new URL(file);
++                        }
++                        final URL _url = url;
++                        return new jarInputStreamProvider() {
++
++                                @Override
++                                public JarInputStream getJarInputStream() throws IOException {
++                                        if (bytes != null) {
++//                                              System.out.println("Jalview2XML: opening byte jarInputStream for bytes.length=" + bytes.length);
++                                                return new JarInputStream(new ByteArrayInputStream(bytes));
++                                        }
++                                        if (_url != null) {
++//                                              System.out.println("Jalview2XML: opening url jarInputStream for " + _url);
++                                                return new JarInputStream(_url.openStream());
++                                        } else {
++//                                              System.out.println("Jalview2XML: opening file jarInputStream for " + file);
++                                                return new JarInputStream(new FileInputStream(file));
++                                        }
++                                }
++
++                                @Override
++                                public String getFilename() {
++                                        return file;
++                                }
++                        };
++                } catch (IOException e) {
++                        e.printStackTrace();
++                        return null;
++                }
+         }
 -      }
 -
 -      @Override
 -      public String getFilename()
 -      {
 -        return file;
 -      }
 -    };
 -  }
  
    /**
     * Recover jalview session from a jalview project archive. Caller may
  
          if (jarentry != null && jarentry.getName().endsWith(".xml"))
          {
 -          InputStreamReader in = new InputStreamReader(jin, UTF_8);
 -          // JalviewModel object = new JalviewModel();
 -
            JAXBContext jc = JAXBContext
                    .newInstance("jalview.xml.binding.jalview");
            XMLStreamReader streamReader = XMLInputFactory.newInstance()
                    .unmarshal(streamReader, JalviewModel.class);
            JalviewModel object = jbe.getValue();
  
 -          /*
 -          Unmarshaller unmar = new Unmarshaller(object);
 -          unmar.setValidation(false);
 -          object = (JalviewModel) unmar.unmarshal(in);
 -          */
            if (true) // !skipViewport(object))
            {
              _af = loadFromObject(object, file, true, jprovider);
            String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
            filedat = oldFiles.get(new File(reformatedOldFilename));
          }
-         newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
+         newFileLoc.append(Platform.escapeBackslashes(filedat.getFilePath()));
          pdbfilenames.add(filedat.getFilePath());
          pdbids.add(filedat.getPdbId());
          seqmaps.add(filedat.getSeqList().toArray(new SequenceI[0]));
    {
      AlignFrame af = null;
      af = new AlignFrame(al, safeInt(view.getWidth()),
 -            safeInt(view.getHeight()), uniqueSeqSetId, viewId);
 +            safeInt(view.getHeight()), uniqueSeqSetId, viewId) 
 +//    {
- //            
- //            @Override
- //            protected void processKeyEvent(java.awt.event.KeyEvent e) {
- //                    System.out.println("Jalview2XML   AF " + e);
- //                    super.processKeyEvent(e);
- //                    
- //            }
- //            
++//      
++//      @Override
++//      protected void processKeyEvent(java.awt.event.KeyEvent e) {
++//              System.out.println("Jalview2XML   AF " + e);
++//              super.processKeyEvent(e);
++//              
++//      }
++//      
 +//    }
 +    ;
  
      af.setFileName(file, FileFormat.Jalview);
  
          }
          else
          {
-           featureOrder.put(featureType, new Float(
+           featureOrder.put(featureType, Float.valueOf(
                    fs / jm.getFeatureSettings().getSetting().size()));
          }
          if (safeBoolean(setting.isDisplay()))
        for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
        {
          Group grp = jm.getFeatureSettings().getGroup().get(gs);
-         fgtable.put(grp.getName(), new Boolean(grp.isDisplay()));
+         fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
        }
        // FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
        // fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
@@@ -41,6 -41,7 +41,7 @@@ import jalview.io.DataSourceType
  import jalview.io.StructureFile;
  import jalview.util.MappingUtils;
  import jalview.util.MessageManager;
+ import jalview.util.Platform;
  import jalview.ws.sifts.SiftsClient;
  import jalview.ws.sifts.SiftsException;
  import jalview.ws.sifts.SiftsSettings;
@@@ -56,9 -57,9 +57,9 @@@ import java.util.List
  import java.util.Map;
  import java.util.Vector;
  
 -import MCview.Atom;
 -import MCview.PDBChain;
 -import MCview.PDBfile;
 +import mc_view.Atom;
 +import mc_view.PDBChain;
 +import mc_view.PDBfile;
  
  public class StructureSelectionManager
  {
      StringBuilder sb = new StringBuilder(64);
      for (StructureMapping sm : mappings)
      {
-       if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
+       if (Platform.pathEquals(sm.pdbfile, pdbfile)
+               && seqs.contains(sm.sequence))
        {
          sb.append(sm.mappingDetails);
          sb.append(NEWLINE);
          instances.remove(jalviewLite);
          try
          {
-           mnger.finalize();
+           /* bsoares 2019-03-20 finalize deprecated, no apparent external
+            * resources to close
+            */
+           // mnger.finalize();
          } catch (Throwable x)
          {
          }
   */
  package jalview.util;
  
 +import jalview.javascript.json.JSON;
 +
 +import java.awt.Toolkit;
  import java.awt.event.MouseEvent;
 +import java.io.BufferedReader;
 +import java.io.File;
 +import java.io.FileOutputStream;
 +import java.io.FileReader;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.InputStreamReader;
 +import java.io.Reader;
 +import java.net.URL;
 +import java.util.Properties;
 +
 +import javax.swing.SwingUtilities;
 +
 +import org.json.simple.parser.JSONParser;
 +import org.json.simple.parser.ParseException;
  
  /**
   * System platform information used by Applet and Application
   */
  public class Platform
  {
 -  private static Boolean isAMac = null, isWindows = null;
 +
 +  private static boolean isJS = /** @j2sNative true || */
 +          false;
 +
 +  private static Boolean isNoJSMac = null, isNoJSWin = null, isMac = null,
 +          isWin = null;
  
    private static Boolean isHeadless = null;
  
    /**
 -   * sorry folks - Macs really are different
 +   * added to group mouse events into Windows and nonWindows (mac, unix, linux)
     * 
 -   * @return true if we do things in a special way.
 +   * @return
     */
 -  public static boolean isAMac()
 +  public static boolean isMac()
    {
 -    if (isAMac == null)
 -    {
 -      isAMac = System.getProperty("os.name").indexOf("Mac") > -1;
 -    }
 +    return (isMac == null
 +            ? (isMac = (System.getProperty("os.name").indexOf("Mac") >= 0))
 +            : isMac);
 +  }
  
 -    return isAMac.booleanValue();
 +  /**
 +   * added to group mouse events into Windows and nonWindows (mac, unix, linux)
 +   * 
 +   * @return
 +   */
 +  public static boolean isWin()
 +  {
 +    return (isWin == null
 +            ? (isWin = (System.getProperty("os.name").indexOf("Win") >= 0))
 +            : isWin);
 +  }
  
 +  /**
 +   * 
 +   * @return true if HTML5 JavaScript
 +   */
 +  public static boolean isJS()
 +  {
 +    return isJS;
 +  }
 +
 +  /**
 +   * sorry folks - Macs really are different
 +   * 
 +   * BH: disabled for SwingJS -- will need to check key-press issues
 +   * 
 +   * @return true if we do things in a special way.
 +   */
 +  public static boolean isAMacAndNotJS()
 +  {
 +    return (isNoJSMac == null ? (isNoJSMac = !isJS && isMac()) : isNoJSMac);
    }
  
    /**
     * 
     * @return true if we have to cope with another platform variation
     */
 -  public static boolean isWindows()
 +  public static boolean isWindowsAndNotJS()
    {
 -    if (isWindows == null)
 -    {
 -      isWindows = System.getProperty("os.name").indexOf("Win") > -1;
 -    }
 -    return isWindows.booleanValue();
 +    return (isNoJSWin == null ? (isNoJSWin = !isJS && isWin()) : isNoJSWin);
    }
  
    /**
    }
  
    /**
-    * escape a string according to the local platform's escape character
+    * Answers the input with every backslash replaced with a double backslash (an
+    * 'escaped' single backslash)
     * 
-    * @param file
-    * @return escaped file
+    * @param s
+    * @return
     */
-   public static String escapeString(String file)
+   public static String escapeBackslashes(String s)
    {
-     StringBuffer f = new StringBuffer();
-     int p = 0, lastp = 0;
-     while ((p = file.indexOf('\\', lastp)) > -1)
-     {
-       f.append(file.subSequence(lastp, p));
-       f.append("\\\\");
-       lastp = p + 1;
-     }
-     f.append(file.substring(lastp));
-     return f.toString();
+     return s == null ? null : s.replace("\\", "\\\\");
    }
  
    /**
     * Answers true if the mouse event has Meta-down (Command key on Mac) or
     * Ctrl-down (on other o/s). Note this answers _false_ if the Ctrl key is
 -   * pressed instead of the Meta/Cmd key on Mac. To test for Ctrl-click on Mac,
 -   * you can use e.isPopupTrigger().
 +   * pressed instead of the Meta/Cmd key on Mac. To test for Ctrl-pressed on
 +   * Mac, you can use e.isPopupTrigger().
     * 
     * @param e
     * @return
     */
    public static boolean isControlDown(MouseEvent e)
    {
 -    boolean aMac = isAMac();
 -    return isControlDown(e, aMac);
 +    return isControlDown(e, isMac());
    }
  
    /**
     */
    protected static boolean isControlDown(MouseEvent e, boolean aMac)
    {
-     if (!aMac)
-     {
-       return e.isControlDown();
-     }
-     // answer false for right mouse button
-     // shortcut key will be META for a Mac
-     return !e.isPopupTrigger()
-             && (Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
-                     & e.getModifiers()) != 0;
-     // could we use e.isMetaDown() here?
-   }
 -    if (aMac)
++          if (aMac)
++          {
++            /*
++             * answer false for right mouse button
++             */
++            if (e.isPopupTrigger())
++            {
++              return false;
++            }
++            return (jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() // .getMenuShortcutKeyMaskEx()
++                    & e.getModifiersEx()) != 0; // getModifiers()) != 0;
++          }
++          return e.isControlDown();
++        }
 +
 +  // BH: I don't know about that previous method. Here is what SwingJS uses.
 +  // Notice the distinction in mouse events. (BUTTON3_MASK == META)
 +  //
 +  // private static boolean isPopupTrigger(int id, int mods, boolean isWin) {
 +  // boolean rt = ((mods & InputEvent.BUTTON3_MASK) != 0);
 +  // if (isWin) {
 +  // if (id != MouseEvent.MOUSE_RELEASED)
 +  // return false;
 +  ////
 +  //// // Oddly, Windows returns InputEvent.META_DOWN_MASK on release, though
 +  //// // BUTTON3_DOWN_MASK for pressed. So here we just accept both.
 +  ////
 +  //// actually, we can use XXX_MASK, not XXX_DOWN_MASK and avoid this issue,
 +  // because
 +  //// J2S adds the appropriate extended (0x3FC0) and simple (0x3F) modifiers.
 +  ////
 +  // return rt;
 +  // } else {
 +  // // mac, linux, unix
 +  // if (id != MouseEvent.MOUSE_PRESSED)
 +  // return false;
 +  // boolean lt = ((mods & InputEvent.BUTTON1_MASK) != 0);
 +  // boolean ctrl = ((mods & InputEvent.CTRL_MASK) != 0);
 +  // return rt || (ctrl && lt);
 +  // }
 +  // }
 +  //
 +
 +  /**
 +   * Windows (not Mac, Linux, or Unix) and right button to test for the
 +   * right-mouse pressed event in Windows that would have opened a menu or a
 +   * Mac.
 +   * 
 +   * @param e
 +   * @return
 +   */
 +  public static boolean isWinRightButton(MouseEvent e)
 +  {
 +    // was !isAMac(), but that is true also for Linux and Unix and JS,
 +
 +    return isWin() && SwingUtilities.isRightMouseButton(e);
 +  }
 +
 +  /**
 +   * Windows (not Mac, Linux, or Unix) and middle button -- for mouse wheeling
 +   * without pressing the button.
 +   * 
 +   * @param e
 +   * @return
 +   */
 +  public static boolean isWinMiddleButton(MouseEvent e)
 +  {
 +    // was !isAMac(), but that is true also for Linux and Unix and JS
 +    return isWin() && SwingUtilities.isMiddleMouseButton(e);
 +  }
 +
 +  public static boolean allowMnemonics()
 +  {
 +    return !isMac();
 +  }
 +
 +  public final static int TIME_RESET = 0;
 +
 +  public final static int TIME_MARK = 1;
 +
 +  public static final int TIME_SET = 2;
 +
 +  public static final int TIME_GET = 3;
 +
 +  public static long time, mark, set, duration;
 +
 +  public static void timeCheck(String msg, int mode)
 +  {
 +    long t = System.currentTimeMillis();
 +    switch (mode)
      {
 -      /*
 -       * answer false for right mouse button
 -       */
 -      if (e.isPopupTrigger())
 +    case TIME_RESET:
 +      time = mark = t;
 +      if (msg != null)
 +      {
 +        System.err.println("Platform: timer reset\t\t\t" + msg);
 +      }
 +      break;
 +    case TIME_MARK:
 +      if (set > 0)
 +      {
 +        duration += (t - set);
 +      }
 +      else
        {
 -        return false;
 +        if (time == 0)
 +        {
 +          time = mark = t;
 +        }
 +        if (msg != null)
 +        {
 +          System.err.println("Platform: timer mark\t" + ((t - time) / 1000f)
 +                  + "\t" + ((t - mark) / 1000f) + "\t" + msg);
 +        }
 +        mark = t;
        }
 -      return (jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() // .getMenuShortcutKeyMaskEx()
 -              & e.getModifiersEx()) != 0; // getModifiers()) != 0;
 +      break;
 +    case TIME_SET:
 +      set = t;
 +      break;
 +    case TIME_GET:
 +      if (msg != null)
 +      {
 +        System.err.println("Platform: timer dur\t" + ((t - time) / 1000f)
 +                + "\t" + ((duration) / 1000f) + "\t" + msg);
 +      }
 +      set = 0;
 +      break;
      }
 -    return e.isControlDown();
 +  }
 +
 +  public static void cacheFileData(String path, Object data)
 +  {
 +    if (!isJS() || data == null)
 +    {
 +      return;
 +    }
 +    /**
 +     * @j2sNative
 +     * 
 +     *            swingjs.JSUtil.cacheFileData$S$O(path, data);
 +     * 
 +     */
 +  }
 +
 +  public static void cacheFileData(File file)
 +  {
 +    byte[] data;
 +    if (!isJS() || (data = Platform.getFileBytes(file)) == null)
 +    {
 +      return;
 +    }
 +    cacheFileData(file.toString(), data);
 +  }
 +
 +  public static byte[] getFileBytes(File f)
 +  {
 +    return /** @j2sNative f && f._bytes || */
 +    null;
 +  }
 +
 +  public static byte[] getFileAsBytes(String fileStr)
 +  {
 +    byte[] bytes = null;
 +    // BH 2018 hack for no support for access-origin
 +    /**
 +     * @j2sNative bytes = swingjs.JSUtil.getFileAsBytes$O(fileStr)
 +     */
 +    cacheFileData(fileStr, bytes);
 +    return bytes;
 +  }
 +
 +  @SuppressWarnings("unused")
 +  public static String getFileAsString(String url)
 +  {
 +    String ret = null;
 +    /**
 +     * @j2sNative
 +     * 
 +     *            ret = swingjs.JSUtil.getFileAsString$S(url);
 +     * 
 +     * 
 +     */
 +    cacheFileData(url, ret);
 +    return ret;
 +  }
 +
 +  public static boolean setFileBytes(File f, String urlstring)
 +  {
 +    if (!isJS())
 +    {
 +      return false;
 +    }
 +    @SuppressWarnings("unused")
 +    byte[] bytes = getFileAsBytes(urlstring);
 +    /**
 +     * @j2sNative f._bytes = bytes;
 +     */
 +    return true;
 +  }
 +
 +  public static void addJ2SBinaryType(String ext)
 +  {
 +    /**
 +     * @j2sNative
 +     * 
 +     *            J2S._binaryTypes.push("." + ext + "?");
 +     * 
 +     */
 +  }
 +
 +  /**
 +   * Encode the URI using JavaScript encodeURIComponent
 +   * 
 +   * @param value
 +   * @return encoded value
 +   */
 +  public static String encodeURI(String value)
 +  {
 +    /**
 +     * @j2sNative value = encodeURIComponent(value);
 +     */
 +    return value;
 +  }
 +
 +  /**
 +   * Open the URL using a simple window call if this is JavaScript
 +   * 
 +   * @param url
 +   * @return true if window has been opened
 +   */
 +  public static boolean openURL(String url)
 +  {
 +    if (!isJS())
 +    {
 +      return false;
 +    }
 +    /**
 +     * @j2sNative
 +     * 
 +     * 
 +     *            window.open(url);
 +     */
 +    return true;
 +  }
 +
 +  public static String getUniqueAppletID()
 +  {
 +    @SuppressWarnings("unused")
 +    ThreadGroup g = Thread.currentThread().getThreadGroup();
 +    /**
 +     * @j2sNative return g.html5Applet._uniqueId;
 +     *
 +     */
 +    return null;
 +
 +  }
 +
 +  /**
 +   * Read the Info block for this applet.
 +   * 
 +   * @param prefix
 +   *          "jalview_"
 +   * @param p
 +   * @return unique id for this applet
 +   */
 +  public static void readInfoProperties(String prefix, Properties p)
 +  {
 +    if (!isJS())
 +    {
 +      return;
 +    }
 +    @SuppressWarnings("unused")
 +    ThreadGroup g = Thread.currentThread().getThreadGroup();
 +    String id = getUniqueAppletID();
 +    String key = "", value = "";
 +    /**
 +     * @j2sNative var info = g.html5Applet.__Info || {}; for (var key in info) {
 +     *            if (key.indexOf(prefix) == 0) { value = "" + info[key];
 +     */
 +
 +    System.out.println(
 +            "Platform id=" + id + " reading Info." + key + " = " + value);
 +    p.put(id + "_" + key, value);
 +
 +    /**
 +     * @j2sNative
 +     * 
 +     * 
 +     *            } }
 +     */
 +  }
 +
 +  public static void setAjaxJSON(URL url)
 +  {
 +    if (isJS())
 +    {
 +      JSON.setAjax(url);
 +    }
 +  }
 +
 +  public static Object parseJSON(InputStream response)
 +          throws IOException, ParseException
 +  {
 +    if (isJS())
 +    {
 +      return JSON.parse(response);
 +    }
 +
 +    BufferedReader br = null;
 +    try
 +    {
 +      br = new BufferedReader(new InputStreamReader(response, "UTF-8"));
 +      return new JSONParser().parse(br);
 +    } finally
 +    {
 +      if (br != null)
 +      {
 +        try
 +        {
 +          br.close();
 +        } catch (IOException e)
 +        {
 +          // ignore
 +        }
 +      }
 +    }
 +  }
 +
 +  public static Object parseJSON(String json) throws ParseException
 +  {
 +    return (isJS() ? JSON.parse(json)
 +            : new JSONParser().parse(json));
 +  }
 +
 +  public static Object parseJSON(Reader r)
 +          throws IOException, ParseException
 +  {
 +    if (r == null)
 +    {
 +      return null;
 +    }
 +
 +    if (!isJS())
 +    {
 +      return new JSONParser().parse(r);
 +    }
 +    // Using a file reader is not currently supported in SwingJS JavaScript
 +
 +    if (r instanceof FileReader)
 +    {
 +      throw new IOException(
 +              "StringJS does not support FileReader parsing for JSON -- but it could...");
 +    }
 +    return JSON.parse(r);
 +
 +  }
 +
 +  /**
 +   * Dump the input stream to an output file.
 +   * 
 +   * @param is
 +   * @param outFile
 +   * @throws IOException
 +   *           if the file cannot be created or there is a problem reading the
 +   *           input stream.
 +   */
 +  public static void streamToFile(InputStream is, File outFile)
 +          throws IOException
 +  {
 +    FileOutputStream fio = new FileOutputStream(outFile);
 +    try
 +    {
 +      if (isJS()
 +              && /**
 +                  * @j2sNative outFile.setBytes$O && outFile.setBytes$O(is) &&
 +                  */
 +              true)
 +      {
 +        return;
 +      }
 +      byte[] bb = new byte[32 * 1024];
 +      int l;
 +      while ((l = is.read(bb)) > 0)
 +      {
 +        fio.write(bb, 0, l);
 +      }
 +    } finally
 +    {
 +      fio.close();
 +    }
 +  }
 +
 +  /**
 +   * Add a known domain that implements access-control-allow-origin:*
 +   * 
 +   * These should be reviewed periodically.
 +   * 
 +   * @param domain
 +   *          for a service that is not allowing ajax
 +   * 
 +   * @author hansonr@stolaf.edu
 +   * 
 +   */
 +  public static void addJ2SDirectDatabaseCall(String domain)
 +  {
 +
 +    if (isJS())
 +    {
 +      System.out.println(
 +            "Platform adding known access-control-allow-origin * for domain "
 +                    + domain);
 +      /**
 +       * @j2sNative
 +       * 
 +       *            J2S.addDirectDatabaseCall(domain);
 +       */
 +    }
 +
 +  }
 +
 +  public static void getURLCommandArguments()
 +  {
 +
 +    /**
 +     * Retrieve the first query field as command arguments to Jalview. Include
 +     * only if prior to "?j2s" or "&j2s" or "#". Assign the applet's __Info.args
 +     * element to this value.
 +     * 
 +     * @j2sNative var a =
 +     *            decodeURI((document.location.href.replace("&","?").split("?j2s")[0]
 +     *            + "?").split("?")[1].split("#")[0]); a &&
 +     *            (J2S.thisApplet.__Info.args = a.split(" "));
 +     */
 +
    }
  
+   /**
+    * A (case sensitive) file path comparator that ignores the difference between /
+    * and \
+    * 
+    * @param path1
+    * @param path2
+    * @return
+    */
+   public static boolean pathEquals(String path1, String path2)
+   {
+     if (path1 == null)
+     {
+       return path2 == null;
+     }
+     if (path2 == null)
+     {
+       return false;
+     }
+     String p1 = path1.replace('\\', '/');
+     String p2 = path2.replace('\\', '/');
+     return p1.equals(p2);
+   }
  }
@@@ -37,7 -37,6 +37,7 @@@ import java.beans.PropertyChangeListene
  import java.beans.PropertyChangeSupport;
  import java.util.ArrayList;
  import java.util.Arrays;
 +import java.util.Comparator;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Hashtable;
@@@ -613,7 -612,7 +613,7 @@@ public abstract class FeatureRendererMo
     * @param type
     * @return
     */
 -  protected boolean showFeatureOfType(String type)
 +  public boolean showFeatureOfType(String type)
    {
      return type == null ? false : (av.getFeaturesDisplayed() == null ? true
              : av.getFeaturesDisplayed().isVisible(type));
      {
        featureOrder = new Hashtable<>();
      }
-     featureOrder.put(type, new Float(position));
+     featureOrder.put(type, Float.valueOf(position));
      return position;
    }
  
      }
      if (newGroupsVisible)
      {
-       featureGroups.put(group, new Boolean(true));
+       featureGroups.put(group, Boolean.valueOf(true));
        return true;
      }
      return false;
    @Override
    public void setGroupVisibility(String group, boolean visible)
    {
-     featureGroups.put(group, new Boolean(visible));
+     featureGroups.put(group, Boolean.valueOf(visible));
    }
  
    @Override
        for (String gst : toset)
        {
          Boolean st = featureGroups.get(gst);
-         featureGroups.put(gst, new Boolean(visible));
+         featureGroups.put(gst, Boolean.valueOf(visible));
          if (st != null)
          {
            rdrw = rdrw || (visible != st.booleanValue());
      return filter == null ? true : filter.matches(sf);
    }
  
 +  /**
 +   * Answers true unless the specified group is set to hidden. Defaults to true
 +   * if group visibility is not set.
 +   * 
 +   * @param group
 +   * @return
 +   */
 +  public boolean isGroupVisible(String group)
 +  {
 +    if (!featureGroups.containsKey(group))
 +    {
 +      return true;
 +    }
 +    return featureGroups.get(group);
 +  }
 +
 +  /**
 +   * Orders features in render precedence (last in order is last to render, so
 +   * displayed on top of other features)
 +   * 
 +   * @param order
 +   */
 +  public void orderFeatures(Comparator<String> order)
 +  {
 +    Arrays.sort(renderOrder, order);
 +  }
 +
    @Override
    public boolean isVisible(SequenceFeature feature)
    {
      }
      return true;
    }
 -
  }
index 313ec1c,fe6d962..fe6d962
mode 100644,100755..100644
@@@ -119,6 -119,7 +119,7 @@@ import java.util.Map
   * 
   */
  public class EpsGraphics2D extends java.awt.Graphics2D
+         implements AutoCloseable
  {
  
    public static final String VERSION = "0.8.8";
     * OutputStream is automatically flushed before being closed. If you forget to
     * do this, the file may be incomplete.
     */
+   @Override
    public void close() throws IOException
    {
      flush();
     * Draws a 3D rectangle outline. If it is raised, light appears to come from
     * the top left.
     */
+   @Override
    public void draw3DRect(int x, int y, int width, int height, boolean raised)
    {
      Color originalColor = getColor();
     * Fills a 3D rectangle. If raised, it has bright fill and light appears to
     * come from the top left.
     */
+   @Override
    public void fill3DRect(int x, int y, int width, int height, boolean raised)
    {
      Color originalColor = getColor();
    /**
     * Draws a Shape on the EPS document.
     */
+   @Override
    public void draw(Shape s)
    {
      draw(s, "stroke");
    /**
     * Draws an Image on the EPS document.
     */
+   @Override
    public boolean drawImage(Image img, AffineTransform xform,
            ImageObserver obs)
    {
    /**
     * Draws a BufferedImage on the EPS document.
     */
+   @Override
    public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)
    {
      BufferedImage img1 = op.filter(img, null);
    /**
     * Draws a RenderedImage on the EPS document.
     */
+   @Override
    public void drawRenderedImage(RenderedImage img, AffineTransform xform)
    {
      Hashtable properties = new Hashtable();
    /**
     * Draws a RenderableImage by invoking its createDefaultRendering method.
     */
+   @Override
    public void drawRenderableImage(RenderableImage img, AffineTransform xform)
    {
      drawRenderedImage(img.createDefaultRendering(), xform);
    /**
     * Draws a string at (x,y)
     */
+   @Override
    public void drawString(String str, int x, int y)
    {
      drawString(str, (float) x, (float) y);
    /**
     * Draws a string at (x,y)
     */
+   @Override
    public void drawString(String s, float x, float y)
    {
      if (s != null && s.length() > 0)
     * Draws the characters of an AttributedCharacterIterator, starting from
     * (x,y).
     */
+   @Override
    public void drawString(AttributedCharacterIterator iterator, int x, int y)
    {
      drawString(iterator, (float) x, (float) y);
     * Draws the characters of an AttributedCharacterIterator, starting from
     * (x,y).
     */
+   @Override
    public void drawString(AttributedCharacterIterator iterator, float x,
            float y)
    {
    /**
     * Draws a GlyphVector at (x,y)
     */
+   @Override
    public void drawGlyphVector(GlyphVector g, float x, float y)
    {
      Shape shape = g.getOutline(x, y);
    /**
     * Fills a Shape on the EPS document.
     */
+   @Override
    public void fill(Shape s)
    {
      draw(s, "fill");
     * Checks whether or not the specified Shape intersects the specified
     * Rectangle, which is in device space.
     */
+   @Override
    public boolean hit(Rectangle rect, Shape s, boolean onStroke)
    {
      return s.intersects(rect);
    /**
     * Returns the device configuration associated with this EpsGraphics2D object.
     */
+   @Override
    public GraphicsConfiguration getDeviceConfiguration()
    {
      GraphicsConfiguration gc = null;
     * Sets the Composite to be used by this EpsGraphics2D. EpsGraphics2D does not
     * make use of these.
     */
+   @Override
    public void setComposite(Composite comp)
    {
      _composite = comp;
     * Sets the Paint attribute for the EpsGraphics2D object. Only Paint objects
     * of type Color are respected by EpsGraphics2D.
     */
+   @Override
    public void setPaint(Paint paint)
    {
      _paint = paint;
     * Sets the stroke. Only accepts BasicStroke objects (or subclasses of
     * BasicStroke).
     */
+   @Override
    public void setStroke(Stroke s)
    {
      if (s instanceof BasicStroke)
    /**
     * Sets a rendering hint. These are not used by EpsGraphics2D.
     */
+   @Override
    public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
    {
      // Do nothing.
     * Returns the value of a single preference for the rendering algorithms.
     * Rendering hints are not used by EpsGraphics2D.
     */
+   @Override
    public Object getRenderingHint(RenderingHints.Key hintKey)
    {
      return null;
    /**
     * Sets the rendering hints. These are ignored by EpsGraphics2D.
     */
+   @Override
    public void setRenderingHints(Map hints)
    {
      // Do nothing.
    /**
     * Adds rendering hints. These are ignored by EpsGraphics2D.
     */
+   @Override
    public void addRenderingHints(Map hints)
    {
      // Do nothing.
    /**
     * Returns the preferences for the rendering algorithms.
     */
+   @Override
    public RenderingHints getRenderingHints()
    {
      return new RenderingHints(null);
     * Translates the origin of the EpsGraphics2D context to the point (x,y) in
     * the current coordinate system.
     */
+   @Override
    public void translate(int x, int y)
    {
      translate((double) x, (double) y);
     * Concatenates the current EpsGraphics2D Transformation with a translation
     * transform.
     */
+   @Override
    public void translate(double tx, double ty)
    {
      transform(AffineTransform.getTranslateInstance(tx, ty));
    /**
     * Concatenates the current EpsGraphics2D Transform with a rotation transform.
     */
+   @Override
    public void rotate(double theta)
    {
      rotate(theta, 0, 0);
     * Concatenates the current EpsGraphics2D Transform with a translated rotation
     * transform.
     */
+   @Override
    public void rotate(double theta, double x, double y)
    {
      transform(AffineTransform.getRotateInstance(theta, x, y));
     * Concatenates the current EpsGraphics2D Transform with a scaling
     * transformation.
     */
+   @Override
    public void scale(double sx, double sy)
    {
      transform(AffineTransform.getScaleInstance(sx, sy));
    /**
     * Concatenates the current EpsGraphics2D Transform with a shearing transform.
     */
+   @Override
    public void shear(double shx, double shy)
    {
      transform(AffineTransform.getShearInstance(shx, shy));
     * Composes an AffineTransform object with the Transform in this EpsGraphics2D
     * according to the rule last-specified-first-applied.
     */
+   @Override
    public void transform(AffineTransform Tx)
    {
      _transform.concatenate(Tx);
    /**
     * Sets the AffineTransform to be used by this EpsGraphics2D.
     */
+   @Override
    public void setTransform(AffineTransform Tx)
    {
      if (Tx == null)
    /**
     * Gets the AffineTransform used by this EpsGraphics2D.
     */
+   @Override
    public AffineTransform getTransform()
    {
      return new AffineTransform(_transform);
    /**
     * Returns the current Paint of the EpsGraphics2D object.
     */
+   @Override
    public Paint getPaint()
    {
      return _paint;
    /**
     * returns the current Composite of the EpsGraphics2D object.
     */
+   @Override
    public Composite getComposite()
    {
      return _composite;
    /**
     * Sets the background color to be used by the clearRect method.
     */
+   @Override
    public void setBackground(Color color)
    {
      if (color == null)
    /**
     * Gets the background color that is used by the clearRect method.
     */
+   @Override
    public Color getBackground()
    {
      return _backgroundColor;
     * Returns the Stroke currently used. Guaranteed to be an instance of
     * BasicStroke.
     */
+   @Override
    public Stroke getStroke()
    {
      return _stroke;
     * Intersects the current clip with the interior of the specified Shape and
     * sets the clip to the resulting intersection.
     */
+   @Override
    public void clip(Shape s)
    {
      if (_clip == null)
    /**
     * Returns the FontRenderContext.
     */
+   @Override
    public FontRenderContext getFontRenderContext()
    {
      return _fontRenderContext;
    /**
     * Returns a new Graphics object that is identical to this EpsGraphics2D.
     */
+   @Override
    public Graphics create()
    {
      return new EpsGraphics2D(this);
     * Returns an EpsGraphics2D object based on this Graphics object, but with a
     * new translation and clip area.
     */
+   @Override
    public Graphics create(int x, int y, int width, int height)
    {
      Graphics g = create();
     * Returns the current Color. This will be a default value (black) until it is
     * changed using the setColor method.
     */
+   @Override
    public Color getColor()
    {
      return _color;
    /**
     * Sets the Color to be used when drawing all future shapes, text, etc.
     */
+   @Override
    public void setColor(Color c)
    {
      if (c == null)
     * Sets the paint mode of this EpsGraphics2D object to overwrite the
     * destination EpsDocument with the current color.
     */
+   @Override
    public void setPaintMode()
    {
      // Do nothing - paint mode is the only method supported anyway.
     * <b><i><font color="red">Not implemented</font></i></b> - performs no
     * action.
     */
+   @Override
    public void setXORMode(Color c1)
    {
      methodNotSupported();
    /**
     * Returns the Font currently being used.
     */
+   @Override
    public Font getFont()
    {
      return _font;
    /**
     * Sets the Font to be used in future text.
     */
+   @Override
    public void setFont(Font font)
    {
      if (font == null)
        font = Font.decode(null);
      }
      _font = font;
-     append("/" + _font.getPSName() + " findfont " + ((int) _font.getSize())
+     append("/" + _font.getPSName() + " findfont " + (_font.getSize())
              + " scalefont setfont");
    }
  
    /**
     * Gets the font metrics of the current font.
     */
+   @Override
    public FontMetrics getFontMetrics()
    {
      return getFontMetrics(getFont());
    /**
     * Gets the font metrics for the specified font.
     */
+   @Override
    public FontMetrics getFontMetrics(Font f)
    {
      BufferedImage image = new BufferedImage(1, 1,
    /**
     * Returns the bounding rectangle of the current clipping area.
     */
+   @Override
    public Rectangle getClipBounds()
    {
      if (_clip == null)
    /**
     * Intersects the current clip with the specified rectangle.
     */
+   @Override
    public void clipRect(int x, int y, int width, int height)
    {
      clip(new Rectangle(x, y, width, height));
    /**
     * Sets the current clip to the rectangle specified by the given coordinates.
     */
+   @Override
    public void setClip(int x, int y, int width, int height)
    {
      setClip(new Rectangle(x, y, width, height));
    /**
     * Gets the current clipping area.
     */
+   @Override
    public Shape getClip()
    {
      if (_clip == null)
    /**
     * Sets the current clipping area to an arbitrary clip shape.
     */
+   @Override
    public void setClip(Shape clip)
    {
      if (clip != null)
     * <b><i><font color="red">Not implemented</font></i></b> - performs no
     * action.
     */
+   @Override
    public void copyArea(int x, int y, int width, int height, int dx, int dy)
    {
      methodNotSupported();
    /**
     * Draws a straight line from (x1,y1) to (x2,y2).
     */
+   @Override
    public void drawLine(int x1, int y1, int x2, int y2)
    {
      Shape shape = new Line2D.Float(x1, y1, x2, y2);
    /**
     * Fills a rectangle with top-left corner placed at (x,y).
     */
+   @Override
    public void fillRect(int x, int y, int width, int height)
    {
      Shape shape = new Rectangle(x, y, width, height);
    /**
     * Draws a rectangle with top-left corner placed at (x,y).
     */
+   @Override
    public void drawRect(int x, int y, int width, int height)
    {
      Shape shape = new Rectangle(x, y, width, height);
     * Clears a rectangle with top-left corner placed at (x,y) using the current
     * background color.
     */
+   @Override
    public void clearRect(int x, int y, int width, int height)
    {
      Color originalColor = getColor();
    /**
     * Draws a rounded rectangle.
     */
+   @Override
    public void drawRoundRect(int x, int y, int width, int height,
            int arcWidth, int arcHeight)
    {
    /**
     * Fills a rounded rectangle.
     */
+   @Override
    public void fillRoundRect(int x, int y, int width, int height,
            int arcWidth, int arcHeight)
    {
    /**
     * Draws an oval.
     */
+   @Override
    public void drawOval(int x, int y, int width, int height)
    {
      Shape shape = new Ellipse2D.Float(x, y, width, height);
    /**
     * Fills an oval.
     */
+   @Override
    public void fillOval(int x, int y, int width, int height)
    {
      Shape shape = new Ellipse2D.Float(x, y, width, height);
    /**
     * Draws an arc.
     */
+   @Override
    public void drawArc(int x, int y, int width, int height, int startAngle,
            int arcAngle)
    {
    /**
     * Fills an arc.
     */
+   @Override
    public void fillArc(int x, int y, int width, int height, int startAngle,
            int arcAngle)
    {
    /**
     * Draws a polyline.
     */
+   @Override
    public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
    {
      if (nPoints > 0)
    /**
     * Draws a polygon made with the specified points.
     */
+   @Override
    public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
    {
      Shape shape = new Polygon(xPoints, yPoints, nPoints);
    /**
     * Draws a polygon.
     */
+   @Override
    public void drawPolygon(Polygon p)
    {
      draw(p);
    /**
     * Fills a polygon made with the specified points.
     */
+   @Override
    public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
    {
      Shape shape = new Polygon(xPoints, yPoints, nPoints);
    /**
     * Fills a polygon.
     */
+   @Override
    public void fillPolygon(Polygon p)
    {
      draw(p, "fill");
    /**
     * Draws the specified characters, starting from (x,y)
     */
+   @Override
    public void drawChars(char[] data, int offset, int length, int x, int y)
    {
      String string = new String(data, offset, length);
    /**
     * Draws the specified bytes, starting from (x,y)
     */
+   @Override
    public void drawBytes(byte[] data, int offset, int length, int x, int y)
    {
      String string = new String(data, offset, length);
    /**
     * Draws an image.
     */
+   @Override
    public boolean drawImage(Image img, int x, int y, ImageObserver observer)
    {
      return drawImage(img, x, y, Color.white, observer);
    /**
     * Draws an image.
     */
+   @Override
    public boolean drawImage(Image img, int x, int y, int width, int height,
            ImageObserver observer)
    {
    /**
     * Draws an image.
     */
+   @Override
    public boolean drawImage(Image img, int x, int y, Color bgcolor,
            ImageObserver observer)
    {
    /**
     * Draws an image.
     */
+   @Override
    public boolean drawImage(Image img, int x, int y, int width, int height,
            Color bgcolor, ImageObserver observer)
    {
    /**
     * Draws an image.
     */
+   @Override
    public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
            int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
    {
    /**
     * Draws an image.
     */
+   @Override
    public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
            int sx1, int sy1, int sx2, int sy2, Color bgcolor,
            ImageObserver observer)
     * only remaining EpsGraphics2D instance pointing at a EpsDocument object,
     * then the EpsDocument object shall become eligible for garbage collection.
     */
+   @Override
    public void dispose()
    {
      _document = null;
    }
  
+   /* bsoares 2019-03-20
+    * finalize is now deprecated. Implementing AutoCloseable instead
    /**
     * Finalizes the object.
-    */
+   @Override
    public void finalize()
    {
      super.finalize();
    }
+    */
  
    /**
     * Returns the entire contents of the EPS document, complete with headers and
     * bounding box. The returned String is suitable for being written directly to
     * disk as an EPS file.
     */
+   @Override
    public String toString()
    {
      StringWriter writer = new StringWriter();
     * Returns true if the specified rectangular area might intersect the current
     * clipping area.
     */
+   @Override
    public boolean hitClip(int x, int y, int width, int height)
    {
      if (_clip == null)
    /**
     * Returns the bounding rectangle of the current clipping area.
     */
+   @Override
    public Rectangle getClipBounds(Rectangle r)
    {
      if (_clip == null)
@@@ -75,6 -75,7 +75,7 @@@ public class VCFLoaderTes
      Cache.loadProperties("test/jalview/io/testProps.jvprops");
      Cache.setProperty("VCF_FIELDS", ".*");
      Cache.setProperty("VEP_FIELDS", ".*");
+     Cache.setProperty("VCF_ASSEMBLY", "GRCh38=GRCh38");
      Cache.initLogger();
    }
  
       * verify SNP variant feature(s) computed and added to protein
       * first codon AGC varies to ACC giving S/T
       */
 -    DBRefEntry[] dbRefs = al.getSequenceAt(1).getDBRefs();
 +    List<DBRefEntry> dbRefs = al.getSequenceAt(1).getDBRefs();
      SequenceI peptide = null;
      for (DBRefEntry dbref : dbRefs)
      {
       * verify variant feature(s) computed and added to protein
       * last codon GCT varies to GGT giving A/G in the last peptide position
       */
 -    DBRefEntry[] dbRefs = al.getSequenceAt(3).getDBRefs();
 +    List<DBRefEntry> dbRefs = al.getSequenceAt(3).getDBRefs();
      SequenceI peptide = null;
      for (DBRefEntry dbref : dbRefs)
      {
       * and GAG/GGG which is E/G in position 4
       * the insertion variant is not transferred to the peptide
       */
 -    DBRefEntry[] dbRefs = al.findName("transcript3").getDBRefs();
 +    List<DBRefEntry> dbRefs = al.findName("transcript3").getDBRefs();
      SequenceI peptide = null;
      for (DBRefEntry dbref : dbRefs)
      {