Merge branch 'bug/JAL-2682parseId' into develop
authorJim Procter <jprocter@issues.jalview.org>
Mon, 23 Oct 2017 14:59:30 +0000 (15:59 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Mon, 23 Oct 2017 14:59:30 +0000 (15:59 +0100)
161 files changed:
.ant-targets-build.xml [new file with mode: 0644]
.checkstyle
.gitignore
RELEASE
benchmarking/.classpath [new file with mode: 0644]
benchmarking/.gitignore [new file with mode: 0644]
benchmarking/.settings/org.eclipse.core.resources.prefs [new file with mode: 0644]
benchmarking/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
benchmarking/.settings/org.eclipse.m2e.core.prefs [new file with mode: 0644]
benchmarking/README [new file with mode: 0644]
benchmarking/pom.xml [new file with mode: 0644]
benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java [new file with mode: 0644]
build.xml
examples/groovy/PIDmatrix.groovy [new file with mode: 0644]
help/help.jhm
help/helpTOC.xml
help/html/features/overview.gif [deleted file]
help/html/features/overview.html
help/html/features/overview.png [new file with mode: 0644]
help/html/features/preferences.html
help/html/releases.html
help/html/whatsNew.html
lib/jabaws-min-client-2.2.0.jar
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraResidue.java
src/jalview/api/AlignViewportI.java
src/jalview/api/AlignmentColsCollectionI.java
src/jalview/api/AlignmentRowsCollectionI.java
src/jalview/api/AlignmentViewPanel.java
src/jalview/api/RendererListenerI.java [new file with mode: 0644]
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/AnnotationColourChooser.java
src/jalview/appletgui/AnnotationColumnChooser.java
src/jalview/appletgui/AnnotationLabels.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/AnnotationRowFilter.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/FontChooser.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/OverviewCanvas.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/RedundancyPanel.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqPanel.java
src/jalview/appletgui/SequenceRenderer.java
src/jalview/appletgui/SliderPanel.java
src/jalview/appletgui/SplitFrame.java
src/jalview/appletgui/UserDefinedColours.java
src/jalview/commands/RemoveGapColCommand.java
src/jalview/commands/RemoveGapsCommand.java
src/jalview/controller/AlignViewController.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/AllColsCollection.java
src/jalview/datamodel/AllRowsCollection.java
src/jalview/datamodel/CigarArray.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/datamodel/VisibleColsCollection.java
src/jalview/datamodel/VisibleRowsCollection.java
src/jalview/datamodel/features/SequenceFeatures.java
src/jalview/datamodel/xdb/embl/EmblEntry.java
src/jalview/ext/ensembl/EnsemblGene.java
src/jalview/ext/ensembl/EnsemblGenomes.java
src/jalview/ext/ensembl/EnsemblInfo.java
src/jalview/ext/ensembl/EnsemblLookup.java
src/jalview/ext/ensembl/EnsemblProtein.java
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/ext/ensembl/EnsemblSeqProxy.java
src/jalview/ext/ensembl/EnsemblSymbol.java
src/jalview/ext/ensembl/EnsemblXref.java
src/jalview/ext/ensembl/Species.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/rbvi/chimera/AtomSpecModel.java
src/jalview/fts/service/pdb/PDBFTSPanel.java
src/jalview/fts/service/pdb/PDBFTSRestClient.java
src/jalview/fts/service/uniprot/UniprotFTSPanel.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationChooser.java
src/jalview/gui/AnnotationColourChooser.java
src/jalview/gui/AnnotationColumnChooser.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/AnnotationRowFilter.java
src/jalview/gui/CrossRefAction.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureColourChooser.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/FontChooser.java
src/jalview/gui/IdPanel.java
src/jalview/gui/IdwidthAdjuster.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/OverviewCanvas.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/gui/ProgressPanel.java [new file with mode: 0644]
src/jalview/gui/RedundancyPanel.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SequenceRenderer.java
src/jalview/gui/SliderPanel.java
src/jalview/gui/SplitFrame.java
src/jalview/gui/StructureViewerBase.java
src/jalview/gui/TextColourChooser.java
src/jalview/gui/TreePanel.java
src/jalview/gui/UserDefinedColours.java
src/jalview/io/WSWUBlastClient.java
src/jalview/jbgui/GPreferences.java
src/jalview/jbgui/GStructureChooser.java
src/jalview/renderer/OverviewRenderer.java
src/jalview/renderer/OverviewResColourFinder.java [new file with mode: 0644]
src/jalview/renderer/ResidueColourFinder.java [new file with mode: 0644]
src/jalview/renderer/ResidueShader.java
src/jalview/renderer/seqfeatures/FeatureRenderer.java
src/jalview/schemes/ColourSchemeI.java
src/jalview/schemes/RNAHelicesColourChooser.java
src/jalview/schemes/ResidueColourScheme.java
src/jalview/schemes/UserColourScheme.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/util/Platform.java
src/jalview/util/UrlConstants.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/workers/AnnotationWorker.java
src/jalview/workers/ColumnCounterSetWorker.java
src/jalview/workers/ConsensusThread.java
src/jalview/workers/ConservationThread.java
src/jalview/workers/StrucConsensusThread.java
src/jalview/ws/DasSequenceFeatureFetcher.java
src/jalview/ws/dbsources/EmblXmlSource.java
src/jalview/ws/dbsources/Uniprot.java
src/jalview/ws/ebi/EBIFetchClient.java
src/jalview/ws/jws2/AADisorderClient.java
src/jalview/ws/jws2/AbstractJabaCalcWorker.java
src/jalview/ws/seqfetcher/ASequenceFetcher.java
test/jalview/datamodel/CigarArrayTest.java [new file with mode: 0644]
test/jalview/datamodel/SequenceTest.java
test/jalview/datamodel/features/SequenceFeaturesTest.java
test/jalview/ext/ensembl/EnsemblGeneTest.java
test/jalview/ext/ensembl/EnsemblRestClientTest.java
test/jalview/ext/ensembl/EnsemblSeqProxyTest.java
test/jalview/ext/ensembl/SpeciesTest.java [new file with mode: 0644]
test/jalview/ext/rbvi/chimera/AtomSpecModelTest.java
test/jalview/gui/SequenceRendererTest.java
test/jalview/io/CrossRef2xmlTests.java
test/jalview/renderer/OverviewResColourFinderTest.java [new file with mode: 0644]
test/jalview/renderer/ResidueColourFinderTest.java [new file with mode: 0644]
test/jalview/renderer/ResidueShaderTest.java
test/jalview/renderer/seqfeatures/FeatureColourFinderTest.java
test/jalview/structures/models/AAStructureBindingModelTest.java
test/jalview/ws/ebi/EBIFetchClientTest.java
utils/InstallAnywhere/Jalview.iap_xml
utils/checkstyle/checkstyle-suppress.xml
utils/checkstyle/import-control.xml

diff --git a/.ant-targets-build.xml b/.ant-targets-build.xml
new file mode 100644 (file)
index 0000000..15432a1
--- /dev/null
@@ -0,0 +1,31 @@
+build
+buildPropertiesFile
+buildTests
+buildextclients
+buildindices
+castorbinding
+clean
+compileApplet
+distclean
+help
+init
+linkcheck
+makeApplet
+makedist
+makefulldist
+obfuscate
+packageApplet
+prepare
+prepareTests
+preparejnlp
+prepubapplet_1
+pubapplet
+runenv
+signApplet
+sourcedist
+sourcedoc
+sourcescrub
+testclean
+testng
+usage
+writejnlpf
index 0329bb7..a87fa04 100644 (file)
@@ -8,5 +8,4 @@
     <file-match-pattern match-pattern="src/.*.java" include-pattern="true"/>
     <file-match-pattern match-pattern="resources/.*.properties" include-pattern="true"/>
   </fileset>
-  <filter name="NonSrcDirs" enabled="false"/>
 </fileset-config>
index bfd5da9..2a55560 100644 (file)
@@ -11,3 +11,5 @@
 .gitattributes
 TESTNG
 /jalviewApplet.jar
+/benchmarking/lib
+*.class
\ No newline at end of file
diff --git a/RELEASE b/RELEASE
index 0229909..cecefec 100644 (file)
--- a/RELEASE
+++ b/RELEASE
@@ -1,2 +1,2 @@
-jalview.release=releases/Release_2_10_2_Branch
-jalview.version=2.10.2b1
+jalview.release=releases/Release_2_10_2b1_Branch
+jalview.version=2.10.2b2
diff --git a/benchmarking/.classpath b/benchmarking/.classpath
new file mode 100644 (file)
index 0000000..131ff24
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="target/classes" path="src/main/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry combineaccessrules="false" kind="src" path="/Jalview Release 2.7"/>
+       <classpathentry kind="lib" path="/Jalview Release 2.7/jalviewApplet.jar"/>
+       <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/benchmarking/.gitignore b/benchmarking/.gitignore
new file mode 100644 (file)
index 0000000..f4da43d
--- /dev/null
@@ -0,0 +1,6 @@
+/target/
+/bin
+/results
+*.log
+*.json
+*~
diff --git a/benchmarking/.settings/org.eclipse.core.resources.prefs b/benchmarking/.settings/org.eclipse.core.resources.prefs
new file mode 100644 (file)
index 0000000..e9441bb
--- /dev/null
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding/<project>=UTF-8
diff --git a/benchmarking/.settings/org.eclipse.jdt.core.prefs b/benchmarking/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..714351a
--- /dev/null
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/benchmarking/.settings/org.eclipse.m2e.core.prefs b/benchmarking/.settings/org.eclipse.m2e.core.prefs
new file mode 100644 (file)
index 0000000..f897a7f
--- /dev/null
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/benchmarking/README b/benchmarking/README
new file mode 100644 (file)
index 0000000..60b94a9
--- /dev/null
@@ -0,0 +1,25 @@
+To set up benchmarking:
+
+1. In the jalview directory run 
+  ant makedist
+
+This builds a jalview.jar file and puts it into dist/
+
+2. Make a lib directory in benchmarking/ if not already present.
+
+3. Purge any previous maven dependencies:
+   mvn dependency:purge-local-repository -DactTransitively=false -DreResolve=false
+
+4. Run
+  mvn install:install-file -Dfile=../dist/jalview.jar -DgroupId=jalview.org -DartifactId=jalview -Dversion=1.0 -Dpackaging=jar -DlocalRepositoryPath=lib
+
+to install the jalview.jar file in the local maven repository. The pom.xml in the benchmarking references this installation, so if you change the names the pom.xml file will also need to be updated.
+
+5. Build and run jmh benchmarking. In the benchmarking directory:
+  mvn clean install
+  java -jar target/benchmarks.jar
+  
+  To get JSON output instead use:
+  java -jar target/benchmarks.jar -rf json
+  
+  JSON output can be viewed quickly by drag-dropping on http://jmh.morethan.io/
\ No newline at end of file
diff --git a/benchmarking/pom.xml b/benchmarking/pom.xml
new file mode 100644 (file)
index 0000000..3bced18
--- /dev/null
@@ -0,0 +1,183 @@
+<!--
+Copyright (c) 2014, Oracle America, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Oracle nor the names of its contributors may be used
+   to endorse or promote products derived from this software without
+   specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.jalview</groupId>
+    <artifactId>benchmarking</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <name>JMH benchmark sample: Java</name>
+
+    <!--
+       This is the demo/sample template build script for building Java benchmarks with JMH.
+       Edit as needed.
+    -->
+
+       <repositories>
+               <repository>
+               <id>lib</id>
+               <url>file://${project.basedir}/lib</url>
+               </repository>
+       </repositories>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.openjdk.jmh</groupId>
+            <artifactId>jmh-core</artifactId>
+            <version>${jmh.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openjdk.jmh</groupId>
+            <artifactId>jmh-generator-annprocess</artifactId>
+            <version>${jmh.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+               <groupId>jalview.org</groupId>
+               <artifactId>jalview</artifactId>
+               <version>1.0</version>
+        </dependency>
+    </dependencies>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
+        <!--
+            JMH version to use with this project.
+          -->
+        <jmh.version>1.19</jmh.version>
+
+        <!--
+            Java source/target to use for compilation.
+          -->
+        <javac.target>1.8</javac.target>
+
+        <!--
+            Name of the benchmark Uber-JAR to generate.
+          -->
+        <uberjar.name>benchmarks</uberjar.name>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <compilerVersion>${javac.target}</compilerVersion>
+                    <source>${javac.target}</source>
+                    <target>${javac.target}</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.2</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <finalName>${uberjar.name}</finalName>
+                            <transformers>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <mainClass>org.openjdk.jmh.Main</mainClass>
+                                </transformer>
+                            </transformers>
+                            <filters>
+                                <filter>
+                                    <!--
+                                        Shading signed JARs will fail without this.
+                                        http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar
+                                    -->
+                                    <artifact>*:*</artifact>
+                                    <excludes>
+                                        <exclude>META-INF/*.SF</exclude>
+                                        <exclude>META-INF/*.DSA</exclude>
+                                        <exclude>META-INF/*.RSA</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <artifactId>maven-clean-plugin</artifactId>
+                    <version>2.5</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-deploy-plugin</artifactId>
+                    <version>2.8.1</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-install-plugin</artifactId>
+                    <version>2.5.1</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-jar-plugin</artifactId>
+                    <version>2.4</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-javadoc-plugin</artifactId>
+                    <version>2.9.1</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-resources-plugin</artifactId>
+                    <version>2.6</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-site-plugin</artifactId>
+                    <version>3.3</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-source-plugin</artifactId>
+                    <version>2.2.1</version>
+                </plugin>
+                <plugin>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>2.17</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+</project>
diff --git a/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java b/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java
new file mode 100644 (file)
index 0000000..eb35e3b
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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 org.jalview;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Param;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
+
+/*
+ * A class to benchmark hidden columns performance
+ */
+@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
+@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
+@Fork(1)
+public class HiddenColumnsBenchmark 
+{      
+       /*
+        * State with multiple hidden columns and a start position set
+        */
+       @State(Scope.Thread)
+       public static class HiddenColsAndStartState
+       {
+               @Param({"300", "10000", "100000"})
+               public int maxcols;
+               
+               @Param({"1", "50", "90"})
+               public int startpcnt; // position as percentage of maxcols
+               
+               @Param({"1","15","100"})
+               public int hide;
+               
+               HiddenColumns h = new HiddenColumns();
+               Random rand = new Random();
+               
+               public int hiddenColumn;
+               public int visibleColumn;
+       
+               @Setup
+               public void setup()
+               {
+                       rand.setSeed(1234);
+                       int lastcol = 0;
+               while (lastcol < maxcols)
+               {
+                       int count = rand.nextInt(100); 
+                       lastcol += count;
+                       h.hideColumns(lastcol, lastcol+hide);
+                       lastcol+=hide;
+               }
+               
+               // make sure column at start is hidden
+               hiddenColumn = (int)(maxcols * startpcnt/100.0);
+               h.hideColumns(hiddenColumn, hiddenColumn);
+               
+               // and column <hide> after start is visible
+               ColumnSelection sel = new ColumnSelection();
+               h.revealHiddenColumns(hiddenColumn+hide, sel);
+               visibleColumn = hiddenColumn+hide;
+               
+               System.out.println("Maxcols: " + maxcols + " HiddenCol: " + hiddenColumn + " Hide: " + hide);
+               System.out.println("Number of hidden columns: " + h.getSize());
+               }
+       }
+       
+       /* Convention: functions in alphabetical order */
+       
+       @Benchmark
+       @BenchmarkMode({Mode.Throughput})
+       public int benchAdjustForHiddenColumns(HiddenColsAndStartState tstate)
+       {
+               return tstate.h.adjustForHiddenColumns(tstate.visibleColumn);
+       }
+       
+       @Benchmark
+       @BenchmarkMode({Mode.Throughput})
+       public int benchFindColumnPosition(HiddenColsAndStartState tstate)
+       {
+               return tstate.h.findColumnPosition(tstate.visibleColumn);
+       }
+       
+       @Benchmark
+       @BenchmarkMode({Mode.Throughput})
+       public List<Integer> benchFindHiddenRegionPositions(HiddenColsAndStartState tstate)
+       {
+               return tstate.h.findHiddenRegionPositions();
+       }
+       
+       @Benchmark
+       @BenchmarkMode({Mode.Throughput})
+       public ArrayList<int[]> benchGetHiddenColumnsCopy(HiddenColsAndStartState tstate)
+       {
+               return tstate.h.getHiddenColumnsCopy();
+       }
+       
+       
+       @Benchmark
+       @BenchmarkMode({Mode.Throughput})
+    public int benchGetSize(HiddenColsAndStartState tstate)
+    {
+               return tstate.h.getSize();
+    }
+
+   @Benchmark
+    @BenchmarkMode({Mode.Throughput})
+    public HiddenColumns benchHideCols(HiddenColsAndStartState tstate) 
+    {
+       tstate.h.hideColumns(tstate.visibleColumn,
+                       tstate.visibleColumn+2000); 
+       return tstate.h;
+    }
+   
+       @Benchmark
+       @BenchmarkMode({Mode.Throughput})
+    public boolean benchIsVisible(HiddenColsAndStartState tstate) 
+    {
+       return tstate.h.isVisible(tstate.hiddenColumn); 
+    }
+       
+       @Benchmark
+       @BenchmarkMode({Mode.Throughput})
+    public HiddenColumns benchReveal(HiddenColsAndStartState tstate) 
+    {
+               ColumnSelection sel = new ColumnSelection();
+       tstate.h.revealHiddenColumns(tstate.hiddenColumn, sel);
+       return tstate.h;
+    }
+       
+       @Benchmark
+       @BenchmarkMode({Mode.Throughput})
+    public HiddenColumns benchRevealAll(HiddenColsAndStartState tstate) 
+    {
+               ColumnSelection sel = new ColumnSelection();
+       tstate.h.revealAllHiddenColumns(sel);
+       return tstate.h;
+    }
+       
+       
+}
\ No newline at end of file
index 9e21593..f39fdf3 100755 (executable)
--- a/build.xml
+++ b/build.xml
           <offline_allowed />
         </information>
         <resources>
-          <j2se version="9+" />
+          <j2se version="1.7+" />
           <jar main="true" href="jalview.jar"/>
           <fileset dir="${packageDir}">
             <exclude name="jalview.jar" />
     </presetdef>
 
     <jnlpf toFile="${jnlpFile}" />
-    <!-- add a j2se entry for java 9 -->
-    <replace file="${jnlpFile}" value="j2se version=&quot;7+&quot; initial-heap-size=&quot;${inih}&quot; max-heap-size=&quot;${maxh}&quot; java-vm-args=&quot;--add-modules=java.se.ee&quot;">
-          <replacetoken>j2se version="9+"</replacetoken>
+    <!-- add the add-modules j2se attribute for java 9 -->
+    <replace file="${jnlpFile}" value="j2se version=&quot;1.7+&quot; initial-heap-size=&quot;${inih}&quot; max-heap-size=&quot;${maxh}&quot; java-vm-args=&quot;--add-modules=java.se.ee&quot;">
+          <replacetoken>j2se version="1.7+"</replacetoken>
            
         </replace>
   </target>
diff --git a/examples/groovy/PIDmatrix.groovy b/examples/groovy/PIDmatrix.groovy
new file mode 100644 (file)
index 0000000..b97abcc
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+import jalview.analysis.scoremodels.ScoreModels
+import jalview.analysis.scoremodels.SimilarityParams
+
+// generate matrix for current selection using standard Jalview PID
+
+printSimilarityMatrix(true,true,SimilarityParams.Jalview)
+
+/** 
+ * this function prints a sequence similarity matrix in PHYLIP format. 
+ * printSimilarityMatrix(selected-only, include-ids, pidMethod)
+ * 
+ * Allowed values for pidMethod:
+ * 
+ * Jalview's Comparison.PID method includes matching gaps 
+ * and counts over the length of the shorter gapped sequence
+ * SimilarityParams.Jalview;
+ *
+ * 'SeqSpace' mode PCA calculation does not count matching 
+ * gaps but uses longest gapped sequence length
+ *  SimilarityParams.SeqSpace;
+ *
+ * PID calcs from the Raghava-Barton paper
+ * SimilarityParams.PID1: ignores gap-gap, does not score gap-residue,
+ * includes gap-residue in lengths, matches on longer of two sequences.
+ * 
+ * SimilarityParams.PID2: ignores gap-gap,ignores gap-residue, 
+ * matches on longer of two sequences
+ * 
+ * SimilarityParams.PID3: ignores gap-gap,ignores gap-residue, 
+ * matches on shorter of sequences only
+ * 
+ * SimilarityParams.PID4: ignores gap-gap,does not score gap-residue,
+ * includes gap-residue in lengths,matches on shorter of sequences only.
+ */
+
+void printSimilarityMatrix(boolean selview=false, boolean includeids=true, SimilarityParams pidMethod) {
+
+  def currentAlignFrame = jalview.bin.Jalview.getCurrentAlignFrame()
+
+  jalview.gui.AlignViewport av = currentAlignFrame.getCurrentView()
+
+  jalview.datamodel.AlignmentView seqStrings = av.getAlignmentView(selview)
+
+  if (!selview || av.getSelectionGroup()==null) {
+    start = 0
+    end = av.getAlignment().getWidth()
+    seqs = av.getAlignment().getSequencesArray()
+  } else {
+    start = av.getSelectionGroup().getStartRes()
+    end = av.getSelectionGroup().getEndRes() + 1
+    seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment())
+  }
+
+  distanceCalc = ScoreModels.getInstance().getScoreModel("PID",
+      (jalview.api.AlignmentViewPanel) currentAlignFrame.alignPanel)
+
+  def distance=distanceCalc.findSimilarities(
+      seqStrings.getSequenceStrings(jalview.util.Comparison.GAP_DASH),pidMethod)
+
+  // output the PHYLIP Matrix
+
+  print distance.width()+" "+distance.height()+"\n"
+
+  p = 0
+
+  for (v in 1..distance.height()) {
+
+    if (includeids) {
+      print seqs[p++].getDisplayId(false)+" "
+    }
+
+    for (r in 1..distance.width()) {
+      print distance.getValue(v-1,r-1)+" "
+    }
+
+    print "\n"
+  }
+}
\ No newline at end of file
index c12436f..010bca8 100755 (executable)
@@ -22,7 +22,7 @@
    <mapID target="home" url="html/index.html" />
    
    <mapID target="new" url="html/whatsNew.html"/>
-   <mapID target="release" url="html/releases.html#Jalview.2.10.2b1"/>
+   <mapID target="release" url="html/releases.html#Jalview.2.10.3"/>
    <mapID target="alannotation" url="html/features/annotation.html"/>
    <mapID target="keys" url="html/keys.html"/>
    <mapID target="newkeys" url="html/features/newkeystrokes.html"/>
    <mapID target="printSetupIcon" url="icons/setup.png" />
    
    <mapID target="overview" url="html/features/overview.html" />
+   <mapID target="overviewprefs" url="html/features/preferences.html#overview" />
 </map>
index f3311a7..4636ea3 100755 (executable)
@@ -28,6 +28,7 @@
                                <tocitem text="Groovy Features Counter example" target="groovy.featurescounter"/>
                                <tocitem text="Custom Colourschemes in Groovy" target="groovy.colours"/>
                                <tocitem text="Omit hidden regions in Overview" target="overview"/>
+                               <tocitem text="Show gaps as grey in overview" target="overviewprefs"/>
                                <tocitem text="identifers.org for URL Links" target="linksprefs" />
                                <tocitem text="New features in Split Frame View" target="splitframe.mirrorfonts" />
                </tocitem>
diff --git a/help/html/features/overview.gif b/help/html/features/overview.gif
deleted file mode 100755 (executable)
index b5b1bc5..0000000
Binary files a/help/html/features/overview.gif and /dev/null differ
index ac5aecb..6401fdd 100755 (executable)
     <strong>View&#8594;Overview window</strong>
   </p>
   <p>Select the overview window menu item to get a navigable image
-    of the whole alignment.</p>
+    of the whole alignment. By default, gaps are shown as dark grey, in
+    the overview (since 2.10.2b1).</p>
   <p>The red box indicates the currently viewed region of the
     alignment, this may be moved by clicking and dragging with the
     mouse.</p>
   <p>Click anywhere else in the overview to centre the view on that
     position</p>
-    <p></p>
+  <p></p>
   <p>
     <strong>Hiding hidden regions in the overview</strong>
   </p>
     Hidden sequences and columns are by default shown as dark-grey rows
     and columns in the overview. Hidden regions can also be omitted
     entirely (to make the Overview 'WYSIWIG') by <strong>Right-clicking</strong>
-    (or CMD-Clicking) to open the overview's popup menu.<br />
-    <br /> <em>The option to include/exclude hidden regions in the
+    (or CMD-Clicking) to open the overview's popup menu.<br /> <br />
+    <em>The option to include/exclude hidden regions in the
       overview was introduced in Jalview 2.10.2</em>.
   
   <p>
-    <img src="overview.gif" width="407" height="137">
+    <img src="overview.png" width="800" height="196" alt="1hdc.pfam example alignment">
   </p>
   <p>&nbsp;</p>
+  <em>Previous to 2.10.2b1, gaps were white, and sequences shown as
+    dark grey unless coloured.</em>
 </body>
 </html>
diff --git a/help/html/features/overview.png b/help/html/features/overview.png
new file mode 100644 (file)
index 0000000..d7aaa19
Binary files /dev/null and b/help/html/features/overview.png differ
index acd7ba6..b29b66b 100755 (executable)
@@ -41,6 +41,9 @@
         Preferences</a> tab allows you to configure default colourschemes
       for a new alignment window.
     </li>
+    <li>The <a href="#overview"><strong>&quot;Overview&quot;</strong>
+        Preferences</a> tab configures defaults for the overview window.
+    </li>
     <li>The <a href="#structure"><strong>&quot;Structure&quot;</strong>
         Preferences</a> tab allows you to configure options for obtaining
       and displaying structure information.
       by Annotation...</a> is selected from the alignment window's colours
     menu.
   </p>
+   <p>
+    <a name="overview"><strong>&quot;Overview&quot;
+        Preferences tab</strong>
+  </p>
+  <p>
+    <em>Use legacy gap colouring (gaps are white)</em> - when enabled,
+    Jalview's overview shows gaps as white, and sequences with no
+    colourscheme applied as grey.
+  </p>
+  <p>
+    <em>Show Hidden regions when opening overview</em> - default setting
+    for inclusion of hidden regions.
+  </p>
+  <p>
+    <em>Gap Colour</em> - When legacy gap colouring is not enabled, this
+    configures the default colour for gaps in the overview.
+  </p>
+  <p>
+    <em>Hidden Colour</em> - colour used to highlight regions in the
+    overview that are hidden in the alignment.
+  </p>
+  <p>
+    <em>Gap Colour</em> - The default colour scheme for a new alignment
+    window. If the chosen option is &quot;User Defined&quot; then the
+    last User Defined Colour loaded or saved via the User Defined
+    Colours panel will be loaded.
+  </p>
   <p>
     <a name="structure"><strong>&quot;Structure&quot;
         Preferences tab</strong></a><em> added in Jalview 2.8.2</em>
index c331ae1..9749f91 100755 (executable)
@@ -70,21 +70,141 @@ li:before {
     <tr>
       <td width="60" nowrap>
         <div align="center">
+          <strong><a name="Jalview.2.10.3">2.10.3</a><br />
+            <em>10/10/2017</em></strong>
+        </div>
+      </td>
+      <td><div align="left">
+          <em></em>
+          <ul>
+            <li>
+              <!-- JAL-2446 -->Faster and more efficient management and
+              rendering of sequence features
+            </li>
+            <li>
+              <!-- JAL 2523-->More reliable Ensembl fetching with HTTP
+              429 rate limit request hander
+            </li>
+            <li>
+              <!-- JAL-2773 -->Structure views don't get updated unless
+              their colours have changed
+            </li>
+          </ul>
+          <ul><li>Example groovy script for generating a matrix of percent identity scores for current alignment.</li></ul>
+      </td>
+      <td><div align="left">
+          <em></em>
+          <ul>
+            <li><!-- JAL-2777 -->Structures with whitespace chainCode cannot be viewed in Chimera</li>
+            <li><!-- JAL-2728 -->Protein annotation panel too high in CDS/Protein view
+            </li> 
+            <li><!-- JAL-2757 -->Can't edit the query after the server error warning icon is shown in Uniprot and PDB Free Text Search Dialogs
+            </li> 
+            <li><!-- JAL-2253 -->Slow EnsemblGenome ID lookup</li>
+          </ul>
+      </td>
+    </tr>
+    <tr>
+      <td width="60" nowrap>
+        <div align="center">
+          <strong><a name="Jalview.2.10.2b2">2.10.2b2</a><br />
+            <em>2/10/2017</em></strong>
+        </div>
+      </td>
+      <td><div align="left">
+          <em>New features in Jalview Desktop</em>
+          <ul>
+            <li>
+              <!-- JAL-2748 -->Uniprot Sequence Fetcher now uses web API at uniprot.org 
+            </li>
+            <li>  <!-- JAL-2745 -->HTTPS used for all connections to ebi.ac.uk 
+            </li>
+          </ul>
+        </div></td>
+      <td><div align="left">
+        </div></td>
+    </tr>
+    <tr>
+      <td width="60" nowrap>
+        <div align="center">
           <strong><a name="Jalview.2.10.2b1">2.10.2b1</a><br />
-            <em>TBA</em></strong>
+            <em>7/9/2017</em></strong>
         </div>
       </td>
       <td><div align="left">
           <em></em>
           <ul>
+            <li>
+              <!-- JAL-2588 -->Show gaps in overview window by colouring
+              in grey (sequences used to be coloured grey, and gaps were
+              white)
+            </li>
+            <li>
+              <!-- JAL-2588,JAL-2527 -->Overview tab in Jalview Desktop
+              Preferences
+            </li>
+            <li>
+              <!-- JAL-2587 -->Overview updates immediately on increase
+              in size and progress bar shown as higher resolution
+              overview is recalculated
+            </li>
+
           </ul>
         </div></td>
       <td><div align="left">
           <em></em>
           <ul>
+            <li>
+              <!-- JAL-2664 -->Overview window redraws every hidden
+              column region row by row
+            </li>
+            <li>
+              <!-- JAL-2681 -->duplicate protein sequences shown after
+              retrieving Ensembl crossrefs for sequences from Uniprot
+            </li>
+            <li>
+              <!-- JAL-2603 -->Overview window throws NPE if show boxes
+              format setting is unticked
+            </li>
+            <li>
+              <!-- JAL-2610 -->Groups are coloured wrongly in overview
+              if group has show boxes format setting unticked
+            </li>
+            <li>
+              <!-- JAL-2672,JAL-2665 -->Redraw problems when
+              autoscrolling whilst dragging current selection group to
+              include sequences and columns not currently displayed
+            </li>
+            <li>
+              <!-- JAL-2691 -->Not all chains are mapped when multimeric
+              assemblies are imported via CIF file
+            </li>
+            <li>
+              <!-- JAL-2704 -->Gap colour in custom colourscheme is not
+              displayed when threshold or conservation colouring is also
+              enabled.
+            </li>
+            <li>
+              <!-- JAL-2549 -->JABAWS 2.2 services report wrong JABAWS
+              server version
+            </li>
+            <li>
+              <!-- JAL-2673 -->Jalview continues to scroll after
+              dragging a selected region off the visible region of the
+              alignment
+            </li>
+            <li>
+              <!-- JAL-2724 -->Cannot apply annotation based
+              colourscheme to all groups in a view
+            </li>
+            <li>
+              <!-- JAL-2511 -->IDs don't line up with sequences
+              initially after font size change using the Font chooser or
+              middle-mouse zoom
+            </li>
           </ul>
         </div></td>
-    
+    </tr>
     <tr>
       <td width="60" nowrap>
         <div align="center">
index c002eb8..3475012 100755 (executable)
 </head>
 <body>
   <p>
-  <strong>Jalview 2.10.2b1 bugfix release</strong>
+    <strong>What's new in Jalview 2.10.3 ?</strong>
   </p>
   <p>
-    This is patch release for 2.10.2. See the <a
-      href="releases.html#Jalview.2.10.2b1">release notes</a>.
-  </p>
-  <p>
-    <strong>What's new in Jalview 2.10.2 ?</strong>
-  </p>
-  <p>
-    Version 2.10.2 was released in August 2017, and introduced new user
-    interface features, improved and more extensible tree and PCA
-    analysis, more robust 3D structure viewing with UCSF Chimera and an
-    updated service client for JABAWS. The full list of bug fixes and
-    new features can be found in the <a
-      href="releases.html#Jalview.2.10.2"> 2.10.2 Release Notes</a>, but
+    Version 2.10.3 is due for release in October 2017. The full list of
+    bug fixes and new features can be found in the <a
+      href="releases.html#Jalview.2.10.3"> 2.10.3 Release Notes</a>, but
     the highlights are below.
   </p>
-  <ul>
-    <li><strong>New dialog and faster and more
-        configurable Tree and PCA calculations</strong><br> Menu entries for
-      calculating PCA and different types of tree have been replaced by
-      a single <a href="calculations/calculations.html"><em>Calculations</em>
-        dialog box</a>. The underlying implementation for the PCA and tree
-      calculations have been made faster and more memory efficient.</li>
-    <li><strong>Extensible score models</strong><br />A new
-      framework has also been created for the score models used to
-      calculate distances between sequences and shade alignments. This
-      framework allows import of substitution matrices in NCBI and
-      AAIndex format.<br /> <strong>PCA Bug Fixes</strong>. Jalview's
-      implementation of PCA differed in its treatment of gaps and
-      non-standard residues. The BLOSUM62 matrix also included a typo
-      that affected results. See the <a
-      href="releases.html#2102scoremodelbugs">2.10.2 release note
-        about score model bugs</a> for details and how to reinstate legacy
-      behaviour.</li>
-    <li><strong>Update to JABAWS 2.2</strong><br />Jalview's
-      alignment, protein conservation analysis, and protein disorder and
-      RNA secondary structure prediction services are now provided by <a
-      href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS 2.2</a>.
-      Several of the programs provided as JABAWS 2.2 services have been
-      updated, so their options and parameters have changed.</li>
-    <li><strong>URL linkouts to other bioinformatics
-        databases</strong><br />New preferences for <a
-      href="webServices/urllinks.html">opening web pages for
-        database cross-references</a> via the UK Elixir's EMBL-EBI's MIRIAM
-      database and identifiers.org services.</li>
-    <li><strong>Showing and hiding regions</strong> <br /> <a
-      href="menus/popupMenu.html#hideinserts">Hide insertions</a> in the
-      PopUp menu has changed its behaviour. Prior to 2.10.2, columns
-      were only shown or hidden according to gaps in the sequence under
-      the popup menu. Now, only columns that are gapped in all selected
-      sequences as well as the sequence under the popup menu are hidden,
-      and column visibility outside the selected region is left as is.
-      This makes it easy to filter insertions from the alignment view
-      (just select the region containing insertions to remove) without
-      affecting the rest of the hidden columns.</li>
-    <li><strong>Gap count - a.k.a. the Occupancy
-        Annotation Row</strong><br /> Another way to filter columns according to
-      the presence of gaps is to enable the <strong>Occupancy
-        Annotation</strong> row via Jalview's Preferences. This annotation row
-      shows a histogram of the number of aligned residues at each
-      column. The <a href="features/columnFilterByAnnotation.html">Select
-        By Annotation</a> dialog now also includes a percentage threshold
-      mode, to make it easy to filter alignments to show only those
-      columns with a particular fraction of aligned sequences.</li>
-    <li><strong>Recent search history for Find, PDBe and
-        Uniprot</strong><br />Easily repeat a previous search for <a
-      href="features/search.html#queryhistory">Find</a> and the free
-      text search system (for querying Uniprot and the PDBe).</li>
-    <li><strong>Improved Overview Window</strong><br />The <a
-      href="features/overview.html">alignment overview</a> is now easier
-      to use when working with alignments of more than 5000 rows and
-      columns, and features a new pop-up menu that allows hidden regions
-      to be excluded from the overview. It also works with CDS/Protein
-      alignments and MSA views in wrapped mode.</li>
-    <li><strong>3D Structure</strong><br />Jalview's communication
-      with UCSF Chimera has been made more robust, particularly when
-      working with many structures and long sequences. Regions in
-      structures that correspond to hidden regions in an alignment view
-      are now left un-coloured, making it easier to highlight specific
-      features in 3D. See below for <a href="#experimental">experimental
-        features for exchanging annotation between Chimera and Jalview.</a></li>
-  </ul>
-  <p>
-    <strong>Scripting</strong><br />New <a
-      href="http://www.jalview.org/examples/groovy">groovy examples</a>
-    demonstrate Jalview 2.10.2 APIs for creation of data-driven
-    colourschemes, and custom alignment file handlers. The <a
-      href="groovy/featuresCounter.html">FeatureAnnotationWorker</a>
-    introduced in Jalview 2.10 has also been refactored to allow
-    efficient counting across multiple feature types. Please be aware
-    that feature counter scripts created for earlier versions will not
-    execute in Jalview 2.10.2.
-  </p>
   <p>
     <strong><a name="experimental">Experimental Features</a></strong>
   </p>
index bf1e8b1..37426c3 100644 (file)
Binary files a/lib/jabaws-min-client-2.2.0.jar and b/lib/jabaws-min-client-2.2.0.jar differ
index c9d2e63..5d9bdff 100644 (file)
@@ -1295,7 +1295,6 @@ label.database = Database
 label.urltooltip = Only one url, which must use a sequence id, can be selected for the 'On Click' option
 label.edit_sequence_url_link = Edit sequence URL link
 warn.name_cannot_be_duplicate = User-defined URL names must be unique and cannot be MIRIAM ids
-label.invalid_name = Invalid Name !
 label.output_seq_details = Output Sequence Details to list all database references
 label.urllinks = Links
 label.default_cache_size = Default Cache Size
@@ -1310,3 +1309,13 @@ label.occupancy_descr = Number of aligned positions
 label.show_experimental = Enable experimental features
 label.show_experimental_tip = Enable any new and currently 'experimental' features (see Latest Release Notes for details)
 label.warning_hidden = Warning: {0} {1} is currently hidden
+label.overview_settings = Overview settings
+label.ov_legacy_gap = Use legacy gap colouring (gaps are white)
+label.gap_colour = Gap colour:
+label.ov_show_hide_default = Show hidden regions when opening overview
+label.hidden_colour = Hidden colour:
+label.select_gap_colour = Select gap colour
+label.select_hidden_colour = Select hidden colour
+label.overview = Overview
+label.reset_to_defaults = Reset to defaults
+label.oview_calc = Recalculating overview...
index 64f06c8..e8fd411 100644 (file)
@@ -1295,7 +1295,6 @@ label.database = Base de datos
 label.urltooltip = Sólo una url, que debe usar una id de secuencia, puede ser seleccionada en la opción 'On Click'
 label.edit_sequence_url_link = Editar link de secuencia URL
 warn.name_cannot_be_duplicate = Los nombres URL definidos por el usuario deben ser Ãºnicos y no pueden ser ids de MIRIAM
-label.invalid_name = Nombre inválido !
 label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas
 label.urllinks = Enlaces
 label.default_cache_size = Tamaño del caché por defecto
@@ -1310,3 +1309,13 @@ label.togglehidden = Mostrar regiones ocultas
 label.show_experimental = Habilitar funciones experimentales
 label.show_experimental_tip = Habilitar funciones nuevas y experimentales (ver Latest Release Notes para más detalles)
 label.warning_hidden = Advertencia: {0} {1} está actualmente oculto
+label.overview_settings = Ajustes para la ventana resumen
+label.ov_legacy_gap = <html>Utilizar el color heredado de huecos<br>(los huecos son blancos)
+label.gap_colour = Color de huecos:
+label.ov_show_hide_default = Mostrar regiones ocultas al abrir el resumen
+label.hidden_colour = Color de las regiones ocultas:
+label.select_gap_colour = Seleccionar color de huecos
+label.select_hidden_colour = Seleccionar color de las regiones ocultas 
+label.overview = Resumen
+label.reset_to_defaults = Restablecen a los predeterminados
+label.oview_calc = Recalculando resumen
index 0045e97..3abbe75 100644 (file)
@@ -383,6 +383,8 @@ public class ChimeraResidue implements ChimeraStructuralObject,
   public void splitInsertionCode(String residue)
   {
     // OK, split the index into number and insertion code
+    // JBPNote - m.matches() can be true even if there is no resnum - this can
+    // cause NumberFormatExceptions below
     Pattern p = Pattern.compile("(\\d*)([A-Z]?)");
     Matcher m = p.matcher(residue);
     if (m.matches())
index 9e6d1c0..3cb06c1 100644 (file)
@@ -24,7 +24,6 @@ import jalview.analysis.Conservation;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
-import jalview.datamodel.CigarArray;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.ProfilesI;
 import jalview.datamodel.SearchResultsI;
@@ -243,16 +242,6 @@ public interface AlignViewportI extends ViewStyleI
   void clearSequenceColours();
 
   /**
-   * This method returns the visible alignment as text, as seen on the GUI, ie
-   * if columns are hidden they will not be returned in the result. Use this for
-   * calculating trees, PCA, redundancy etc on views which contain hidden
-   * columns.
-   * 
-   * @return String[]
-   */
-  CigarArray getViewAsCigars(boolean selectedRegionOnly);
-
-  /**
    * return a compact representation of the current alignment selection to pass
    * to an analysis function
    * 
@@ -486,6 +475,7 @@ public interface AlignViewportI extends ViewStyleI
    * 
    * @return
    */
+  @Override
   boolean isProteinFontAsCdna();
 
   /**
@@ -493,5 +483,6 @@ public interface AlignViewportI extends ViewStyleI
    * 
    * @return
    */
+  @Override
   void setProteinFontAsCdna(boolean b);
 }
index 3a3f660..06b1675 100644 (file)
@@ -30,4 +30,11 @@ public interface AlignmentColsCollectionI extends Iterable<Integer>
    * @return true if the column at the position is hidden
    */
   public boolean isHidden(int c);
+
+  /**
+   * Answers if any column in this collection is hidden
+   * 
+   * @return true if there is at least 1 hidden column
+   */
+  public boolean hasHidden();
 }
index 24affc5..fbf6ceb 100644 (file)
@@ -34,6 +34,13 @@ public interface AlignmentRowsCollectionI extends Iterable<Integer>
   public boolean isHidden(int r);
 
   /**
+   * Answers if any row in this collection is hidden
+   * 
+   * @return true if there is at least 1 hidden row
+   */
+  public boolean hasHidden();
+
+  /**
    * Answers the sequence at the given position in the alignment
    * 
    * @param r
index ef59996..0b1ca21 100644 (file)
@@ -43,9 +43,10 @@ public interface AlignmentViewPanel extends OOMHandlerI
    * 
    * @param updateOverview
    *          - if true, the overview panel will also be updated and repainted
+   * @param updateStructures
+   *          - if true then any linked structure views will also be updated
    */
-
-  void paintAlignment(boolean updateOverview);
+  void paintAlignment(boolean updateOverview, boolean updateStructures);
 
   /**
    * automatically adjust annotation panel height for new annotation whilst
diff --git a/src/jalview/api/RendererListenerI.java b/src/jalview/api/RendererListenerI.java
new file mode 100644 (file)
index 0000000..0ce4116
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.api;
+
+import java.beans.PropertyChangeListener;
+
+public interface RendererListenerI extends PropertyChangeListener
+{
+
+}
index 9d44479..46bd4fd 100644 (file)
@@ -383,7 +383,7 @@ public class APopupMenu extends java.awt.PopupMenu
   void addFeatureLinks(final SequenceI seq, List<String> links)
   {
     Menu linkMenu = new Menu(MessageManager.getString("action.link"));
-    Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+    Map<String, List<String>> linkset = new LinkedHashMap<>();
 
     for (String link : links)
     {
@@ -485,8 +485,8 @@ public class APopupMenu extends java.awt.PopupMenu
      * Temporary store to hold distinct calcId / type pairs for the tooltip.
      * Using TreeMap means calcIds are shown in alphabetical order.
      */
-    SortedMap<String, String> tipEntries = new TreeMap<String, String>();
-    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
+    SortedMap<String, String> tipEntries = new TreeMap<>();
+    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
     AlignmentI al = this.ap.av.getAlignment();
     AlignmentUtils.findAddableReferenceAnnotations(forSequences, tipEntries,
             candidates, al);
@@ -825,8 +825,8 @@ public class APopupMenu extends java.awt.PopupMenu
       }
 
       int gSize = sg.getSize();
-      List<SequenceI> seqs = new ArrayList<SequenceI>();
-      List<SequenceFeature> features = new ArrayList<SequenceFeature>();
+      List<SequenceI> seqs = new ArrayList<>();
+      List<SequenceFeature> features = new ArrayList<>();
 
       for (int i = 0; i < gSize; i++)
       {
@@ -930,7 +930,7 @@ public class APopupMenu extends java.awt.PopupMenu
     {
       seq.setName(dialog.getName());
       seq.setDescription(dialog.getDescription());
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
@@ -1163,7 +1163,7 @@ public class APopupMenu extends java.awt.PopupMenu
 
   void refresh()
   {
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   protected void clustalColour_actionPerformed()
@@ -1339,7 +1339,7 @@ public class APopupMenu extends java.awt.PopupMenu
     SequenceGroup sg = ap.av.getSelectionGroup();
     ap.av.getAlignment().deleteGroup(sg);
     ap.av.setSelectionGroup(null);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   void createGroupMenuItem_actionPerformed()
@@ -1440,8 +1440,8 @@ public class APopupMenu extends java.awt.PopupMenu
      * the insertion order, which is the order of the annotations on the
      * alignment.
      */
-    Map<String, List<List<String>>> shownTypes = new LinkedHashMap<String, List<List<String>>>();
-    Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<String, List<List<String>>>();
+    Map<String, List<List<String>>> shownTypes = new LinkedHashMap<>();
+    Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<>();
     AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
             AlignmentAnnotationUtils.asList(annotations), forSequences);
 
index ed04a0a..676d3cf 100644 (file)
@@ -343,7 +343,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     createAlignFrameWindow(embedded);
     validate();
     alignPanel.adjustAnnotationHeight();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   public AlignViewport getAlignViewport()
@@ -415,7 +415,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       {
         viewport.featureSettings.refreshTable();
       }
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       statusBar.setText(MessageManager
               .getString("label.successfully_added_features_alignment"));
     }
@@ -691,7 +691,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       break;
 
     }
-    alignPanel.paintAlignment(true);
+    // TODO: repaint flags set only if the keystroke warrants it
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -917,7 +918,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       applyAutoAnnotationSettings_actionPerformed();
     }
-    alignPanel.paintAlignment(true);
+    // TODO: repaint flags set only if warranted
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -1094,7 +1096,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     else if (source == invertColSel)
     {
       viewport.invertColumnSelection();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(false, false);
       viewport.sendSelection();
     }
     else if (source == remove2LeftMenuItem)
@@ -1128,34 +1130,34 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     else if (source == showColumns)
     {
       viewport.showAllHiddenColumns();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == showSeqs)
     {
       viewport.showAllHiddenSeqs();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       // uncomment if we want to slave sequence selections in split frame
       // viewport.sendSelection();
     }
     else if (source == hideColumns)
     {
       viewport.hideSelectedColumns();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == hideSequences
             && viewport.getSelectionGroup() != null)
     {
       viewport.hideAllSelectedSeqs();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       // uncomment if we want to slave sequence selections in split frame
       // viewport.sendSelection();
     }
     else if (source == hideAllButSelection)
     {
       toggleHiddenRegions(false, false);
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == hideAllSelection)
@@ -1164,14 +1166,14 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       viewport.expandColSelection(sg, false);
       viewport.hideAllSelectedSeqs();
       viewport.hideSelectedColumns();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == showAllHidden)
     {
       viewport.showAllHiddenColumns();
       viewport.showAllHiddenSeqs();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
       viewport.sendSelection();
     }
     else if (source == showGroupConsensus)
@@ -1781,7 +1783,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     }
     viewport.getAlignment().moveSelectedSequencesByOne(sg,
             up ? null : viewport.getHiddenRepSequences(), up);
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
 
     /*
      * Also move cDNA/protein complement sequences
@@ -1793,7 +1795,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
               viewport, complement);
       complement.getAlignment().moveSelectedSequencesByOne(mappedSelection,
               up ? null : complement.getHiddenRepSequences(), up);
-      getSplitFrame().getComplement(this).alignPanel.paintAlignment(true);
+      getSplitFrame().getComplement(this).alignPanel.paintAlignment(true,
+              false);
     }
   }
 
@@ -2226,7 +2229,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -2263,7 +2266,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2283,7 +2286,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2303,7 +2306,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   public void invertColSel_actionPerformed()
   {
     viewport.invertColumnSelection();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2595,19 +2598,19 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   {
     viewport.setShowJVSuffix(seqLimits.getState());
     alignPanel.fontChanged();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   protected void colourTextMenuItem_actionPerformed()
   {
     viewport.setColourText(colourTextMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   protected void displayNonconservedMenuItem_actionPerformed()
   {
     viewport.setShowUnconserved(displayNonconservedMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   protected void wrapMenuItem_actionPerformed()
@@ -2617,7 +2620,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     scaleAbove.setEnabled(wrapMenuItem.getState());
     scaleLeft.setEnabled(wrapMenuItem.getState());
     scaleRight.setEnabled(wrapMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   public void overviewMenuItem_actionPerformed()
@@ -2660,7 +2663,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   {
     viewport.setGlobalColourScheme(cs);
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   protected void modifyPID_actionPerformed()
@@ -2735,7 +2738,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   public void sortIDMenuItem_actionPerformed()
@@ -2744,7 +2747,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     AlignmentSorter.sortByID(viewport.getAlignment());
     addHistoryItem(
             new OrderCommand("ID Sort", oldOrder, viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   public void sortLengthMenuItem_actionPerformed()
@@ -2753,7 +2756,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     AlignmentSorter.sortByLength(viewport.getAlignment());
     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   public void sortGroupMenuItem_actionPerformed()
@@ -2762,7 +2765,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     AlignmentSorter.sortByGroup(viewport.getAlignment());
     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
 
   }
 
@@ -2802,7 +2805,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
           current.insertCharAt(Width - 1, viewport.getGapCharacter());
         }
       }
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(false, false);
     }
 
     if ((viewport.getSelectionGroup() != null
@@ -2866,7 +2869,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
           current.insertCharAt(Width - 1, viewport.getGapCharacter());
         }
       }
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(false, false);
 
     }
 
@@ -2919,7 +2922,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     addHistoryItem(new OrderCommand(MessageManager
             .formatMessage("label.order_by_params", new String[]
             { title }), oldOrder, viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -2977,7 +2980,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       addHistoryItem(new OrderCommand(undoname, oldOrder,
               viewport.getAlignment()));
     }
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     return true;
   }
 
index 8e333ba..906acc1 100644 (file)
@@ -530,7 +530,7 @@ public class AlignmentPanel extends Panel
       vpRanges.scrollToWrappedVisible(start);
     }
 
-    paintAlignment(redrawOverview);
+    paintAlignment(redrawOverview, false);
     return true;
   }
 
@@ -579,7 +579,7 @@ public class AlignmentPanel extends Panel
     apvscroll.addNotify();
     hscroll.addNotify();
     validate();
-    paintAlignment(true);
+    paintAlignment(true, false);
   }
 
   /**
@@ -930,7 +930,8 @@ public class AlignmentPanel extends Panel
    * Repaint the alignment and annotations, and, optionally, any overview window
    */
   @Override
-  public void paintAlignment(boolean updateOverview)
+  public void paintAlignment(boolean updateOverview,
+          boolean updateStructures)
   {
     final AnnotationSorter sorter = new AnnotationSorter(getAlignment(),
             av.isShowAutocalculatedAbove());
@@ -938,13 +939,14 @@ public class AlignmentPanel extends Panel
             av.getSortAnnotationsBy());
     repaint();
 
-    if (updateOverview)
+    if (updateStructures)
     {
-      // TODO: determine if this paintAlignment changed structure colours
       jalview.structure.StructureSelectionManager
               .getStructureSelectionManager(av.applet)
               .sequenceColoursChanged(this);
-
+    }
+    if (updateOverview)
+    {
       if (overviewPanel != null)
       {
         overviewPanel.updateOverviewImage();
index 8de751a..533226e 100644 (file)
@@ -85,7 +85,7 @@ public class AnnotationColourChooser extends Panel implements
     oldcs = av.getGlobalColourScheme();
     if (av.getAlignment().getGroups() != null)
     {
-      oldgroupColours = new HashMap<SequenceGroup, ColourSchemeI>();
+      oldgroupColours = new HashMap<>();
       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
       {
         oldgroupColours.put(sg, sg.getColourScheme());
@@ -180,8 +180,8 @@ public class AnnotationColourChooser extends Panel implements
     // TODO remove duplication with gui.AnnotationRowFilter
     // TODO add 'per sequence only' option / parameter
 
-    annotationLabels = new HashMap<AlignmentAnnotation, String>();
-    Vector<String> list = new Vector<String>();
+    annotationLabels = new HashMap<>();
+    Vector<String> list = new Vector<>();
     AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
     if (anns == null)
     {
@@ -376,7 +376,7 @@ public class AnnotationColourChooser extends Panel implements
     else if (evt.getSource() == cancel)
     {
       reset();
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
       frame.setVisible(false);
     }
 
@@ -417,7 +417,7 @@ public class AnnotationColourChooser extends Panel implements
       }
 
       currentAnnotation.threshold.value = slider.getValue() / 1000f;
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
@@ -559,7 +559,7 @@ public class AnnotationColourChooser extends Panel implements
 
     // update colours in linked windows
     ap.alignmentChanged();
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   void reset()
@@ -572,7 +572,7 @@ public class AnnotationColourChooser extends Panel implements
         sg.setColourScheme(oldgroupColours.get(sg));
       }
     }
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   @Override
@@ -588,7 +588,7 @@ public class AnnotationColourChooser extends Panel implements
   @Override
   public void mouseReleased(MouseEvent evt)
   {
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   @Override
index b4c1d54..7674de7 100644 (file)
@@ -306,7 +306,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
         av.getAlignment().setHiddenColumns(oldHidden);
       }
       av.sendSelection();
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
 
   }
@@ -348,7 +348,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
           sliderDragging = false;
           valueChanged(true);
         }
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, true);
       }
     });
   }
@@ -359,8 +359,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     if (slider.isEnabled())
     {
       getCurrentAnnotation().threshold.value = slider.getValue() / 1000f;
-      updateView();
-      ap.paintAlignment(false);
+      updateView(); // this also calls paintAlignment(true,true)
     }
   }
 
@@ -515,7 +514,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     filterParams = null;
     av.setAnnotationColumnSelectionState(this);
     av.sendSelection();
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   public HiddenColumns getOldHiddenColumns()
index 2fb737a..d8f65a5 100755 (executable)
@@ -226,7 +226,8 @@ public class AnnotationLabels extends Panel
     ap.annotationPanel.adjustPanelHeight();
     setSize(getSize().width, ap.annotationPanel.getSize().height);
     ap.validate();
-    ap.paintAlignment(true);
+    // TODO: only paint if we needed to
+    ap.paintAlignment(true, true);
   }
 
   boolean editLabelDescription(AlignmentAnnotation annotation)
@@ -548,7 +549,7 @@ public class AnnotationLabels extends Panel
                 {
                   ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap);
                 }
-                ap.paintAlignment(true);
+                ap.paintAlignment(true, true);
               }
             });
             popup.add(cbmi);
@@ -756,7 +757,7 @@ public class AnnotationLabels extends Panel
                 }
               }
             }
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
           }
@@ -813,7 +814,7 @@ public class AnnotationLabels extends Panel
               sg.addSequence(aa[selectedRow].sequenceRef, false);
             }
             ap.av.setSelectionGroup(sg);
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
           }
index 6fe71de..c06f7b1 100755 (executable)
@@ -439,7 +439,8 @@ public class AnnotationPanel extends Panel
       graphStretchY = evt.getY();
       av.calcPanelHeight();
       needValidating = true;
-      ap.paintAlignment(true);
+      // TODO: only update overview visible geometry
+      ap.paintAlignment(true, false);
     }
     else
     {
index 5efd177..c96dbab 100644 (file)
@@ -114,7 +114,7 @@ public abstract class AnnotationRowFilter extends Panel
   public void cancel_actionPerformed(ActionEvent e)
   {
     reset();
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
     frame.setVisible(false);
   }
 
index b35c079..df407d6 100644 (file)
@@ -493,7 +493,7 @@ public class FeatureRenderer
     }
     // findAllFeatures();
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
 
     return true;
   }
index 20d4d74..9a67499 100755 (executable)
@@ -377,8 +377,8 @@ public class FeatureSettings extends Panel
   // Group selection states
   void resetTable(boolean groupsChanged)
   {
-    List<String> displayableTypes = new ArrayList<String>();
-    Set<String> foundGroups = new HashSet<String>();
+    List<String> displayableTypes = new ArrayList<>();
+    Set<String> foundGroups = new HashSet<>();
 
     AlignmentI alignment = av.getAlignment();
 
@@ -391,7 +391,7 @@ public class FeatureSettings extends Panel
        * and keep track of which groups are visible
        */
       Set<String> groups = seq.getFeatures().getFeatureGroups(true);
-      Set<String> visibleGroups = new HashSet<String>();
+      Set<String> visibleGroups = new HashSet<>();
       for (String group : groups)
       {
         // if (group == null || fr.checkGroupVisibility(group, true))
@@ -600,7 +600,7 @@ public class FeatureSettings extends Panel
 
     fr.setFeaturePriority(data);
 
-    ap.paintAlignment(updateOverview);
+    ap.paintAlignment(updateOverview, updateOverview);
   }
 
   MyCheckbox selectedCheck;
@@ -680,7 +680,7 @@ public class FeatureSettings extends Panel
   {
     featurePanel.removeAll();
     resetTable(false);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   @Override
@@ -732,7 +732,7 @@ public class FeatureSettings extends Panel
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     fr.setTransparency((100 - transparency.getValue()) / 100f);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   class MyCheckbox extends Checkbox
index c9a92b2..443ebce 100644 (file)
@@ -261,7 +261,7 @@ public class FontChooser extends Panel implements ItemListener
       {
         ap.av.setCharWidth(oldCharWidth);
       }
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, false);
     }
     else if (tp != null)
     {
index 7d9d278..15e269c 100755 (executable)
@@ -70,7 +70,7 @@ public class IdPanel extends Panel
     // TODO: add in group link parameter
 
     // make a list of label,url pairs
-    HashMap<String, String> urlList = new HashMap<String, String>();
+    HashMap<String, String> urlList = new HashMap<>();
     if (viewport.applet != null)
     {
       for (int i = 1; i < 10; i++)
@@ -198,7 +198,7 @@ public class IdPanel extends Panel
     }
 
     lastid = seq;
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
   }
 
   @Override
@@ -295,7 +295,7 @@ public class IdPanel extends Panel
       }
       else
       {
-        nlinks = new ArrayList<String>();
+        nlinks = new ArrayList<>();
       }
 
       for (SequenceFeature sf : sq.getFeatures().getNonPositionalFeatures())
@@ -333,7 +333,7 @@ public class IdPanel extends Panel
       selectSeq(seq);
     }
 
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
   }
 
   void selectSeq(int seq)
@@ -459,7 +459,7 @@ public class IdPanel extends Panel
           running = false;
         }
 
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, false);
         try
         {
           Thread.sleep(100);
index a0466d3..9597b44 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.appletgui;
 
 import jalview.renderer.OverviewRenderer;
+import jalview.renderer.OverviewResColourFinder;
 import jalview.viewmodel.OverviewDimensions;
 
 import java.awt.Color;
@@ -48,10 +49,6 @@ public class OverviewCanvas extends Component
 
   private AlignViewport av;
 
-  // Can set different properties in this seqCanvas than
-  // main visible SeqCanvas
-  private SequenceRenderer sr;
-
   private jalview.renderer.seqfeatures.FeatureRenderer fr;
 
   private Frame nullFrame;
@@ -65,10 +62,6 @@ public class OverviewCanvas extends Component
     nullFrame = new Frame();
     nullFrame.addNotify();
 
-    sr = new SequenceRenderer(av);
-    sr.graphics = nullFrame.getGraphics();
-    sr.renderGaps = false;
-    sr.forOverview = true;
     fr = new jalview.renderer.seqfeatures.FeatureRenderer(av);
   }
 
@@ -119,7 +112,8 @@ public class OverviewCanvas extends Component
 
     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
 
-    or = new OverviewRenderer(sr, fr, od);
+    or = new OverviewRenderer(fr, od, av.getAlignment(),
+            av.getResidueShading(), new OverviewResColourFinder());
     miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
     offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
 
index be552c0..0256055 100755 (executable)
@@ -148,11 +148,12 @@ public class OverviewPanel extends Panel implements Runnable,
     }
     else
     {
+      // don't do anything if the mouse press is in the overview's box
+      // (wait to see if it's a drag instead)
+      // otherwise update the viewport
       if (!od.isPositionInBox(evt.getX(), evt.getY()))
-      {
-        // don't do anything if the mouse press is in the overview's box
-        // (wait to see if it's a drag instead)
-        // otherwise update the viewport
+      { 
+       draggingBox = false;
         od.updateViewportFromMouse(evt.getX(), evt.getY(),
                 av.getAlignment().getHiddenSequences(),
                 av.getAlignment().getHiddenColumns());
@@ -170,10 +171,6 @@ public class OverviewPanel extends Panel implements Runnable,
   @Override
   public void mouseReleased(MouseEvent evt)
   {
-    if (draggingBox)
-    {
-      draggingBox = false;
-    }
   }
 
   @Override
@@ -203,7 +200,7 @@ public class OverviewPanel extends Panel implements Runnable,
                 av.getAlignment().getHiddenSequences(),
                 av.getAlignment().getHiddenColumns());
       }
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
index 2aba20c..bd36b0d 100644 (file)
@@ -160,7 +160,7 @@ public class RedundancyPanel extends SliderPanel
 
     float value = slider.getValue();
 
-    List<SequenceI> redundantSequences = new ArrayList<SequenceI>();
+    List<SequenceI> redundantSequences = new ArrayList<>();
     for (int i = 0; i < redundancy.length; i++)
     {
       if (value <= redundancy[i])
@@ -247,7 +247,7 @@ public class RedundancyPanel extends SliderPanel
               ap.av.getAlignment().getSequences());
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
 
     if (historyList.size() == 0)
     {
index 514c3f9..7d4150d 100755 (executable)
@@ -141,7 +141,7 @@ public class ScalePanel extends Panel
       sg.setStartRes(min);
       sg.setEndRes(max);
     }
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -167,7 +167,7 @@ public class ScalePanel extends Panel
         {
           av.showColumn(reveal[0]);
           reveal = null;
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
           av.sendSelection();
         }
       });
@@ -183,7 +183,7 @@ public class ScalePanel extends Panel
           {
             av.showAllHiddenColumns();
             reveal = null;
-            ap.paintAlignment(true);
+            ap.paintAlignment(true, true);
             av.sendSelection();
           }
         });
@@ -208,7 +208,7 @@ public class ScalePanel extends Panel
             av.setSelectionGroup(null);
           }
 
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
           av.sendSelection();
         }
       });
@@ -239,7 +239,7 @@ public class ScalePanel extends Panel
 
     if (!stretchingGroup)
     {
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
 
       return;
     }
@@ -256,7 +256,7 @@ public class ScalePanel extends Panel
     }
 
     stretchingGroup = false;
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -285,7 +285,7 @@ public class ScalePanel extends Panel
     {
       stretchingGroup = true;
       cs.stretchGroup(res, sg, min, max);
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
index fc7c46e..55320ed 100644 (file)
@@ -335,7 +335,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       sg.addSequence(sequence, false);
       av.setSelectionGroup(sg);
     }
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -983,7 +983,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
       lastMousePress = evt.getPoint();
 
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
       ap.annotationPanel.image = null;
       return;
     }
@@ -1402,7 +1402,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   {
     if (scrollThread != null)
     {
-      scrollThread.running = false;
+      scrollThread.threadRunning = false;
       scrollThread = null;
     }
 
@@ -1450,7 +1450,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         {
           if (links == null)
           {
-            links = new Vector<String>();
+            links = new Vector<>();
           }
           links.addAll(sf.links);
         }
@@ -1524,7 +1524,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       }
     }
     PaintRefresher.Refresh(ap, av.getSequenceSetId());
-    ap.paintAlignment(needOverviewUpdate);
+    ap.paintAlignment(needOverviewUpdate, needOverviewUpdate);
     needOverviewUpdate = false;
     changeEndRes = false;
     changeStartRes = false;
@@ -1649,7 +1649,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       mouseExited(evt);
     }
 
-    if (scrollThread != null)
+    if ((scrollThread != null) && (scrollThread.isRunning()))
     {
       scrollThread.setEvent(evt);
     }
@@ -1665,9 +1665,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       oldSeq = 0;
     }
 
-    if (scrollThread != null)
+    if ((scrollThread != null) && (scrollThread.isRunning()))
     {
-      scrollThread.running = false;
+      scrollThread.stopScrolling();
       scrollThread = null;
     }
   }
@@ -1690,9 +1690,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   {
     if (evt == null)
     {
-      if (scrollThread != null)
+      if ((scrollThread != null) && (scrollThread.isRunning()))
       {
-        scrollThread.running = false;
+        scrollThread.stopScrolling();
         scrollThread = null;
       }
       mouseDragging = false;
@@ -1715,7 +1715,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   {
     MouseEvent evt;
 
-    boolean running = false;
+    private volatile boolean threadRunning = true;
 
     public ScrollThread()
     {
@@ -1729,14 +1729,18 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
     public void stopScrolling()
     {
-      running = false;
+      threadRunning = false;
+    }
+
+    public boolean isRunning()
+    {
+      return threadRunning;
     }
 
     @Override
     public void run()
     {
-      running = true;
-      while (running)
+      while (threadRunning)
       {
 
         if (evt != null)
@@ -1745,23 +1749,23 @@ public class SeqPanel extends Panel implements MouseMotionListener,
           if (mouseDragging && evt.getY() < 0
                   && av.getRanges().getStartSeq() > 0)
           {
-            running = av.getRanges().scrollUp(true);
+            av.getRanges().scrollUp(true);
           }
 
           if (mouseDragging && evt.getY() >= getSize().height && av
                   .getAlignment().getHeight() > av.getRanges().getEndSeq())
           {
-            running = av.getRanges().scrollUp(false);
+            av.getRanges().scrollUp(false);
           }
 
           if (mouseDragging && evt.getX() < 0)
           {
-            running = av.getRanges().scrollRight(false);
+            av.getRanges().scrollRight(false);
           }
 
           else if (mouseDragging && evt.getX() >= getSize().width)
           {
-            running = av.getRanges().scrollRight(true);
+            av.getRanges().scrollRight(true);
           }
         }
 
index a382c60..e55f2a5 100755 (executable)
@@ -22,7 +22,7 @@ package jalview.appletgui;
 
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
-import jalview.renderer.ResidueShaderI;
+import jalview.renderer.ResidueColourFinder;
 import jalview.renderer.seqfeatures.FeatureColourFinder;
 
 import java.awt.Color;
@@ -40,19 +40,18 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
   boolean renderGaps = true;
 
-  SequenceGroup currentSequenceGroup = null;
-
   SequenceGroup[] allGroups = null;
 
   Color resBoxColour;
 
   Graphics graphics;
 
-  boolean forOverview = false;
+  ResidueColourFinder resColourFinder;
 
   public SequenceRenderer(AlignViewport av)
   {
     this.av = av;
+    resColourFinder = new ResidueColourFinder();
   }
 
   /**
@@ -69,25 +68,6 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     this.renderGaps = renderGaps;
   }
 
-  protected Color getResidueBoxColour(SequenceI seq, int i)
-  {
-    allGroups = av.getAlignment().findAllGroups(seq);
-
-    if (inCurrentSequenceGroup(i))
-    {
-      if (currentSequenceGroup.getDisplayBoxes())
-      {
-        getBoxColour(currentSequenceGroup.getGroupColourScheme(), seq, i);
-      }
-    }
-    else if (av.getShowBoxes())
-    {
-      getBoxColour(av.getResidueShading(), seq, i);
-    }
-
-    return resBoxColour;
-  }
-
   /**
    * Get the residue colour at the given sequence position - as determined by
    * the sequence group colour (if any), else the colour scheme, possibly
@@ -104,31 +84,9 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   {
     // TODO replace 8 or so code duplications with calls to this method
     // (refactored as needed)
-    Color col = getResidueBoxColour(seq, position);
-
-    if (finder != null)
-    {
-      col = finder.findFeatureColour(col, seq, position);
-    }
-    return col;
-  }
-
-  void getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
-  {
-    if (shader.getColourScheme() != null)
-    {
-      resBoxColour = shader.findColour(seq.getCharAt(i), i, seq);
-    }
-    else if (forOverview
-            && !jalview.util.Comparison.isGap(seq.getCharAt(i)))
-    {
-      resBoxColour = Color.lightGray;
-    }
-    else
-    {
-      resBoxColour = Color.white;
-    }
-
+    return resColourFinder.getResidueColour(av.getShowBoxes(),
+            av.getResidueShading(),
+            allGroups, seq, position, finder);
   }
 
   public Color findSequenceColour(SequenceI seq, int i)
@@ -165,23 +123,28 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     int curWidth = av.getCharWidth(), avCharWidth = av.getCharWidth(),
             avCharHeight = av.getCharHeight();
 
+    Color resBoxColour = Color.white;
     Color tempColour = null;
     while (i <= end)
     {
       resBoxColour = Color.white;
       if (i < length)
       {
-        if (inCurrentSequenceGroup(i))
+        SequenceGroup currentSequenceGroup = resColourFinder
+                .getCurrentSequenceGroup(allGroups, i);
+        if (currentSequenceGroup != null)
         {
           if (currentSequenceGroup.getDisplayBoxes())
           {
-            getBoxColour(currentSequenceGroup.getGroupColourScheme(), seq,
+            resBoxColour = resColourFinder.getBoxColour(
+                    currentSequenceGroup.getGroupColourScheme(), seq,
                     i);
           }
         }
         else if (av.getShowBoxes())
         {
-          getBoxColour(av.getResidueShading(), seq, i);
+          resBoxColour = resColourFinder
+                  .getBoxColour(av.getResidueShading(), seq, i);
         }
       }
 
@@ -245,7 +208,9 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
         continue;
       }
 
-      if (inCurrentSequenceGroup(i))
+      SequenceGroup currentSequenceGroup = resColourFinder
+              .getCurrentSequenceGroup(allGroups, i);
+      if (currentSequenceGroup != null)
       {
         if (!currentSequenceGroup.getDisplayText())
         {
@@ -254,7 +219,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
         if (currentSequenceGroup.getColourText())
         {
-          getBoxColour(currentSequenceGroup.getGroupColourScheme(), seq, i);
+          resBoxColour = resColourFinder.getBoxColour(
+                  currentSequenceGroup.getGroupColourScheme(), seq, i);
           graphics.setColor(resBoxColour.darker());
         }
         if (currentSequenceGroup.getShowNonconserved())
@@ -271,7 +237,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
         if (av.getColourText())
         {
-          getBoxColour(av.getResidueShading(), seq, i);
+          resBoxColour = resColourFinder
+                  .getBoxColour(av.getResidueShading(), seq, i);
           if (av.getShowBoxes())
           {
             graphics.setColor(resBoxColour.darker());
@@ -358,28 +325,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     return sequenceChar;
   }
 
-  boolean inCurrentSequenceGroup(int res)
-  {
-    if (allGroups == null)
-    {
-      return false;
-    }
-
-    for (int i = 0; i < allGroups.length; i++)
-    {
-      if (allGroups[i].getStartRes() <= res
-              && allGroups[i].getEndRes() >= res)
-      {
-        currentSequenceGroup = allGroups[i];
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  public void drawHighlightedText(SequenceI seq, int start, int end, int x1,
-          int y1)
+  public void drawHighlightedText(SequenceI seq, int start, int end,
+          int x1, int y1)
   {
     int avCharWidth = av.getCharWidth(), avCharHeight = av.getCharHeight();
     int pady = avCharHeight / 5;
index 565ebe8..5841e80 100644 (file)
@@ -441,7 +441,7 @@ public class SliderPanel extends Panel
   @Override
   public void mouseReleased(MouseEvent evt)
   {
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 
   @Override
index ed531d3..777e307 100644 (file)
@@ -187,9 +187,9 @@ public class SplitFrame extends EmbmenuFrame
     createSplitFrameWindow(embedded, applet);
     validate();
     topFrame.alignPanel.adjustAnnotationHeight();
-    topFrame.alignPanel.paintAlignment(true);
+    topFrame.alignPanel.paintAlignment(true, true);
     bottomFrame.alignPanel.adjustAnnotationHeight();
-    bottomFrame.alignPanel.paintAlignment(true);
+    bottomFrame.alignPanel.paintAlignment(true, true);
   }
 
   /**
index d1c0e1b..6831a73 100644 (file)
@@ -64,7 +64,7 @@ public class UserDefinedColours extends Panel
 
   Button selectedButton;
 
-  Vector<Color> oldColours = new Vector<Color>();
+  Vector<Color> oldColours = new Vector<>();
 
   ColourSchemeI oldColourScheme;
 
@@ -520,7 +520,7 @@ public class UserDefinedColours extends Panel
                 ap.av.isIgnoreGapsConsensus());
       }
       ap.seqPanel.seqCanvas.img = null;
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
     else if (jmol != null)
     {
@@ -599,7 +599,7 @@ public class UserDefinedColours extends Panel
       {
         ap.av.setGlobalColourScheme(oldColourScheme);
       }
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
 
     frame.setVisible(false);
index 3266874..32e5fb4 100644 (file)
  */
 package jalview.commands;
 
-/*
- * Jalview - A Sequence Alignment Editor and Viewer Copyright (C) 2007 AM
- * Waterhouse, J Procter, G Barton, M Clamp, S Searle
- * 
- * This program 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 2 of the License, or (at your option) any later
- * version.
- * 
- * This program 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
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 
@@ -110,6 +91,7 @@ public class RemoveGapColCommand extends EditCommand
     performEdit(0, null);
   }
 
+  @Override
   public int getSize()
   {
     // We're interested in the number of columns deleted,
index c5c35f1..27831dd 100644 (file)
  */
 package jalview.commands;
 
-/*
- * Jalview - A Sequence Alignment Editor and Viewer Copyright (C) 2007 AM
- * Waterhouse, J Procter, G Barton, M Clamp, S Searle
- * 
- * This program 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 2 of the License, or (at your option) any later
- * version.
- * 
- * This program 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
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 
index dd05843..69e31cf 100644 (file)
@@ -190,7 +190,7 @@ public class AlignViewController implements AlignViewControllerI
       if (changed)
       {
         viewport.setColumnSelection(cs);
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(false, false);
         int columnCount = invert
                 ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
                         - bs.cardinality()
@@ -215,7 +215,7 @@ public class AlignViewController implements AlignViewControllerI
       if (!extendCurrent)
       {
         cs.clear();
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(false, false);
       }
     }
     return false;
@@ -337,7 +337,7 @@ public class AlignViewController implements AlignViewControllerI
     AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
     avcg.addHistoryItem(new OrderCommand(methodText, oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
 
   }
 
@@ -375,7 +375,7 @@ public class AlignViewController implements AlignViewControllerI
       {
         avcg.getFeatureSettingsUI().discoverAllFeatureData();
       }
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
 
     return featuresFile;
@@ -414,7 +414,7 @@ public class AlignViewController implements AlignViewControllerI
       if (changed)
       {
         viewport.setColumnSelection(cs);
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(false, false);
         int columnCount = invert
                 ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
                         - bs.cardinality()
@@ -438,7 +438,7 @@ public class AlignViewController implements AlignViewControllerI
       if (!extendCurrent)
       {
         cs.clear();
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(false, false);
       }
     }
     return false;
index 1b5207f..084b80e 100755 (executable)
@@ -5,16 +5,16 @@
  * 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 License 
+ * 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 License for more details.
+ * PURPOSE.  See the GNU General Public License for more details.
  * 
- * You should have received a copy of the GNU General License
+ * 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.
  */
index 4ac4f83..e216c46 100644 (file)
@@ -50,4 +50,10 @@ public class AllColsCollection implements AlignmentColsCollectionI
   {
     return !hidden.isVisible(c);
   }
+
+  @Override
+  public boolean hasHidden()
+  {
+    return hidden.hasHiddenColumns();
+  }
 }
index 9a33094..10c47f0 100644 (file)
@@ -59,4 +59,10 @@ public class AllRowsCollection implements AlignmentRowsCollectionI
   {
     return alignment.getSequenceAtAbsoluteIndex(seq);
   }
+
+  @Override
+  public boolean hasHidden()
+  {
+    return (hidden.getSize() > 0);
+  }
 }
index b6224c2..1723f1d 100644 (file)
@@ -170,32 +170,30 @@ public class CigarArray extends CigarBase
         hideStart = region[0];
         hideEnd = region[1];
         // edit hidden regions to selection range
-        if (hideStart < last)
+
+        // just move on if hideEnd is before last
+        if (hideEnd < last)
         {
-          if (hideEnd > last)
-          {
-            hideStart = last;
-          }
-          else
-          {
-            continue;
-          }
+          continue;
         }
-
+        // exit if next region is after end
         if (hideStart > end)
         {
           break;
         }
 
-        if (hideEnd > end)
+        // truncate region at start if last falls in region
+        if ((hideStart < last) && (hideEnd >= last))
         {
-          hideEnd = end;
+          hideStart = last;
         }
 
-        if (hideStart > hideEnd)
+        // truncate region at end if end falls in region
+        if (hideEnd > end) // already checked that hideStart<=end
         {
-          break;
+          hideEnd = end;
         }
+
         /**
          * form operations...
          */
@@ -207,7 +205,7 @@ public class CigarArray extends CigarBase
         last = hideEnd + 1;
       }
       // Final match if necessary.
-      if (last < end)
+      if (last <= end)
       {
         addOperation(CigarArray.M, end - last + 1);
       }
index 1b91ee5..96b0757 100755 (executable)
@@ -82,7 +82,7 @@ public class Sequence extends ASequence implements SequenceI
    */
   int index = -1;
 
-  private SequenceFeatures sequenceFeatureStore;
+  private SequenceFeaturesI sequenceFeatureStore;
 
   /*
    * A cursor holding the approximate current view position to the sequence,
@@ -1844,7 +1844,9 @@ public class Sequence extends ASequence implements SequenceI
      * and we may have included adjacent or enclosing features;
      * remove any that are not enclosing, non-contact features
      */
-    if (endPos > this.end || Comparison.isGap(sequence[toColumn - 1]))
+    boolean endColumnIsGapped = toColumn > 0 && toColumn <= sequence.length
+            && Comparison.isGap(sequence[toColumn - 1]);
+    if (endPos > this.end || endColumnIsGapped)
     {
       ListIterator<SequenceFeature> it = result.listIterator();
       while (it.hasNext())
index 6964b53..e2f15e1 100755 (executable)
@@ -27,6 +27,8 @@ import jalview.renderer.ResidueShaderI;
 import jalview.schemes.ColourSchemeI;
 
 import java.awt.Color;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -39,6 +41,26 @@ import java.util.Map;
  */
 public class SequenceGroup implements AnnotatedCollectionI
 {
+  // TODO ideally this event notification functionality should be separated into
+  // a
+  // subclass of ViewportProperties similarly to ViewportRanges. Done here as
+  // quick fix for JAL-2665
+  public static final String SEQ_GROUP_CHANGED = "Sequence group changed";
+
+  protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+          this);
+
+  public void addPropertyChangeListener(PropertyChangeListener listener)
+  {
+    changeSupport.addPropertyChangeListener(listener);
+  }
+
+  public void removePropertyChangeListener(PropertyChangeListener listener)
+  {
+    changeSupport.removePropertyChangeListener(listener);
+  }
+  // end of event notification functionality initialisation
+
   String groupName;
 
   String description;
@@ -496,6 +518,8 @@ public class SequenceGroup implements AnnotatedCollectionI
       if (s != null && !sequences.contains(s))
       {
         sequences.add(s);
+        changeSupport.firePropertyChange(SEQ_GROUP_CHANGED,
+                sequences.size() - 1, sequences.size());
       }
 
       if (recalc)
@@ -693,6 +717,8 @@ public class SequenceGroup implements AnnotatedCollectionI
     synchronized (sequences)
     {
       sequences.remove(s);
+      changeSupport.firePropertyChange(SEQ_GROUP_CHANGED,
+              sequences.size() + 1, sequences.size());
 
       if (recalc)
       {
@@ -729,7 +755,9 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   public void setStartRes(int i)
   {
+    int before = startRes;
     startRes = i;
+    changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes);
   }
 
   /**
@@ -739,7 +767,9 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   public void setEndRes(int i)
   {
+    int before = endRes;
     endRes = i;
+    changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, endRes);
   }
 
   /**
@@ -1349,7 +1379,10 @@ public class SequenceGroup implements AnnotatedCollectionI
   {
     synchronized (sequences)
     {
+      int before = sequences.size();
       sequences.clear();
+      changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before,
+              sequences.size());
     }
   }
 
index bc32fac..e9437a7 100644 (file)
@@ -51,4 +51,10 @@ public class VisibleColsCollection implements AlignmentColsCollectionI
     return false;
   }
 
+  @Override
+  public boolean hasHidden()
+  {
+    return false;
+  }
+
 }
index ee0557f..fd7cf47 100644 (file)
@@ -56,4 +56,10 @@ public class VisibleRowsCollection implements AlignmentRowsCollectionI
   {
     return alignment.getSequenceAtAbsoluteIndex(seq);
   }
+
+  @Override
+  public boolean hasHidden()
+  {
+    return false;
+  }
 }
index 52da8c7..8d5ba58 100644 (file)
@@ -149,6 +149,14 @@ public class SequenceFeatures implements SequenceFeaturesI
     }
 
     Set<String> featureTypes = getFeatureTypes(ontologyTerm);
+    if (featureTypes.isEmpty())
+    {
+      /*
+       * no features of the specified type or any sub-type
+       */
+      return new ArrayList<>();
+    }
+
     return getAllFeatures(featureTypes.toArray(new String[featureTypes
             .size()]));
   }
index 8cc81d9..bbe6a20 100644 (file)
@@ -279,7 +279,7 @@ public class EmblEntry
     String translation = null;
     String proteinName = "";
     String proteinId = null;
-    Map<String, String> vals = new Hashtable<String, String>();
+    Map<String, String> vals = new Hashtable<>();
 
     /*
      * codon_start 1/2/3 in EMBL corresponds to phase 0/1/2 in CDS
index 365c1c2..50dfa90 100644 (file)
@@ -161,8 +161,9 @@ public class EnsemblGene extends EnsemblSeqProxy
   }
 
   /**
-   * Converts a query, which may contain one or more gene or transcript
-   * identifiers, into a non-redundant list of gene identifiers.
+   * Converts a query, which may contain one or more gene, transcript, or
+   * external (to Ensembl) identifiers, into a non-redundant list of gene
+   * identifiers.
    * 
    * @param accessions
    * @return
@@ -173,54 +174,30 @@ public class EnsemblGene extends EnsemblSeqProxy
 
     for (String acc : accessions.split(getAccessionSeparator()))
     {
-      if (isGeneIdentifier(acc))
-      {
-        if (!geneIds.contains(acc))
-        {
-          geneIds.add(acc);
-        }
-      }
-
       /*
-       * if given a transcript id, look up its gene parent
+       * First try lookup as an Ensembl (gene or transcript) identifier
        */
-      else if (isTranscriptIdentifier(acc))
+      String geneId = new EnsemblLookup(getDomain()).getGeneId(acc);
+      if (geneId != null)
       {
-        String geneId = new EnsemblLookup(getDomain()).getParent(acc);
-        if (geneId != null && !geneIds.contains(geneId))
+        if (!geneIds.contains(geneId))
         {
           geneIds.add(geneId);
         }
       }
-      else if (isProteinIdentifier(acc))
-      {
-        String tscriptId = new EnsemblLookup(getDomain()).getParent(acc);
-        if (tscriptId != null)
-        {
-          String geneId = new EnsemblLookup(getDomain())
-                  .getParent(tscriptId);
-
-          if (geneId != null && !geneIds.contains(geneId))
-          {
-            geneIds.add(geneId);
-          }
-        }
-        // NOTE - acc is lost if it resembles an ENS.+ ID but isn't actually
-        // resolving to one... e.g. ENSMICP00000009241
-      }
-      /*
-       * if given a gene or other external name, lookup and fetch 
-       * the corresponding gene for all model organisms 
-       */
       else
       {
+        /*
+         * if given a gene or other external name, lookup and fetch 
+         * the corresponding gene for all model organisms 
+         */
         List<String> ids = new EnsemblSymbol(getDomain(), getDbSource(),
-                getDbVersion()).getIds(acc);
-        for (String geneId : ids)
+                getDbVersion()).getGeneIds(acc);
+        for (String id : ids)
         {
-          if (!geneIds.contains(geneId))
+          if (!geneIds.contains(id))
           {
-            geneIds.add(geneId);
+            geneIds.add(id);
           }
         }
       }
@@ -229,30 +206,6 @@ public class EnsemblGene extends EnsemblSeqProxy
   }
 
   /**
-   * Attempts to get Ensembl stable identifiers for model organisms for a gene
-   * name by calling the xrefs symbol REST service to resolve the gene name.
-   * 
-   * @param query
-   * @return
-   */
-  protected String getGeneIdentifiersForName(String query)
-  {
-    List<String> ids = new EnsemblSymbol(getDomain(), getDbSource(),
-            getDbVersion()).getIds(query);
-    if (ids != null)
-    {
-      for (String id : ids)
-      {
-        if (isGeneIdentifier(id))
-        {
-          return id;
-        }
-      }
-    }
-    return null;
-  }
-
-  /**
    * Constructs all transcripts for the gene, as identified by "transcript"
    * features whose Parent is the requested gene. The coding transcript
    * sequences (i.e. with introns omitted) are added to the alignment.
@@ -428,6 +381,12 @@ public class EnsemblGene extends EnsemblSeqProxy
   /**
    * Returns a list of the transcript features on the sequence whose Parent is
    * the gene for the accession id.
+   * <p>
+   * Transcript features are those of type "transcript", or any of its sub-types
+   * in the Sequence Ontology e.g. "mRNA", "processed_transcript". We also
+   * include "NMD_transcript_variant", because this type behaves like a
+   * transcript identifier in Ensembl, although strictly speaking it is not in
+   * the SO.
    * 
    * @param accId
    * @param geneSequence
@@ -439,19 +398,18 @@ public class EnsemblGene extends EnsemblSeqProxy
     List<SequenceFeature> transcriptFeatures = new ArrayList<SequenceFeature>();
 
     String parentIdentifier = GENE_PREFIX + accId;
-    // todo optimise here by transcript type!
+
     List<SequenceFeature> sfs = geneSequence.getFeatures()
-            .getPositionalFeatures();
+            .getFeaturesByOntology(SequenceOntologyI.TRANSCRIPT);
+    sfs.addAll(geneSequence.getFeatures().getPositionalFeatures(
+            SequenceOntologyI.NMD_TRANSCRIPT_VARIANT));
 
     for (SequenceFeature sf : sfs)
     {
-      if (isTranscript(sf.getType()))
+      String parent = (String) sf.getValue(PARENT);
+      if (parentIdentifier.equals(parent))
       {
-        String parent = (String) sf.getValue(PARENT);
-        if (parentIdentifier.equals(parent))
-        {
-          transcriptFeatures.add(sf);
-        }
+        transcriptFeatures.add(sf);
       }
     }
 
index ef46a5b..b40df50 100644 (file)
@@ -39,17 +39,12 @@ public class EnsemblGenomes extends EnsemblGene
   }
 
   @Override
-  public boolean isGeneIdentifier(String query)
-  {
-    return true;
-  }
-
-  @Override
   public String getDbName()
   {
     return "EnsemblGenomes";
   }
 
+  private String Wrong[];
   @Override
   public String getTestQuery()
   {
index 3108194..7668941 100644 (file)
@@ -70,11 +70,6 @@ class EnsemblInfo
   // flag set to true if REST major version is not the one expected
   boolean restMajorVersionMismatch;
 
-  /*
-   * absolute time to wait till if we overloaded the REST service
-   */
-  long retryAfter;
-
   /**
    * Constructor given expected REST version number e.g 4.5 or 3.4.3
    * 
index eb8f90e..31da9c0 100644 (file)
@@ -43,6 +43,13 @@ import org.json.simple.parser.ParseException;
 public class EnsemblLookup extends EnsemblRestClient
 {
 
+  private static final String OBJECT_TYPE_TRANSLATION = "Translation";
+  private static final String PARENT = "Parent";
+  private static final String OBJECT_TYPE_TRANSCRIPT = "Transcript";
+  private static final String ID = "id";
+  private static final String OBJECT_TYPE_GENE = "Gene";
+  private static final String OBJECT_TYPE = "object_type";
+
   /**
    * Default constructor (to use rest.ensembl.org)
    */
@@ -87,7 +94,7 @@ public class EnsemblLookup extends EnsemblRestClient
   protected URL getUrl(String identifier)
   {
     String url = getDomain() + "/lookup/id/" + identifier
-            + "?content-type=application/json";
+            + CONTENT_TYPE_JSON;
     try
     {
       return new URL(url);
@@ -122,7 +129,7 @@ public class EnsemblLookup extends EnsemblRestClient
    * @param identifier
    * @return
    */
-  public String getParent(String identifier)
+  public String getGeneId(String identifier)
   {
     List<String> ids = Arrays.asList(new String[] { identifier });
 
@@ -134,7 +141,7 @@ public class EnsemblLookup extends EnsemblRestClient
       {
         br = getHttpResponse(url, ids);
       }
-      return (parseResponse(br));
+      return br == null ? null : parseResponse(br);
     } catch (IOException e)
     {
       // ignore
@@ -155,8 +162,10 @@ public class EnsemblLookup extends EnsemblRestClient
   }
 
   /**
-   * Parses "Parent" from the JSON response and returns the value, or null if
-   * not found
+   * Parses the JSON response and returns the gene identifier, or null if not
+   * found. If the returned object_type is Gene, returns the id, if Transcript
+   * returns the Parent. If it is Translation (peptide identifier), then the
+   * Parent is the transcript identifier, so we redo the search with this value.
    * 
    * @param br
    * @return
@@ -164,17 +173,42 @@ public class EnsemblLookup extends EnsemblRestClient
    */
   protected String parseResponse(BufferedReader br) throws IOException
   {
-    String parent = null;
+    String geneId = null;
     JSONParser jp = new JSONParser();
     try
     {
       JSONObject val = (JSONObject) jp.parse(br);
-      parent = val.get("Parent").toString();
+      String type = val.get(OBJECT_TYPE).toString();
+      if (OBJECT_TYPE_GENE.equalsIgnoreCase(type))
+      {
+        geneId = val.get(ID).toString();
+      }
+      else if (OBJECT_TYPE_TRANSCRIPT.equalsIgnoreCase(type))
+      {
+        geneId = val.get(PARENT).toString();
+      }
+      else if (OBJECT_TYPE_TRANSLATION.equalsIgnoreCase(type))
+      {
+        String transcriptId = val.get(PARENT).toString();
+        try
+        {
+          geneId = getGeneId(transcriptId);
+        } catch (StackOverflowError e)
+        {
+          /*
+           * unlikely data condition error!
+           */
+          System.err
+                  .println("** Ensembl lookup "
+                          + getUrl(transcriptId).toString()
+                          + " looping on Parent!");
+        }
+      }
     } catch (ParseException e)
     {
       // ignore
     }
-    return parent;
+    return geneId;
   }
 
 }
index 1554a0b..99006aa 100644 (file)
@@ -23,8 +23,6 @@ package jalview.ext.ensembl;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
 
-import java.util.List;
-
 import com.stevesoft.pat.Regex;
 
 /**
index ad6c70c..b1bc8e5 100644 (file)
@@ -31,6 +31,7 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
+import java.net.ProtocolException;
 import java.net.URL;
 import java.util.HashMap;
 import java.util.List;
@@ -42,8 +43,6 @@ import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.json.simple.parser.JSONParser;
 
-import com.stevesoft.pat.Regex;
-
 /**
  * Base class for Ensembl REST service clients
  * 
@@ -55,15 +54,21 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 
   private static final int CONNECT_TIMEOUT_MS = 10 * 1000; // 10 seconds
 
+  private static final int MAX_RETRIES = 3;
+
+  private static final int HTTP_OK = 200;
+
+  private static final int HTTP_OVERLOAD = 429;
+
   /*
    * update these constants when Jalview has been checked / updated for
    * changes to Ensembl REST API (ref JAL-2105)
    * @see https://github.com/Ensembl/ensembl-rest/wiki/Change-log
    * @see http://rest.ensembl.org/info/rest?content-type=application/json
    */
-  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "5.0";
+  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "6.0";
 
-  private static final String LATEST_ENSEMBL_REST_VERSION = "5.0";
+  private static final String LATEST_ENSEMBL_REST_VERSION = "6.1";
 
   private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
 
@@ -76,18 +81,11 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 
   private final static long VERSION_RETEST_INTERVAL = 1000L * 3600; // 1 hr
 
-  private static final Regex PROTEIN_REGEX = new Regex(
-          "(ENS)([A-Z]{3}|)P[0-9]{11}$");
-
-  private static final Regex TRANSCRIPT_REGEX = new Regex(
-          "(ENS)([A-Z]{3}|)T[0-9]{11}$");
-
-  private static final Regex GENE_REGEX = new Regex(
-          "(ENS)([A-Z]{3}|)G[0-9]{11}$");
+  protected static final String CONTENT_TYPE_JSON = "?content-type=application/json";
 
   static
   {
-    domainData = new HashMap<String, EnsemblInfo>();
+    domainData = new HashMap<>();
     domainData.put(ENSEMBL_REST,
             new EnsemblInfo(ENSEMBL_REST, LATEST_ENSEMBL_REST_VERSION));
     domainData.put(ENSEMBL_GENOMES_REST, new EnsemblInfo(
@@ -114,42 +112,6 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     setDomain(d);
   }
 
-  /**
-   * Answers true if the query matches the regular expression pattern for an
-   * Ensembl transcript stable identifier
-   * 
-   * @param query
-   * @return
-   */
-  public boolean isTranscriptIdentifier(String query)
-  {
-    return query == null ? false : TRANSCRIPT_REGEX.search(query);
-  }
-
-  /**
-   * Answers true if the query matches the regular expression pattern for an
-   * Ensembl protein stable identifier
-   * 
-   * @param query
-   * @return
-   */
-  public boolean isProteinIdentifier(String query)
-  {
-    return query == null ? false : PROTEIN_REGEX.search(query);
-  }
-
-  /**
-   * Answers true if the query matches the regular expression pattern for an
-   * Ensembl gene stable identifier
-   * 
-   * @param query
-   * @return
-   */
-  public boolean isGeneIdentifier(String query)
-  {
-    return query == null ? false : GENE_REGEX.search(query);
-  }
-
   @Override
   public boolean queryInProgress()
   {
@@ -204,21 +166,25 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    * @see http://rest.ensembl.org/documentation/info/ping
    * @return
    */
-  private boolean checkEnsembl()
+  boolean checkEnsembl()
   {
     BufferedReader br = null;
     try
     {
       // note this format works for both ensembl and ensemblgenomes
       // info/ping.json works for ensembl only (March 2016)
-      URL ping = new URL(
-              getDomain() + "/info/ping?content-type=application/json");
+      URL ping = new URL(getDomain() + "/info/ping" + CONTENT_TYPE_JSON);
 
       /*
        * expect {"ping":1} if ok
        * if ping takes more than 2 seconds to respond, treat as if unavailable
        */
       br = getHttpResponse(ping, null, 2 * 1000);
+      if (br == null)
+      {
+        // error reponse status
+        return false;
+      }
       JSONParser jp = new JSONParser();
       JSONObject val = (JSONObject) jp.parse(br);
       String pingString = val.get("ping").toString();
@@ -281,7 +247,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   }
 
   /**
-   * Writes the HTTP request and gets the response as a reader.
+   * Sends the HTTP request and gets the response as a reader
    * 
    * @param url
    * @param ids
@@ -295,7 +261,56 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   protected BufferedReader getHttpResponse(URL url, List<String> ids,
           int readTimeout) throws IOException
   {
-    // long now = System.currentTimeMillis();
+    int retriesLeft = MAX_RETRIES;
+    HttpURLConnection connection = null;
+    int responseCode = 0;
+
+    while (retriesLeft > 0)
+    {
+      connection = tryConnection(url, ids, readTimeout);
+      responseCode = connection.getResponseCode();
+      if (responseCode == HTTP_OVERLOAD) // 429
+      {
+        retriesLeft--;
+        checkRetryAfter(connection);
+      }
+      else
+      {
+        retriesLeft = 0;
+      }
+    }
+    if (responseCode != HTTP_OK) // 200
+    {
+      /*
+       * note: a GET request for an invalid id returns an error code e.g. 415
+       * but POST request returns 200 and an empty Fasta response 
+       */
+      System.err.println("Response code " + responseCode + " for " + url);
+      return null;
+    }
+
+    InputStream response = connection.getInputStream();
+
+    // System.out.println(getClass().getName() + " took "
+    // + (System.currentTimeMillis() - now) + "ms to fetch");
+
+    BufferedReader reader = null;
+    reader = new BufferedReader(new InputStreamReader(response, "UTF-8"));
+    return reader;
+  }
+
+  /**
+   * @param url
+   * @param ids
+   * @param readTimeout
+   * @return
+   * @throws IOException
+   * @throws ProtocolException
+   */
+  protected HttpURLConnection tryConnection(URL url, List<String> ids,
+          int readTimeout) throws IOException, ProtocolException
+  {
+    // System.out.println(System.currentTimeMillis() + " " + url);
     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
 
     /*
@@ -320,77 +335,40 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     {
       writePostBody(connection, ids);
     }
-
-    int responseCode = connection.getResponseCode();
-
-    if (responseCode != 200)
-    {
-      /*
-       * note: a GET request for an invalid id returns an error code e.g. 415
-       * but POST request returns 200 and an empty Fasta response 
-       */
-      System.err.println("Response code " + responseCode + " for " + url);
-      return null;
-    }
-    // get content
-    InputStream response = connection.getInputStream();
-
-    // System.out.println(getClass().getName() + " took "
-    // + (System.currentTimeMillis() - now) + "ms to fetch");
-
-    checkRateLimits(connection);
-
-    BufferedReader reader = null;
-    reader = new BufferedReader(new InputStreamReader(response, "UTF-8"));
-    return reader;
+    return connection;
   }
 
   /**
-   * Inspect response headers for any sign of server overload and respect any
-   * 'retry-after' directive
+   * Inspects response headers for a 'retry-after' directive, and waits for the
+   * directed period (if less than 10 seconds)
    * 
    * @see https://github.com/Ensembl/ensembl-rest/wiki/Rate-Limits
    * @param connection
    */
-  void checkRateLimits(HttpURLConnection connection)
+  void checkRetryAfter(HttpURLConnection connection)
   {
-    // number of requests allowed per time interval:
-    String limit = connection.getHeaderField("X-RateLimit-Limit");
-    // length of quota time interval in seconds:
-    // String period = connection.getHeaderField("X-RateLimit-Period");
-    // seconds remaining until usage quota is reset:
-    String reset = connection.getHeaderField("X-RateLimit-Reset");
-    // number of requests remaining from quota for current period:
-    String remaining = connection.getHeaderField("X-RateLimit-Remaining");
-    // number of seconds to wait before retrying (if remaining == 0)
     String retryDelay = connection.getHeaderField("Retry-After");
 
     // to test:
     // retryDelay = "5";
 
-    EnsemblInfo info = domainData.get(getDomain());
     if (retryDelay != null)
     {
-      System.err.println("Ensembl REST service rate limit exceeded, wait "
-              + retryDelay + " seconds before retrying");
       try
       {
-        info.retryAfter = System.currentTimeMillis()
-                + (1000 * Integer.valueOf(retryDelay));
-      } catch (NumberFormatException e)
+        int retrySecs = Integer.valueOf(retryDelay);
+        if (retrySecs > 0 && retrySecs < 10)
+        {
+          System.err
+                  .println("Ensembl REST service rate limit exceeded, waiting "
+                          + retryDelay + " seconds before retrying");
+          Thread.sleep(1000 * retrySecs);
+        }
+      } catch (NumberFormatException | InterruptedException e)
       {
-        System.err
-                .println("Unexpected value for Retry-After: " + retryDelay);
+        System.err.println("Error handling Retry-After: " + e.getMessage());
       }
     }
-    else
-    {
-      info.retryAfter = 0;
-      // debug:
-      // System.out.println(String.format(
-      // "%s Ensembl requests remaining of %s (reset in %ss)",
-      // remaining, limit, reset));
-    }
   }
 
   /**
@@ -408,20 +386,6 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     long now = System.currentTimeMillis();
 
     /*
-     * check if we are waiting for 'Retry-After' to expire
-     */
-    if (info.retryAfter > now)
-    {
-      System.err.println("Still " + (1 + (info.retryAfter - now) / 1000)
-              + " secs to wait before retrying Ensembl");
-      return false;
-    }
-    else
-    {
-      info.retryAfter = 0;
-    }
-
-    /*
      * recheck if Ensembl is up if it was down, or the recheck period has elapsed
      */
     boolean retestAvailability = (now
@@ -497,9 +461,12 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     URL url = null;
     try
     {
-      url = new URL(
-              getDomain() + "/info/rest?content-type=application/json");
+      url = new URL(getDomain() + "/info/rest" + CONTENT_TYPE_JSON);
       BufferedReader br = getHttpResponse(url, null);
+      if (br == null)
+      {
+        return;
+      }
       JSONObject val = (JSONObject) jp.parse(br);
       String version = val.get("release").toString();
       String majorVersion = version.substring(0, version.indexOf("."));
@@ -558,18 +525,35 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   {
     JSONParser jp = new JSONParser();
     URL url = null;
+    BufferedReader br = null;
+
     try
     {
-      url = new URL(
-              getDomain() + "/info/data?content-type=application/json");
-      BufferedReader br = getHttpResponse(url, null);
-      JSONObject val = (JSONObject) jp.parse(br);
-      JSONArray versions = (JSONArray) val.get("releases");
-      domainData.get(getDomain()).dataVersion = versions.get(0).toString();
+      url = new URL(getDomain() + "/info/data" + CONTENT_TYPE_JSON);
+      br = getHttpResponse(url, null);
+      if (br != null)
+      {
+        JSONObject val = (JSONObject) jp.parse(br);
+        JSONArray versions = (JSONArray) val.get("releases");
+        domainData.get(getDomain()).dataVersion = versions.get(0)
+                .toString();
+      }
     } catch (Throwable t)
     {
       System.err.println(
               "Error checking Ensembl data version: " + t.getMessage());
+    } finally
+    {
+      if (br != null)
+      {
+        try
+        {
+          br.close();
+        } catch (IOException e)
+        {
+          // ignore
+        }
+      }
     }
   }
 
index 4da4f15..577111e 100644 (file)
@@ -792,8 +792,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
       return false;
     }
 
-    long start = System.currentTimeMillis();
-    // SequenceFeature[] sfs = sourceSequence.getSequenceFeatures();
+//    long start = System.currentTimeMillis();
     List<SequenceFeature> sfs = sourceSequence.getFeatures()
             .getPositionalFeatures();
     MapList mapping = getGenomicRangesFromFeatures(sourceSequence,
@@ -805,10 +804,10 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
 
     boolean result = transferFeatures(sfs, targetSequence, mapping,
             accessionId);
-    System.out.println("transferFeatures (" + (sfs.size()) + " --> "
-            + targetSequence.getFeatures().getFeatureCount(true) + ") to "
-            + targetSequence.getName() + " took "
-            + (System.currentTimeMillis() - start) + "ms");
+//    System.out.println("transferFeatures (" + (sfs.size()) + " --> "
+//            + targetSequence.getFeatures().getFeatureCount(true) + ") to "
+//            + targetSequence.getName() + " took "
+//            + (System.currentTimeMillis() - start) + "ms");
     return result;
   }
 
index 9f86731..75598a0 100644 (file)
@@ -42,6 +42,10 @@ import org.json.simple.parser.ParseException;
  */
 public class EnsemblSymbol extends EnsemblXref
 {
+  private static final String GENE = "gene";
+  private static final String TYPE = "type";
+  private static final String ID = "id";
+
   /**
    * Constructor given the target domain to fetch data from
    * 
@@ -73,8 +77,9 @@ public class EnsemblSymbol extends EnsemblXref
       while (rvals.hasNext())
       {
         JSONObject val = (JSONObject) rvals.next();
-        String id = val.get("id").toString();
-        if (id != null && isGeneIdentifier(id))
+        String id = val.get(ID).toString();
+        String type = val.get(TYPE).toString();
+        if (id != null && GENE.equals(type))
         {
           result = id;
           break;
@@ -87,12 +92,31 @@ public class EnsemblSymbol extends EnsemblXref
     return result;
   }
 
-  protected URL getUrl(String id, Species species)
+  /**
+   * Constructs the URL for the REST symbol endpoint
+   * 
+   * @param id
+   *          the accession id (Ensembl or external)
+   * @param species
+   *          a species name recognisable by Ensembl
+   * @param type
+   *          an optional type to filter the response (gene, transcript,
+   *          translation)
+   * @return
+   */
+  protected URL getUrl(String id, Species species, String... type)
   {
-    String url = getDomain() + "/xrefs/symbol/" + species.toString() + "/"
-            + id + "?content-type=application/json";
+    StringBuilder sb = new StringBuilder();
+    sb.append(getDomain()).append("/xrefs/symbol/")
+            .append(species.toString()).append("/").append(id)
+            .append(CONTENT_TYPE_JSON);
+    for (String t : type)
+    {
+      sb.append("&object_type=").append(t);
+    }
     try
     {
+      String url = sb.toString();
       return new URL(url);
     } catch (MalformedURLException e)
     {
@@ -107,7 +131,7 @@ public class EnsemblSymbol extends EnsemblXref
    * @param identifier
    * @return
    */
-  public List<String> getIds(String identifier)
+  public List<String> getGeneIds(String identifier)
   {
     List<String> result = new ArrayList<String>();
     List<String> ids = new ArrayList<String>();
@@ -119,19 +143,20 @@ public class EnsemblSymbol extends EnsemblXref
     {
       for (String query : queries)
       {
-        for (Species taxon : Species.values())
+        for (Species taxon : Species.getModelOrganisms())
         {
-          if (taxon.isModelOrganism())
+          URL url = getUrl(query, taxon, GENE);
+          if (url != null)
           {
-            URL url = getUrl(query, taxon);
-            if (url != null)
-            {
-              br = getHttpResponse(url, ids);
-            }
-            String geneId = parseSymbolResponse(br);
-            if (geneId != null)
+            br = getHttpResponse(url, ids);
+            if (br != null)
             {
-              result.add(geneId);
+              String geneId = parseSymbolResponse(br);
+              System.out.println(url + " returned " + geneId);
+              if (geneId != null && !result.contains(geneId))
+              {
+                result.add(geneId);
+              }
             }
           }
         }
index c0b00b1..27c448e 100644 (file)
@@ -124,8 +124,11 @@ class EnsemblXref extends EnsemblRestClient
       if (url != null)
       {
         br = getHttpResponse(url, ids);
+        if (br != null)
+        {
+          result = parseResponse(br);
+        }
       }
-      return (parseResponse(br));
     } catch (IOException e)
     {
       // ignore
@@ -168,16 +171,13 @@ class EnsemblXref extends EnsemblRestClient
       while (rvals.hasNext())
       {
         JSONObject val = (JSONObject) rvals.next();
-        String dbName = val.get("dbname").toString();
-        if (dbName.equals(GO_GENE_ONTOLOGY))
-        {
-          continue;
-        }
+        String db = val.get("dbname").toString();
         String id = val.get("primary_id").toString();
-        if (dbName != null && id != null)
+        if (db != null && id != null
+                && !GO_GENE_ONTOLOGY.equals(db))
         {
-          dbName = DBRefUtils.getCanonicalName(dbName);
-          DBRefEntry dbref = new DBRefEntry(dbName, getXRefVersion(), id);
+          db = DBRefUtils.getCanonicalName(db);
+          DBRefEntry dbref = new DBRefEntry(db, getXRefVersion(), id);
           result.add(dbref);
         }
       }
@@ -211,7 +211,7 @@ class EnsemblXref extends EnsemblRestClient
   protected URL getUrl(String identifier)
   {
     String url = getDomain() + "/xrefs/id/" + identifier
-            + "?content-type=application/json&all_levels=1";
+            + CONTENT_TYPE_JSON + "&all_levels=1";
     try
     {
       return new URL(url);
index af01225..cc5465e 100644 (file)
@@ -20,6 +20,9 @@
  */
 package jalview.ext.ensembl;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * Selected species identifiers used by Ensembl
  * 
@@ -38,6 +41,18 @@ enum Species
   chimpanzee(false), cat(false), zebrafish(true), chicken(true),
   dmelanogaster(true);
 
+  static Set<Species> modelOrganisms = new HashSet<>();
+
+  static
+  {
+    for (Species s : values())
+    {
+      if (s.isModelOrganism())
+      {
+        modelOrganisms.add(s);
+      }
+    }
+  }
   boolean modelOrganism;
 
   private Species(boolean model)
@@ -49,4 +64,9 @@ enum Species
   {
     return modelOrganism;
   }
+
+  public static Set<Species> getModelOrganisms()
+  {
+    return modelOrganisms;
+  }
 }
index 96dfcfe..50aba62 100644 (file)
@@ -975,6 +975,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
         notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
                 (String) data[0]);
         // also highlight in alignment
+        // deliberate fall through
       case HOVER:
         notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
                 (String) data[0]);
index f923f7f..39d6704 100644 (file)
@@ -120,7 +120,7 @@ public class AtomSpecModel
 
       for (String chain : modelData.keySet())
       {
-        chain = chain.trim();
+        chain = " ".equals(chain) ? chain : chain.trim();
 
         List<int[]> rangeList = modelData.get(chain);
 
@@ -192,9 +192,10 @@ public class AtomSpecModel
     {
       sb.append(start).append("-").append(end);
     }
-    if (chain.length() > 0)
-    {
-      sb.append(".").append(chain);
+
+    sb.append(".");
+    if (!" ".equals(chain)) {
+      sb.append(chain);
     }
   }
 }
index 2a53ab9..19f7db4 100644 (file)
@@ -43,13 +43,13 @@ public class PDBFTSPanel extends GFTSPanel
 
   private static final String PDB_FTS_CACHE_KEY = "CACHE.PDB_FTS";
 
-  public PDBFTSPanel(SequenceFetcher seqFetcher)
+  public PDBFTSPanel(SequenceFetcher fetcher)
   {
     super();
     pageLimit = PDBFTSRestClient.getInstance().getDefaultResponsePageSize();
-    this.seqFetcher = seqFetcher;
-    this.progressIndicator = (seqFetcher == null) ? null
-            : seqFetcher.getProgressIndicator();
+    this.seqFetcher = fetcher;
+    this.progressIndicator = (fetcher == null) ? null
+            : fetcher.getProgressIndicator();
   }
 
   @Override
@@ -86,15 +86,16 @@ public class PDBFTSPanel extends GFTSPanel
           request.setSearchTerm(searchTerm + ")");
           request.setOffSet(offSet);
           request.setWantedFields(wantedFields);
-          FTSRestClientI pdbRestCleint = PDBFTSRestClient.getInstance();
+          FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
           FTSRestResponse resultList;
           try
           {
-            resultList = pdbRestCleint.executeRequest(request);
+            resultList = pdbRestClient.executeRequest(request);
           } catch (Exception e)
           {
             setErrorMessage(e.getMessage());
             checkForErrors();
+            setSearchInProgress(false);
             return;
           }
 
index a483f44..cbeaff1 100644 (file)
@@ -59,7 +59,7 @@ public class PDBFTSRestClient extends FTSRestClient
 
   private static FTSRestClientI instance = null;
 
-  public static final String PDB_SEARCH_ENDPOINT = "http://www.ebi.ac.uk/pdbe/search/pdb/select?";
+  public static final String PDB_SEARCH_ENDPOINT = "https://www.ebi.ac.uk/pdbe/search/pdb/select?";
 
   protected PDBFTSRestClient()
   {
index 2dad2f7..020331a 100644 (file)
@@ -40,18 +40,18 @@ public class UniprotFTSPanel extends GFTSPanel
   private static String defaultFTSFrameTitle = MessageManager
           .getString("label.uniprot_sequence_fetcher");
 
-  private static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
+  private static Map<String, Integer> tempUserPrefs = new HashMap<>();
 
   private static final String UNIPROT_FTS_CACHE_KEY = "CACHE.UNIPROT_FTS";
 
-  public UniprotFTSPanel(SequenceFetcher seqFetcher)
+  public UniprotFTSPanel(SequenceFetcher fetcher)
   {
     super();
     pageLimit = UniProtFTSRestClient.getInstance()
             .getDefaultResponsePageSize();
-    this.seqFetcher = seqFetcher;
-    this.progressIndicator = (seqFetcher == null) ? null
-            : seqFetcher.getProgressIndicator();
+    this.seqFetcher = fetcher;
+    this.progressIndicator = (fetcher == null) ? null
+            : fetcher.getProgressIndicator();
   }
 
   @Override
@@ -85,17 +85,17 @@ public class UniprotFTSPanel extends GFTSPanel
           request.setSearchTerm(searchTerm);
           request.setOffSet(offSet);
           request.setWantedFields(wantedFields);
-          FTSRestClientI uniProtRestCleint = UniProtFTSRestClient
+          FTSRestClientI uniProtRestClient = UniProtFTSRestClient
                   .getInstance();
           FTSRestResponse resultList;
           try
           {
-            resultList = uniProtRestCleint.executeRequest(request);
+            resultList = uniProtRestClient.executeRequest(request);
           } catch (Exception e)
           {
-            e.printStackTrace();
             setErrorMessage(e.getMessage());
             checkForErrors();
+            setSearchInProgress(false);
             return;
           }
 
@@ -183,7 +183,7 @@ public class UniprotFTSPanel extends GFTSPanel
   {
     disableActionButtons();
     StringBuilder selectedIds = new StringBuilder();
-    HashSet<String> selectedIdsSet = new HashSet<String>();
+    HashSet<String> selectedIdsSet = new HashSet<>();
     int primaryKeyColIndex = 0;
     try
     {
index 1bd1541..143e672 100644 (file)
@@ -1711,7 +1711,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     viewport.getAlignment().moveSelectedSequencesByOne(sg,
             viewport.getHiddenRepSequences(), up);
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   synchronized void slideSequences(boolean right, int size)
@@ -2397,7 +2397,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -2423,7 +2423,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
   }
 
@@ -2448,7 +2448,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2479,7 +2479,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // alignPanel to decide if overview needs
     // updating.
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2488,7 +2488,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void invertColSel_actionPerformed(ActionEvent e)
   {
     viewport.invertColumnSelection();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     viewport.sendSelection();
   }
 
@@ -2868,21 +2868,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     alignPanel.getIdPanel().getIdCanvas()
             .setPreferredSize(alignPanel.calculateIdWidth());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   @Override
   public void idRightAlign_actionPerformed(ActionEvent e)
   {
     viewport.setRightAlignIds(idRightAlign.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   @Override
   public void centreColumnLabels_actionPerformed(ActionEvent e)
   {
     viewport.setCentreColumnLabels(centreColumnLabelsMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /*
@@ -2915,7 +2915,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setColourText(colourTextMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -2944,7 +2944,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void showAllColumns_actionPerformed(ActionEvent e)
   {
     viewport.showAllHiddenColumns();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3048,7 +3048,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.expandColSelection(sg, false);
     viewport.hideAllSelectedSeqs();
     viewport.hideSelectedColumns();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3064,7 +3064,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     viewport.showAllHiddenColumns();
     viewport.showAllHiddenSeqs();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3072,7 +3072,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void hideSelColumns_actionPerformed(ActionEvent e)
   {
     viewport.hideSelectedColumns();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3093,7 +3093,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleAbove_actionPerformed(ActionEvent e)
   {
     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
-    alignPanel.paintAlignment(true);
+    // TODO: do we actually need to update overview for scale above change ?
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3106,7 +3107,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleLeft_actionPerformed(ActionEvent e)
   {
     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3119,7 +3120,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleRight_actionPerformed(ActionEvent e)
   {
     viewport.setScaleRightWrapped(scaleRight.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3132,7 +3133,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -3145,7 +3146,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void viewTextMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setShowText(viewTextMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -3158,7 +3159,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   public FeatureSettings featureSettings;
@@ -3196,7 +3197,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void showSeqFeatures_actionPerformed(ActionEvent evt)
   {
     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -3353,7 +3354,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     viewport.setGlobalColourScheme(cs);
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -3438,7 +3439,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             viewport.getAlignment().getSequenceAt(0));
     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3454,7 +3455,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     AlignmentSorter.sortByID(viewport.getAlignment());
     addHistoryItem(
             new OrderCommand("ID Sort", oldOrder, viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3470,7 +3471,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     AlignmentSorter.sortByLength(viewport.getAlignment());
     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3487,7 +3488,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
             viewport.getAlignment()));
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3644,7 +3645,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         addHistoryItem(new OrderCommand(order.getName(), oldOrder,
                 viewport.getAlignment()));
 
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, false);
       }
     });
   }
@@ -3673,7 +3674,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 viewport.getAlignment());// ,viewport.getSelectionGroup());
         addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
                 viewport.getAlignment()));
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, false);
       }
     });
   }
@@ -3788,7 +3789,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       addHistoryItem(new OrderCommand(undoname, oldOrder,
               viewport.getAlignment()));
     }
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     return true;
   }
 
@@ -4386,7 +4387,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // Java's Transferable for native dnd
     evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
     Transferable t = evt.getTransferable();
-    List<String> files = new ArrayList<>();
+    final AlignFrame thisaf = this;
+    final List<String> files = new ArrayList<>();
     List<DataSourceType> protocols = new ArrayList<>();
 
     try
@@ -4398,133 +4400,146 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     if (files != null)
     {
-      try
+      new Thread(new Runnable()
       {
-        // check to see if any of these files have names matching sequences in
-        // the alignment
-        SequenceIdMatcher idm = new SequenceIdMatcher(
-                viewport.getAlignment().getSequencesArray());
-        /**
-         * Object[] { String,SequenceI}
-         */
-        ArrayList<Object[]> filesmatched = new ArrayList<>();
-        ArrayList<String> filesnotmatched = new ArrayList<>();
-        for (int i = 0; i < files.size(); i++)
+        @Override
+        public void run()
         {
-          String file = files.get(i).toString();
-          String pdbfn = "";
-          DataSourceType protocol = FormatAdapter.checkProtocol(file);
-          if (protocol == DataSourceType.FILE)
-          {
-            File fl = new File(file);
-            pdbfn = fl.getName();
-          }
-          else if (protocol == DataSourceType.URL)
-          {
-            URL url = new URL(file);
-            pdbfn = url.getFile();
-          }
-          if (pdbfn.length() > 0)
+          try
           {
-            // attempt to find a match in the alignment
-            SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
-            int l = 0, c = pdbfn.indexOf(".");
-            while (mtch == null && c != -1)
+            // check to see if any of these files have names matching sequences
+            // in
+            // the alignment
+            SequenceIdMatcher idm = new SequenceIdMatcher(
+                    viewport.getAlignment().getSequencesArray());
+            /**
+             * Object[] { String,SequenceI}
+             */
+            ArrayList<Object[]> filesmatched = new ArrayList<>();
+            ArrayList<String> filesnotmatched = new ArrayList<>();
+            for (int i = 0; i < files.size(); i++)
             {
-              do
-              {
-                l = c;
-              } while ((c = pdbfn.indexOf(".", l)) > l);
-              if (l > -1)
+              String file = files.get(i).toString();
+              String pdbfn = "";
+              DataSourceType protocol = FormatAdapter.checkProtocol(file);
+              if (protocol == DataSourceType.FILE)
               {
-                pdbfn = pdbfn.substring(0, l);
+                File fl = new File(file);
+                pdbfn = fl.getName();
               }
-              mtch = idm.findAllIdMatches(pdbfn);
-            }
-            if (mtch != null)
-            {
-              FileFormatI type = null;
-              try
-              {
-                type = new IdentifyFile().identify(file, protocol);
-              } catch (Exception ex)
+              else if (protocol == DataSourceType.URL)
               {
-                type = null;
+                URL url = new URL(file);
+                pdbfn = url.getFile();
               }
-              if (type != null && type.isStructureFile())
+              if (pdbfn.length() > 0)
               {
-                filesmatched.add(new Object[] { file, protocol, mtch });
-                continue;
+                // attempt to find a match in the alignment
+                SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
+                int l = 0, c = pdbfn.indexOf(".");
+                while (mtch == null && c != -1)
+                {
+                  do
+                  {
+                    l = c;
+                  } while ((c = pdbfn.indexOf(".", l)) > l);
+                  if (l > -1)
+                  {
+                    pdbfn = pdbfn.substring(0, l);
+                  }
+                  mtch = idm.findAllIdMatches(pdbfn);
+                }
+                if (mtch != null)
+                {
+                  FileFormatI type = null;
+                  try
+                  {
+                    type = new IdentifyFile().identify(file, protocol);
+                  } catch (Exception ex)
+                  {
+                    type = null;
+                  }
+                  if (type != null && type.isStructureFile())
+                  {
+                    filesmatched.add(new Object[] { file, protocol, mtch });
+                    continue;
+                  }
+                }
+                // File wasn't named like one of the sequences or wasn't a PDB
+                // file.
+                filesnotmatched.add(file);
               }
             }
-            // File wasn't named like one of the sequences or wasn't a PDB file.
-            filesnotmatched.add(file);
-          }
-        }
-        int assocfiles = 0;
-        if (filesmatched.size() > 0)
-        {
-          if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
-                  || JvOptionPane.showConfirmDialog(this,
-                          MessageManager.formatMessage(
-                                  "label.automatically_associate_structure_files_with_sequences_same_name",
-                                  new Object[]
-                                  { Integer.valueOf(filesmatched.size())
-                                          .toString() }),
-                          MessageManager.getString(
-                                  "label.automatically_associate_structure_files_by_name"),
-                          JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION)
-
-          {
-            for (Object[] fm : filesmatched)
+            int assocfiles = 0;
+            if (filesmatched.size() > 0)
             {
-              // try and associate
-              // TODO: may want to set a standard ID naming formalism for
-              // associating PDB files which have no IDs.
-              for (SequenceI toassoc : (SequenceI[]) fm[2])
+              if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
+                      || JvOptionPane.showConfirmDialog(thisaf,
+                              MessageManager.formatMessage(
+                                      "label.automatically_associate_structure_files_with_sequences_same_name",
+                                      new Object[]
+                                      { Integer.valueOf(filesmatched.size())
+                                              .toString() }),
+                              MessageManager.getString(
+                                      "label.automatically_associate_structure_files_by_name"),
+                              JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION)
+
               {
-                PDBEntry pe = new AssociatePdbFileWithSeq()
-                        .associatePdbWithSeq((String) fm[0],
-                                (DataSourceType) fm[1], toassoc, false,
-                                Desktop.instance);
-                if (pe != null)
+                for (Object[] fm : filesmatched)
                 {
-                  System.err.println("Associated file : " + ((String) fm[0])
-                          + " with " + toassoc.getDisplayId(true));
-                  assocfiles++;
+                  // try and associate
+                  // TODO: may want to set a standard ID naming formalism for
+                  // associating PDB files which have no IDs.
+                  for (SequenceI toassoc : (SequenceI[]) fm[2])
+                  {
+                    PDBEntry pe = new AssociatePdbFileWithSeq()
+                            .associatePdbWithSeq((String) fm[0],
+                                    (DataSourceType) fm[1], toassoc, false,
+                                    Desktop.instance);
+                    if (pe != null)
+                    {
+                      System.err.println("Associated file : "
+                              + ((String) fm[0]) + " with "
+                              + toassoc.getDisplayId(true));
+                      assocfiles++;
+                    }
+                  }
+                  // TODO: do we need to update overview ? only if features are
+                  // shown I guess
+                  alignPanel.paintAlignment(true, false);
                 }
               }
-              alignPanel.paintAlignment(true);
             }
-          }
-        }
-        if (filesnotmatched.size() > 0)
-        {
-          if (assocfiles > 0 && (Cache.getDefault(
-                  "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false)
-                  || JvOptionPane.showConfirmDialog(this,
-                          "<html>" + MessageManager.formatMessage(
-                                  "label.ignore_unmatched_dropped_files_info",
-                                  new Object[]
-                                  { Integer.valueOf(filesnotmatched.size())
-                                          .toString() })
-                                  + "</html>",
-                          MessageManager.getString(
-                                  "label.ignore_unmatched_dropped_files"),
-                          JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION))
-          {
-            return;
-          }
-          for (String fn : filesnotmatched)
+            if (filesnotmatched.size() > 0)
+            {
+              if (assocfiles > 0 && (Cache.getDefault(
+                      "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false)
+                      || JvOptionPane.showConfirmDialog(thisaf,
+                              "<html>" + MessageManager.formatMessage(
+                                      "label.ignore_unmatched_dropped_files_info",
+                                      new Object[]
+                                      { Integer.valueOf(
+                                              filesnotmatched.size())
+                                              .toString() })
+                                      + "</html>",
+                              MessageManager.getString(
+                                      "label.ignore_unmatched_dropped_files"),
+                              JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION))
+              {
+                return;
+              }
+              for (String fn : filesnotmatched)
+              {
+                loadJalviewDataFile(fn, null, null, null);
+              }
+
+            }
+          } catch (Exception ex)
           {
-            loadJalviewDataFile(fn, null, null, null);
+            ex.printStackTrace();
           }
-
         }
-      } catch (Exception ex)
-      {
-        ex.printStackTrace();
-      }
+      }).start();
     }
   }
 
@@ -4638,7 +4653,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           {
             if (parseFeaturesFile(file, sourceType))
             {
-              alignPanel.paintAlignment(true);
+              alignPanel.paintAlignment(true, true);
             }
           }
           else
@@ -4653,7 +4668,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         alignPanel.adjustAnnotationHeight();
         viewport.updateSequenceIdColours();
         buildSortByAnnotationScoresMenu();
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, true);
       }
     } catch (Exception ex)
     {
@@ -5178,7 +5193,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /*
@@ -5267,7 +5282,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -5279,7 +5294,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       viewport.getAlignment().setSeqrep(null);
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -5369,7 +5384,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     this.alignPanel.av.setSortAnnotationsBy(getAnnotationSortOrder());
     this.alignPanel.av
             .setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
index 25f44c5..ff2ffbb 100644 (file)
@@ -214,7 +214,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     alignFrame.updateEditMenuBar();
 
-    paintAlignment(true);
+    // no idea if we need to update structure
+    paintAlignment(true, true);
 
   }
 
@@ -231,7 +232,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
             new Dimension(10, av.getCharHeight() + fm.getDescent()));
     idSpaceFillerPanel1.setPreferredSize(
             new Dimension(10, av.getCharHeight() + fm.getDescent()));
-
+    idwidthAdjuster.invalidate();
+    scalePanelHolder.invalidate();
     getIdPanel().getIdCanvas().gg = null;
     getSeqPanel().seqCanvas.img = null;
     getAnnotationPanel().adjustPanelHeight();
@@ -242,11 +244,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
     getIdPanel().getIdCanvas().setPreferredSize(d);
     hscrollFillerPanel.setPreferredSize(d);
 
-    if (this.alignFrame.getSplitViewContainer() != null)
-    {
-      ((SplitFrame) this.alignFrame.getSplitViewContainer()).adjustLayout();
-    }
-
     repaint();
   }
 
@@ -485,7 +482,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
       scrollNeeded = vpRanges.scrollToWrappedVisible(start);
     }
 
-    paintAlignment(redrawOverview);
+    paintAlignment(redrawOverview, false);
 
     return scrollNeeded;
   }
@@ -542,7 +539,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
     validateAnnotationDimensions(true);
     addNotify();
-    paintAlignment(true);
+    // TODO: many places call this method and also paintAlignment with various
+    // different settings. this means multiple redraws are triggered...
+    paintAlignment(true, false);
   }
 
   /**
@@ -841,12 +840,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
     repaint();
   }
 
-  /**
-   * Repaint the alignment including the annotations and overview panels (if
-   * shown).
+  /* (non-Javadoc)
+   * @see jalview.api.AlignmentViewPanel#paintAlignment(boolean)
    */
   @Override
-  public void paintAlignment(boolean updateOverview)
+  public void paintAlignment(boolean updateOverview,
+          boolean updateStructures)
   {
     final AnnotationSorter sorter = new AnnotationSorter(getAlignment(),
             av.isShowAutocalculatedAbove());
@@ -854,10 +853,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
             av.getSortAnnotationsBy());
     repaint();
 
-    if (updateOverview)
+    if (updateStructures)
     {
-      // TODO: determine if this paintAlignment changed structure colours
       av.getStructureSelectionManager().sequenceColoursChanged(this);
+    }
+    if (updateOverview)
+    {
 
       if (overviewPanel != null)
       {
@@ -1100,8 +1101,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
      * single graphics context), then reset to (0, scale height)
      */
     alignmentGraphics.translate(alignmentGraphicsOffset, scaleHeight);
-    getSeqPanel().seqCanvas.drawPanel(alignmentGraphics, startRes, endRes,
-            startSeq, endSeq, 0);
+    getSeqPanel().seqCanvas.drawPanelForPrinting(alignmentGraphics, startRes,
+            endRes, startSeq, endSeq);
     alignmentGraphics.translate(-alignmentGraphicsOffset, 0);
 
     if (av.isShowAnnotation() && (endSeq == alignmentHeight))
@@ -1228,7 +1229,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     pg.translate(idWidth, 0);
 
-    getSeqPanel().seqCanvas.drawWrappedPanel(pg, pwidth - idWidth,
+    getSeqPanel().seqCanvas.drawWrappedPanelForPrinting(pg, pwidth - idWidth,
             totalHeight, 0);
 
     if ((pi * pheight) < totalHeight)
@@ -1870,7 +1871,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     if (adjustHeight)
     {
       // sort, repaint, update overview
-      paintAlignment(true);
+      paintAlignment(true, false);
     }
     else
     {
index 26796de..84883d7 100644 (file)
@@ -82,7 +82,7 @@ public class AnnotationChooser extends JPanel
   private boolean applyToUnselectedSequences;
 
   // currently selected 'annotation type' checkboxes
-  private Map<String, String> selectedTypes = new HashMap<String, String>();
+  private Map<String, String> selectedTypes = new HashMap<>();
 
   /**
    * Constructor.
@@ -202,7 +202,7 @@ public class AnnotationChooser extends JPanel
     // this.ap.alabels.setSize(this.ap.alabels.getSize().width,
     // this.ap.annotationPanel.getSize().height);
     // this.ap.validate();
-    this.ap.paintAlignment(true);
+    this.ap.paintAlignment(true, false);
   }
 
   /**
@@ -233,7 +233,7 @@ public class AnnotationChooser extends JPanel
     // this.ap.alabels.setSize(this.ap.alabels.getSize().width,
     // this.ap.annotationPanel.getSize().height);
     // this.ap.validate();
-    this.ap.paintAlignment(true);
+    this.ap.paintAlignment(true, false);
   }
 
   /**
@@ -251,7 +251,7 @@ public class AnnotationChooser extends JPanel
 
     this.ap.updateAnnotation();
     // this.ap.annotationPanel.adjustPanelHeight();
-    this.ap.paintAlignment(true);
+    this.ap.paintAlignment(true, false);
   }
 
   /**
@@ -356,7 +356,7 @@ public class AnnotationChooser extends JPanel
   public static List<String> getAnnotationTypes(AlignmentI alignment,
           boolean sequenceSpecificOnly)
   {
-    List<String> result = new ArrayList<String>();
+    List<String> result = new ArrayList<>();
     for (AlignmentAnnotation aa : alignment.getAlignmentAnnotation())
     {
       if (!sequenceSpecificOnly || aa.sequenceRef != null)
index f088791..153f70c 100644 (file)
@@ -79,7 +79,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     oldcs = av.getGlobalColourScheme();
     if (av.getAlignment().getGroups() != null)
     {
-      oldgroupColours = new Hashtable<SequenceGroup, ColourSchemeI>();
+      oldgroupColours = new Hashtable<>();
       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
       {
         if (sg.getColourScheme() != null)
@@ -122,7 +122,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     }
     Vector<String> annotItems = getAnnotationItems(
             seqAssociated.isSelected());
-    annotations = new JComboBox<String>(annotItems);
+    annotations = new JComboBox<>(annotItems);
 
     populateThresholdComboBox(threshold);
 
@@ -341,7 +341,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       getCurrentAnnotation().threshold.value = slider.getValue() / 1000f;
       propagateSeqAssociatedThreshold(updateAllAnnotation,
               getCurrentAnnotation());
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
@@ -415,12 +415,9 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     colorAlignmentContaining(getCurrentAnnotation(), selectedThresholdItem);
 
     ap.alignmentChanged();
-    // ensure all associated views (overviews, structures, etc) are notified of
-    // updated colours.
-    ap.paintAlignment(true);
   }
 
-  protected boolean colorAlignmentContaining(AlignmentAnnotation currentAnn,
+  protected void colorAlignmentContaining(AlignmentAnnotation currentAnn,
           int selectedThresholdOption)
   {
 
@@ -456,25 +453,10 @@ public class AnnotationColourChooser extends AnnotationRowFilter
         {
           continue;
         }
-
-        if (useOriginalColours.isSelected())
-        {
-          sg.setColourScheme(new AnnotationColourGradient(currentAnn,
-                  sg.getColourScheme(), selectedThresholdOption));
-          ((AnnotationColourGradient) sg.cs)
-                  .setSeqAssociated(seqAssociated.isSelected());
-        }
-        else
-        {
-          sg.setColourScheme(new AnnotationColourGradient(currentAnn,
-                  minColour.getBackground(), maxColour.getBackground(),
-                  selectedThresholdOption));
-          ((AnnotationColourGradient) sg.cs)
-                  .setSeqAssociated(seqAssociated.isSelected());
-        }
+        sg.setColourScheme(
+                acg.getInstance(sg, ap.av.getHiddenRepSequences()));
       }
     }
-    return false;
   }
 
 }
index 84b2c6f..020e027 100644 (file)
@@ -254,7 +254,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
         av.getAlignment().setHiddenColumns(oldHidden);
       }
       av.sendSelection();
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
   }
 
@@ -267,7 +267,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
       updateView();
       propagateSeqAssociatedThreshold(updateAllAnnotation,
               getCurrentAnnotation());
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
@@ -391,7 +391,8 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
     av.getColumnSelection().filterAnnotations(
             getCurrentAnnotation().annotations, filterParams);
 
-    if (getActionOption() == ACTION_OPTION_HIDE)
+    boolean hideCols = getActionOption() == ACTION_OPTION_HIDE;
+    if (hideCols)
     {
       av.hideSelectedColumns();
     }
@@ -399,7 +400,8 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
 
     filterParams = null;
     av.setAnnotationColumnSelectionState(this);
-    ap.paintAlignment(true);
+    // only update overview and structures if columns were hidden
+    ap.paintAlignment(hideCols, hideCols);
   }
 
   public HiddenColumns getOldHiddenColumns()
index d07cae2..b94a615 100755 (executable)
@@ -705,7 +705,7 @@ public class AnnotationLabels extends JPanel
         d = ap.annotationSpaceFillerHolder.getPreferredSize();
         ap.annotationSpaceFillerHolder
                 .setPreferredSize(new Dimension(d.width, d.height - dif));
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, false);
       }
 
       ap.addNotify();
@@ -855,7 +855,7 @@ public class AnnotationLabels extends JPanel
               }
             }
 
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
           }
@@ -912,7 +912,7 @@ public class AnnotationLabels extends JPanel
               sg.addSequence(aa[selectedRow].sequenceRef, false);
             }
             ap.av.setSelectionGroup(sg);
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
           }
index be8f5f6..12d1369 100755 (executable)
@@ -670,7 +670,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       }
       graphStretchY = evt.getY();
       adjustPanelHeight();
-      ap.paintAlignment(true);
+      ap.paintAlignment(false, false);
     }
     else
     {
index 8b2486f..71ad6a5 100644 (file)
@@ -80,7 +80,7 @@ public abstract class AnnotationRowFilter extends JPanel
    */
   protected boolean sliderDragging = false;
 
-  protected JComboBox<String> threshold = new JComboBox<String>();
+  protected JComboBox<String> threshold = new JComboBox<>();
 
   protected JComboBox<String> annotations;
 
@@ -177,7 +177,6 @@ public abstract class AnnotationRowFilter extends JPanel
           sliderDragging = false;
           valueChanged(true);
         }
-        ap.paintAlignment(true);
       }
     });
   }
@@ -192,9 +191,9 @@ public abstract class AnnotationRowFilter extends JPanel
    */
   public Vector<String> getAnnotationItems(boolean isSeqAssociated)
   {
-    annotationLabels = new HashMap<AlignmentAnnotation, String>();
+    annotationLabels = new HashMap<>();
 
-    Vector<String> list = new Vector<String>();
+    Vector<String> list = new Vector<>();
     int index = 1;
     int[] anmap = new int[av.getAlignment()
             .getAlignmentAnnotation().length];
@@ -271,7 +270,7 @@ public abstract class AnnotationRowFilter extends JPanel
   public void cancel_actionPerformed()
   {
     reset();
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
     try
     {
       frame.setClosed(true);
@@ -413,6 +412,11 @@ public abstract class AnnotationRowFilter extends JPanel
     this.currentAnnotation = annotation;
   }
 
+  /**
+   * update associated view model and trigger any necessary repaints.
+   * 
+   * @param updateAllAnnotation
+   */
   protected abstract void valueChanged(boolean updateAllAnnotation);
 
   protected abstract void updateView();
index 01ee1ff..2d1dfd4 100644 (file)
@@ -242,7 +242,7 @@ public class CrossRefAction implements Runnable
       String linkedTitle = MessageManager
               .getString("label.linked_view_title");
       Desktop.addInternalFrame(sf, linkedTitle, -1, -1);
-      sf.adjustDivider();
+      sf.adjustInitialLayout();
 
       // finally add the top, then bottom frame to the view list
       xrefViews.add(dna ? copyThis.alignPanel : newFrame.alignPanel);
index c8d900d..1f8983f 100644 (file)
@@ -269,12 +269,14 @@ public class Desktop extends jalview.jbgui.GDesktop
     public void endDraggingFrame(JComponent f)
     {
       delegate.endDraggingFrame(f);
+      desktop.repaint();
     }
 
     @Override
     public void endResizingFrame(JComponent f)
     {
       delegate.endResizingFrame(f);
+      desktop.repaint();
     }
 
     @Override
@@ -344,10 +346,6 @@ public class Desktop extends jalview.jbgui.GDesktop
     boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
             false);
     desktop = new MyDesktopPane(selmemusage);
-    if (Platform.isAMac())
-    {
-      desktop.setDoubleBuffered(false);
-    }
     showMemusage.setSelected(selmemusage);
     desktop.setBackground(Color.white);
     getContentPane().setLayout(new BorderLayout());
@@ -361,7 +359,9 @@ public class Desktop extends jalview.jbgui.GDesktop
     // This line prevents Windows Look&Feel resizing all new windows to maximum
     // if previous window was maximised
     desktop.setDesktopManager(
-            new MyDesktopManager(new DefaultDesktopManager()));
+            new MyDesktopManager(
+                    (Platform.isWindows() ? new DefaultDesktopManager()
+                            : desktop.getDesktopManager())));
 
     Rectangle dims = getLastKnownDimensions("");
     if (dims != null)
@@ -866,13 +866,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     frame.setResizable(resizable);
     frame.setMaximizable(resizable);
     frame.setIconifiable(resizable);
-    if (Platform.isAMac())
-    {
-      frame.setIconifiable(false);
-      frame.setFrameIcon(null);
-      // frame.setDesktopIcon(null);
-      frame.setDoubleBuffered(false);
-    }
+
     if (frame.getX() < 1 && frame.getY() < 1)
     {
       frame.setLocation(xOffset * openFrameCount,
@@ -1011,8 +1005,8 @@ public class Desktop extends jalview.jbgui.GDesktop
     // Java's Transferable for native dnd
     evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
     Transferable t = evt.getTransferable();
-    List<String> files = new ArrayList<String>();
-    List<DataSourceType> protocols = new ArrayList<DataSourceType>();
+    List<String> files = new ArrayList<>();
+    List<DataSourceType> protocols = new ArrayList<>();
 
     try
     {
@@ -1720,7 +1714,7 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   JPanel progressPanel;
 
-  ArrayList<JPanel> fileLoadingPanels = new ArrayList<JPanel>();
+  ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
 
   public void startLoading(final String fileName)
   {
@@ -1812,7 +1806,7 @@ public class Desktop extends jalview.jbgui.GDesktop
       // TODO: verify that frames are recoverable when in headless mode
       return null;
     }
-    List<AlignmentPanel> aps = new ArrayList<AlignmentPanel>();
+    List<AlignmentPanel> aps = new ArrayList<>();
     AlignFrame[] frames = getAlignFrames();
     if (frames == null)
     {
@@ -1847,7 +1841,7 @@ public class Desktop extends jalview.jbgui.GDesktop
    */
   public static AlignmentViewport[] getViewports(String sequenceSetId)
   {
-    List<AlignmentViewport> viewp = new ArrayList<AlignmentViewport>();
+    List<AlignmentViewport> viewp = new ArrayList<>();
     if (desktop != null)
     {
       AlignFrame[] frames = Desktop.getAlignFrames();
@@ -2360,7 +2354,7 @@ public class Desktop extends jalview.jbgui.GDesktop
           // SEQUENCE_ID which is not the default EMBL_EBI link
           ListIterator<String> li = links.listIterator();
           boolean check = false;
-          List<JLabel> urls = new ArrayList<JLabel>();
+          List<JLabel> urls = new ArrayList<>();
           while (li.hasNext())
           {
             String link = li.next();
@@ -2454,6 +2448,7 @@ public class Desktop extends jalview.jbgui.GDesktop
         Thread worker = new Thread(this);
         worker.start();
       }
+      repaint();
     }
 
     public boolean isShowMemoryUsage()
@@ -2545,7 +2540,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     {
       return null;
     }
-    List<AlignFrame> avp = new ArrayList<AlignFrame>();
+    List<AlignFrame> avp = new ArrayList<>();
     // REVERSE ORDER
     for (int i = frames.length - 1; i > -1; i--)
     {
@@ -2590,7 +2585,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     {
       return null;
     }
-    List<GStructureViewer> avp = new ArrayList<GStructureViewer>();
+    List<GStructureViewer> avp = new ArrayList<>();
     // REVERSE ORDER
     for (int i = frames.length - 1; i > -1; i--)
     {
@@ -2733,8 +2728,8 @@ public class Desktop extends jalview.jbgui.GDesktop
   {
     if (progressBars == null)
     {
-      progressBars = new Hashtable<Long, JPanel>();
-      progressBarHandlers = new Hashtable<Long, IProgressIndicatorHandler>();
+      progressBars = new Hashtable<>();
+      progressBarHandlers = new Hashtable<>();
     }
 
     if (progressBars.get(new Long(id)) != null)
index b27328d..d8db546 100644 (file)
@@ -147,7 +147,7 @@ public class FeatureColourChooser extends JalviewDialog
          */
         if (ap != null)
         {
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
         }
       }
     });
@@ -396,9 +396,9 @@ public class FeatureColourChooser extends JalviewDialog
    * feature type, and repaints the alignment, and optionally the Overview
    * and/or structure viewer if open
    * 
-   * @param updateOverview
+   * @param updateStructsAndOverview
    */
-  void changeColour(boolean updateOverview)
+  void changeColour(boolean updateStructsAndOverview)
   {
     // Check if combobox is still adjusting
     if (adjusting)
@@ -507,7 +507,7 @@ public class FeatureColourChooser extends JalviewDialog
     }
     fr.setColour(type, acg);
     cs = acg;
-    ap.paintAlignment(updateOverview);
+    ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview);
   }
 
   @Override
@@ -539,7 +539,7 @@ public class FeatureColourChooser extends JalviewDialog
   void reset()
   {
     fr.setColour(type, oldcs);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
     cs = null;
   }
 
@@ -565,7 +565,7 @@ public class FeatureColourChooser extends JalviewDialog
       /*
        * force repaint of any Overview window or structure
        */
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     } catch (NumberFormatException ex)
     {
     }
index 17f5a71..9c4b009 100644 (file)
@@ -243,7 +243,7 @@ public class FeatureRenderer
       JPanel choosePanel = new JPanel();
       choosePanel.add(new JLabel(
               MessageManager.getString("label.select_feature") + ":"));
-      final JComboBox<String> overlaps = new JComboBox<String>();
+      final JComboBox<String> overlaps = new JComboBox<>();
       List<String> added = new ArrayList<>();
       for (SequenceFeature sf : features)
       {
@@ -487,7 +487,7 @@ public class FeatureRenderer
 
         featuresAdded();
 
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, true);
 
         return true;
       }
@@ -497,7 +497,7 @@ public class FeatureRenderer
       }
     }
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
 
     return true;
   }
index bd74db5..b768339 100644 (file)
@@ -131,6 +131,11 @@ public class FeatureSettings extends JPanel
   private static final int MIN_WIDTH = 400;
 
   private static final int MIN_HEIGHT = 400;
+  
+  /**
+   * when true, constructor is still executing - so ignore UI events
+   */
+  protected volatile boolean inConstruction = true;
 
   /**
    * Constructor
@@ -303,6 +308,7 @@ public class FeatureSettings extends JPanel
               };
             });
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
+    inConstruction = false;
   }
 
   protected void popupSort(final int selectedRow, final String type,
@@ -485,7 +491,7 @@ public class FeatureSettings extends JPanel
   @Override
   synchronized public void discoverAllFeatureData()
   {
-    Set<String> allGroups = new HashSet<String>();
+    Set<String> allGroups = new HashSet<>();
     AlignmentI alignment = af.getViewport().getAlignment();
 
     for (int i = 0; i < alignment.getHeight(); i++)
@@ -528,6 +534,7 @@ public class FeatureSettings extends JPanel
     final String grp = group;
     final JCheckBox check = new JCheckBox(group, visible);
     check.setFont(new Font("Serif", Font.BOLD, 12));
+    check.setToolTipText(group);
     check.addItemListener(new ItemListener()
     {
       @Override
@@ -556,12 +563,12 @@ public class FeatureSettings extends JPanel
       return;
     }
     resettingTable = true;
-    typeWidth = new Hashtable<String, float[]>();
+    typeWidth = new Hashtable<>();
     // TODO: change avWidth calculation to 'per-sequence' average and use long
     // rather than float
 
-    Set<String> displayableTypes = new HashSet<String>();
-    Set<String> foundGroups = new HashSet<String>();
+    Set<String> displayableTypes = new HashSet<>();
+    Set<String> foundGroups = new HashSet<>();
 
     /*
      * determine which feature types may be visible depending on 
@@ -577,7 +584,7 @@ public class FeatureSettings extends JPanel
        * and keep track of which groups are visible
        */
       Set<String> groups = seq.getFeatures().getFeatureGroups(true);
-      Set<String> visibleGroups = new HashSet<String>();
+      Set<String> visibleGroups = new HashSet<>();
       for (String group : groups)
       {
         if (group == null || checkGroupState(group))
@@ -1057,7 +1064,7 @@ public class FeatureSettings extends JPanel
   {
     if (fr.setFeaturePriority(data, visibleNew))
     {
-      af.alignPanel.paintAlignment(true);
+      af.alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -1236,8 +1243,11 @@ public class FeatureSettings extends JPanel
       @Override
       public void stateChanged(ChangeEvent evt)
       {
-        fr.setTransparency((100 - transparency.getValue()) / 100f);
-        af.alignPanel.paintAlignment(true);
+        if (!inConstruction)
+        {
+          fr.setTransparency((100 - transparency.getValue()) / 100f);
+          af.alignPanel.paintAlignment(true,true);
+        }
       }
     });
 
index 5271e4f..80ac189 100755 (executable)
@@ -183,7 +183,7 @@ public class FontChooser extends GFontChooser
   {
     ap.av.antiAlias = smoothFont.isSelected();
     ap.getAnnotationPanel().image = null;
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, false);
     if (ap.av.getCodingComplement() != null && ap.av.isProteinFontAsCdna())
     {
       ((AlignViewport) ap.av
@@ -235,7 +235,7 @@ public class FontChooser extends GFontChooser
       ap.av.setScaleProteinAsCdna(oldProteinScale);
       ap.av.setProteinFontAsCdna(oldMirrorFont);
       ap.av.antiAlias = oldSmoothFont;
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, false);
 
       if (scaleAsCdna.isVisible() && scaleAsCdna.isEnabled())
       {
@@ -327,22 +327,17 @@ public class FontChooser extends GFontChooser
       ap.fontChanged();
 
       /*
-       * adjust other half of split frame if any, if either same
-       * font, or proportionate scaling, is selected
+       * adjust other half of split frame if present, whether or not same font or
+       * scale to cDNA is selected, because a font change may affect character
+       * width, and this is kept the same in both panels
        */
-      if (fontAsCdna.isEnabled())
+      if (fontAsCdna.isVisible())
       {
         if (fontAsCdna.isSelected())
         {
-          /*
-           * copy the font
-           */
           ap.av.getCodingComplement().setFont(newFont, true);
         }
 
-        /*
-         * adjust layout for font change / reset / sizing
-         */
         SplitFrame splitFrame = (SplitFrame) ap.alignFrame
                 .getSplitViewContainer();
         splitFrame.adjustLayout();
index 3cc0ed3..a46c2c1 100755 (executable)
@@ -138,7 +138,7 @@ public class IdPanel extends JPanel
     }
 
     lastid = seq;
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -313,7 +313,7 @@ public class IdPanel extends JPanel
 
     av.isSelectionGroupChanged(true);
 
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -507,7 +507,7 @@ public class IdPanel extends JPanel
           running = false;
         }
 
-        alignPanel.paintAlignment(false);
+        alignPanel.paintAlignment(false, false);
 
         try
         {
index 3c4107f..8400543 100755 (executable)
@@ -75,6 +75,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mousePressed(MouseEvent evt)
   {
     oldX = evt.getX();
@@ -86,6 +87,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseReleased(MouseEvent evt)
   {
     active = false;
@@ -112,6 +114,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseEntered(MouseEvent evt)
   {
     active = true;
@@ -124,6 +127,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseExited(MouseEvent evt)
   {
     active = false;
@@ -136,6 +140,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseDragged(MouseEvent evt)
   {
     active = true;
@@ -149,7 +154,7 @@ public class IdwidthAdjuster extends JPanel
     {
       viewport.setIdWidth(newWidth);
 
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, false);
     }
 
     oldX = evt.getX();
@@ -161,6 +166,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseMoved(MouseEvent evt)
   {
   }
@@ -171,6 +177,7 @@ public class IdwidthAdjuster extends JPanel
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseClicked(MouseEvent evt)
   {
   }
@@ -181,6 +188,7 @@ public class IdwidthAdjuster extends JPanel
    * @param g
    *          DOCUMENT ME!
    */
+  @Override
   public void paintComponent(Graphics g)
   {
     g.setColor(Color.white);
index 1658f0f..b357234 100644 (file)
@@ -2295,6 +2295,7 @@ public class Jalview2XML
 
       jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
       af = loadJalviewAlign(jprovider);
+      af.setMenusForViewport();
 
     } catch (MalformedURLException e)
     {
index 27f9c3f..7371eb5 100644 (file)
@@ -21,7 +21,9 @@
 package jalview.gui;
 
 import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
 import jalview.renderer.OverviewRenderer;
+import jalview.renderer.OverviewResColourFinder;
 import jalview.viewmodel.OverviewDimensions;
 
 import java.awt.Color;
@@ -41,6 +43,8 @@ public class OverviewCanvas extends JComponent
 
   private volatile boolean updaterunning = false;
 
+  private boolean dispose = false;
+
   private BufferedImage miniMe;
 
   private BufferedImage lastMiniMe = null;
@@ -57,16 +61,29 @@ public class OverviewCanvas extends JComponent
 
   private AlignViewportI av;
 
+  private OverviewResColourFinder cf;
+
+  private ProgressPanel progressPanel;
+
   public OverviewCanvas(OverviewDimensions overviewDims,
-          AlignViewportI alignvp)
+          AlignViewportI alignvp, ProgressPanel pp)
   {
     od = overviewDims;
     av = alignvp;
+    progressPanel = pp;
 
     sr = new SequenceRenderer(av);
     sr.renderGaps = false;
-    sr.forOverview = true;
     fr = new jalview.renderer.seqfeatures.FeatureRenderer(av);
+
+    boolean useLegacy = Cache.getDefault(Preferences.USE_LEGACY_GAP, false);
+    Color gapCol = Cache.getDefaultColour(Preferences.GAP_COLOUR,
+            jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP);
+    Color hiddenCol = Cache.getDefaultColour(Preferences.HIDDEN_COLOUR,
+            jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_HIDDEN);
+    cf = new OverviewResColourFinder(useLegacy, gapCol, hiddenCol);
+
+    setSize(od.getWidth(), od.getHeight());
   }
 
   /**
@@ -126,7 +143,11 @@ public class OverviewCanvas extends JComponent
 
     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
 
-    or = new OverviewRenderer(sr, fr, od);
+    or = new OverviewRenderer(fr, od, av.getAlignment(),
+            av.getResidueShading(), cf);
+
+    or.addPropertyChangeListener(progressPanel);
+
     miniMe = or.draw(od.getRows(av.getAlignment()),
             od.getColumns(av.getAlignment()));
 
@@ -142,10 +163,15 @@ public class OverviewCanvas extends JComponent
     }
     System.gc();
 
+    or.removePropertyChangeListener(progressPanel);
+    or = null;
     if (restart)
     {
       restart = false;
-      draw(showSequenceFeatures, showAnnotation, transferRenderer);
+      if (!dispose)
+      {
+        draw(showSequenceFeatures, showAnnotation, transferRenderer);
+      }
     }
     else
     {
@@ -173,16 +199,71 @@ public class OverviewCanvas extends JComponent
     }
     else if (lastMiniMe != null)
     {
-      g.drawImage(lastMiniMe, 0, 0, this);
-      if (lastMiniMe != miniMe)
+      // is this a resize?
+      if ((getWidth() > 0) && (getHeight() > 0)
+              && ((getWidth() != od.getWidth())
+                      || (getHeight() != od.getHeight())))
       {
-        g.setColor(TRANS_GREY);
-        g.fillRect(0, 0, getWidth(), getHeight());
+        // if there is annotation, scale the alignment and annotation separately
+        if (od.getGraphHeight() > 0)
+        {
+          BufferedImage topImage = lastMiniMe.getSubimage(0, 0,
+                  od.getWidth(), od.getSequencesHeight());
+          BufferedImage bottomImage = lastMiniMe.getSubimage(0,
+                  od.getSequencesHeight(), od.getWidth(),
+                  od.getGraphHeight());
+
+          // must be done at this point as we rely on using old width/height
+          // above, and new width/height below
+          od.setWidth(getWidth());
+          od.setHeight(getHeight());
+
+          // stick the images back together so lastMiniMe is consistent in the
+          // event of a repaint - BUT probably not thread safe
+          lastMiniMe = new BufferedImage(od.getWidth(), od.getHeight(),
+                  BufferedImage.TYPE_INT_RGB);
+          Graphics lg = lastMiniMe.getGraphics();
+          lg.drawImage(topImage, 0, 0, od.getWidth(),
+                  od.getSequencesHeight(), null);
+          lg.drawImage(bottomImage, 0, od.getSequencesHeight(),
+                  od.getWidth(), od.getGraphHeight(), this);
+          lg.dispose();
+        }
+        else
+        {
+          od.setWidth(getWidth());
+          od.setHeight(getHeight());
+        }
+
+        // scale lastMiniMe to the new size
+        g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
+
+        // make sure the box is in the right place
+        od.setBoxPosition(av.getAlignment().getHiddenSequences(),
+                av.getAlignment().getHiddenColumns());
+      }
+      else // not a resize
+      {
+        // fall back to normal behaviour
+        g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
       }
     }
 
+    // draw the box
     g.setColor(Color.red);
     od.drawBox(g);
   }
 
+  public void dispose()
+  {
+    dispose = true;
+    synchronized (this)
+    {
+      restart = true;
+      if (or != null)
+      {
+        or.setRedraw(true);
+      }
+    }
+  }
 }
index 28de801..51d7a84 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import jalview.bin.Cache;
+import jalview.renderer.OverviewRenderer;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.viewmodel.OverviewDimensions;
@@ -68,6 +70,8 @@ public class OverviewPanel extends JPanel
 
   private boolean draggingBox = false;
 
+  private ProgressPanel progressPanel;
+
   /**
    * Creates a new OverviewPanel object.
    * 
@@ -79,30 +83,62 @@ public class OverviewPanel extends JPanel
     this.av = alPanel.av;
     this.ap = alPanel;
 
-    od = new OverviewDimensionsShowHidden(av.getRanges(),
+    showHidden = Cache.getDefault(Preferences.SHOW_OV_HIDDEN_AT_START,
+            true);
+    if (showHidden)
+    {
+      od = new OverviewDimensionsShowHidden(av.getRanges(),
             (av.isShowAnnotation()
                     && av.getAlignmentConservationAnnotation() != null));
+    }
+    else
+    {
+      od = new OverviewDimensionsHideHidden(av.getRanges(),
+              (av.isShowAnnotation()
+                      && av.getAlignmentConservationAnnotation() != null));
+    }
 
-    setSize(od.getWidth(), od.getHeight());
-
-    oviewCanvas = new OverviewCanvas(od, av);
     setLayout(new BorderLayout());
+    progressPanel = new ProgressPanel(OverviewRenderer.UPDATE,
+            MessageManager.getString("label.oview_calc"), getWidth());
+    this.add(progressPanel, BorderLayout.SOUTH);
+    oviewCanvas = new OverviewCanvas(od, av, progressPanel);
+
     add(oviewCanvas, BorderLayout.CENTER);
 
     av.getRanges().addPropertyChangeListener(this);
 
+    // without this the overview window does not size to fit the overview canvas
+    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+
     addComponentListener(new ComponentAdapter()
     {
       @Override
       public void componentResized(ComponentEvent evt)
       {
-        if ((getWidth() != od.getWidth())
-                || (getHeight() != (od.getHeight())))
+        // Resize is called on the initial display of the overview.
+        // This code adjusts sizes to account for the progress bar if it has not
+        // already been accounted for, which triggers another resize call for
+        // the correct sizing, at which point the overview image is updated.
+        // (This avoids a double recalculation of the image.)
+        if (getWidth() == od.getWidth() && getHeight() == od.getHeight()
+                + progressPanel.getHeight())
         {
           updateOverviewImage();
-          setBoxPosition();
+        }
+        else
+        {
+          if ((getWidth() > 0) && (getHeight() > 0))
+          {
+            od.setWidth(getWidth());
+            od.setHeight(getHeight() - progressPanel.getHeight());
+          }
+
+          setPreferredSize(new Dimension(od.getWidth(),
+                  od.getHeight() + progressPanel.getHeight()));
         }
       }
+
     });
 
     addMouseMotionListener(new MouseMotionAdapter()
@@ -158,13 +194,13 @@ public class OverviewPanel extends JPanel
           }
         }
         else
-        // if (!av.getWrapAlignment())
         {
+          // don't do anything if the mouse press is in the overview's box
+          // (wait to see if it's a drag instead)
+          // otherwise update the viewport
           if (!od.isPositionInBox(evt.getX(), evt.getY()))
           {
-            // don't do anything if the mouse press is in the overview's box
-            // (wait to see if it's a drag instead)
-            // otherwise update the viewport
+            draggingBox = false;
             od.updateViewportFromMouse(evt.getX(), evt.getY(),
                     av.getAlignment().getHiddenSequences(),
                     av.getAlignment().getHiddenColumns());
@@ -180,15 +216,6 @@ public class OverviewPanel extends JPanel
       }
 
       @Override
-      public void mouseReleased(MouseEvent evt)
-      {
-        if (draggingBox)
-        {
-          draggingBox = false;
-        }
-      }
-
-      @Override
       public void mouseClicked(MouseEvent evt)
       {
         if (SwingUtilities.isRightMouseButton(evt))
@@ -197,8 +224,6 @@ public class OverviewPanel extends JPanel
         }
       }
     });
-
-    updateOverviewImage();
   }
 
   /*
@@ -266,10 +291,11 @@ public class OverviewPanel extends JPanel
     if ((getWidth() > 0) && (getHeight() > 0))
     {
       od.setWidth(getWidth());
-      od.setHeight(getHeight());
+      od.setHeight(getHeight() - progressPanel.getHeight());
     }
-
-    setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+    
+    setPreferredSize(new Dimension(od.getWidth(),
+            od.getHeight() + progressPanel.getHeight()));
 
     if (oviewCanvas.restartDraw())
     {
@@ -279,16 +305,21 @@ public class OverviewPanel extends JPanel
     Thread thread = new Thread(this);
     thread.start();
     repaint();
+
+    
   }
 
   @Override
   public void run()
   {
-    oviewCanvas.draw(av.isShowSequenceFeatures(),
-            (av.isShowAnnotation()
-                    && av.getAlignmentConservationAnnotation() != null),
-            ap.getSeqPanel().seqCanvas.getFeatureRenderer());
-    setBoxPosition();
+    if (oviewCanvas != null)
+    {
+      oviewCanvas.draw(av.isShowSequenceFeatures(),
+              (av.isShowAnnotation()
+                      && av.getAlignmentConservationAnnotation() != null),
+              ap.getSeqPanel().seqCanvas.getFeatureRenderer());
+      setBoxPosition();
+    }
   }
 
   /**
@@ -298,9 +329,12 @@ public class OverviewPanel extends JPanel
    */
   private void setBoxPosition()
   {
-    od.setBoxPosition(av.getAlignment().getHiddenSequences(),
-            av.getAlignment().getHiddenColumns());
-    repaint();
+    if (od != null)
+    {
+      od.setBoxPosition(av.getAlignment().getHiddenSequences(),
+              av.getAlignment().getHiddenColumns());
+      repaint();
+    }
   }
 
   @Override
@@ -317,8 +351,10 @@ public class OverviewPanel extends JPanel
     try
     {
       av.getRanges().removePropertyChangeListener(this);
+      oviewCanvas.dispose();
     } finally
     {
+      progressPanel = null;
       av = null;
       oviewCanvas = null;
       ap = null;
index 2473ba9..850a09a 100644 (file)
@@ -455,8 +455,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         buildGroupURLMenu(sg, groupLinks);
       }
       // Add a 'show all structures' for the current selection
-      Hashtable<String, PDBEntry> pdbe = new Hashtable<String, PDBEntry>(),
-              reppdb = new Hashtable<String, PDBEntry>();
+      Hashtable<String, PDBEntry> pdbe = new Hashtable<>(), reppdb = new Hashtable<>();
+
       SequenceI sqass = null;
       for (SequenceI sq : ap.av.getSequenceSelection())
       {
@@ -523,7 +523,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
   void addFeatureLinks(final SequenceI seq, List<String> links)
   {
     JMenu linkMenu = new JMenu(MessageManager.getString("action.link"));
-    Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+    Map<String, List<String>> linkset = new LinkedHashMap<>();
 
     for (String link : links)
     {
@@ -609,8 +609,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
      * the insertion order, which is the order of the annotations on the
      * alignment.
      */
-    Map<String, List<List<String>>> shownTypes = new LinkedHashMap<String, List<List<String>>>();
-    Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<String, List<List<String>>>();
+    Map<String, List<List<String>>> shownTypes = new LinkedHashMap<>();
+    Map<String, List<List<String>>> hiddenTypes = new LinkedHashMap<>();
     AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
             AlignmentAnnotationUtils.asList(annotations), forSequences);
 
@@ -716,7 +716,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
 
     SequenceI[] seqs = ap.av.getSelectionAsNewSequence();
     String[][] idandseqs = GroupUrlLink.formStrings(seqs);
-    Hashtable<String, Object[]> commonDbrefs = new Hashtable<String, Object[]>();
+    Hashtable<String, Object[]> commonDbrefs = new Hashtable<>();
     for (int sq = 0; sq < seqs.length; sq++)
     {
 
@@ -1377,8 +1377,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
      * Temporary store to hold distinct calcId / type pairs for the tooltip.
      * Using TreeMap means calcIds are shown in alphabetical order.
      */
-    SortedMap<String, String> tipEntries = new TreeMap<String, String>();
-    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
+    SortedMap<String, String> tipEntries = new TreeMap<>();
+    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
     AlignmentI al = this.ap.av.getAlignment();
     AlignmentUtils.findAddableReferenceAnnotations(forSequences, tipEntries,
             candidates, al);
@@ -1561,7 +1561,9 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
   void refresh()
   {
     ap.updateAnnotation();
-    ap.paintAlignment(true);
+    // removed paintAlignment(true) here:
+    // updateAnnotation calls paintAlignment already, so don't need to call
+    // again
 
     PaintRefresher.Refresh(this, ap.av.getSequenceSetId());
   }
@@ -1741,7 +1743,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       }
 
       sequence.setName(dialog.getName().replace(' ', '_'));
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
 
     sequence.setDescription(dialog.getDescription());
@@ -1929,8 +1931,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       return;
     }
 
-    List<SequenceI> seqs = new ArrayList<SequenceI>();
-    List<SequenceFeature> features = new ArrayList<SequenceFeature>();
+    List<SequenceI> seqs = new ArrayList<>();
+    List<SequenceFeature> features = new ArrayList<>();
 
     /*
      * assemble dataset sequences, and template new sequence features,
index c3c9239..6635dbe 100755 (executable)
@@ -109,6 +109,14 @@ public class Preferences extends GPreferences
 
   public static final String SHOW_OCCUPANCY = "SHOW_OCCUPANCY";
 
+  public static final String SHOW_OV_HIDDEN_AT_START = "SHOW_OV_HIDDEN_AT_START";
+
+  public static final String USE_LEGACY_GAP = "USE_LEGACY_GAP";
+
+  public static final String GAP_COLOUR = "GAP_COLOUR";
+
+  public static final String HIDDEN_COLOUR = "HIDDEN_COLOUR";
+
   private static final int MIN_FONT_SIZE = 1;
 
   private static final int MAX_FONT_SIZE = 30;
@@ -155,7 +163,7 @@ public class Preferences extends GPreferences
      * .properties file as '|' separated strings
      */
 
-    groupURLLinks = new ArrayList<String>();
+    groupURLLinks = new ArrayList<>();
   }
 
   JInternalFrame frame;
@@ -309,6 +317,21 @@ public class Preferences extends GPreferences
             Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX", Color.red));
 
     /*
+     * Set overview panel defaults
+     */
+    gapColour.setBackground(
+            Cache.getDefaultColour(GAP_COLOUR,
+                    jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP));
+    hiddenColour.setBackground(
+            Cache.getDefaultColour(HIDDEN_COLOUR,
+                    jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_HIDDEN));
+    useLegacyGap.setSelected(Cache.getDefault(USE_LEGACY_GAP, false));
+    gapLabel.setEnabled(!useLegacyGap.isSelected());
+    gapColour.setEnabled(!useLegacyGap.isSelected());
+    showHiddenAtStart
+            .setSelected(Cache.getDefault(SHOW_OV_HIDDEN_AT_START, true));
+
+    /*
      * Set Structure tab defaults.
      */
     final boolean structSelected = Cache.getDefault(STRUCT_FROM_PDB, false);
@@ -631,6 +654,16 @@ public class Preferences extends GPreferences
             maxColour.getBackground());
 
     /*
+     * Save Overview settings
+     */
+    Cache.setColourProperty(GAP_COLOUR, gapColour.getBackground());
+    Cache.setColourProperty(HIDDEN_COLOUR, hiddenColour.getBackground());
+    Cache.applicationProperties.setProperty(USE_LEGACY_GAP,
+            Boolean.toString(useLegacyGap.isSelected()));
+    Cache.applicationProperties.setProperty(SHOW_OV_HIDDEN_AT_START,
+            Boolean.toString(showHiddenAtStart.isSelected()));
+
+    /*
      * Save Structure settings
      */
     Cache.applicationProperties.setProperty(ADD_TEMPFACT_ANN,
@@ -1035,6 +1068,63 @@ public class Preferences extends GPreferences
   }
 
   @Override
+  public void gapColour_actionPerformed(JPanel gap)
+  {
+    if (!useLegacyGap.isSelected())
+    {
+      Color col = JColorChooser.showDialog(this,
+              MessageManager.getString("label.select_gap_colour"),
+              gapColour.getBackground());
+      if (col != null)
+      {
+        gap.setBackground(col);
+      }
+      gap.repaint();
+    }
+  }
+
+  @Override
+  public void hiddenColour_actionPerformed(JPanel hidden)
+  {
+    Color col = JColorChooser.showDialog(this,
+            MessageManager.getString("label.select_hidden_colour"),
+            hiddenColour.getBackground());
+    if (col != null)
+    {
+      hidden.setBackground(col);
+    }
+    hidden.repaint();
+  }
+
+  @Override
+  protected void useLegacyGaps_actionPerformed(ActionEvent e)
+  {
+    boolean enabled = useLegacyGap.isSelected();
+    if (enabled)
+    {
+      gapColour.setBackground(
+              jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_LEGACY_GAP);
+    }
+    else
+    {
+      gapColour.setBackground(
+              jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP);
+    }
+    gapColour.setEnabled(!enabled);
+    gapLabel.setEnabled(!enabled);
+  }
+
+  @Override
+  protected void resetOvDefaults_actionPerformed(ActionEvent e)
+  {
+    useLegacyGap.setSelected(false);
+    useLegacyGaps_actionPerformed(null);
+    showHiddenAtStart.setSelected(true);
+    hiddenColour.setBackground(
+            jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_HIDDEN);
+  }
+
+  @Override
   protected void userIdWidth_actionPerformed()
   {
     try
diff --git a/src/jalview/gui/ProgressPanel.java b/src/jalview/gui/ProgressPanel.java
new file mode 100644 (file)
index 0000000..170e9eb
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.gui;
+
+import jalview.api.RendererListenerI;
+
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.beans.PropertyChangeEvent;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * A class to manage a panel containing a label and progress bar updated by an
+ * event firing
+ * 
+ * @author kmourao
+ *
+ */
+public class ProgressPanel extends JPanel implements RendererListenerI
+{
+  // max value of progress bar: values expected to be %s
+  private final int MAXVALUE = 100;
+
+  private final String VISIBLE = "VISIBLE";
+
+  private final String INVISIBLE = "INVISIBLE";
+
+  // name of event property which updates the progress bar
+  private String eventName;
+
+  private JProgressBar progressBar;
+
+  private JLabel progressLabel;
+
+  private JPanel labelPanel = new JPanel();
+
+  private CardLayout labelLayout = new CardLayout();
+
+  private JPanel barPanel = new JPanel();
+
+  private CardLayout barLayout = new CardLayout();
+
+  /**
+   * Construct a JPanel containing a progress bar and a label.
+   * 
+   * @param eventPropertyName
+   *          The name of the event property to update the progress bar
+   * @param label
+   *          The label to place next to the progress bar
+   */
+  public ProgressPanel(String eventPropertyName, String label, int maxwidth)
+  {
+    super(new BorderLayout(10, 0));
+    setBorder(new EmptyBorder(0, 3, 0, 0));
+
+    eventName = eventPropertyName;
+    String labelText = label;
+
+    final int w = maxwidth;
+
+    progressBar = new JProgressBar()
+    {
+      @Override
+      public Dimension getMaximumSize()
+      {
+        return new Dimension(w, 1);
+      }
+    };
+    progressBar.setMinimum(0);
+    progressBar.setPreferredSize(progressBar.getMaximumSize());
+    progressLabel = new JLabel(labelText);
+    progressLabel.setFont(new java.awt.Font("Verdana", 0, 11));
+
+    // Use a CardLayout to stop the progress bar panel moving around when
+    // changing visibility
+    labelPanel.setLayout(labelLayout);
+    barPanel.setLayout(barLayout);
+  
+    labelPanel.add(progressLabel, VISIBLE);
+    labelPanel.add(new JPanel(), INVISIBLE);
+    barPanel.add(progressBar, VISIBLE);
+    barPanel.add(new JPanel(), INVISIBLE);
+
+    labelLayout.show(labelPanel, VISIBLE);
+    barLayout.show(barPanel, VISIBLE);
+
+    add(labelPanel, BorderLayout.WEST);
+    add(barPanel, BorderLayout.CENTER);
+    add(new JLabel(" "), BorderLayout.EAST);
+
+    setBorder(BorderFactory.createLineBorder(Color.black));
+    // setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
+  }
+
+  @Override
+  /**
+   * Update the progress bar in response to the event. Expects the value
+   * supplied by the event to be in the range 0-100 i.e. a percentage
+   */
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    if (evt.getPropertyName().equals(eventName))
+    {
+      int progress = (int) evt.getNewValue();
+      progressBar.setValue(progress);
+
+      // switch progress bar to visible if it is not visible and current
+      // progress is less than MAXVALUE
+      // switch progress bar to invisible if it is visible and we reached
+      // MAXVALUE
+      if (progress < MAXVALUE && !progressBar.isVisible())
+      {
+        labelLayout.show(labelPanel, VISIBLE);
+        barLayout.show(barPanel, VISIBLE);
+      }
+      if (progress >= MAXVALUE)
+      {
+        labelLayout.show(labelPanel, INVISIBLE);
+        barLayout.show(barPanel, INVISIBLE);
+      }
+    }
+  }
+}
index 8bf2fba..c4390c0 100755 (executable)
@@ -54,7 +54,7 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
 
   AlignmentPanel ap;
 
-  Stack<CommandI> historyList = new Stack<CommandI>();
+  Stack<CommandI> historyList = new Stack<>();
 
   // simpler than synching with alignFrame.
 
@@ -194,7 +194,7 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
     }
 
     float value = slider.getValue();
-    List<SequenceI> redundantSequences = new ArrayList<SequenceI>();
+    List<SequenceI> redundantSequences = new ArrayList<>();
     for (int i = 0; i < redundancy.length; i++)
     {
       if (value <= redundancy[i])
@@ -295,7 +295,7 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
       af.updateEditMenuBar();
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
 
     if (historyList.size() == 0)
     {
index 1db4051..e677769 100755 (executable)
@@ -168,7 +168,7 @@ public class ScalePanel extends JPanel
         {
           av.showColumn(reveal[0]);
           reveal = null;
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
           av.sendSelection();
         }
       });
@@ -184,7 +184,7 @@ public class ScalePanel extends JPanel
           {
             av.showAllHiddenColumns();
             reveal = null;
-            ap.paintAlignment(true);
+            ap.paintAlignment(true, true);
             av.sendSelection();
           }
         });
@@ -208,7 +208,7 @@ public class ScalePanel extends JPanel
             av.setSelectionGroup(null);
           }
 
-          ap.paintAlignment(true);
+          ap.paintAlignment(true, true);
           av.sendSelection();
         }
       });
@@ -260,7 +260,7 @@ public class ScalePanel extends JPanel
       sg.setEndRes(max);
     }
     av.setSelectionGroup(sg);
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -297,7 +297,7 @@ public class ScalePanel extends JPanel
       }
       else
       {
-        ap.paintAlignment(false);
+        ap.paintAlignment(false, false);
       }
       return;
     }
@@ -316,7 +316,7 @@ public class ScalePanel extends JPanel
       }
     }
     stretchingGroup = false;
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -346,7 +346,7 @@ public class ScalePanel extends JPanel
     {
       stretchingGroup = true;
       cs.stretchGroup(res, sg, min, max);
-      ap.paintAlignment(false);
+      ap.paintAlignment(false, false);
     }
   }
 
index d4b3e73..4e896a0 100755 (executable)
@@ -30,6 +30,7 @@ import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
+import java.awt.AlphaComposite;
 import java.awt.BasicStroke;
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -56,16 +57,12 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
   final FeatureRenderer fr;
 
-  final SequenceRenderer sr;
+  final SequenceRenderer seqRdr;
 
   BufferedImage img;
 
   Graphics2D gg;
 
-  int imgWidth;
-
-  int imgHeight;
-
   AlignViewport av;
 
   boolean fastPaint = false;
@@ -78,6 +75,14 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
   int cursorY = 0;
 
+  int charHeight = 0;
+
+  int charWidth = 0;
+
+  boolean fastpainting = false;
+
+  AnnotationPanel annotations;
+
   /**
    * Creates a new SeqCanvas object.
    * 
@@ -89,7 +94,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     this.av = ap.av;
     updateViewport();
     fr = new FeatureRenderer(ap);
-    sr = new SequenceRenderer(av);
+    seqRdr = new SequenceRenderer(av);
     setLayout(new BorderLayout());
     PaintRefresher.Register(this, av.getSequenceSetId());
     setBackground(Color.white);
@@ -99,7 +104,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
   public SequenceRenderer getSequenceRenderer()
   {
-    return sr;
+    return seqRdr;
   }
 
   public FeatureRenderer getFeatureRenderer()
@@ -107,8 +112,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     return fr;
   }
 
-  int charHeight = 0, charWidth = 0;
-
   private void updateViewport()
   {
     charHeight = av.getCharHeight();
@@ -268,7 +271,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     }
   }
 
-  boolean fastpainting = false;
 
   /**
    * need to make this thread safe move alignment rendering in response to
@@ -281,7 +283,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    */
   public void fastPaint(int horizontal, int vertical)
   {
-    if (fastpainting || gg == null)
+    if (fastpainting || gg == null || img == null)
     {
       return;
     }
@@ -297,8 +299,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     int transX = 0;
     int transY = 0;
 
-    gg.copyArea(horizontal * charWidth, vertical * charHeight, imgWidth,
-            imgHeight, -horizontal * charWidth, -vertical * charHeight);
+    gg.copyArea(horizontal * charWidth, vertical * charHeight,
+            img.getWidth(), img.getHeight(), -horizontal * charWidth,
+            -vertical * charHeight);
 
     if (horizontal > 0) // scrollbar pulled right, image to the left
     {
@@ -319,7 +322,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       }
       else
       {
-        transY = imgHeight - ((vertical + 1) * charHeight);
+        transY = img.getHeight() - ((vertical + 1) * charHeight);
       }
     }
     else if (vertical < 0)
@@ -343,73 +346,205 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   @Override
   public void paintComponent(Graphics g)
   {
-    updateViewport();
-    BufferedImage lcimg = img; // take reference since other threads may null
-    // img and call later.
     super.paintComponent(g);
 
-    if (lcimg != null && (fastPaint
+    updateViewport();
+
+    ViewportRanges ranges = av.getRanges();
+
+    int width = getWidth();
+    int height = getHeight();
+
+    width -= (width % charWidth);
+    height -= (height % charHeight);
+
+    // selectImage is the selection group outline image
+    BufferedImage selectImage = drawSelectionGroup(
+            ranges.getStartRes(), ranges.getEndRes(),
+            ranges.getStartSeq(), ranges.getEndSeq());
+
+    if ((img != null) && (fastPaint
             || (getVisibleRect().width != g.getClipBounds().width)
             || (getVisibleRect().height != g.getClipBounds().height)))
     {
+      BufferedImage lcimg = buildLocalImage(selectImage);
       g.drawImage(lcimg, 0, 0, this);
       fastPaint = false;
-      return;
     }
+    else if ((width > 0) && (height > 0))
+    {
+      // img is a cached version of the last view we drew, if any
+      // if we have no img or the size has changed, make a new one
+      if (img == null || width != img.getWidth()
+              || height != img.getHeight())
+      {
+        img = setupImage();
+        if (img == null)
+        {
+          return;
+        }
+        gg = (Graphics2D) img.getGraphics();
+        gg.setFont(av.getFont());
+      }
+
+      if (av.antiAlias)
+      {
+        gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                RenderingHints.VALUE_ANTIALIAS_ON);
+      }
+
+      gg.setColor(Color.white);
+      gg.fillRect(0, 0, img.getWidth(), img.getHeight());
+
+      if (av.getWrapAlignment())
+      {
+        drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes());
+      }
+      else
+      {
+        drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
+                ranges.getStartSeq(), ranges.getEndSeq(), 0);
+      }
 
-    // this draws the whole of the alignment
-    imgWidth = getWidth();
-    imgHeight = getHeight();
+      // lcimg is a local *copy* of img which we'll draw selectImage on top of
+      BufferedImage lcimg = buildLocalImage(selectImage);
+      g.drawImage(lcimg, 0, 0, this);
+    }
+  }
 
-    imgWidth -= (imgWidth % charWidth);
-    imgHeight -= (imgHeight % charHeight);
+  /**
+   * Draw an alignment panel for printing
+   * 
+   * @param g1
+   *          Graphics object to draw with
+   * @param startRes
+   *          start residue of print area
+   * @param endRes
+   *          end residue of print area
+   * @param startSeq
+   *          start sequence of print area
+   * @param endSeq
+   *          end sequence of print area
+   */
+  public void drawPanelForPrinting(Graphics g1, int startRes, int endRes,
+          int startSeq, int endSeq)
+  {
+    drawPanel(g1, startRes, endRes, startSeq, endSeq, 0);
 
-    if ((imgWidth < 1) || (imgHeight < 1))
+    BufferedImage selectImage = drawSelectionGroup(startRes, endRes,
+            startSeq, endSeq);
+    if (selectImage != null)
     {
-      return;
+      ((Graphics2D) g1).setComposite(AlphaComposite
+              .getInstance(AlphaComposite.SRC_OVER));
+      g1.drawImage(selectImage, 0, 0, this);
     }
+  }
+
+  /**
+   * Draw a wrapped alignment panel for printing
+   * 
+   * @param g
+   *          Graphics object to draw with
+   * @param canvasWidth
+   *          width of drawing area
+   * @param canvasHeight
+   *          height of drawing area
+   * @param startRes
+   *          start residue of print area
+   */
+  public void drawWrappedPanelForPrinting(Graphics g, int canvasWidth,
+          int canvasHeight, int startRes)
+  {
+    SequenceGroup group = av.getSelectionGroup();
+
+    drawWrappedPanel(g, canvasWidth, canvasHeight, startRes);
 
-    if (lcimg == null || imgWidth != lcimg.getWidth()
-            || imgHeight != lcimg.getHeight())
+    if (group != null)
     {
+      BufferedImage selectImage = null;
       try
       {
-        lcimg = img = new BufferedImage(imgWidth, imgHeight,
-                BufferedImage.TYPE_INT_RGB);
-        gg = (Graphics2D) img.getGraphics();
-        gg.setFont(av.getFont());
+        selectImage = new BufferedImage(canvasWidth, canvasHeight,
+                BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works
       } catch (OutOfMemoryError er)
       {
         System.gc();
-        System.err.println("SeqCanvas OutOfMemory Redraw Error.\n" + er);
-        new OOMWarning("Creating alignment image for display", er);
-
-        return;
+        System.err.println("Print image OutOfMemory Error.\n" + er);
+        new OOMWarning("Creating wrapped alignment image for printing", er);
+      }
+      if (selectImage != null)
+      {
+        Graphics2D g2 = selectImage.createGraphics();
+        setupSelectionGroup(g2, selectImage);
+        drawWrappedSelection(g2, group, canvasWidth, canvasHeight,
+                startRes);
+
+        g2.setComposite(
+                AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
+        g.drawImage(selectImage, 0, 0, this);
+        g2.dispose();
       }
     }
+  }
 
-    if (av.antiAlias)
+  /*
+   * Make a local image by combining the cached image img
+   * with any selection
+   */
+  private BufferedImage buildLocalImage(BufferedImage selectImage)
+  {
+    // clone the cached image
+    BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(),
+            img.getType());
+    Graphics2D g2d = lcimg.createGraphics();
+    g2d.drawImage(img, 0, 0, null);
+
+    // overlay selection group on lcimg
+    if (selectImage != null)
     {
-      gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-              RenderingHints.VALUE_ANTIALIAS_ON);
+      g2d.setComposite(
+              AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
+      g2d.drawImage(selectImage, 0, 0, this);
     }
+    g2d.dispose();
 
-    gg.setColor(Color.white);
-    gg.fillRect(0, 0, imgWidth, imgHeight);
+    return lcimg;
+  }
 
-    ViewportRanges ranges = av.getRanges();
-    if (av.getWrapAlignment())
+  /*
+   * Set up a buffered image of the correct height and size for the sequence canvas
+   */
+  private BufferedImage setupImage()
+  {
+    BufferedImage lcimg = null;
+
+    int width = getWidth();
+    int height = getHeight();
+
+    width -= (width % charWidth);
+    height -= (height % charHeight);
+
+    if ((width < 1) || (height < 1))
     {
-      drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes());
+      return null;
     }
-    else
+
+    try
     {
-      drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
-              ranges.getStartSeq(), ranges.getEndSeq(), 0);
-    }
+      lcimg = new BufferedImage(width, height,
+              BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works
+    } catch (OutOfMemoryError er)
+    {
+      System.gc();
+      System.err.println(
+              "Group image OutOfMemory Redraw Error.\n" + er);
+      new OOMWarning("Creating alignment image for display", er);
 
-    g.drawImage(lcimg, 0, 0, this);
+      return null;
+    }
 
+    return lcimg;
   }
 
   /**
@@ -484,7 +619,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    * @param startRes
    *          DOCUMENT ME!
    */
-  public void drawWrappedPanel(Graphics g, int canvasWidth,
+  private void drawWrappedPanel(Graphics g, int canvasWidth,
           int canvasHeight, int startRes)
   {
     updateViewport();
@@ -620,7 +755,62 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     }
   }
 
-  AnnotationPanel annotations;
+  /*
+   * Draw a selection group over a wrapped alignment
+   */
+  private void drawWrappedSelection(Graphics2D g, SequenceGroup group,
+          int canvasWidth,
+          int canvasHeight, int startRes)
+  {
+    // height gap above each panel
+    int hgap = charHeight;
+    if (av.getScaleAboveWrapped())
+    {
+      hgap += charHeight;
+    }
+
+    int cWidth = (canvasWidth - labelWidthEast - labelWidthWest)
+            / charWidth;
+    int cHeight = av.getAlignment().getHeight() * charHeight;
+
+    int startx = startRes;
+    int endx;
+    int ypos = hgap; // vertical offset
+    int maxwidth = av.getAlignment().getWidth();
+
+    if (av.hasHiddenColumns())
+    {
+      maxwidth = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(maxwidth);
+    }
+
+    // chop the wrapped alignment extent up into panel-sized blocks and treat
+    // each block as if it were a block from an unwrapped alignment
+    while ((ypos <= canvasHeight) && (startx < maxwidth))
+    {
+      // set end value to be start + width, or maxwidth, whichever is smaller
+      endx = startx + cWidth - 1;
+
+      if (endx > maxwidth)
+      {
+        endx = maxwidth;
+      }
+
+      g.translate(labelWidthWest, 0);
+
+      drawUnwrappedSelection(g, group, startx, endx, 0,
+              av.getAlignment().getHeight() - 1,
+              ypos);
+
+      g.translate(-labelWidthWest, 0);
+
+      // update vertical offset
+      ypos += cHeight + getAnnotationHeight() + hgap;
+
+      // update horizontal offset
+      startx += cWidth;
+    }
+  }
 
   int getAnnotationHeight()
   {
@@ -644,6 +834,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    * marker.
    * 
    * @param g1
+   *          Graphics object to draw with
    * @param startRes
    *          offset of the first column in the visible region (0..)
    * @param endRes
@@ -749,7 +940,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
           int endSeq, int offset)
   {
     g.setFont(av.getFont());
-    sr.prepare(g, av.isRenderGaps());
+    seqRdr.prepare(g, av.isRenderGaps());
 
     SequenceI nextSeq;
 
@@ -764,7 +955,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
         // empty
         continue;
       }
-      sr.drawSequence(nextSeq, av.getAlignment().findAllGroups(nextSeq),
+      seqRdr.drawSequence(nextSeq, av.getAlignment().findAllGroups(nextSeq),
               startRes, endRes, offset + ((i - startSeq) * charHeight));
 
       if (av.isShowSequenceFeatures())
@@ -785,10 +976,10 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
         {
           for (int r = 0; r < visibleResults.length; r += 2)
           {
-            sr.drawHighlightedText(nextSeq, visibleResults[r],
-                    visibleResults[r + 1],
-                    (visibleResults[r] - startRes) * charWidth,
-                    offset + ((i - startSeq) * charHeight));
+            seqRdr.drawHighlightedText(nextSeq, visibleResults[r],
+                    visibleResults[r + 1], (visibleResults[r] - startRes)
+                            * charWidth, offset
+                            + ((i - startSeq) * charHeight));
           }
         }
       }
@@ -796,7 +987,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       if (av.cursorMode && cursorY == i && cursorX >= startRes
               && cursorX <= endRes)
       {
-        sr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * charWidth,
+        seqRdr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * charWidth,
                 offset + ((i - startSeq) * charHeight));
       }
     }
@@ -817,15 +1008,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     // ///////////////////////////////////
     // Now outline any areas if necessary
     // ///////////////////////////////////
-    SequenceGroup group = av.getSelectionGroup();
 
-    int sx = -1;
-    int sy = -1;
-    int ex = -1;
+    SequenceGroup group = null;
     int groupIndex = -1;
-    int visWidth = (endRes - startRes + 1) * charWidth;
 
-    if ((group == null) && (av.getAlignment().getGroups().size() > 0))
+    if (av.getAlignment().getGroups().size() > 0)
     {
       group = av.getAlignment().getGroups().get(0);
       groupIndex = 0;
@@ -833,168 +1020,309 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
     if (group != null)
     {
+      g.setStroke(new BasicStroke());
+      g.setColor(group.getOutlineColour());
+      
       do
       {
-        int oldY = -1;
-        int i = 0;
-        boolean inGroup = false;
-        int top = -1;
-        int bottom = -1;
+        drawPartialGroupOutline(g, group, startRes, endRes, startSeq,
+                endSeq, offset);
+
+        groupIndex++;
+
+        g.setStroke(new BasicStroke());
 
-        for (i = startSeq; i <= endSeq; i++)
+        if (groupIndex >= av.getAlignment().getGroups().size())
         {
-          sx = (group.getStartRes() - startRes) * charWidth;
-          sy = offset + ((i - startSeq) * charHeight);
-          ex = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth)
-                  - 1;
+          break;
+        }
 
-          if (sx + ex < 0 || sx > visWidth)
-          {
-            continue;
-          }
+        group = av.getAlignment().getGroups().get(groupIndex);
 
-          if ((sx <= (endRes - startRes) * charWidth)
-                  && group.getSequences(null)
-                          .contains(av.getAlignment().getSequenceAt(i)))
-          {
-            if ((bottom == -1) && !group.getSequences(null)
-                    .contains(av.getAlignment().getSequenceAt(i + 1)))
-            {
-              bottom = sy + charHeight;
-            }
+      } while (groupIndex < av.getAlignment().getGroups().size());
 
-            if (!inGroup)
-            {
-              if (((top == -1) && (i == 0)) || !group.getSequences(null)
-                      .contains(av.getAlignment().getSequenceAt(i - 1)))
-              {
-                top = sy;
-              }
+    }
 
-              oldY = sy;
-              inGroup = true;
+  }
 
-              if (group == av.getSelectionGroup())
-              {
-                g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
-                        BasicStroke.JOIN_ROUND, 3f, new float[]
-                        { 5f, 3f }, 0f));
-                g.setColor(Color.RED);
-              }
-              else
-              {
-                g.setStroke(new BasicStroke());
-                g.setColor(group.getOutlineColour());
-              }
-            }
-          }
-          else
-          {
-            if (inGroup)
-            {
-              if (sx >= 0 && sx < visWidth)
-              {
-                g.drawLine(sx, oldY, sx, sy);
-              }
 
-              if (sx + ex < visWidth)
-              {
-                g.drawLine(sx + ex, oldY, sx + ex, sy);
-              }
+  /*
+   * Draw the selection group as a separate image and overlay
+   */
+  private BufferedImage drawSelectionGroup(int startRes, int endRes,
+          int startSeq, int endSeq)
+  {
+    // get a new image of the correct size
+    BufferedImage selectionImage = setupImage();
 
-              if (sx < 0)
-              {
-                ex += sx;
-                sx = 0;
-              }
+    if (selectionImage == null)
+    {
+      return null;
+    }
 
-              if (sx + ex > visWidth)
-              {
-                ex = visWidth;
-              }
+    SequenceGroup group = av.getSelectionGroup();
+    if (group == null)
+    {
+      // nothing to draw
+      return null;
+    }
 
-              else if (sx + ex >= (endRes - startRes + 1) * charWidth)
-              {
-                ex = (endRes - startRes + 1) * charWidth;
-              }
+    // set up drawing colour
+    Graphics2D g = (Graphics2D) selectionImage.getGraphics();
 
-              if (top != -1)
-              {
-                g.drawLine(sx, top, sx + ex, top);
-                top = -1;
-              }
+    setupSelectionGroup(g, selectionImage);
 
-              if (bottom != -1)
-              {
-                g.drawLine(sx, bottom, sx + ex, bottom);
-                bottom = -1;
-              }
+    if (!av.getWrapAlignment())
+    {
+      drawUnwrappedSelection(g, group, startRes, endRes, startSeq, endSeq,
+              0);
+    }
+    else
+    {
+      drawWrappedSelection(g, group, getWidth(), getHeight(),
+              av.getRanges().getStartRes());
+    }
 
-              inGroup = false;
-            }
-          }
+    g.dispose();
+    return selectionImage;
+  }
+
+  /*
+   * Set up graphics for selection group
+   */
+  private void setupSelectionGroup(Graphics2D g,
+          BufferedImage selectionImage)
+  {
+    // set background to transparent
+    g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
+    g.fillRect(0, 0, selectionImage.getWidth(), selectionImage.getHeight());
+
+    // set up foreground to draw red dashed line
+    g.setComposite(AlphaComposite.Src);
+    g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
+            BasicStroke.JOIN_ROUND, 3f, new float[]
+    { 5f, 3f }, 0f));
+    g.setColor(Color.RED);
+  }
+
+  /*
+   * Draw a selection group over an unwrapped alignment
+   * @param g graphics object to draw with
+   * @param group selection group
+   * @param startRes start residue of area to draw
+   * @param endRes end residue of area to draw
+   * @param startSeq start sequence of area to draw
+   * @param endSeq end sequence of area to draw
+   * @param offset vertical offset (used when called from wrapped alignment code)
+   */
+  private void drawUnwrappedSelection(Graphics2D g, SequenceGroup group,
+          int startRes, int endRes, int startSeq, int endSeq, int offset)
+  {
+    if (!av.hasHiddenColumns())
+    {
+      drawPartialGroupOutline(g, group, startRes, endRes, startSeq, endSeq,
+              offset);
+    }
+    else
+    {
+      // package into blocks of visible columns
+      int screenY = 0;
+      int blockStart = startRes;
+      int blockEnd = endRes;
+
+      for (int[] region : av.getAlignment().getHiddenColumns()
+              .getHiddenColumnsCopy())
+      {
+        int hideStart = region[0];
+        int hideEnd = region[1];
+
+        if (hideStart <= blockStart)
+        {
+          blockStart += (hideEnd - hideStart) + 1;
+          continue;
         }
 
+        blockEnd = hideStart - 1;
+
+        g.translate(screenY * charWidth, 0);
+        drawPartialGroupOutline(g, group,
+                blockStart, blockEnd, startSeq, endSeq, offset);
+
+        g.translate(-screenY * charWidth, 0);
+        screenY += blockEnd - blockStart + 1;
+        blockStart = hideEnd + 1;
+
+        if (screenY > (endRes - startRes))
+        {
+          // already rendered last block
+          break;
+        }
+      }
+
+      if (screenY <= (endRes - startRes))
+      {
+        // remaining visible region to render
+        blockEnd = blockStart + (endRes - startRes) - screenY;
+        g.translate(screenY * charWidth, 0);
+        drawPartialGroupOutline(g, group,
+                blockStart, blockEnd, startSeq, endSeq, offset);
+        
+        g.translate(-screenY * charWidth, 0);
+      }
+    }
+  }
+
+  /*
+   * Draw the selection group as a separate image and overlay
+   */
+  private void drawPartialGroupOutline(Graphics2D g, SequenceGroup group,
+          int startRes, int endRes, int startSeq, int endSeq,
+          int verticalOffset)
+  {
+    int visWidth = (endRes - startRes + 1) * charWidth;
+
+    int oldY = -1;
+    int i = 0;
+    boolean inGroup = false;
+    int top = -1;
+    int bottom = -1;
+
+    int sx = -1;
+    int sy = -1;
+    int xwidth = -1;
+
+    for (i = startSeq; i <= endSeq; i++)
+    {
+      // position of start residue of group relative to startRes, in pixels
+      sx = (group.getStartRes() - startRes) * charWidth;
+
+      // width of group in pixels
+      xwidth = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth)
+              - 1;
+
+      sy = verticalOffset + (i - startSeq) * charHeight;
+
+      if (sx + xwidth < 0 || sx > visWidth)
+      {
+        continue;
+      }
+
+      if ((sx <= (endRes - startRes) * charWidth)
+              && group.getSequences(null)
+                      .contains(av.getAlignment().getSequenceAt(i)))
+      {
+        if ((bottom == -1) && !group.getSequences(null)
+                .contains(av.getAlignment().getSequenceAt(i + 1)))
+        {
+          bottom = sy + charHeight;
+        }
+
+        if (!inGroup)
+        {
+          if (((top == -1) && (i == 0)) || !group.getSequences(null)
+                  .contains(av.getAlignment().getSequenceAt(i - 1)))
+          {
+            top = sy;
+          }
+
+          oldY = sy;
+          inGroup = true;
+        }
+      }
+      else
+      {
         if (inGroup)
         {
-          sy = offset + ((i - startSeq) * charHeight);
+          // if start position is visible, draw vertical line to left of
+          // group
           if (sx >= 0 && sx < visWidth)
           {
             g.drawLine(sx, oldY, sx, sy);
           }
 
-          if (sx + ex < visWidth)
+          // if end position is visible, draw vertical line to right of
+          // group
+          if (sx + xwidth < visWidth)
           {
-            g.drawLine(sx + ex, oldY, sx + ex, sy);
+            g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
           }
 
           if (sx < 0)
           {
-            ex += sx;
+            xwidth += sx;
             sx = 0;
           }
 
-          if (sx + ex > visWidth)
-          {
-            ex = visWidth;
-          }
-          else if (sx + ex >= (endRes - startRes + 1) * charWidth)
+          // don't let width extend beyond current block, or group extent
+          // fixes JAL-2672
+          if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
           {
-            ex = (endRes - startRes + 1) * charWidth;
+            xwidth = (endRes - startRes + 1) * charWidth - sx;
           }
-
+          
+          // draw horizontal line at top of group
           if (top != -1)
           {
-            g.drawLine(sx, top, sx + ex, top);
+            g.drawLine(sx, top, sx + xwidth, top);
             top = -1;
           }
 
+          // draw horizontal line at bottom of group
           if (bottom != -1)
           {
-            g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);
+            g.drawLine(sx, bottom, sx + xwidth, bottom);
             bottom = -1;
           }
 
           inGroup = false;
         }
+      }
+    }
 
-        groupIndex++;
+    if (inGroup)
+    {
+      sy = verticalOffset + ((i - startSeq) * charHeight);
+      if (sx >= 0 && sx < visWidth)
+      {
+        g.drawLine(sx, oldY, sx, sy);
+      }
 
-        g.setStroke(new BasicStroke());
+      if (sx + xwidth < visWidth)
+      {
+        g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
+      }
 
-        if (groupIndex >= av.getAlignment().getGroups().size())
-        {
-          break;
-        }
+      if (sx < 0)
+      {
+        xwidth += sx;
+        sx = 0;
+      }
 
-        group = av.getAlignment().getGroups().get(groupIndex);
+      if (sx + xwidth > visWidth)
+      {
+        xwidth = visWidth;
+      }
+      else if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
+      {
+        xwidth = (endRes - startRes + 1) * charWidth;
+      }
 
-      } while (groupIndex < av.getAlignment().getGroups().size());
+      if (top != -1)
+      {
+        g.drawLine(sx, top, sx + xwidth, top);
+        top = -1;
+      }
 
-    }
+      if (bottom != -1)
+      {
+        g.drawLine(sx, bottom - 1, sx + xwidth, bottom - 1);
+        bottom = -1;
+      }
 
+      inGroup = false;
+    }
   }
-
+  
   /**
    * Highlights search results in the visible region by rendering as white text
    * on a black background. Any previous highlighting is removed. Answers true
@@ -1166,7 +1494,12 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   {
     String eventName = evt.getPropertyName();
 
-    if (av.getWrapAlignment())
+    if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED))
+    {
+      fastPaint = true;
+      repaint();
+    }
+    else if (av.getWrapAlignment())
     {
       if (eventName.equals(ViewportRanges.STARTRES))
       {
index e8cc68b..516652b 100644 (file)
@@ -484,7 +484,7 @@ public class SeqPanel extends JPanel
       av.setSelectionGroup(sg);
     }
 
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     av.sendSelection();
   }
 
@@ -852,11 +852,12 @@ public class SeqPanel extends JPanel
 
   /**
    * set when the current UI interaction has resulted in a change that requires
-   * overview shading to be recalculated. this could be changed to something
-   * more expressive that indicates what actually has changed, so selective
-   * redraws can be applied
+   * shading in overviews and structures to be recalculated. this could be
+   * changed to a something more expressive that indicates what actually has
+   * changed, so selective redraws can be applied (ie. only structures, only
+   * overview, etc)
    */
-  private boolean needOverviewUpdate = false; // TODO: refactor to avcontroller
+  private boolean updateOverviewAndStructs = false; // TODO: refactor to avcontroller
 
   /**
    * set if av.getSelectionGroup() refers to a group that is defined on the
@@ -1057,7 +1058,7 @@ public class SeqPanel extends JPanel
         }
         if (newWidth > 0)
         {
-          ap.paintAlignment(false);
+          ap.paintAlignment(false, false);
           if (copyChanges)
           {
             /*
@@ -1111,7 +1112,7 @@ public class SeqPanel extends JPanel
     }
 
     mouseDragging = true;
-    if (scrollThread != null)
+    if ((scrollThread != null) && (scrollThread.isRunning()))
     {
       scrollThread.setEvent(evt);
     }
@@ -1537,9 +1538,9 @@ public class SeqPanel extends JPanel
       oldSeq = 0;
     }
 
-    if (scrollThread != null)
+    if ((scrollThread != null) && (scrollThread.isRunning()))
     {
-      scrollThread.running = false;
+      scrollThread.stopScrolling();
       scrollThread = null;
     }
   }
@@ -1558,7 +1559,7 @@ public class SeqPanel extends JPanel
       return;
     }
 
-    if (mouseDragging)
+    if (mouseDragging && scrollThread == null)
     {
       scrollThread = new ScrollThread();
     }
@@ -1656,7 +1657,7 @@ public class SeqPanel extends JPanel
     final int res = findColumn(evt);
     final int seq = findSeq(evt);
     oldSeq = seq;
-    needOverviewUpdate = false;
+    updateOverviewAndStructs = false;
 
     startWrapBlock = wrappedBlock;
 
@@ -1721,43 +1722,53 @@ public class SeqPanel extends JPanel
 
     if (stretchGroup == null)
     {
-      // Only if left mouse button do we want to change group sizes
+      createStretchGroup(res, sequence);
+    }
 
-      // define a new group here
-      SequenceGroup sg = new SequenceGroup();
-      sg.setStartRes(res);
-      sg.setEndRes(res);
-      sg.addSequence(sequence, false);
-      av.setSelectionGroup(sg);
-      stretchGroup = sg;
+    if (stretchGroup != null)
+    {
+      stretchGroup.addPropertyChangeListener(seqCanvas);
+    }
 
-      if (av.getConservationSelected())
-      {
-        SliderPanel.setConservationSlider(ap, av.getResidueShading(),
-                ap.getViewName());
-      }
+    seqCanvas.repaint();
+  }
 
-      if (av.getAbovePIDThreshold())
-      {
-        SliderPanel.setPIDSliderSource(ap, av.getResidueShading(),
-                ap.getViewName());
-      }
-      // TODO: stretchGroup will always be not null. Is this a merge error ?
-      if ((stretchGroup != null) && (stretchGroup.getEndRes() == res))
-      {
-        // Edit end res position of selected group
-        changeEndRes = true;
-      }
-      else if ((stretchGroup != null)
-              && (stretchGroup.getStartRes() == res))
-      {
-        // Edit end res position of selected group
-        changeStartRes = true;
-      }
-      stretchGroup.getWidth();
+  private void createStretchGroup(int res, SequenceI sequence)
+  {
+    // Only if left mouse button do we want to change group sizes
+    // define a new group here
+    SequenceGroup sg = new SequenceGroup();
+    sg.setStartRes(res);
+    sg.setEndRes(res);
+    sg.addSequence(sequence, false);
+    av.setSelectionGroup(sg);
+    stretchGroup = sg;
+
+    if (av.getConservationSelected())
+    {
+      SliderPanel.setConservationSlider(ap, av.getResidueShading(),
+              ap.getViewName());
     }
 
-    seqCanvas.repaint();
+    if (av.getAbovePIDThreshold())
+    {
+      SliderPanel.setPIDSliderSource(ap, av.getResidueShading(),
+              ap.getViewName());
+    }
+    // TODO: stretchGroup will always be not null. Is this a merge error ?
+    // or is there a threading issue here?
+    if ((stretchGroup != null) && (stretchGroup.getEndRes() == res))
+    {
+      // Edit end res position of selected group
+      changeEndRes = true;
+    }
+    else if ((stretchGroup != null) && (stretchGroup.getStartRes() == res))
+    {
+      // Edit end res position of selected group
+      changeStartRes = true;
+    }
+    stretchGroup.getWidth();
+
   }
 
   /**
@@ -1805,10 +1816,13 @@ public class SeqPanel extends JPanel
     {
       return;
     }
+
+    stretchGroup.removePropertyChangeListener(seqCanvas);
+
     // always do this - annotation has own state
     // but defer colourscheme update until hidden sequences are passed in
     boolean vischange = stretchGroup.recalcConservation(true);
-    needOverviewUpdate |= vischange && av.isSelectionDefinedGroup()
+    updateOverviewAndStructs |= vischange && av.isSelectionDefinedGroup()
             && afterDrag;
     if (stretchGroup.cs != null)
     {
@@ -1828,8 +1842,10 @@ public class SeqPanel extends JPanel
       }
     }
     PaintRefresher.Refresh(this, av.getSequenceSetId());
-    ap.paintAlignment(needOverviewUpdate);
-    needOverviewUpdate = false;
+    // TODO: structure colours only need updating if stretchGroup used to or now
+    // does contain sequences with structure views
+    ap.paintAlignment(updateOverviewAndStructs, updateOverviewAndStructs);
+    updateOverviewAndStructs = false;
     changeEndRes = false;
     changeStartRes = false;
     stretchGroup = null;
@@ -1883,7 +1899,7 @@ public class SeqPanel extends JPanel
       if (res > (stretchGroup.getStartRes() - 1))
       {
         stretchGroup.setEndRes(res);
-        needOverviewUpdate |= av.isSelectionDefinedGroup();
+        updateOverviewAndStructs |= av.isSelectionDefinedGroup();
       }
     }
     else if (changeStartRes)
@@ -1891,7 +1907,7 @@ public class SeqPanel extends JPanel
       if (res < (stretchGroup.getEndRes() + 1))
       {
         stretchGroup.setStartRes(res);
-        needOverviewUpdate |= av.isSelectionDefinedGroup();
+        updateOverviewAndStructs |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1925,7 +1941,7 @@ public class SeqPanel extends JPanel
       if (stretchGroup.getSequences(null).contains(nextSeq))
       {
         stretchGroup.deleteSequence(seq, false);
-        needOverviewUpdate |= av.isSelectionDefinedGroup();
+        updateOverviewAndStructs |= av.isSelectionDefinedGroup();
       }
       else
       {
@@ -1935,7 +1951,7 @@ public class SeqPanel extends JPanel
         }
 
         stretchGroup.addSequence(nextSeq, false);
-        needOverviewUpdate |= av.isSelectionDefinedGroup();
+        updateOverviewAndStructs |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1946,21 +1962,19 @@ public class SeqPanel extends JPanel
 
     mouseDragging = true;
 
-    if (scrollThread != null)
+    if ((scrollThread != null) && (scrollThread.isRunning()))
     {
       scrollThread.setEvent(evt);
     }
-
-    seqCanvas.repaint();
   }
 
   void scrollCanvas(MouseEvent evt)
   {
     if (evt == null)
     {
-      if (scrollThread != null)
+      if ((scrollThread != null) && (scrollThread.isRunning()))
       {
-        scrollThread.running = false;
+        scrollThread.stopScrolling();
         scrollThread = null;
       }
       mouseDragging = false;
@@ -1983,7 +1997,7 @@ public class SeqPanel extends JPanel
   {
     MouseEvent evt;
 
-    boolean running = false;
+    private volatile boolean threadRunning = true;
 
     public ScrollThread()
     {
@@ -1997,37 +2011,40 @@ public class SeqPanel extends JPanel
 
     public void stopScrolling()
     {
-      running = false;
+      threadRunning = false;
+    }
+
+    public boolean isRunning()
+    {
+      return threadRunning;
     }
 
     @Override
     public void run()
     {
-      running = true;
-
-      while (running)
+      while (threadRunning)
       {
         if (evt != null)
         {
           if (mouseDragging && (evt.getY() < 0)
                   && (av.getRanges().getStartSeq() > 0))
           {
-            running = av.getRanges().scrollUp(true);
+            av.getRanges().scrollUp(true);
           }
 
           if (mouseDragging && (evt.getY() >= getHeight()) && (av
                   .getAlignment().getHeight() > av.getRanges().getEndSeq()))
           {
-            running = av.getRanges().scrollUp(false);
+            av.getRanges().scrollUp(false);
           }
 
           if (mouseDragging && (evt.getX() < 0))
           {
-            running = av.getRanges().scrollRight(false);
+            av.getRanges().scrollRight(false);
           }
           else if (mouseDragging && (evt.getX() >= getWidth()))
           {
-            running = av.getRanges().scrollRight(true);
+            av.getRanges().scrollRight(true);
           }
         }
 
index 4498f88..0a1e8ef 100755 (executable)
@@ -23,9 +23,8 @@ package jalview.gui;
 import jalview.api.AlignViewportI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
-import jalview.renderer.ResidueShaderI;
+import jalview.renderer.ResidueColourFinder;
 import jalview.renderer.seqfeatures.FeatureColourFinder;
-import jalview.util.Comparison;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
@@ -41,17 +40,15 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
   boolean renderGaps = true;
 
-  SequenceGroup currentSequenceGroup = null;
-
   SequenceGroup[] allGroups = null;
 
-  Color resBoxColour;
+  // Color resBoxColour;
 
   Graphics graphics;
 
   boolean monospacedFont;
 
-  boolean forOverview = false;
+  ResidueColourFinder resColourFinder;
 
   /**
    * Creates a new SequenceRenderer object
@@ -61,6 +58,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   public SequenceRenderer(AlignViewportI viewport)
   {
     this.av = viewport;
+    resColourFinder = new ResidueColourFinder();
   }
 
   /**
@@ -83,26 +81,6 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     this.renderGaps = renderGaps;
   }
 
-  protected Color getResidueBoxColour(SequenceI seq, int i)
-  {
-    // rate limiting step when rendering overview for lots of groups
-    allGroups = av.getAlignment().findAllGroups(seq);
-
-    if (inCurrentSequenceGroup(i))
-    {
-      if (currentSequenceGroup.getDisplayBoxes())
-      {
-        getBoxColour(currentSequenceGroup.getGroupColourScheme(), seq, i);
-      }
-    }
-    else if (av.getShowBoxes())
-    {
-      getBoxColour(av.getResidueShading(), seq, i);
-    }
-
-    return resBoxColour;
-  }
-
   /**
    * Get the residue colour at the given sequence position - as determined by
    * the sequence group colour (if any), else the colour scheme, possibly
@@ -117,39 +95,11 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   public Color getResidueColour(final SequenceI seq, int position,
           FeatureColourFinder finder)
   {
-    Color col = getResidueBoxColour(seq, position);
-
-    if (finder != null)
-    {
-      col = finder.findFeatureColour(col, seq, position);
-    }
-    return col;
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param shader
-   *          DOCUMENT ME!
-   * @param seq
-   *          DOCUMENT ME!
-   * @param i
-   *          DOCUMENT ME!
-   */
-  void getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
-  {
-    if (shader.getColourScheme() != null)
-    {
-      resBoxColour = shader.findColour(seq.getCharAt(i), i, seq);
-    }
-    else if (forOverview && !Comparison.isGap(seq.getCharAt(i)))
-    {
-      resBoxColour = Color.lightGray;
-    }
-    else
-    {
-      resBoxColour = Color.white;
-    }
+    allGroups = av.getAlignment().findAllGroups(seq);
+    return resColourFinder.getResidueColour(av.getShowBoxes(),
+            av.getResidueShading(),
+            allGroups, seq, position,
+            finder);
   }
 
   /**
@@ -208,6 +158,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   public synchronized void drawBoxes(SequenceI seq, int start, int end,
           int y1)
   {
+    Color resBoxColour = Color.white;
+
     if (seq == null)
     {
       return; // fix for racecondition
@@ -227,17 +179,22 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
       if (i < length)
       {
-        if (inCurrentSequenceGroup(i))
+        SequenceGroup currentSequenceGroup = resColourFinder
+                .getCurrentSequenceGroup(
+                allGroups, i);
+        if (currentSequenceGroup != null)
         {
           if (currentSequenceGroup.getDisplayBoxes())
           {
-            getBoxColour(currentSequenceGroup.getGroupColourScheme(), seq,
+            resBoxColour = resColourFinder.getBoxColour(
+                    currentSequenceGroup.getGroupColourScheme(), seq,
                     i);
           }
         }
         else if (av.getShowBoxes())
         {
-          getBoxColour(av.getResidueShading(), seq, i);
+          resBoxColour = resColourFinder
+                  .getBoxColour(av.getResidueShading(), seq, i);
         }
       }
 
@@ -317,10 +274,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
       boolean srep = av.isDisplayReferenceSeq();
       boolean getboxColour = false;
       boolean isarep = av.getAlignment().getSeqrep() == seq;
-      boolean isgrep = currentSequenceGroup != null
-              ? currentSequenceGroup.getSeqrep() == seq
-              : false;
-      char sr_c;
+      Color resBoxColour = Color.white;
+
       for (int i = start; i <= end; i++)
       {
 
@@ -333,7 +288,10 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           continue;
         }
 
-        if (inCurrentSequenceGroup(i))
+        SequenceGroup currentSequenceGroup = resColourFinder
+                .getCurrentSequenceGroup(
+                allGroups, i);
+        if (currentSequenceGroup != null)
         {
           if (!currentSequenceGroup.getDisplayText())
           {
@@ -344,7 +302,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
                   || currentSequenceGroup.getColourText())
           {
             getboxColour = true;
-            getBoxColour(currentSequenceGroup.getGroupColourScheme(), seq,
+            resBoxColour = resColourFinder.getBoxColour(
+                    currentSequenceGroup.getGroupColourScheme(), seq,
                     i);
 
             if (currentSequenceGroup.getColourText())
@@ -366,6 +325,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           {
             graphics.setColor(currentSequenceGroup.textColour);
           }
+          boolean isgrep = currentSequenceGroup != null
+                  ? currentSequenceGroup.getSeqrep() == seq : false;
           if (!isarep && !isgrep
                   && currentSequenceGroup.getShowNonconserved()) // todo
                                                                  // optimize
@@ -386,7 +347,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           if (av.getColourText())
           {
             getboxColour = true;
-            getBoxColour(av.getResidueShading(), seq, i);
+            resBoxColour = resColourFinder
+                    .getBoxColour(av.getResidueShading(), seq, i);
 
             if (av.getShowBoxes())
             {
@@ -402,7 +364,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           {
             if (!getboxColour)
             {
-              getBoxColour(av.getResidueShading(), seq, i);
+              resBoxColour = resColourFinder
+                      .getBoxColour(av.getResidueShading(), seq, i);
             }
 
             if (resBoxColour.getRed() + resBoxColour.getBlue()
@@ -473,35 +436,6 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   /**
    * DOCUMENT ME!
    * 
-   * @param res
-   *          DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  boolean inCurrentSequenceGroup(int res)
-  {
-    if (allGroups == null)
-    {
-      return false;
-    }
-
-    for (int i = 0; i < allGroups.length; i++)
-    {
-      if ((allGroups[i].getStartRes() <= res)
-              && (allGroups[i].getEndRes() >= res))
-      {
-        currentSequenceGroup = allGroups[i];
-
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
    * @param seq
    *          DOCUMENT ME!
    * @param start
index e6ec822..93a2457 100755 (executable)
@@ -127,7 +127,7 @@ public class SliderPanel extends GSliderPanel
       @Override
       public void mouseReleased(MouseEvent evt)
       {
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, true);
       }
     });
 
index beb2d62..5bff407 100644 (file)
@@ -194,15 +194,29 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
   }
 
   /**
-   * Adjust the divider for a sensible split of the real estate (for example,
+   * Adjusts the divider for a sensible split of the real estate (for example,
    * when many transcripts are shown with a single protein). This should only be
    * called after the split pane has been laid out (made visible) so it has a
-   * height.
+   * height. The aim is to avoid unnecessary vertical scroll bars, while
+   * ensuring that at least 2 sequences are visible in each panel.
+   * <p>
+   * Once laid out, the user may choose to customise as they wish, so this
+   * method is not called again after the initial layout.
    */
-  protected void adjustDivider()
+  protected void adjustInitialLayout()
   {
-    final AlignViewport topViewport = ((AlignFrame) getTopFrame()).viewport;
-    final AlignViewport bottomViewport = ((AlignFrame) getBottomFrame()).viewport;
+    AlignFrame topFrame = (AlignFrame) getTopFrame();
+    AlignFrame bottomFrame = (AlignFrame) getBottomFrame();
+
+    /*
+     * recompute layout of top and bottom panels to reflect their
+     * actual (rather than requested) height
+     */
+    topFrame.alignPanel.adjustAnnotationHeight();
+    bottomFrame.alignPanel.adjustAnnotationHeight();
+
+    final AlignViewport topViewport = topFrame.viewport;
+    final AlignViewport bottomViewport = bottomFrame.viewport;
     final AlignmentI topAlignment = topViewport.getAlignment();
     final AlignmentI bottomAlignment = bottomViewport.getAlignment();
     boolean topAnnotations = topViewport.isShowAnnotation();
@@ -214,6 +228,29 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     int bottomCharHeight = bottomViewport.getViewStyle().getCharHeight();
 
     /*
+     * calculate the minimum ratio that leaves at least the height 
+     * of two sequences (after rounding) visible in the top panel
+     */
+    int topPanelHeight = topFrame.getHeight();
+    int bottomPanelHeight = bottomFrame.getHeight();
+    int topSequencesHeight = topFrame.alignPanel.getSeqPanel().seqCanvas
+            .getHeight();
+    int topPanelMinHeight = topPanelHeight
+            - Math.max(0, topSequencesHeight - 3 * topCharHeight);
+    double totalHeight = (double) topPanelHeight + bottomPanelHeight;
+    double minRatio = topPanelMinHeight / totalHeight;
+
+    /*
+     * calculate the maximum ratio that leaves at least the height 
+     * of two sequences (after rounding) visible in the bottom panel
+     */
+    int bottomSequencesHeight = bottomFrame.alignPanel.getSeqPanel().seqCanvas
+            .getHeight();
+    int bottomPanelMinHeight = bottomPanelHeight
+            - Math.max(0, bottomSequencesHeight - 3 * bottomCharHeight);
+    double maxRatio = (totalHeight - bottomPanelMinHeight) / totalHeight;
+
+    /*
      * estimate ratio of (topFrameContent / bottomFrameContent)
      */
     int insets = Platform.isAMac() ? MAC_INSETS_HEIGHT
@@ -223,13 +260,14 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
             + (topAnnotations ? topViewport.calcPanelHeight() : 0);
     int bottomHeight = insets + (3 + bottomCount) * bottomCharHeight
             + (bottomAnnotations ? bottomViewport.calcPanelHeight() : 0);
-    double ratio = ((double) topHeight) / (topHeight + bottomHeight);
+    double ratio = ((double) topHeight)
+            / (double) (topHeight + bottomHeight);
 
     /*
-     * limit to 0.2 <= ratio <= 0.8 to avoid concealing all sequences
+     * limit ratio to avoid concealing all sequences
      */
-    ratio = Math.min(ratio, 0.8d);
-    ratio = Math.max(ratio, 0.2d);
+    ratio = Math.min(ratio, maxRatio);
+    ratio = Math.max(ratio, minRatio);
     setRelativeDividerLocation(ratio);
   }
 
index 3ba9947..c8854a7 100644 (file)
@@ -83,18 +83,18 @@ public abstract class StructureViewerBase extends GStructureViewer
   /**
    * list of sequenceSet ids associated with the view
    */
-  protected List<String> _aps = new ArrayList<String>();
+  protected List<String> _aps = new ArrayList<>();
 
   /**
    * list of alignment panels to use for superposition
    */
-  protected Vector<AlignmentPanel> _alignwith = new Vector<AlignmentPanel>();
+  protected Vector<AlignmentPanel> _alignwith = new Vector<>();
 
   /**
    * list of alignment panels that are used for colouring structures by aligned
    * sequences
    */
-  protected Vector<AlignmentPanel> _colourwith = new Vector<AlignmentPanel>();
+  protected Vector<AlignmentPanel> _colourwith = new Vector<>();
 
   private String viewId = null;
 
@@ -170,7 +170,7 @@ public abstract class StructureViewerBase extends GStructureViewer
   {
     if (_alignwith == null)
     {
-      _alignwith = new Vector<AlignmentPanel>();
+      _alignwith = new Vector<>();
     }
     if (_alignwith.size() == 0 && ap != null)
     {
@@ -468,7 +468,9 @@ public abstract class StructureViewerBase extends GStructureViewer
     if (apanel.getSeqPanel().seqCanvas.fr != null)
     {
       apanel.getSeqPanel().seqCanvas.fr.featuresAdded();
-      apanel.paintAlignment(true);
+      // note - we don't do a refresh for structure here because we do it
+      // explicitly for all panels later on
+      apanel.paintAlignment(true, false);
     }
 
     /*
@@ -717,11 +719,11 @@ public abstract class StructureViewerBase extends GStructureViewer
 
     if (_colourwith == null)
     {
-      _colourwith = new Vector<AlignmentPanel>();
+      _colourwith = new Vector<>();
     }
     if (_alignwith == null)
     {
-      _alignwith = new Vector<AlignmentPanel>();
+      _alignwith = new Vector<>();
     }
 
     ViewSelectionMenu seqColourBy = new ViewSelectionMenu(
@@ -888,7 +890,7 @@ public abstract class StructureViewerBase extends GStructureViewer
     binding.setColourBySequence(seqColour.isSelected());
     if (_colourwith == null)
     {
-      _colourwith = new Vector<AlignmentPanel>();
+      _colourwith = new Vector<>();
     }
     if (binding.isColourBySequence())
     {
index 3986561..53e2dee 100644 (file)
@@ -184,9 +184,9 @@ public class TextColourChooser
    */
   protected void saveInitialSettings()
   {
-    groupColour1 = new HashMap<SequenceGroup, Color>();
-    groupColour2 = new HashMap<SequenceGroup, Color>();
-    groupThreshold = new HashMap<SequenceGroup, Integer>();
+    groupColour1 = new HashMap<>();
+    groupColour2 = new HashMap<>();
+    groupThreshold = new HashMap<>();
 
     if (sg == null)
     {
@@ -237,7 +237,7 @@ public class TextColourChooser
       sg.textColour = col;
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(false, false);
   }
 
   void colour2Changed(Color col)
@@ -255,7 +255,7 @@ public class TextColourChooser
       sg.textColour2 = col;
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(false, false);
   }
 
   void thresholdChanged(int value)
@@ -273,7 +273,7 @@ public class TextColourChooser
       sg.thresholdTextColour = value;
     }
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(false, false);
   }
 
   void setGroupTextColour()
index 5e14fce..9403057 100755 (executable)
@@ -493,7 +493,7 @@ public class TreePanel extends GTreePanel
 
     if (treeCanvas.applyToAllViews)
     {
-      final ArrayList<CommandI> commands = new ArrayList<CommandI>();
+      final ArrayList<CommandI> commands = new ArrayList<>();
       for (AlignmentPanel ap : PaintRefresher
               .getAssociatedPanels(av.getSequenceSetId()))
       {
@@ -550,13 +550,14 @@ public class TreePanel extends GTreePanel
 
   public CommandI sortAlignmentIn(AlignmentPanel ap)
   {
+    // TODO: move to alignment view controller
     AlignmentViewport viewport = ap.av;
     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
     AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
     CommandI undo;
     undo = new OrderCommand("Tree Sort", oldOrder, viewport.getAlignment());
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, false);
     return undo;
   }
 
index 8b45c40..3290500 100755 (executable)
@@ -136,7 +136,7 @@ public class UserDefinedColours extends GUserDefinedColours
   UserDefinedColours()
   {
     super();
-    selectedButtons = new ArrayList<JButton>();
+    selectedButtons = new ArrayList<>();
   }
 
   void showFrame()
@@ -163,7 +163,7 @@ public class UserDefinedColours extends GUserDefinedColours
 
     if (upperCaseButtons == null)
     {
-      upperCaseButtons = new ArrayList<JButton>();
+      upperCaseButtons = new ArrayList<>();
     }
 
     for (int i = 0; i < 20; i++)
@@ -194,7 +194,7 @@ public class UserDefinedColours extends GUserDefinedColours
 
       if (lowerCaseButtons == null)
       {
-        lowerCaseButtons = new ArrayList<JButton>();
+        lowerCaseButtons = new ArrayList<>();
       }
 
       for (int i = 0; i < 20; i++)
@@ -631,8 +631,8 @@ public class UserDefinedColours extends GUserDefinedColours
   @Override
   protected void loadbutton_actionPerformed()
   {
-    upperCaseButtons = new ArrayList<JButton>();
-    lowerCaseButtons = new ArrayList<JButton>();
+    upperCaseButtons = new ArrayList<>();
+    lowerCaseButtons = new ArrayList<>();
 
     JalviewFileChooser chooser = new JalviewFileChooser("jc",
             "Jalview User Colours");
@@ -876,7 +876,7 @@ public class UserDefinedColours extends GUserDefinedColours
   protected void cancelButton_actionPerformed()
   {
     ap.alignFrame.changeColour(oldColourScheme);
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
 
     try
     {
index 6e7df71..d526a31 100755 (executable)
@@ -184,7 +184,7 @@ public class WSWUBlastClient
         }
       }
     }
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, false);
 
   }
 
index 633d2b8..1ca0802 100755 (executable)
@@ -95,11 +95,11 @@ public class GPreferences extends JPanel
 
   protected JCheckBox rightAlign = new JCheckBox();
 
-  protected JComboBox<String> fontSizeCB = new JComboBox<String>();
+  protected JComboBox<String> fontSizeCB = new JComboBox<>();
 
-  protected JComboBox<String> fontStyleCB = new JComboBox<String>();
+  protected JComboBox<String> fontStyleCB = new JComboBox<>();
 
-  protected JComboBox<String> fontNameCB = new JComboBox<String>();
+  protected JComboBox<String> fontNameCB = new JComboBox<>();
 
   protected JCheckBox showOccupancy = new JCheckBox();
 
@@ -111,15 +111,15 @@ public class GPreferences extends JPanel
 
   protected JCheckBox scaleProteinToCdna = new JCheckBox();
 
-  protected JComboBox<String> gapSymbolCB = new JComboBox<String>();
+  protected JComboBox<String> gapSymbolCB = new JComboBox<>();
 
   protected JCheckBox wrap = new JCheckBox();
 
-  protected JComboBox<String> sortby = new JComboBox<String>();
+  protected JComboBox<String> sortby = new JComboBox<>();
 
-  protected JComboBox<String> sortAnnBy = new JComboBox<String>();
+  protected JComboBox<String> sortAnnBy = new JComboBox<>();
 
-  protected JComboBox<String> sortAutocalc = new JComboBox<String>();
+  protected JComboBox<String> sortAutocalc = new JComboBox<>();
 
   protected JCheckBox startupCheckbox = new JCheckBox();
 
@@ -159,7 +159,7 @@ public class GPreferences extends JPanel
 
   protected JCheckBox addTempFactor = new JCheckBox();
 
-  protected JComboBox<String> structViewer = new JComboBox<String>();
+  protected JComboBox<String> structViewer = new JComboBox<>();
 
   protected JTextField chimeraPath = new JTextField();
 
@@ -176,9 +176,22 @@ public class GPreferences extends JPanel
 
   protected JPanel maxColour = new JPanel();
 
-  protected JComboBox<String> protColour = new JComboBox<String>();
+  protected JComboBox<String> protColour = new JComboBox<>();
 
-  protected JComboBox<String> nucColour = new JComboBox<String>();
+  protected JComboBox<String> nucColour = new JComboBox<>();
+
+  /*
+   * Overview tab components
+   */
+  protected JPanel gapColour = new JPanel();
+
+  protected JPanel hiddenColour = new JPanel();
+
+  protected JCheckBox useLegacyGap;
+
+  protected JCheckBox showHiddenAtStart;
+
+  protected JLabel gapLabel;
 
   /*
    * Connections tab components
@@ -216,7 +229,7 @@ public class GPreferences extends JPanel
   /*
    * Output tab components
    */
-  protected JComboBox<Object> epsRendering = new JComboBox<Object>();
+  protected JComboBox<Object> epsRendering = new JComboBox<>();
 
   protected JLabel userIdWidthlabel = new JLabel();
 
@@ -294,6 +307,9 @@ public class GPreferences extends JPanel
     tabbedPane.add(initColoursTab(),
             MessageManager.getString("label.colours"));
 
+    tabbedPane.add(initOverviewTab(),
+            MessageManager.getString("label.overview"));
+
     tabbedPane.add(initStructureTab(),
             MessageManager.getString("label.structure"));
 
@@ -963,6 +979,151 @@ public class GPreferences extends JPanel
   }
 
   /**
+   * Initialises the Overview tabbed panel.
+   * 
+   * @return
+   */
+  private JPanel initOverviewTab()
+  {
+    JPanel overviewPanel = new JPanel();
+    overviewPanel.setBorder(new TitledBorder(
+            MessageManager.getString("label.overview_settings")));
+
+    gapColour.setFont(LABEL_FONT);
+    // fixing the border colours stops apparent colour bleed from the panel
+    gapColour.setBorder(
+            BorderFactory.createEtchedBorder(Color.white, Color.lightGray));
+    gapColour.setPreferredSize(new Dimension(40, 20));
+    gapColour.addMouseListener(new MouseAdapter()
+    {
+      @Override
+      public void mousePressed(MouseEvent e)
+      {
+        gapColour_actionPerformed(gapColour);
+      }
+    });
+
+    hiddenColour.setFont(LABEL_FONT);
+    // fixing the border colours stops apparent colour bleed from the panel
+    hiddenColour.setBorder(
+            BorderFactory.createEtchedBorder(Color.white, Color.lightGray));
+    hiddenColour.setPreferredSize(new Dimension(40, 20));
+    hiddenColour.addMouseListener(new MouseAdapter()
+    {
+      @Override
+      public void mousePressed(MouseEvent e)
+      {
+        hiddenColour_actionPerformed(hiddenColour);
+      }
+    });
+    
+    useLegacyGap = new JCheckBox(
+            MessageManager.getString("label.ov_legacy_gap"));
+    useLegacyGap.setFont(LABEL_FONT);
+    useLegacyGap.setHorizontalAlignment(SwingConstants.LEFT);
+    useLegacyGap.setVerticalTextPosition(SwingConstants.TOP);
+    gapLabel = new JLabel(
+            MessageManager.getString("label.gap_colour"));
+    gapLabel.setFont(LABEL_FONT);
+    gapLabel.setHorizontalAlignment(SwingConstants.LEFT);
+    gapLabel.setVerticalTextPosition(SwingConstants.TOP);
+    showHiddenAtStart = new JCheckBox(
+            MessageManager.getString("label.ov_show_hide_default"));
+    showHiddenAtStart.setFont(LABEL_FONT);
+    showHiddenAtStart.setHorizontalAlignment(SwingConstants.LEFT);
+    showHiddenAtStart.setVerticalTextPosition(SwingConstants.TOP);
+    JLabel hiddenLabel = new JLabel(
+            MessageManager.getString("label.hidden_colour"));
+    hiddenLabel.setFont(LABEL_FONT);
+    hiddenLabel.setHorizontalAlignment(SwingConstants.LEFT);
+    hiddenLabel.setVerticalTextPosition(SwingConstants.TOP);
+
+    useLegacyGap.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        useLegacyGaps_actionPerformed(e);
+      }
+    });
+
+    overviewPanel.setLayout(new GridBagLayout());
+    GridBagConstraints c1 = new GridBagConstraints();
+
+    c1.fill = GridBagConstraints.HORIZONTAL;
+    c1.gridx = 0;
+    c1.gridy = 0;
+    c1.weightx = 1;
+    c1.ipady = 20;
+    c1.anchor = GridBagConstraints.FIRST_LINE_START;
+    overviewPanel.add(useLegacyGap, c1);
+
+    GridBagConstraints c2 = new GridBagConstraints();
+    c2.fill = GridBagConstraints.HORIZONTAL;
+    c2.gridx = 1;
+    c2.gridy = 0;
+    c2.insets = new Insets(0, 15, 0, 10);
+    overviewPanel.add(gapLabel, c2);
+
+    GridBagConstraints c3 = new GridBagConstraints();
+    c3.fill = GridBagConstraints.HORIZONTAL;
+    c3.gridx = 2;
+    c3.gridy = 0;
+    c3.insets = new Insets(0, 0, 0, 15);
+    overviewPanel.add(gapColour, c3);
+
+    GridBagConstraints c4 = new GridBagConstraints();
+    c4.fill = GridBagConstraints.HORIZONTAL;
+    c4.gridx = 0;
+    c4.gridy = 1;
+    c4.weightx = 1;
+    overviewPanel.add(showHiddenAtStart, c4);
+
+    GridBagConstraints c5 = new GridBagConstraints();
+    c5.fill = GridBagConstraints.HORIZONTAL;
+    c5.gridx = 1;
+    c5.gridy = 1;
+    c5.insets = new Insets(0, 15, 0, 10);
+    overviewPanel.add(hiddenLabel, c5);
+
+    GridBagConstraints c6 = new GridBagConstraints();
+    c6.fill = GridBagConstraints.HORIZONTAL;
+    c6.gridx = 2;
+    c6.gridy = 1;
+    c6.insets = new Insets(0, 0, 0, 15);
+    overviewPanel.add(hiddenColour, c6);
+
+    JButton resetButton = new JButton(
+            MessageManager.getString("label.reset_to_defaults"));
+
+    resetButton.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        resetOvDefaults_actionPerformed(e);
+      }
+    });
+
+    GridBagConstraints c7 = new GridBagConstraints();
+    c7.fill = GridBagConstraints.NONE;
+    c7.gridx = 0;
+    c7.gridy = 2;
+    c7.insets = new Insets(10, 0, 0, 0);
+    c7.anchor = GridBagConstraints.WEST;
+    overviewPanel.add(resetButton, c7);
+
+    // Add padding so the panel doesn't look ridiculous
+    JPanel spacePanel = new JPanel();
+    overviewPanel.add(spacePanel,
+            new GridBagConstraints(0, 3, 1, 1, 1.0, 1.0,
+                    GridBagConstraints.WEST, GridBagConstraints.BOTH,
+                    new Insets(0, 0, 0, 5), 0, 0));
+
+    return overviewPanel;
+  }
+
+  /**
    * Initialises the Structure tabbed panel.
    * 
    * @return
@@ -1494,12 +1655,28 @@ public class GPreferences extends JPanel
   {
   }
 
+  protected void gapColour_actionPerformed(JPanel panel)
+  {
+  }
+
+  protected void hiddenColour_actionPerformed(JPanel panel)
+  {
+  }
+
   protected void showunconserved_actionPerformed(ActionEvent e)
   {
     // TODO Auto-generated method stub
 
   }
 
+  protected void useLegacyGaps_actionPerformed(ActionEvent e)
+  {
+  }
+
+  protected void resetOvDefaults_actionPerformed(ActionEvent e)
+  {
+  }
+
   /**
    * DOCUMENT ME!
    * 
index 3e6cd2a..7c4672a 100644 (file)
@@ -165,6 +165,9 @@ public abstract class GStructureChooser extends JPanel
 
   protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
 
+  /**
+   * 'cached' structure view
+   */
   protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
 
   protected JTable tbl_local_pdb = new JTable();
index 0f8cda6..1c50aab 100644 (file)
@@ -22,22 +22,38 @@ package jalview.renderer;
 
 import jalview.api.AlignmentColsCollectionI;
 import jalview.api.AlignmentRowsCollectionI;
+import jalview.api.RendererListenerI;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.seqfeatures.FeatureColourFinder;
 import jalview.renderer.seqfeatures.FeatureRenderer;
 import jalview.viewmodel.OverviewDimensions;
 
+import java.awt.AlphaComposite;
 import java.awt.Color;
 import java.awt.Graphics;
+import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeSupport;
 
 public class OverviewRenderer
 {
-  private FeatureColourFinder finder;
+  // transparency of hidden cols/seqs overlay
+  private final float TRANSPARENCY = 0.5f;
+
+  private final Color HIDDEN_COLOUR = Color.DARK_GRAY.darker();
+
+  public static final String UPDATE = "OverviewUpdate";
+
+  private static final int MAX_PROGRESS = 100;
 
-  private jalview.api.SequenceRenderer sr;
+  private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+          this);
+
+  private FeatureColourFinder finder;
 
   // image to render on
   private BufferedImage miniMe;
@@ -48,17 +64,32 @@ public class OverviewRenderer
   // raw number of pixels to allocate to each row
   private float pixelsPerSeq;
 
+  // height in pixels of graph
+  private int graphHeight;
+
   // flag to indicate whether to halt drawing
   private volatile boolean redraw = false;
 
-  public OverviewRenderer(jalview.api.SequenceRenderer seqRenderer,
-          FeatureRenderer fr, OverviewDimensions od)
+  // reference to alignment, needed to get sequence groups
+  private AlignmentI al;
+
+  private ResidueShaderI shader;
+
+  private OverviewResColourFinder resColFinder;
+
+  public OverviewRenderer(FeatureRenderer fr, OverviewDimensions od,
+          AlignmentI alignment,
+          ResidueShaderI resshader, OverviewResColourFinder colFinder)
   {
-    sr = seqRenderer;
     finder = new FeatureColourFinder(fr);
+    resColFinder = colFinder;
+
+    al = alignment;
+    shader = resshader;
 
     pixelsPerCol = od.getPixelsPerCol();
     pixelsPerSeq = od.getPixelsPerSeq();
+    graphHeight = od.getGraphHeight();
     miniMe = new BufferedImage(od.getWidth(), od.getHeight(),
             BufferedImage.TYPE_INT_RGB);
   }
@@ -78,6 +109,12 @@ public class OverviewRenderer
     int rgbcolor = Color.white.getRGB();
     int seqIndex = 0;
     int pixelRow = 0;
+    int alignmentHeight = miniMe.getHeight() - graphHeight;
+    int totalPixels = miniMe.getWidth() * alignmentHeight;
+
+    int lastRowUpdate = 0;
+    int lastUpdate = 0;
+    changeSupport.firePropertyChange(UPDATE, -1, 0);
 
     for (int alignmentRow : rows)
     {
@@ -85,15 +122,17 @@ public class OverviewRenderer
       {
         break;
       }
-
+    
       // get details of this alignment row
-      boolean hidden = rows.isHidden(alignmentRow);
       SequenceI seq = rows.getSequence(alignmentRow);
 
+      // rate limiting step when rendering overview for lots of groups
+      SequenceGroup[] allGroups = al.findAllGroups(seq);
+
       // calculate where this row extends to in pixels
       int endRow = Math.min(Math.round((seqIndex + 1) * pixelsPerSeq) - 1,
               miniMe.getHeight() - 1);
-
+    
       int colIndex = 0;
       int pixelCol = 0;
       for (int alignmentCol : cols)
@@ -102,21 +141,19 @@ public class OverviewRenderer
         {
           break;
         }
-
+    
         // calculate where this column extends to in pixels
         int endCol = Math.min(Math.round((colIndex + 1) * pixelsPerCol) - 1,
                 miniMe.getWidth() - 1);
-
+    
         // don't do expensive colour determination if we're not going to use it
         // NB this is important to avoid performance issues in the overview
         // panel
         if (pixelCol <= endCol)
         {
-          // determine the colour based on the sequence and column position
-          rgbcolor = getColumnColourFromSequence(seq,
-                  hidden || cols.isHidden(alignmentCol), alignmentCol,
-                  finder);
-
+          rgbcolor = getColumnColourFromSequence(allGroups, seq,
+                  alignmentCol, finder);
+    
           // fill in the appropriate number of pixels
           for (int row = pixelRow; row <= endRow; ++row)
           {
@@ -126,35 +163,193 @@ public class OverviewRenderer
             }
           }
 
+          // store last update value
+          lastUpdate = sendProgressUpdate(
+                  (pixelCol + 1) * (endRow - pixelRow), totalPixels,
+                  lastRowUpdate, lastUpdate);
+
           pixelCol = endCol + 1;
         }
         colIndex++;
       }
-      pixelRow = endRow + 1;
+
+      if (pixelRow != endRow + 1)
+      {
+        // store row offset and last update value
+        lastRowUpdate = sendProgressUpdate(endRow + 1, alignmentHeight, 0,
+                lastUpdate);
+        lastUpdate = lastRowUpdate;
+        pixelRow = endRow + 1;
+      }
       seqIndex++;
     }
+
+    overlayHiddenRegions(rows, cols);
+    // final update to progress bar if present
+    if (redraw)
+    {
+      sendProgressUpdate(pixelRow - 1, alignmentHeight, 0, 0);
+    }
+    else
+    {
+      sendProgressUpdate(alignmentHeight, miniMe.getHeight(), 0, 0);
+    }
     return miniMe;
   }
 
   /*
+   * Calculate progress update value and fire event
+   * @param rowOffset number of rows to offset calculation by
+   * @return new rowOffset - return value only to be used when at end of a row
+   */
+  private int sendProgressUpdate(int position, int maximum, int rowOffset,
+          int lastUpdate)
+  {
+    int newUpdate = rowOffset
+            + Math.round(MAX_PROGRESS * ((float) position / maximum));
+    if (newUpdate > lastUpdate)
+    {
+      changeSupport.firePropertyChange(UPDATE, rowOffset, newUpdate);
+      return newUpdate;
+    }
+    return newUpdate;
+  }
+
+  /*
    * Find the colour of a sequence at a specified column position
+   * 
+   * @param seq
+   *          sequence to get colour for
+   * @param lastcol
+   *          column position to get colour for
+   * @param fcfinder
+   *          FeatureColourFinder to use
+   * @return colour of sequence at this position, as RGB
    */
-  private int getColumnColourFromSequence(jalview.datamodel.SequenceI seq,
-          boolean isHidden, int lastcol, FeatureColourFinder fcfinder)
+  private int getColumnColourFromSequence(SequenceGroup[] allGroups,
+          jalview.datamodel.SequenceI seq,
+          int lastcol, FeatureColourFinder fcfinder)
   {
     Color color = Color.white;
 
     if ((seq != null) && (seq.getLength() > lastcol))
     {
-      color = sr.getResidueColour(seq, lastcol, fcfinder);
+      color = resColFinder.getResidueColour(true, shader, allGroups, seq,
+              lastcol,
+              fcfinder);
     }
 
-    if (isHidden)
+    return color.getRGB();
+  }
+
+  /**
+   * Overlay the hidden regions on the overview image
+   * 
+   * @param rows
+   *          collection of rows the overview is built over
+   * @param cols
+   *          collection of columns the overview is built over
+   */
+  private void overlayHiddenRegions(AlignmentRowsCollectionI rows,
+          AlignmentColsCollectionI cols)
+  {
+    if (cols.hasHidden() || rows.hasHidden())
     {
-      color = color.darker().darker();
+      BufferedImage mask = buildHiddenImage(rows, cols, miniMe.getWidth(),
+              miniMe.getHeight());
+
+      Graphics2D g = (Graphics2D) miniMe.getGraphics();
+      g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
+              TRANSPARENCY));
+      g.drawImage(mask, 0, 0, miniMe.getWidth(), miniMe.getHeight(), null);
     }
+  }
 
-    return color.getRGB();
+  /**
+   * Build a masking image of hidden columns and rows to be applied on top of
+   * the main overview image.
+   * 
+   * @param rows
+   *          collection of rows the overview is built over
+   * @param cols
+   *          collection of columns the overview is built over
+   * @param width
+   *          width of overview in pixels
+   * @param height
+   *          height of overview in pixels
+   * @return BufferedImage containing mask of hidden regions
+   */
+  private BufferedImage buildHiddenImage(AlignmentRowsCollectionI rows,
+          AlignmentColsCollectionI cols, int width, int height)
+  {
+    // new masking image
+    BufferedImage hiddenImage = new BufferedImage(width, height,
+            BufferedImage.TYPE_INT_ARGB);
+
+    int colIndex = 0;
+    int pixelCol = 0;
+
+    Color hidden = resColFinder.getHiddenColour();
+
+    Graphics2D g2d = (Graphics2D) hiddenImage.getGraphics();
+
+    // set background to transparent
+    g2d.setComposite(AlphaComposite.Clear);
+    g2d.fillRect(0, 0, width, height);
+
+    // set next colour to opaque
+    g2d.setComposite(AlphaComposite.Src);
+
+    for (int alignmentCol : cols)
+    {
+      if (redraw)
+      {
+        break;
+      }
+
+      // calculate where this column extends to in pixels
+      int endCol = Math.min(Math.round((colIndex + 1) * pixelsPerCol) - 1,
+              hiddenImage.getWidth() - 1);
+
+      if (pixelCol <= endCol)
+      {
+        // determine the colour based on the sequence and column position
+        if (cols.isHidden(alignmentCol))
+        {
+          g2d.setColor(hidden);
+          g2d.fillRect(pixelCol, 0, endCol - pixelCol + 1, height);
+        }
+
+        pixelCol = endCol + 1;
+      }
+      colIndex++;
+
+    }
+
+    int seqIndex = 0;
+    int pixelRow = 0;
+    for (int alignmentRow : rows)
+    {
+      if (redraw)
+      {
+        break;
+      }
+
+      // calculate where this row extends to in pixels
+      int endRow = Math.min(Math.round((seqIndex + 1) * pixelsPerSeq) - 1,
+              miniMe.getHeight() - 1);
+
+      // get details of this alignment row
+      if (rows.isHidden(alignmentRow))
+      {
+        g2d.setColor(hidden);
+        g2d.fillRect(0, pixelRow, width, endRow - pixelRow + 1);
+      }
+      pixelRow = endRow + 1;
+      seqIndex++;
+    }
+
+    return hiddenImage;
   }
 
   /**
@@ -185,8 +380,10 @@ public class OverviewRenderer
     {
       if (redraw)
       {
+        changeSupport.firePropertyChange(UPDATE, MAX_PROGRESS - 1, 0);
         break;
       }
+
       if (alignmentCol >= annotations.length)
       {
         break; // no more annotations to draw here
@@ -216,12 +413,22 @@ public class OverviewRenderer
 
           g.fillRect(pixelCol, y - height, endCol - pixelCol + 1, height);
         }
+
         pixelCol = endCol + 1;
         colIndex++;
       }
     }
+    changeSupport.firePropertyChange(UPDATE, MAX_PROGRESS - 1,
+            MAX_PROGRESS);
   }
 
+  /**
+   * Allows redraw flag to be set
+   * 
+   * @param b
+   *          value to set redraw to: true = redraw is occurring, false = no
+   *          redraw
+   */
   public void setRedraw(boolean b)
   {
     synchronized (this)
@@ -229,4 +436,14 @@ public class OverviewRenderer
       redraw = b;
     }
   }
+
+  public void addPropertyChangeListener(RendererListenerI listener)
+  {
+    changeSupport.addPropertyChangeListener(listener);
+  }
+
+  public void removePropertyChangeListener(RendererListenerI listener)
+  {
+    changeSupport.removePropertyChangeListener(listener);
+  }
 }
diff --git a/src/jalview/renderer/OverviewResColourFinder.java b/src/jalview/renderer/OverviewResColourFinder.java
new file mode 100644 (file)
index 0000000..a497d92
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.renderer;
+
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
+
+import java.awt.Color;
+
+public class OverviewResColourFinder extends ResidueColourFinder
+{
+  final Color GAP_COLOUR; // default colour to use at gaps
+
+  final Color RESIDUE_COLOUR; // default colour to use at residues
+
+  final Color HIDDEN_COLOUR; // colour for hidden regions
+
+  boolean useLegacy = false;
+
+  public static final Color OVERVIEW_DEFAULT_GAP = Color.lightGray;
+
+  public static final Color OVERVIEW_DEFAULT_LEGACY_GAP = Color.white;
+
+  public static final Color OVERVIEW_DEFAULT_HIDDEN = Color.darkGray
+          .darker();
+
+  /**
+   * Constructor without colour settings (used by applet)
+   */
+  public OverviewResColourFinder()
+  {
+    this(false, OVERVIEW_DEFAULT_GAP, OVERVIEW_DEFAULT_HIDDEN);
+  }
+
+  /**
+   * Constructor with colour settings
+   * 
+   * @param useLegacyColouring
+   *          whether to use legacy gap colouring (white gaps, grey residues)
+   * @param gapCol
+   *          gap colour if not legacy
+   * @param hiddenCol
+   *          hidden region colour (transparency applied by rendering code)
+   */
+  public OverviewResColourFinder(boolean useLegacyColouring, Color gapCol,
+          Color hiddenCol)
+  {
+    if (useLegacyColouring)
+    {
+      GAP_COLOUR = Color.white;
+      RESIDUE_COLOUR = Color.lightGray;
+      HIDDEN_COLOUR = hiddenCol;
+    }
+    else
+    {
+      GAP_COLOUR = gapCol;
+      RESIDUE_COLOUR = Color.white;
+      HIDDEN_COLOUR = hiddenCol;
+    }
+  }
+
+  @Override
+  public Color getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
+  {
+    Color resBoxColour = RESIDUE_COLOUR;
+    char currentChar = seq.getCharAt(i);
+
+    // In the overview window, gaps are coloured grey, unless the colour scheme
+    // specifies a gap colour, in which case gaps honour the colour scheme
+    // settings
+    if (shader.getColourScheme() != null)
+    {
+      if (Comparison.isGap(currentChar)
+              && (!shader.getColourScheme().hasGapColour()))
+      {
+        resBoxColour = GAP_COLOUR;
+      }
+      else
+      {
+        resBoxColour = shader.findColour(currentChar, i, seq);
+      }
+    }
+    else if (Comparison.isGap(currentChar))
+    {
+      resBoxColour = GAP_COLOUR;
+    }
+
+    return resBoxColour;
+  }
+
+  /**
+   * {@inheritDoc} In the overview, the showBoxes setting is ignored, as the
+   * overview displays the colours regardless.
+   */
+  @Override
+  protected Color getResidueBoxColour(boolean showBoxes,
+          ResidueShaderI shader,
+          SequenceGroup[] allGroups, SequenceI seq, int i)
+  {
+    ResidueShaderI currentShader;
+    SequenceGroup currentSequenceGroup = getCurrentSequenceGroup(allGroups,
+            i);
+    if (currentSequenceGroup != null)
+    {
+      currentShader = currentSequenceGroup.getGroupColourScheme();
+    }
+    else
+    {
+      currentShader = shader;
+    }
+
+    return getBoxColour(currentShader, seq, i);
+  }
+
+  /**
+   * Supply hidden colour
+   * 
+   * @return colour of hidden regions
+   */
+  protected Color getHiddenColour()
+  {
+    return HIDDEN_COLOUR;
+  }
+}
diff --git a/src/jalview/renderer/ResidueColourFinder.java b/src/jalview/renderer/ResidueColourFinder.java
new file mode 100644 (file)
index 0000000..2da7233
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.renderer;
+
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+
+import java.awt.Color;
+
+public class ResidueColourFinder
+{
+  public ResidueColourFinder()
+  {
+  }
+
+  /**
+   * Get the colour of a residue in a sequence
+   * 
+   * @param showBoxes
+   *          true if the viewport's Show Boxes setting is true
+   * @param shader
+   *          the viewport's colour scheme
+   * @param allGroups
+   *          all the groups which seq participates in
+   * @param seq
+   *          the sequence containing the residue
+   * @param position
+   *          the position of the residue in the sequence
+   * @param finder
+   *          FeatureColourFinder for the viewport
+   * @return colour of the residue
+   */
+  public Color getResidueColour(boolean showBoxes, ResidueShaderI shader,
+          SequenceGroup[] allGroups,
+          final SequenceI seq, int position, FeatureColourFinder finder)
+  {
+    Color col = getResidueBoxColour(showBoxes, shader, allGroups, seq,
+            position);
+
+    // if there's a FeatureColourFinder we might override the residue colour
+    // here with feature colouring
+    if (finder != null)
+    {
+      col = finder.findFeatureColour(col, seq, position);
+    }
+    return col;
+  }
+
+  /**
+   * Get the residue colour without accounting for any features
+   * 
+   * @param showBoxes
+   *          true if the viewport's Show Boxes setting is true
+   * @param shader
+   *          the viewport's colour scheme
+   * @param allGroups
+   *          all the groups which seq participates in
+   * @param seq
+   *          the sequence containing the residue
+   * @param i
+   *          the position of the residue in the sequence
+   * @return
+   */
+  protected Color getResidueBoxColour(boolean showBoxes,
+          ResidueShaderI shader,
+          SequenceGroup[] allGroups,
+          SequenceI seq, int i)
+  {
+    SequenceGroup currentSequenceGroup = getCurrentSequenceGroup(allGroups,
+            i);
+    if (currentSequenceGroup != null)
+    {
+      if (currentSequenceGroup.getDisplayBoxes())
+      {
+        return getBoxColour(currentSequenceGroup.getGroupColourScheme(),
+                seq, i);
+      }
+    }
+    else if (showBoxes)
+    {
+      return getBoxColour(shader, seq, i);
+    }
+  
+    return Color.white;
+  }
+
+  /**
+   * Search all the groups for a sequence to find the one which a given res
+   * falls into
+   * 
+   * @param allGroups
+   *          all the groups a sequence participates in
+   * @param res
+   *          the residue to search for
+   * @return a sequence group for res, or null if no sequence group applies
+   */
+  public SequenceGroup getCurrentSequenceGroup(SequenceGroup[] allGroups,
+          int res)
+  {
+    if (allGroups == null)
+    {
+      return null;
+    }
+
+    for (int i = 0; i < allGroups.length; i++)
+    {
+      if ((allGroups[i].getStartRes() <= res)
+              && (allGroups[i].getEndRes() >= res))
+      {
+        return (allGroups[i]);
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param shader
+   *          the viewport's colour scheme
+   * @param seq
+   *          the sequence containing the residue
+   * @param i
+   *          the position of the residue in the sequence
+   */
+  public Color getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
+  {
+    Color resBoxColour = Color.white;
+    if (shader.getColourScheme() != null)
+    {
+      resBoxColour = shader.findColour(seq.getCharAt(i), i, seq);
+    }
+    return resBoxColour;
+  }
+
+}
index 7e4f211..c031170 100644 (file)
@@ -235,6 +235,11 @@ public class ResidueShader implements ResidueShaderI
   @Override
   public Color findColour(char symbol, int position, SequenceI seq)
   {
+    if (colourScheme == null)
+    {
+      return Color.white; // Colour is 'None'
+    }
+
     /*
      * get 'base' colour
      */
@@ -243,14 +248,16 @@ public class ResidueShader implements ResidueShaderI
             : profile.getModalResidue();
     float pid = profile == null ? 0f
             : profile.getPercentageIdentity(ignoreGaps);
-    Color colour = colourScheme == null ? Color.white
-            : colourScheme.findColour(symbol, position, seq, modalResidue,
-                    pid);
+    Color colour = colourScheme.findColour(symbol, position, seq,
+            modalResidue, pid);
 
     /*
      * apply PID threshold and consensus fading if in force
      */
-    colour = adjustColour(symbol, position, colour);
+    if (!Comparison.isGap(symbol))
+    {
+      colour = adjustColour(symbol, position, colour);
+    }
 
     return colour;
   }
index e81e519..1f47da3 100644 (file)
@@ -216,7 +216,8 @@ public class FeatureRenderer extends FeatureRendererModel
       return null;
     }
 
-    if (Comparison.isGap(seq.getCharAt(column)))
+    // column is 'base 1' but getCharAt is an array index (ie from 0)
+    if (Comparison.isGap(seq.getCharAt(column - 1)))
     {
       /*
        * returning null allows the colour scheme to provide gap colour
@@ -401,27 +402,6 @@ public class FeatureRenderer extends FeatureRendererModel
   }
 
   /**
-<<<<<<< HEAD
-=======
-   * Answers true if the feature belongs to a feature group which is not
-   * currently displayed, else false
-   * 
-   * @param sequenceFeature
-   * @return
-   */
-  @Override
-  protected boolean featureGroupNotShown(
-          final SequenceFeature sequenceFeature)
-  {
-    return featureGroups != null && sequenceFeature.featureGroup != null
-            && sequenceFeature.featureGroup.length() != 0
-            && featureGroups.containsKey(sequenceFeature.featureGroup)
-            && !featureGroups.get(sequenceFeature.featureGroup)
-                    .booleanValue();
-  }
-
-  /**
->>>>>>> refs/heads/develop
    * Called when alignment in associated view has new/modified features to
    * discover and display.
    * 
index f16ca21..d70b4e2 100755 (executable)
@@ -98,4 +98,11 @@ public interface ColourSchemeI
    * @return
    */
   boolean isSimple();
+
+  /**
+   * Answers true if the colour scheme has a colour specified for gaps.
+   * 
+   * @return
+   */
+  boolean hasGapColour();
 }
index 15cb157..9809fa9 100644 (file)
@@ -58,7 +58,7 @@ public class RNAHelicesColourChooser
     oldcs = av.getGlobalColourScheme();
     if (av.getAlignment().getGroups() != null)
     {
-      oldgroupColours = new Hashtable<SequenceGroup, ColourSchemeI>();
+      oldgroupColours = new Hashtable<>();
       for (SequenceGroup sg : ap.getAlignment().getGroups())
       {
         if (sg.getColourScheme() != null)
@@ -71,7 +71,7 @@ public class RNAHelicesColourChooser
     this.ap = ap;
 
     adjusting = true;
-    Vector<String> list = new Vector<String>();
+    Vector<String> list = new Vector<>();
     int index = 1;
     AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
     if (anns != null)
@@ -105,6 +105,6 @@ public class RNAHelicesColourChooser
 
     av.setGlobalColourScheme(rhc);
 
-    ap.paintAlignment(true);
+    ap.paintAlignment(true, true);
   }
 }
index 34a5daa..2f7a5e0 100755 (executable)
@@ -208,4 +208,14 @@ public abstract class ResidueColourScheme implements ColourSchemeI
   {
     return true;
   }
+
+  /**
+   * Default method returns false. Override this to return true in colour
+   * schemes that have a colour associated with gap residues.
+   */
+  @Override
+  public boolean hasGapColour()
+  {
+    return false;
+  }
 }
index b86250a..bf62e45 100755 (executable)
@@ -287,7 +287,7 @@ public class UserColourScheme extends ResidueColourScheme
     /*
      * step 1: build a map from colours to the symbol(s) that have the colour
      */
-    Map<Color, List<String>> colours = new HashMap<Color, List<String>>();
+    Map<Color, List<String>> colours = new HashMap<>();
 
     for (char symbol = 'A'; symbol <= 'Z'; symbol++)
     {
@@ -320,7 +320,7 @@ public class UserColourScheme extends ResidueColourScheme
     /*
      * step 2: make a list of { A,G,R=12f9d6 } residues/colour specs
      */
-    List<String> residueColours = new ArrayList<String>();
+    List<String> residueColours = new ArrayList<>();
     for (Entry<Color, List<String>> cols : colours.entrySet())
     {
       boolean first = true;
@@ -350,4 +350,10 @@ public class UserColourScheme extends ResidueColourScheme
     Collections.sort(residueColours);
     return StringUtils.listToDelimitedString(residueColours, ";");
   }
+
+  @Override
+  public boolean hasGapColour()
+  {
+    return (findColour(' ') != null);
+  }
 }
index fbfa486..b973f45 100644 (file)
@@ -340,7 +340,9 @@ public class StructureSelectionManager
    *          - one or more sequences to be mapped to pdbFile
    * @param targetChainIds
    *          - optional chain specification for mapping each sequence to pdb
-   *          (may be nill, individual elements may be nill)
+   *          (may be nill, individual elements may be nill) - JBPNote: JAL-2693
+   *          - this should be List<List<String>>, empty lists indicate no
+   *          predefined mappings
    * @param pdbFile
    *          - structure data resource
    * @param sourceType
index 9f4cea0..2528286 100644 (file)
@@ -142,7 +142,6 @@ public abstract class AAStructureBindingModel
    * @param ssm
    * @param pdbentry
    * @param sequenceIs
-   * @param chains
    * @param protocol
    */
   public AAStructureBindingModel(StructureSelectionManager ssm,
@@ -154,8 +153,60 @@ public abstract class AAStructureBindingModel
     this.nucleotide = Comparison.isNucleotide(sequenceIs);
     this.pdbEntry = pdbentry;
     this.protocol = protocol;
+    resolveChains();
   }
 
+  private boolean resolveChains()
+  {
+    /**
+     * final count of chain mappings discovered
+     */
+    int chainmaps = 0;
+    // JBPNote: JAL-2693 - this should be a list of chain mappings per
+    // [pdbentry][sequence]
+    String[][] newchains = new String[pdbEntry.length][];
+    int pe = 0;
+    for (PDBEntry pdb : pdbEntry)
+    {
+      SequenceI[] seqsForPdb = sequence[pe];
+      if (seqsForPdb != null)
+      {
+        newchains[pe] = new String[seqsForPdb.length];
+        int se = 0;
+        for (SequenceI asq : seqsForPdb)
+        {
+          String chain = (chains != null && chains[pe] != null)
+                  ? chains[pe][se]
+                  : null;
+          SequenceI sq = (asq.getDatasetSequence() == null) ? asq
+                  : asq.getDatasetSequence();
+          if (sq.getAllPDBEntries() != null)
+          {
+            for (PDBEntry pdbentry : sq.getAllPDBEntries())
+            {
+              if (pdb.getFile() != null && pdbentry.getFile() != null
+                      && pdb.getFile().equals(pdbentry.getFile()))
+              {
+                String chaincode = pdbentry.getChainCode();
+                if (chaincode != null && chaincode.length() > 0)
+                {
+                  chain = chaincode;
+                  chainmaps++;
+                  break;
+                }
+              }
+            }
+          }
+          newchains[pe][se] = chain;
+          se++;
+        }
+        pe++;
+      }
+    }
+
+    chains = newchains;
+    return chainmaps > 0;
+  }
   public StructureSelectionManager getSsm()
   {
     return ssm;
index d9f8bea..2c74609 100644 (file)
@@ -30,7 +30,7 @@ import java.awt.event.MouseEvent;
  */
 public class Platform
 {
-  private static Boolean isAMac = null;
+  private static Boolean isAMac = null, isWindows = null;
 
   private static Boolean isHeadless = null;
 
@@ -45,10 +45,29 @@ public class Platform
     {
       isAMac = System.getProperty("os.name").indexOf("Mac") > -1;
     }
+
     return isAMac.booleanValue();
 
   }
 
+  /**
+   * Check if we are on a Microsoft plaform...
+   * 
+   * @return true if we have to cope with another platform variation
+   */
+  public static boolean isWindows()
+  {
+    if (isWindows == null)
+    {
+      isWindows = System.getProperty("os.name").indexOf("Win") > -1;
+    }
+    return isWindows.booleanValue();
+  }
+
+  /**
+   * 
+   * @return true if we are running in non-interactive no UI mode
+   */
   public static boolean isHeadless()
   {
     if (isHeadless == null)
index 3347cc7..d6ece8d 100644 (file)
@@ -55,7 +55,7 @@ public class UrlConstants
    * Default sequence URL link string for EMBL-EBI search
    */
   public static final String DEFAULT_STRING = DEFAULT_LABEL
-          + "|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$";
+          + "|https://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$";
 
   /*
    * not instantiable
index 3702cd0..b260cab 100644 (file)
@@ -33,7 +33,6 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.Annotation;
-import jalview.datamodel.CigarArray;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
@@ -1673,13 +1672,6 @@ public abstract class AlignmentViewport
   }
 
   @Override
-  public CigarArray getViewAsCigars(boolean selectedRegionOnly)
-  {
-    return new CigarArray(alignment, alignment.getHiddenColumns(),
-            (selectedRegionOnly ? selectionGroup : null));
-  }
-
-  @Override
   public jalview.datamodel.AlignmentView getAlignmentView(
           boolean selectedOnly)
   {
index 8569039..8f37f15 100644 (file)
@@ -51,7 +51,7 @@ class AnnotationWorker extends AlignCalcWorker
           AnnotationProviderI counter)
   {
     super(viewport, panel);
-    ourAnnots = new ArrayList<AlignmentAnnotation>();
+    ourAnnots = new ArrayList<>();
     this.counter = counter;
     calcMan.registerWorker(this);
   }
@@ -121,7 +121,10 @@ class AnnotationWorker extends AlignCalcWorker
     if (ap != null)
     {
       ap.adjustAnnotationHeight();
-      ap.paintAlignment(true);
+      // TODO: only need to update colour and geometry if panel height changes
+      // and view is coloured by annotation, and the annotation is actually
+      // changed!
+      ap.paintAlignment(true, true);
     }
   }
 
index 24cb717..74695fe 100644 (file)
@@ -57,7 +57,7 @@ class ColumnCounterSetWorker extends AlignCalcWorker
           AlignmentViewPanel panel, FeatureSetCounterI counter)
   {
     super(viewport, panel);
-    ourAnnots = new ArrayList<AlignmentAnnotation>();
+    ourAnnots = new ArrayList<>();
     this.counter = counter;
     calcMan.registerWorker(this);
   }
@@ -116,7 +116,7 @@ class ColumnCounterSetWorker extends AlignCalcWorker
       {
         ap.adjustAnnotationHeight();
       }
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
 
   }
index 4242b2a..335529c 100644 (file)
@@ -64,7 +64,7 @@ public class ConsensusThread extends AlignCalcWorker
         {
           if (ap != null)
           {
-            ap.paintAlignment(false);
+            ap.paintAlignment(false, false);
           }
           Thread.sleep(200);
         } catch (Exception ex)
@@ -93,7 +93,7 @@ public class ConsensusThread extends AlignCalcWorker
 
       if (ap != null)
       {
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, true);
       }
     } catch (OutOfMemoryError error)
     {
index 571234c..54b0191 100644 (file)
@@ -75,7 +75,7 @@ public class ConservationThread extends AlignCalcWorker
         abortAndDestroy();
         return;
       }
-      List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
+      List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
       AlignmentI alignment = alignViewport.getAlignment();
       conservation = alignViewport.getAlignmentConservationAnnotation();
       quality = alignViewport.getAlignmentQualityAnnot();
@@ -123,7 +123,7 @@ public class ConservationThread extends AlignCalcWorker
     }
     if (ap != null)
     {
-      ap.paintAlignment(true);
+      ap.paintAlignment(true, true);
     }
 
   }
index 5ed2885..61ec3d0 100644 (file)
@@ -139,7 +139,7 @@ public class StrucConsensusThread extends AlignCalcWorker
       calcMan.workerComplete(this);
       if (ap != null)
       {
-        ap.paintAlignment(true);
+        ap.paintAlignment(true, true);
       }
     }
 
index 0a61dff..c661e2c 100644 (file)
@@ -135,7 +135,7 @@ public class DasSequenceFeatureFetcher
           boolean useJDasMultiThread)
   {
     this.useJDASMultiThread = useJDasMultiThread;
-    this.selectedSources = new ArrayList<jalviewSourceI>();
+    this.selectedSources = new ArrayList<>();
     // filter both sequences and sources to eliminate duplicates
     for (jalviewSourceI src : selectedSources2)
     {
@@ -316,17 +316,17 @@ public class DasSequenceFeatureFetcher
     FeaturesClientMultipleSources fc = new FeaturesClientMultipleSources();
     fc.setConnProps(sourceRegistry.getSessionHandler());
     // Now sending requests one at a time to each server
-    ArrayList<jalviewSourceI> srcobj = new ArrayList<jalviewSourceI>();
-    ArrayList<String> src = new ArrayList<String>();
-    List<List<String>> ids = new ArrayList<List<String>>();
-    List<List<DBRefEntry>> idobj = new ArrayList<List<DBRefEntry>>();
-    List<Map<String, SequenceI>> sqset = new ArrayList<Map<String, SequenceI>>();
+    ArrayList<jalviewSourceI> srcobj = new ArrayList<>();
+    ArrayList<String> src = new ArrayList<>();
+    List<List<String>> ids = new ArrayList<>();
+    List<List<DBRefEntry>> idobj = new ArrayList<>();
+    List<Map<String, SequenceI>> sqset = new ArrayList<>();
     for (jalviewSourceI _sr : selectedSources)
     {
 
-      Map<String, SequenceI> slist = new HashMap<String, SequenceI>();
-      List<DBRefEntry> idob = new ArrayList<DBRefEntry>();
-      List<String> qset = new ArrayList<String>();
+      Map<String, SequenceI> slist = new HashMap<>();
+      List<DBRefEntry> idob = new ArrayList<>();
+      List<String> qset = new ArrayList<>();
 
       for (SequenceI seq : sequences)
       {
@@ -368,8 +368,8 @@ public class DasSequenceFeatureFetcher
         sqset.add(slist);
       }
     }
-    Map<String, Map<List<String>, Exception>> errors = new HashMap<String, Map<List<String>, Exception>>();
-    Map<String, Map<List<String>, DasGFFAdapter>> results = new HashMap<String, Map<List<String>, DasGFFAdapter>>();
+    Map<String, Map<List<String>, Exception>> errors = new HashMap<>();
+    Map<String, Map<List<String>, DasGFFAdapter>> results = new HashMap<>();
     if (!useJDASMultiThread)
     {
       Iterator<String> sources = src.iterator();
@@ -390,7 +390,7 @@ public class DasSequenceFeatureFetcher
             if (ers == null)
             {
               results.put(source,
-                      ers = new HashMap<List<String>, DasGFFAdapter>());
+                      ers = new HashMap<>());
             }
             ers.put(qid, dga);
           } catch (Exception ex)
@@ -399,7 +399,7 @@ public class DasSequenceFeatureFetcher
             if (ers == null)
             {
               errors.put(source,
-                      ers = new HashMap<List<String>, Exception>());
+                      ers = new HashMap<>());
             }
             ers.put(qid, ex);
           }
@@ -438,7 +438,7 @@ public class DasSequenceFeatureFetcher
           Map<List<String>, DasGFFAdapter> results,
           Map<List<String>, Exception> errors)
   {
-    Set<SequenceI> sequences = new HashSet<SequenceI>();
+    Set<SequenceI> sequences = new HashSet<>();
     String source = jvsource.getSourceURL();
     // process features
     DasGFFAdapter result = (results == null) ? null : results.get(ids);
@@ -622,7 +622,7 @@ public class DasSequenceFeatureFetcher
         if (seq == af.getViewport().getAlignment().getSequenceAt(index)
                 .getDatasetSequence())
         {
-          af.alignPanel.paintAlignment(true);
+          af.alignPanel.paintAlignment(true, true);
           index = end;
           break;
         }
@@ -647,8 +647,8 @@ public class DasSequenceFeatureFetcher
     // TODO: minimal list of DAS queries to make by querying with untyped ID if
     // distinct from any typed IDs
 
-    List<DBRefEntry> ids = new ArrayList<DBRefEntry>();
-    List<String> qstring = new ArrayList<String>();
+    List<DBRefEntry> ids = new ArrayList<>();
+    List<String> qstring = new ArrayList<>();
     boolean dasCoordSysFound = false;
 
     if (uprefs != null)
index 21b226b..ca90d60 100644 (file)
@@ -91,7 +91,7 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
           File reply) throws Exception
   {
     EmblFile efile = null;
-    List<SequenceI> seqs = new ArrayList<SequenceI>();
+    List<SequenceI> seqs = new ArrayList<>();
 
     if (reply != null && reply.exists())
     {
@@ -107,7 +107,7 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
      * EmbFile reads something like (e.g.) this ungrammatical phrase
      * Entry: <acc> display type is either not supported or entry is not found.
      */
-    List<SequenceI> peptides = new ArrayList<SequenceI>();
+    List<SequenceI> peptides = new ArrayList<>();
     if (efile != null && efile.getEntries() != null)
     {
       for (EmblEntry entry : efile.getEntries())
index c868576..c9beb8e 100644 (file)
@@ -31,13 +31,13 @@ import jalview.datamodel.SequenceI;
 import jalview.datamodel.xdb.uniprot.UniprotEntry;
 import jalview.datamodel.xdb.uniprot.UniprotFeature;
 import jalview.datamodel.xdb.uniprot.UniprotFile;
-import jalview.ws.ebi.EBIFetchClient;
 import jalview.ws.seqfetcher.DbSourceProxyImpl;
 
-import java.io.File;
-import java.io.FileReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.Reader;
 import java.net.URL;
+import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Vector;
 
@@ -162,17 +162,21 @@ public class Uniprot extends DbSourceProxyImpl
       queries = queries.toUpperCase().replaceAll(
               "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
       AlignmentI al = null;
-      EBIFetchClient ebi = new EBIFetchClient();
-      // uniprotxml parameter required since december 2007
-      // uniprotkb dbname changed introduced december 2008
-      File file = ebi.fetchDataAsFile("uniprotkb:" + queries, "uniprotxml",
-              "xml");
+
+      String downloadstring = "http://www.uniprot.org/uniprot/" + queries
+              + ".xml";
+      URL url = null;
+      URLConnection urlconn = null;
+
+      url = new URL(downloadstring);
+      urlconn = url.openConnection();
+      InputStream istr = urlconn.getInputStream();
       Vector<UniprotEntry> entries = getUniprotEntries(
-              new FileReader(file));
+              new InputStreamReader(istr, "UTF-8"));
 
       if (entries != null)
       {
-        ArrayList<SequenceI> seqs = new ArrayList<SequenceI>();
+        ArrayList<SequenceI> seqs = new ArrayList<>();
         for (UniprotEntry entry : entries)
         {
           seqs.add(uniprotEntryToSequenceI(entry));
@@ -184,8 +188,10 @@ public class Uniprot extends DbSourceProxyImpl
       return al;
     } catch (Exception e)
     {
-      stopQuery();
       throw (e);
+    } finally
+    {
+      stopQuery();
     }
   }
 
@@ -203,7 +209,7 @@ public class Uniprot extends DbSourceProxyImpl
     sequence.setDescription(getUniprotEntryDescription(entry));
 
     final String dbVersion = getDbVersion();
-    ArrayList<DBRefEntry> dbRefs = new ArrayList<DBRefEntry>();
+    ArrayList<DBRefEntry> dbRefs = new ArrayList<>();
     for (String accessionId : entry.getAccession())
     {
       DBRefEntry dbRef = new DBRefEntry(DBRefSource.UNIPROT, dbVersion,
@@ -213,7 +219,7 @@ public class Uniprot extends DbSourceProxyImpl
       dbRefs.add(dbRef);
     }
 
-    Vector<PDBEntry> onlyPdbEntries = new Vector<PDBEntry>();
+    Vector<PDBEntry> onlyPdbEntries = new Vector<>();
     for (PDBEntry pdb : entry.getDbReference())
     {
       DBRefEntry dbr = new DBRefEntry();
index 3e8c55e..07a9df4 100644 (file)
@@ -29,6 +29,7 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
@@ -205,7 +206,14 @@ public class EBIFetchClient
     {
       URL rcall = new URL(url);
 
-      InputStream is = new BufferedInputStream(rcall.openStream());
+      HttpURLConnection conn = (HttpURLConnection) rcall.openConnection();
+      int responseCode = conn.getResponseCode();
+      if (responseCode != 200)
+      {
+        System.err.println("Warning: response code " + responseCode
+                + " for " + url);
+      }
+      InputStream is = new BufferedInputStream(conn.getInputStream());
       if (outFile != null)
       {
         FileOutputStream fio = new FileOutputStream(outFile);
@@ -267,12 +275,12 @@ public class EBIFetchClient
     if (database.equalsIgnoreCase(DBRefSource.EMBL)
             || database.equalsIgnoreCase(DBRefSource.EMBLCDS))
     {
-      url = "http://www.ebi.ac.uk/ena/data/view/" + ids.toLowerCase()
+      url = "https://www.ebi.ac.uk/ena/data/view/" + ids.toLowerCase()
               + (format != null ? "&" + format : "");
     }
     else
     {
-      url = "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/"
+      url = "https://www.ebi.ac.uk/Tools/dbfetch/dbfetch/"
               + database.toLowerCase() + "/" + ids.toLowerCase()
               + (format != null ? "/" + format : "");
     }
index c24ea05..9a2316c 100644 (file)
@@ -99,22 +99,22 @@ public class AADisorderClient extends JabawsCalcWorker
   {
     // TODO: turn this into some kind of configuration file that's a bit easier
     // to edit
-    featureMap = new HashMap<String, Map<String, String[]>>();
+    featureMap = new HashMap<>();
     Map<String, String[]> fmap;
     featureMap.put(compbio.ws.client.Services.IUPredWS.toString(),
-            fmap = new HashMap<String, String[]>());
+            fmap = new HashMap<>());
     fmap.put("Glob",
             new String[]
             { "Globular Domain", "Predicted globular domain" });
     featureMap.put(compbio.ws.client.Services.JronnWS.toString(),
-            fmap = new HashMap<String, String[]>());
+            fmap = new HashMap<>());
     featureMap.put(compbio.ws.client.Services.DisemblWS.toString(),
-            fmap = new HashMap<String, String[]>());
+            fmap = new HashMap<>());
     fmap.put("REM465", new String[] { "REM465", "Missing density" });
     fmap.put("HOTLOOPS", new String[] { "HOTLOOPS", "Flexible loops" });
     fmap.put("COILS", new String[] { "COILS", "Random coil" });
     featureMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
-            fmap = new HashMap<String, String[]>());
+            fmap = new HashMap<>());
     fmap.put("GlobDoms",
             new String[]
             { "Globular Domain", "Predicted globular domain" });
@@ -122,9 +122,9 @@ public class AADisorderClient extends JabawsCalcWorker
             new String[]
             { "Protein Disorder", "Probable unstructured peptide region" });
     Map<String, Map<String, Object>> amap;
-    annotMap = new HashMap<String, Map<String, Map<String, Object>>>();
+    annotMap = new HashMap<>();
     annotMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
-            amap = new HashMap<String, Map<String, Object>>());
+            amap = new HashMap<>());
     amap.put("Dydx", new HashMap<String, Object>());
     amap.get("Dydx").put(DONTCOMBINE, DONTCOMBINE);
     amap.get("Dydx").put(THRESHOLD, new double[] { 1, 0 });
@@ -135,7 +135,7 @@ public class AADisorderClient extends JabawsCalcWorker
     amap.put("RawScore", new HashMap<String, Object>());
     amap.get("RawScore").put(INVISIBLE, INVISIBLE);
     annotMap.put(compbio.ws.client.Services.DisemblWS.toString(),
-            amap = new HashMap<String, Map<String, Object>>());
+            amap = new HashMap<>());
     amap.put("COILS", new HashMap<String, Object>());
     amap.put("HOTLOOPS", new HashMap<String, Object>());
     amap.put("REM465", new HashMap<String, Object>());
@@ -148,7 +148,7 @@ public class AADisorderClient extends JabawsCalcWorker
     amap.get("REM465").put(RANGE, new float[] { 0, 1 });
 
     annotMap.put(compbio.ws.client.Services.IUPredWS.toString(),
-            amap = new HashMap<String, Map<String, Object>>());
+            amap = new HashMap<>());
     amap.put("Long", new HashMap<String, Object>());
     amap.put("Short", new HashMap<String, Object>());
     amap.get("Long").put(THRESHOLD, new double[] { 1, 0.5 });
@@ -156,7 +156,7 @@ public class AADisorderClient extends JabawsCalcWorker
     amap.get("Short").put(THRESHOLD, new double[] { 1, 0.5 });
     amap.get("Short").put(RANGE, new float[] { 0, 1 });
     annotMap.put(compbio.ws.client.Services.JronnWS.toString(),
-            amap = new HashMap<String, Map<String, Object>>());
+            amap = new HashMap<>());
     amap.put("JRonn", new HashMap<String, Object>());
     amap.get("JRonn").put(THRESHOLD, new double[] { 1, 0.5 });
     amap.get("JRonn").put(RANGE, new float[] { 0, 1 });
@@ -173,8 +173,8 @@ public class AADisorderClient extends JabawsCalcWorker
       Map<String, Map<String, Object>> annotTypeMap = annotMap
               .get(service.serviceType);
       boolean dispFeatures = false;
-      Map<String, Object> fc = new Hashtable<String, Object>();
-      List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
+      Map<String, Object> fc = new Hashtable<>();
+      List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
       /**
        * grouping for any annotation rows created
        */
@@ -358,7 +358,6 @@ public class AADisorderClient extends JabawsCalcWorker
             // only do this if the alignFrame is currently showing this view.
             af.setShowSeqFeatures(true);
           }
-          ap.paintAlignment(true);
         }
         if (ourAnnot.size() > 0)
         {
@@ -366,6 +365,7 @@ public class AADisorderClient extends JabawsCalcWorker
           // new alignment annotation rows created.
           updateOurAnnots(ourAnnot);
           ap.adjustAnnotationHeight();
+          ap.paintAlignment(true, true);
         }
       }
     }
index 26fe0a2..b972ab8 100644 (file)
@@ -372,7 +372,8 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
         {
           guiProgress.setProgressBar("", progressId);
         }
-        ap.paintAlignment(true);
+        // TODO: may not need to paintAlignment again !
+        ap.paintAlignment(false, false);
       }
       if (msg.length() > 0)
       {
@@ -582,7 +583,7 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
   protected boolean checkDone()
   {
     calcMan.notifyStart(this);
-    ap.paintAlignment(false);
+    ap.paintAlignment(false, false);
     while (!calcMan.notifyWorking(this))
     {
       if (calcMan.isWorking(this))
@@ -593,7 +594,7 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
       {
         if (ap != null)
         {
-          ap.paintAlignment(false);
+          ap.paintAlignment(false, false);
         }
 
         Thread.sleep(200);
index 977f9da..9284f82 100644 (file)
@@ -126,15 +126,16 @@ public class ASequenceFetcher
    */
   public SequenceI[] getSequences(List<DBRefEntry> refs, boolean dna)
   {
-    Vector<SequenceI> rseqs = new Vector<SequenceI>();
-    Hashtable<String, List<String>> queries = new Hashtable<String, List<String>>();
+    Vector<SequenceI> rseqs = new Vector<>();
+    Hashtable<String, List<String>> queries = new Hashtable<>();
     for (DBRefEntry ref : refs)
     {
-      if (!queries.containsKey(ref.getSource()))
+      String canonical = DBRefUtils.getCanonicalName(ref.getSource());
+      if (!queries.containsKey(canonical))
       {
-        queries.put(ref.getSource(), new ArrayList<String>());
+        queries.put(canonical, new ArrayList<String>());
       }
-      List<String> qset = queries.get(ref.getSource());
+      List<String> qset = queries.get(canonical);
       if (!qset.contains(ref.getAccessionId()))
       {
         qset.add(ref.getAccessionId());
@@ -154,14 +155,14 @@ public class ASequenceFetcher
         continue;
       }
 
-      Stack<String> queriesLeft = new Stack<String>();
+      Stack<String> queriesLeft = new Stack<>();
       queriesLeft.addAll(query);
 
       List<DbSourceProxy> proxies = getSourceProxy(db);
       for (DbSourceProxy fetcher : proxies)
       {
-        List<String> queriesMade = new ArrayList<String>();
-        HashSet<String> queriesFound = new HashSet<String>();
+        List<String> queriesMade = new ArrayList<>();
+        HashSet<String> queriesFound = new HashSet<>();
         try
         {
           if (fetcher.isDnaCoding() != dna)
@@ -306,13 +307,13 @@ public class ASequenceFetcher
     Map<String, DbSourceProxy> dblist = fetchableDbs.get(db);
     if (dblist == null)
     {
-      return new ArrayList<DbSourceProxy>();
+      return new ArrayList<>();
     }
 
     /*
      * sort so that primary sources precede secondary
      */
-    List<DbSourceProxy> dbs = new ArrayList<DbSourceProxy>(dblist.values());
+    List<DbSourceProxy> dbs = new ArrayList<>(dblist.values());
     Collections.sort(dbs, proxyComparator);
     return dbs;
   }
@@ -357,14 +358,14 @@ public class ASequenceFetcher
     {
       if (fetchableDbs == null)
       {
-        fetchableDbs = new Hashtable<String, Map<String, DbSourceProxy>>();
+        fetchableDbs = new Hashtable<>();
       }
       Map<String, DbSourceProxy> slist = fetchableDbs
               .get(proxy.getDbSource());
       if (slist == null)
       {
         fetchableDbs.put(proxy.getDbSource(),
-                slist = new Hashtable<String, DbSourceProxy>());
+                slist = new Hashtable<>());
       }
       slist.put(proxy.getDbName(), proxy);
     }
@@ -391,7 +392,7 @@ public class ASequenceFetcher
       return null;
     }
     String[] sources = null;
-    Vector<String> src = new Vector<String>();
+    Vector<String> src = new Vector<>();
     Enumeration<String> dbs = fetchableDbs.keys();
     while (dbs.hasMoreElements())
     {
@@ -413,7 +414,7 @@ public class ASequenceFetcher
 
   public DbSourceProxy[] getDbSourceProxyInstances(Class class1)
   {
-    List<DbSourceProxy> prlist = new ArrayList<DbSourceProxy>();
+    List<DbSourceProxy> prlist = new ArrayList<>();
     for (String fetchable : getSupportedDb())
     {
       for (DbSourceProxy pr : getSourceProxy(fetchable))
diff --git a/test/jalview/datamodel/CigarArrayTest.java b/test/jalview/datamodel/CigarArrayTest.java
new file mode 100644 (file)
index 0000000..7bee423
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.gui.JvOptionPane;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class CigarArrayTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  @Test(groups = "Functional")
+  public void testConstructor()
+  {
+    SequenceI seq1 = new Sequence("sq1",
+            "ASFDDABACBACBACBACBACBACBABCABCBACBABCAB");
+    Sequence seq2 = new Sequence("sq2",
+            "TTTTTTACBCBABCABCABCABCBACBACBABCABCABCBA");
+
+    // construct alignment
+    AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+
+    // hide columns
+    HiddenColumns hc = new HiddenColumns();
+    hc.hideColumns(3, 6);
+    hc.hideColumns(16, 20);
+
+    // select group
+    SequenceGroup sg1 = new SequenceGroup();
+    sg1.addSequence(seq1, false);
+    sg1.setStartRes(2);
+    sg1.setEndRes(23);
+
+    // Cigar array meanings:
+    // M = match
+    // D = deletion
+    // I = insertion
+    // number preceding M/D/I is the number of residues which
+    // match/are deleted/are inserted
+    // In the CigarArray constructor only matches or deletions are created, as
+    // we are comparing a sequence to its own subsequence (the group) + hidden
+    // columns.
+
+    // no hidden columns case
+    CigarArray cig = new CigarArray(al, null, sg1);
+    String result = cig.getCigarstring();
+    assertEquals(result, "22M");
+
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "1M4D9M5D3M");
+
+    // group starts at hidden cols
+    sg1.setStartRes(3);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "4D9M5D3M");
+
+    // group starts at last but 1 hidden col
+    sg1.setStartRes(5);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "2D9M5D3M");
+
+    // group starts at last hidden col
+    sg1.setStartRes(6);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "1D9M5D3M");
+
+    // group starts just after hidden region
+    sg1.setStartRes(7);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "9M5D3M");
+
+    // group ends just before start of hidden region
+    sg1.setStartRes(5);
+    sg1.setEndRes(15);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "2D9M");
+
+    // group ends at start of hidden region
+    sg1.setEndRes(16);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "2D9M1D");
+
+    // group ends 1 after start of hidden region
+    sg1.setEndRes(17);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "2D9M2D");
+
+    // group ends at end of hidden region
+    sg1.setEndRes(20);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "2D9M5D");
+
+    // group ends just after end of hidden region
+    sg1.setEndRes(21);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "2D9M5D1M");
+
+    // group ends 2 after end of hidden region
+    sg1.setEndRes(22);
+    cig = new CigarArray(al, hc, sg1);
+    result = cig.getCigarstring();
+    assertEquals(result, "2D9M5D2M");
+  }
+}
index fce5869..c0cb09c 100644 (file)
@@ -1358,6 +1358,10 @@ public class SequenceTest
     SequenceFeature sfContactFG = new SequenceFeature("Disulfide Bond",
             "desc", 13, 14, 2f, null);
     sq.addSequenceFeature(sfContactFG);
+    // add single position feature at [I]
+    SequenceFeature sfI = new SequenceFeature("Disulfide Bond",
+            "desc", 16, 16, null);
+    sq.addSequenceFeature(sfI);
 
     // no features in columns 1-2 (-A)
     List<SequenceFeature> found = sq.findFeatures(1, 2);
@@ -1384,6 +1388,11 @@ public class SequenceTest
     // columns 10-11 (--) should find nothing
     found = sq.findFeatures(10, 11);
     assertEquals(0, found.size());
+
+    // columns 14-14 (I) should find variant feature
+    found = sq.findFeatures(14, 14);
+    assertEquals(1, found.size());
+    assertTrue(found.contains(sfI));
   }
 
   @Test(groups = { "Functional" })
@@ -1665,6 +1674,38 @@ public class SequenceTest
   }
 
   @Test(groups = { "Functional" })
+  public void testFindFeatures_largeEndPos()
+  {
+    /*
+     * imitate a PDB sequence where end is larger than end position
+     */
+    SequenceI sq = new Sequence("test", "-ABC--DEF--", 1, 20);
+    sq.createDatasetSequence();
+  
+    assertTrue(sq.findFeatures(1, 9).isEmpty());
+    // should be no array bounds exception - JAL-2772
+    assertTrue(sq.findFeatures(1, 15).isEmpty());
+  
+    // add feature on BCD
+    SequenceFeature sfBCD = new SequenceFeature("Cath", "desc", 2, 4, 2f,
+            null);
+    sq.addSequenceFeature(sfBCD);
+  
+    // no features in columns 1-2 (-A)
+    List<SequenceFeature> found = sq.findFeatures(1, 2);
+    assertTrue(found.isEmpty());
+  
+    // columns 1-6 (-ABC--) includes BCD
+    found = sq.findFeatures(1, 6);
+    assertEquals(1, found.size());
+    assertTrue(found.contains(sfBCD));
+
+    // columns 10-11 (--) should find nothing
+    found = sq.findFeatures(10, 11);
+    assertEquals(0, found.size());
+  }
+
+  @Test(groups = { "Functional" })
   public void testSetName()
   {
     SequenceI sq = new Sequence("test", "-ABC---DE-F--");
index a144f03..39d6dce 100644 (file)
@@ -1032,6 +1032,9 @@ public class SequenceFeaturesTest
     assertEquals(features.size(), 2);
     assertTrue(features.contains(sf2));
     assertTrue(features.contains(sf3));
+
+    features = store.getFeaturesByOntology("sequence_variant");
+    assertTrue(features.isEmpty());
   }
 
   @Test(groups = "Functional")
index a8c491c..5920b89 100644 (file)
@@ -296,4 +296,28 @@ public class EnsemblGeneTest
     assertEquals(-1, fc.compare("coding_exon", "feature_variant"));
     assertEquals(1f, fc.getTransparency());
   }
+
+  @Test(groups = "Network")
+  public void testGetGeneIds()
+  {
+    /*
+     * ENSG00000158828 gene id PINK1 human
+     * ENST00000321556 transcript for the same gene - should not be duplicated
+     * P30419 Uniprot identifier for ENSG00000136448
+     * ENST00000592782 transcript for Uniprot gene - should not be duplicated
+     * BRAF - gene name resolvabe (at time of writing) for 6 model species
+     */
+    String ids = "ENSG00000158828 ENST00000321556 P30419 ENST00000592782 BRAF";
+    EnsemblGene testee = new EnsemblGene();
+    List<String> geneIds = testee.getGeneIds(ids);
+    assertEquals(8, geneIds.size());
+    assertTrue(geneIds.contains("ENSG00000158828"));
+    assertTrue(geneIds.contains("ENSG00000136448"));
+    assertTrue(geneIds.contains("ENSG00000157764")); // BRAF human
+    assertTrue(geneIds.contains("ENSMUSG00000002413")); // mouse
+    assertTrue(geneIds.contains("ENSRNOG00000010957")); // rat
+    assertTrue(geneIds.contains("ENSXETG00000004845")); // xenopus
+    assertTrue(geneIds.contains("ENSDARG00000017661")); // zebrafish
+    assertTrue(geneIds.contains("ENSGALG00000012865")); // chicken
+  }
 }
index 31001da..cc3a3db 100644 (file)
  */
 package jalview.ext.ensembl;
 
+import static org.testng.Assert.assertTrue;
+
 import jalview.datamodel.AlignmentI;
 
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.List;
 
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 public class EnsemblRestClientTest
 {
+  private EnsemblRestClient sf;
 
   @Test(suiteName = "live")
   public void testIsEnsemblAvailable()
   {
-    EnsemblRestClient sf = new EnsemblRestClient()
+    boolean isAvailable = sf.isEnsemblAvailable();
+    if (isAvailable)
+    {
+      System.out.println("Ensembl is UP!");
+    }
+    else
+    {
+      System.err
+              .println("Ensembl is DOWN or unreachable ******************* BAD!");
+    }
+  }
+
+  @BeforeMethod(alwaysRun = true)
+  protected void setUp()
+  {
+    sf = new EnsemblRestClient()
     {
 
       @Override
@@ -74,16 +93,14 @@ public class EnsemblRestClientTest
       }
 
     };
-    boolean isAvailable = sf.isEnsemblAvailable();
-    if (isAvailable)
-    {
-      System.out.println("Ensembl is UP!");
-    }
-    else
+  }
+
+  @Test(groups = "Network")
+  public void testCheckEnsembl_overload()
+  {
+    for (int i = 0; i < 20; i++)
     {
-      System.err
-              .println("Ensembl is DOWN or unreachable ******************* BAD!");
+      assertTrue(sf.checkEnsembl(), "Error on " + (i + 1) + "th ping");
     }
   }
-
 }
index aa2c315..e2af26b 100644 (file)
@@ -191,34 +191,6 @@ public class EnsemblSeqProxyTest
 
   }
 
-  @Test(groups = "Functional")
-  public void testIsTranscriptIdentifier()
-  {
-    EnsemblSeqProxy testee = new EnsemblGene();
-    assertFalse(testee.isTranscriptIdentifier(null));
-    assertFalse(testee.isTranscriptIdentifier(""));
-    assertFalse(testee.isTranscriptIdentifier("ENSG00000012345"));
-    assertTrue(testee.isTranscriptIdentifier("ENST00000012345"));
-    assertTrue(testee.isTranscriptIdentifier("ENSMUST00000012345"));
-    assertFalse(testee.isTranscriptIdentifier("enst00000012345"));
-    assertFalse(testee.isTranscriptIdentifier("ENST000000123456"));
-    assertFalse(testee.isTranscriptIdentifier("ENST0000001234"));
-  }
-
-  @Test(groups = "Functional")
-  public void testIsGeneIdentifier()
-  {
-    EnsemblSeqProxy testee = new EnsemblGene();
-    assertFalse(testee.isGeneIdentifier(null));
-    assertFalse(testee.isGeneIdentifier(""));
-    assertFalse(testee.isGeneIdentifier("ENST00000012345"));
-    assertTrue(testee.isGeneIdentifier("ENSG00000012345"));
-    assertTrue(testee.isGeneIdentifier("ENSMUSG00000012345"));
-    assertFalse(testee.isGeneIdentifier("ensg00000012345"));
-    assertFalse(testee.isGeneIdentifier("ENSG000000123456"));
-    assertFalse(testee.isGeneIdentifier("ENSG0000001234"));
-  }
-
   /**
    * Test the method that appends a single allele's reverse complement to a
    * string buffer
diff --git a/test/jalview/ext/ensembl/SpeciesTest.java b/test/jalview/ext/ensembl/SpeciesTest.java
new file mode 100644 (file)
index 0000000..44658e7
--- /dev/null
@@ -0,0 +1,30 @@
+package jalview.ext.ensembl;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.testng.annotations.Test;
+
+public class SpeciesTest
+{
+  @Test
+  public void testGetModelOrganisms()
+  {
+    Set<Species> models = Species.getModelOrganisms();
+    assertTrue(models.contains(Species.human));
+    assertFalse(models.contains(Species.horse));
+    for (Species s : Species.values())
+    {
+      if (s.isModelOrganism())
+      {
+        assertTrue(models.contains(s));
+      }
+      else
+      {
+        assertFalse(models.contains(s));
+      }
+    }
+  }
+}
index c9e1cad..63d5e4e 100644 (file)
@@ -29,6 +29,11 @@ public class AtomSpecModelTest
     assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
     model.addRange(0, 3, 10, "C"); // subsumes 5-9
     assertEquals(model.getAtomSpec(), "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B");
+    model.addRange(5, 25, 35, " "); // empty chain code - e.g. from homology
+                                    // modelling
+    assertEquals(model.getAtomSpec(),
+            "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B|#5:25-35.");
+
   }
 
 }
index c80b830..359377a 100644 (file)
  */
 package jalview.gui;
 
-import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.Assert.assertEquals;
 
+import jalview.bin.Jalview;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.renderer.ResidueShader;
+import jalview.renderer.ResidueShaderI;
 import jalview.schemes.ZappoColourScheme;
 
 import java.awt.Color;
 
 import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 public class SequenceRendererTest
 {
+  AlignmentI al;
+  AlignViewport av;
+
+  SequenceI seq1;
 
   @BeforeClass(alwaysRun = true)
-  public void setUpJvOptionPane()
+  public static void setUpBeforeClass() throws Exception
   {
-    JvOptionPane.setInteractiveMode(false);
-    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+    Jalview.main(
+            new String[]
+    { "-nonews", "-props", "test/jalview/testProps.jvprops" });
   }
 
-  @Test(groups = { "Functional" })
-  public void testGetResidueBoxColour_zappo()
+  @BeforeMethod(alwaysRun = true)
+  public void setUp()
   {
-    SequenceI seq = new Sequence("name", "MATVLGSPRAPAFF"); // FER1_MAIZE...
-    AlignmentI al = new Alignment(new SequenceI[] { seq });
-    final AlignViewport av = new AlignViewport(al);
-    SequenceRenderer sr = new SequenceRenderer(av);
-    av.setGlobalColourScheme(new ZappoColourScheme());
-
-    // @see ResidueProperties.zappo
-    assertEquals(Color.pink, sr.getResidueBoxColour(seq, 0)); // M
-    assertEquals(Color.green, sr.getResidueBoxColour(seq, 2)); // T
-    assertEquals(Color.magenta, sr.getResidueBoxColour(seq, 5)); // G
-    assertEquals(Color.orange, sr.getResidueBoxColour(seq, 12)); // F
+    seq1 = new Sequence("Seq1", "ABCEEEABCABC");
+    SequenceI seq2 = new Sequence("Seq2", "ABCABCABCABC");
+    SequenceI seq3 = new Sequence("Seq3", "ABCABCABCABC");
+    SequenceI[] seqs = new SequenceI[] { seq1, seq2, seq3 };
+    al = new Alignment(seqs);
+    al.setDataset(null);
+    av = new AlignViewport(al);
   }
 
-  @Test(groups = { "Functional" })
-  public void testGetResidueBoxColour_none()
+  @Test(groups = "Functional")
+  public void testGetResidueColour_WithGroup()
   {
-    SequenceI seq = new Sequence("name", "MA--TVLGSPRAPAFF");
-    AlignmentI al = new Alignment(new SequenceI[] { seq });
-    final AlignViewport av = new AlignViewport(al);
     SequenceRenderer sr = new SequenceRenderer(av);
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seq1, false);
+    sg.setStartRes(3);
+    sg.setEndRes(5);
 
-    assertEquals(Color.white, sr.getResidueBoxColour(seq, 0));
-    assertEquals(Color.white, sr.getResidueBoxColour(seq, 2));
+    ResidueShaderI rs = new ResidueShader();
+    rs.setColourScheme(new ZappoColourScheme());
+    sg.setGroupColourScheme(rs);
 
-    // set for overview
-    sr.forOverview = true;
-    assertEquals(Color.lightGray, sr.getResidueBoxColour(seq, 0));
-    assertEquals(Color.white, sr.getResidueBoxColour(seq, 2));
-  }
+    av.getAlignment().addGroup(sg);
 
-  // TODO more tests for getResidueBoxColour covering groups, feature rendering,
-  // gaps, overview...
+    // outside group residues are white
+    assertEquals(Color.white, sr.getResidueColour(seq1, 1, null));
 
+    // within group use Zappo scheme - E = red
+    assertEquals(Color.red, sr.getResidueColour(seq1, 3, null));
+  }
 }
index ec5855f..0715857 100644 (file)
@@ -31,10 +31,12 @@ import jalview.gui.CrossRefAction;
 import jalview.gui.Desktop;
 import jalview.gui.Jalview2XML;
 import jalview.gui.JvOptionPane;
+import jalview.util.DBRefUtils;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 
@@ -65,10 +67,13 @@ public class CrossRef2xmlTests extends Jalview2xmlBase
   public void testRetrieveAndShowCrossref() throws Exception
   {
 
-    List<String> failedDBRetr = new ArrayList<String>();
-    List<String> failedXrefMenuItems = new ArrayList<String>();
-    List<String> failedProjectRecoveries = new ArrayList<String>();
-
+    List<String> failedDBRetr = new ArrayList<>();
+    List<String> failedXrefMenuItems = new ArrayList<>();
+    List<String> failedProjectRecoveries = new ArrayList<>();
+    // only search for ensembl or Uniprot crossrefs
+    List<String> limit=Arrays.asList(new String[] {
+        DBRefUtils.getCanonicalName("ENSEMBL"), 
+        DBRefUtils.getCanonicalName("Uniprot")});
     // for every set of db queries
     // retrieve db query
     // verify presence of expected xrefs
@@ -85,12 +90,11 @@ public class CrossRef2xmlTests extends Jalview2xmlBase
     // . codonframes
     //
     //
-    HashMap<String, String> dbtoviewBit = new HashMap<String, String>();
-    List<String> keyseq = new ArrayList<String>();
-    HashMap<String, File> savedProjects = new HashMap<String, File>();
+    HashMap<String, String> dbtoviewBit = new HashMap<>();
+    List<String> keyseq = new ArrayList<>();
+    HashMap<String, File> savedProjects = new HashMap<>();
 
-    for (String[] did : new String[][] { { "ENSEMBL", "ENSG00000157764" },
-    { "UNIPROT", "P01731" } })
+    for (String[] did : new String[][] { { "UNIPROT", "P00338" } })
     {
       // pass counters - 0 - first pass, 1 means retrieve project rather than
       // perform action
@@ -163,7 +167,8 @@ public class CrossRef2xmlTests extends Jalview2xmlBase
 
         ptypes = (seqs == null || seqs.length == 0) ? null : new CrossRef(
                 seqs, dataset).findXrefSourcesForSequences(dna);
-
+        filterDbRefs(ptypes, limit);
+        
         // start of pass2: retrieve each cross-ref for fetched or restored
         // project.
         do // first cross ref and recover crossref loop
@@ -176,7 +181,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase
             // build next key so we an retrieve all views
             String nextxref = first + " -> " + db + "{" + firstcr_ap + "}";
             // perform crossref action, or retrieve stored project
-            List<AlignmentViewPanel> cra_views = new ArrayList<AlignmentViewPanel>();
+            List<AlignmentViewPanel> cra_views = new ArrayList<>();
             CrossRefAction cra = null;
 
             if (pass2 == 0)
@@ -237,7 +242,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase
 
               }
             }
-            HashMap<String, List<String>> xrptypes = new HashMap<String, List<String>>();
+            HashMap<String, List<String>> xrptypes = new HashMap<>();
             // first save/verify views.
             for (AlignmentViewPanel avp : cra_views)
             {
@@ -274,7 +279,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase
                 nextxref = first + " -> " + db + "{" + firstcr_ap++ + "}";
                 for (String xrefdb : xrptypes.get(nextxref))
                 {
-                  List<AlignmentViewPanel> cra_views2 = new ArrayList<AlignmentViewPanel>();
+                  List<AlignmentViewPanel> cra_views2 = new ArrayList<>();
                   int q = 0;
                   String nextnextxref = nextxref + " -> " + xrefdb + "{"
                           + q + "}";
@@ -437,6 +442,25 @@ public class CrossRef2xmlTests extends Jalview2xmlBase
     }
   }
 
+  private void filterDbRefs(List<String> ptypes, List<String> limit)
+  {
+    if (limit != null)
+    {
+      int p = 0;
+      while (ptypes.size() > p)
+      {
+        if (!limit.contains(ptypes.get(p)))
+        {
+          ptypes.remove(p);
+        }
+        else
+        {
+          p++;
+        }
+      }
+    }
+  }
+
   /**
    * wrapper to trap known defect for AH002001 testcase
    * 
@@ -480,7 +504,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase
   private void assertType(boolean expectProtein,
           AlignmentViewPanel alignmentViewPanel, String message)
   {
-    List<SequenceI> nonType = new ArrayList<SequenceI>();
+    List<SequenceI> nonType = new ArrayList<>();
     for (SequenceI sq : alignmentViewPanel.getAlignViewport()
             .getAlignment().getSequences())
     {
diff --git a/test/jalview/renderer/OverviewResColourFinderTest.java b/test/jalview/renderer/OverviewResColourFinderTest.java
new file mode 100644 (file)
index 0000000..1687516
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.renderer;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignViewport;
+import jalview.gui.JvOptionPane;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.UserColourScheme;
+import jalview.schemes.ZappoColourScheme;
+
+import java.awt.Color;
+import java.util.ArrayList;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class OverviewResColourFinderTest
+{
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetResidueBoxColour_none()
+  {
+    SequenceI seq = new Sequence("name", "MA--TVLGSPRAPAFF");
+    AlignmentI al = new Alignment(new SequenceI[] { seq });
+    final AlignViewport av = new AlignViewport(al);
+    ResidueColourFinder rcf = new OverviewResColourFinder();
+
+    // gaps are grey, residues white
+    assertEquals(Color.white, rcf.getResidueColour(true,
+            av.getResidueShading(),
+            null, seq, 0, null));
+    assertEquals(Color.lightGray, rcf
+            .getResidueColour(true, av.getResidueShading(), null, seq, 2,
+                    null));
+
+    // unaffected by showBoxes setting
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 0, null));
+    assertEquals(Color.lightGray, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 2, null));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetResidueBoxColour_zappo()
+  {
+    SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a
+                                                            // gap
+    AlignmentI al = new Alignment(new SequenceI[] { seq });
+    final AlignViewport av = new AlignViewport(al);
+    ResidueColourFinder rcf = new OverviewResColourFinder();
+    av.setGlobalColourScheme(new ZappoColourScheme());
+
+    // @see ResidueProperties.zappo
+    assertEquals(Color.pink,
+            rcf.getResidueColour(true, av.getResidueShading(),
+            null, seq, 0, null)); // M
+    assertEquals(Color.green,
+            rcf.getResidueColour(true, av.getResidueShading(),
+            null, seq, 2, null)); // T
+    assertEquals(Color.magenta,
+            rcf.getResidueColour(true, av.getResidueShading(),
+            null, seq, 5, null)); // G
+    assertEquals(Color.orange,
+            rcf.getResidueColour(true, av.getResidueShading(),
+            null, seq, 12, null)); // F
+
+    // gap colour not specified so gaps are lightGray
+    assertEquals(Color.lightGray, rcf
+            .getResidueColour(true, av.getResidueShading(), null, seq, 3,
+                    null));
+
+    // unaffected by showBoxes setting
+    assertEquals(Color.pink, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 0, null)); // M
+    assertEquals(Color.green, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 2, null)); // T
+    assertEquals(Color.magenta, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 5, null)); // G
+    assertEquals(Color.orange, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 12, null)); // F
+
+    // gap colour not specified so gaps are lightGray
+    assertEquals(Color.lightGray, rcf
+            .getResidueColour(false, av.getResidueShading(), null, seq, 3,
+                    null));
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetResidueBoxColour_userdef()
+  {
+    SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a
+                                                            // gap
+    AlignmentI al = new Alignment(new SequenceI[] { seq });
+    final AlignViewport av = new AlignViewport(al);
+    ResidueColourFinder rcf = new OverviewResColourFinder();
+
+    Color[] newColours = new Color[24];
+    for (int i = 0; i < 24; i++)
+    {
+      newColours[i] = null;
+    }
+
+    av.setGlobalColourScheme(new UserColourScheme(newColours));
+
+    // gap colour not specified so gaps are lightGray
+    assertEquals(Color.lightGray, rcf
+            .getResidueColour(true, av.getResidueShading(), null, seq, 3,
+                    null));
+
+    newColours[23] = Color.pink;
+    av.setGlobalColourScheme(new UserColourScheme(newColours));
+
+    // gap colour specified as pink
+    assertEquals(Color.pink, rcf.getResidueColour(true,
+            av.getResidueShading(),
+            null, seq, 3, null));
+
+    // unaffected by showBoxes setting
+    // gap colour not specified so gaps are lightGray
+    newColours[23] = null;
+    assertEquals(Color.lightGray, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 3, null));
+
+    newColours[23] = Color.pink;
+    av.setGlobalColourScheme(new UserColourScheme(newColours));
+
+    // gap colour specified as pink
+    assertEquals(Color.pink, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 3, null));
+  }
+
+  @Test
+  public void testGetResidueBoxColour_group()
+  {
+    SequenceI seq = new Sequence("name", "MA--TVLGSPRAPAFF");
+    AlignmentI al = new Alignment(new SequenceI[] { seq });
+    
+    ColourSchemeI cs = new ZappoColourScheme();
+    ArrayList<SequenceI> seqlist = new ArrayList<>();
+    seqlist.add(seq);
+    SequenceGroup sg = new SequenceGroup(seqlist, "testgroup", cs, true,
+            true, true, 5, 9);
+    al.addGroup(sg);
+    SequenceGroup[] groups = new SequenceGroup[1];
+    groups[0] = sg;
+    
+    final AlignViewport av = new AlignViewport(al);
+    ResidueColourFinder rcf = new OverviewResColourFinder();
+    
+    // G in group specified as magenta in Zappo
+    assertEquals(Color.magenta, rcf.getResidueColour(false,
+            av.getResidueShading(), groups, seq, 7, null));
+
+    // Residue outside group coloured white
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), groups, seq, 0, null));
+
+    // Gap outside group coloured lightgray
+    assertEquals(Color.lightGray, rcf.getResidueColour(false,
+            av.getResidueShading(), groups, seq, 2, null));
+
+    // use legacy colouring
+    rcf = new OverviewResColourFinder(true, Color.blue, Color.red);
+  
+    // G in group specified as magenta in Zappo
+    assertEquals(Color.magenta, rcf.getResidueColour(false,
+            av.getResidueShading(), groups, seq, 7, null));
+
+    // Residue outside group coloured lightgray
+    assertEquals(Color.lightGray, rcf.getResidueColour(false,
+            av.getResidueShading(), groups, seq, 0, null));
+
+    // Gap outside group coloured white
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), groups, seq, 2, null));
+
+    // use new colouring
+    rcf = new OverviewResColourFinder(false, Color.blue, Color.red);
+
+    // G in group specified as magenta in Zappo
+    assertEquals(Color.magenta, rcf.getResidueColour(false,
+            av.getResidueShading(), groups, seq, 7, null));
+
+    // Residue outside group coloured white
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), groups, seq, 0, null));
+
+    // Gap outside group coloured blue
+    assertEquals(Color.blue, rcf.getResidueColour(false,
+            av.getResidueShading(), groups, seq, 2, null));
+  }
+
+  @Test
+  public void testGetBoxColour()
+  {
+    SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a
+                                                            // gap
+    AlignmentI al = new Alignment(new SequenceI[] { seq });
+    final AlignViewport av = new AlignViewport(al);
+
+    // non-legacy colouring
+    ResidueColourFinder rcf = new OverviewResColourFinder();
+    ResidueShaderI shader = new ResidueShader();
+
+    // residues white
+    Color c = rcf.getBoxColour(shader, seq, 0);
+    assertEquals(Color.white, c);
+
+    // gaps gap colour
+    c = rcf.getBoxColour(shader, seq, 3);
+    assertEquals(
+            jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP,
+            c);
+
+    // legacy colouring set explicitly via constructor
+    rcf = new OverviewResColourFinder(true, Color.blue, Color.red);
+    shader = new ResidueShader();
+
+    // residues light gray
+    c = rcf.getBoxColour(shader, seq, 0);
+    assertEquals(Color.lightGray, c);
+
+    // gaps white
+    c = rcf.getBoxColour(shader, seq, 3);
+    assertEquals(Color.white, c);
+
+    // legacy colouring off
+    rcf = new OverviewResColourFinder();
+    shader = new ResidueShader();
+
+    // residues white
+    c = rcf.getBoxColour(shader, seq, 0);
+    assertEquals(Color.white, c);
+
+    // gaps gap colour
+    c = rcf.getBoxColour(shader, seq, 3);
+    assertEquals(
+            jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP,
+            c);
+
+    // non legacy colouring with colour scheme
+    rcf = new OverviewResColourFinder(false, Color.blue, Color.red);
+    shader = new ResidueShader(new ZappoColourScheme());
+
+    // M residue pink
+    c = rcf.getBoxColour(shader, seq, 0);
+    assertEquals(Color.pink, c);
+
+    // gaps blue
+    c = rcf.getBoxColour(shader, seq, 3);
+    assertEquals(Color.blue, c);
+
+    // legacy colouring with colour scheme
+    rcf = new OverviewResColourFinder(true, Color.blue, Color.red);
+
+    // M residue pink
+    c = rcf.getBoxColour(shader, seq, 0);
+    assertEquals(Color.pink, c);
+
+    // gaps white
+    c = rcf.getBoxColour(shader, seq, 3);
+    assertEquals(Color.white, c);
+  }
+}
diff --git a/test/jalview/renderer/ResidueColourFinderTest.java b/test/jalview/renderer/ResidueColourFinderTest.java
new file mode 100644 (file)
index 0000000..81fb2c0
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.renderer;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignViewport;
+import jalview.gui.JvOptionPane;
+import jalview.schemes.UserColourScheme;
+import jalview.schemes.ZappoColourScheme;
+
+import java.awt.Color;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class ResidueColourFinderTest
+{
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetResidueColour_zappo()
+  {
+    SequenceI seq = new Sequence("name", "MATVLGSPRAPAFF"); // FER1_MAIZE...
+    AlignmentI al = new Alignment(new SequenceI[] { seq });
+    final AlignViewport av = new AlignViewport(al);
+    ResidueColourFinder rcf = new ResidueColourFinder();
+    av.setGlobalColourScheme(new ZappoColourScheme());
+
+    // @see ResidueProperties.zappo
+    assertEquals(Color.pink,
+            rcf.getResidueColour(true, av.getResidueShading(), null, seq, 0,
+                    null)); // M
+    assertEquals(Color.green,
+            rcf.getResidueColour(true, av.getResidueShading(), null, seq, 2,
+                    null)); // T
+    assertEquals(Color.magenta,
+            rcf.getResidueColour(true, av.getResidueShading(), null, seq, 5,
+                    null)); // G
+    assertEquals(Color.orange,
+            rcf.getResidueColour(true, av.getResidueShading(), null, seq,
+                    12,
+                    null)); // F
+
+    // everything is white if showBoxes is false
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 0, null)); // M
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 2, null)); // T
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 5, null)); // G
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 12, null)); // F
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetResidueColour_none()
+  {
+    SequenceI seq = new Sequence("name", "MA--TVLGSPRAPAFF");
+    AlignmentI al = new Alignment(new SequenceI[] { seq });
+    final AlignViewport av = new AlignViewport(al);
+    ResidueColourFinder rcf = new ResidueColourFinder();
+
+    assertEquals(Color.white,
+            rcf.getResidueColour(true, av.getResidueShading(),
+            null, seq, 0, null));
+    assertEquals(Color.white,
+            rcf.getResidueColour(true, av.getResidueShading(),
+            null, seq, 2, null));
+
+    // no change if showBoxes is false
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 0, null));
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 2, null));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetResidueColour_userdef()
+  {
+    SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a
+                                                            // gap
+    AlignmentI al = new Alignment(new SequenceI[] { seq });
+    final AlignViewport av = new AlignViewport(al);
+    ResidueColourFinder rcf = new ResidueColourFinder();
+
+    Color[] newColours = new Color[24];
+    for (int i = 0; i < 24; i++)
+    {
+      newColours[i] = null;
+    }
+
+    av.setGlobalColourScheme(new UserColourScheme(newColours));
+
+    // gap colour not specified so gap colour is null
+    // this is consistent with previous behaviour, but may not be correct?
+    assertEquals(null, rcf.getResidueColour(true, av.getResidueShading(),
+            null, seq, 3, null));
+
+    newColours[23] = Color.pink;
+    av.setGlobalColourScheme(new UserColourScheme(newColours));
+
+    // gap colour specified as pink
+    assertEquals(Color.pink, rcf.getResidueColour(true,
+            av.getResidueShading(),
+            null, seq, 3, null));
+
+    // everything is white if showBoxes is false
+    newColours[23] = null;
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(),
+            null, seq, 3, null));
+
+    newColours[23] = Color.pink;
+    av.setGlobalColourScheme(new UserColourScheme(newColours));
+
+    // gap colour specified as pink
+    assertEquals(Color.white, rcf.getResidueColour(false,
+            av.getResidueShading(), null, seq, 3, null));
+  }
+
+  // TODO more tests for getResidueColour covering groups, feature rendering...
+}
index 76fd9b4..eba5f59 100644 (file)
@@ -8,9 +8,15 @@ import jalview.analysis.Conservation;
 import jalview.datamodel.Profile;
 import jalview.datamodel.ProfileI;
 import jalview.datamodel.Profiles;
+import jalview.datamodel.ProfilesI;
+import jalview.datamodel.ResidueCount;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.schemes.ColourSchemeI;
 import jalview.schemes.PIDColourScheme;
+import jalview.schemes.ResidueProperties;
+import jalview.schemes.UserColourScheme;
+import jalview.schemes.ZappoColourScheme;
 
 import java.awt.Color;
 import java.util.Collections;
@@ -163,4 +169,165 @@ public class ResidueShaderTest
     assertEquals(Color.WHITE, ccs.applyConservation(colour, 12));
   }
 
+  @Test(groups = "Functional")
+  public void testFindColour_gapColour()
+  {
+    /*
+     * normally, a gap is coloured white
+     */
+    ResidueShader rs = new ResidueShader(new ZappoColourScheme());
+    assertEquals(Color.white, rs.findColour(' ', 7, null));
+
+    /*
+     * a User Colour Scheme may specify a bespoke gap colour
+     */
+    Color[] colours = new Color[ResidueProperties.maxProteinIndex + 1];
+    colours[5] = Color.blue; // Q colour
+    colours[23] = Color.red; // gap colour
+    ColourSchemeI cs = new UserColourScheme(colours);
+    rs = new ResidueShader(cs);
+  
+    assertEquals(Color.red, rs.findColour(' ', 7, null));
+    assertEquals(Color.blue, rs.findColour('Q', 7, null));
+  
+    /*
+     * stub Conservation to return a given consensus string
+     */
+    final String consSequence = "0123456789+*-";
+    Conservation cons = new Conservation(null,
+            Collections.<SequenceI> emptyList(), 0, 0)
+    {
+      @Override
+      public SequenceI getConsSequence()
+      {
+        return new Sequence("seq", consSequence);
+      }
+    };
+    rs.setConservation(cons);
+  
+    /*
+     * with 0% threshold, there should be no fading
+     */
+    rs.setConservationInc(0);
+    assertEquals(Color.red, rs.findColour(' ', 7, null));
+    assertEquals(Color.blue, rs.findColour('Q', 7, null));
+  
+    /*
+     * with 40% threshold, 'fade factor' is 
+     * (11-score)/10 * 40/20 = (11-score)/5
+     * so position 7, score 7 fades 80% of the way to white (255, 255, 255)
+     */
+    rs.setConservationInc(40);
+
+    /*
+     * gap colour is unchanged for Conservation
+     */
+    assertEquals(Color.red, rs.findColour(' ', 7, null));
+    assertEquals(Color.red, rs.findColour('-', 7, null));
+    assertEquals(Color.red, rs.findColour('.', 7, null));
+
+    /*
+     * residue colour is faded 80% of the way from
+     * blue(0, 0, 255) to white(255, 255, 255)
+     * making (204, 204, 255)
+     */
+    assertEquals(new Color(204, 204, 255), rs.findColour('Q', 7, null));
+
+    /*
+     * turn off By Conservation, apply Above Identity Threshold
+     * providing a stub Consensus that has modal residue "Q" with pid 60%
+     */
+    rs.setConservationApplied(false);
+    ProfilesI consensus = getStubConsensus("Q", 60f);
+    rs.setConsensus(consensus);
+
+    // with consensus pid (60) above threshold (50), colours are unchanged
+    rs.setThreshold(50, false);
+    assertEquals(Color.blue, rs.findColour('Q', 7, null));
+    assertEquals(Color.red, rs.findColour('-', 7, null));
+
+    // with consensus pid (60) below threshold (70),
+    // residue colour becomes white, gap colour is unchanged
+    rs.setThreshold(70, false);
+    assertEquals(Color.white, rs.findColour('Q', 7, null));
+    assertEquals(Color.red, rs.findColour('-', 7, null));
+  }
+
+  /**
+   * @param modalResidue
+   * @param pid
+   * @return
+   */
+  protected ProfilesI getStubConsensus(final String modalResidue,
+          final float pid)
+  {
+    ProfilesI consensus = new ProfilesI() {
+
+      @Override
+      public ProfileI get(int i)
+      {
+        return new ProfileI() {
+          @Override
+          public void setCounts(ResidueCount residueCounts)
+          {
+          }
+
+          @Override
+          public float getPercentageIdentity(boolean ignoreGaps)
+          {
+            return pid;
+          }
+
+          @Override
+          public ResidueCount getCounts()
+          {
+            return null;
+          }
+
+          @Override
+          public int getHeight()
+          {
+            return 0;
+          }
+
+          @Override
+          public int getGapped()
+          {
+            return 0;
+          }
+
+          @Override
+          public int getMaxCount()
+          {
+            return 0;
+          }
+
+          @Override
+          public String getModalResidue()
+          {
+            return modalResidue;
+          }
+
+          @Override
+          public int getNonGapped()
+          {
+            return 0;
+         }};
+      }
+
+      @Override
+      public int getStartColumn()
+      {
+        return 0;
+      }
+
+      @Override
+      public int getEndColumn()
+      {
+        return 0;
+      }
+      
+    };
+    return consensus;
+  }
 }
index 7fd7abc..f6dfed6 100644 (file)
@@ -2,6 +2,7 @@ package jalview.renderer.seqfeatures;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
@@ -285,6 +286,28 @@ public class FeatureColourFinderTest
   }
 
   @Test(groups = "Functional")
+  public void testFindFeatureAtEnd()
+  {
+    /*
+     * terminal residue feature
+     */
+    seq.addSequenceFeature(new SequenceFeature("PDBRESNUM", "pdb res 1",
+            seq.getEnd(), seq.getEnd(), Float.NaN, "1seq.pdb"));
+    fr.setColour("PDBRESNUM", new FeatureColour(Color.red));
+    fr.featuresAdded();
+    av.setShowSequenceFeatures(true);
+
+    /*
+     * final column should have PDBRESNUM feature, the others not
+     */
+    Color c = finder.findFeatureColour(Color.blue, seq,
+            seq.getLength() - 2);
+    assertNotEquals(c, Color.red);
+    c = finder.findFeatureColour(Color.blue, seq, seq.getLength() - 1);
+    assertEquals(c, Color.red);
+  }
+
+  @Test(groups = "Functional")
   public void testFindFeatureColour_graduatedFeatureColour()
   {
     seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
index c125ef6..aea3687 100644 (file)
@@ -20,8 +20,8 @@
  */
 package jalview.structures.models;
 
+import static org.testng.Assert.assertFalse;
 import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.api.AlignmentViewPanel;
@@ -36,6 +36,7 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.gui.JvOptionPane;
 import jalview.io.DataSourceType;
+import jalview.io.FileFormats;
 import jalview.schemes.ColourSchemeI;
 import jalview.structure.AtomSpec;
 import jalview.structure.StructureMappingcommandSet;
@@ -43,6 +44,7 @@ import jalview.structure.StructureSelectionManager;
 import jalview.structures.models.AAStructureBindingModel.SuperposeData;
 
 import java.awt.Color;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.List;
@@ -98,6 +100,150 @@ public class AAStructureBindingModelTest
           + "ATOM     33  CA  ALA A  10      26.790   4.320   3.172  1.00 11.98           C  \n"
           + "ATOM     39  CA AVAL A  12      24.424   3.853   6.106  0.50 13.83           C  \n";
 
+  /**
+   * Multichain PDB with identical sequences imported - Binding should correctly
+   * recover chain mappings for each derived sequence
+   */
+  private static final String PDB_4_MC = "HEADER    HYDROLASE                               09-SEP-09   3A6S              \n"
+          + "ATOM      2  CA  MET A   1      15.366 -11.648  24.854  1.00 32.05           C  \n"
+          + "ATOM     10  CA  LYS A   2      16.846  -9.215  22.340  1.00 25.68           C  \n"
+          + "ATOM     19  CA  LYS A   3      15.412  -6.335  20.343  1.00 19.42           C  \n"
+          + "ATOM     28  CA  LEU A   4      15.629  -5.719  16.616  1.00 15.49           C  \n"
+          + "ATOM     36  CA  GLN A   5      14.412  -2.295  15.567  1.00 12.19           C  \n"
+          + "ATOM   1030  CA  MET B   1      18.869  -7.572   3.432  1.00 31.52           C  \n"
+          + "ATOM   1038  CA  LYS B   2      19.182 -10.025   6.313  1.00 26.41           C  \n"
+          + "ATOM   1047  CA  LYS B   3      17.107 -12.963   7.534  1.00 19.71           C  \n"
+          + "ATOM   1056  CA  LEU B   4      16.142 -13.579  11.164  1.00 14.81           C  \n"
+          + "ATOM   1064  CA  GLN B   5      14.648 -17.005  11.785  1.00 13.38           C  \n";
+
+  // TODO: JAL-2227 - import mmCIF PISA assembly & identify master/copy chains
+
+  @Test(groups= {"Functional"})
+  public void testImportPDBPreservesChainMappings() throws IOException
+  {
+    AlignmentI importedAl = new jalview.io.FormatAdapter().readFile(
+            PDB_4_MC, DataSourceType.PASTE, FileFormats.getInstance()
+                    .forName(jalview.io.FileFormat.PDB.toString()));
+    // ideally, we would match on the actual data for the 'File' handle for
+    // pasted files,
+    // see JAL-623 - pasting is still not correctly handled...
+    PDBEntry importedPDB = new PDBEntry("3A6S", "", Type.PDB,
+            "Paste");
+    AAStructureBindingModel binder = new AAStructureBindingModel(
+            new StructureSelectionManager(), new PDBEntry[]
+            { importedPDB },
+            new SequenceI[][]
+            { importedAl.getSequencesArray() }, null)
+    {
+      
+      @Override
+      public void updateColours(Object source)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void releaseReferences(Object svl)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public String[] getStructureFiles()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+      
+      @Override
+      public String superposeStructures(AlignmentI[] alignments,
+              int[] structureIndices, HiddenColumns[] hiddenCols)
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+      
+      @Override
+      public void setJalviewColourScheme(ColourSchemeI cs)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void setBackgroundColour(Color col)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void highlightAtoms(List<AtomSpec> atoms)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+      
+      @Override
+      public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+      
+      @Override
+      protected StructureMappingcommandSet[] getColourBySequenceCommands(
+              String[] files, SequenceRenderer sr, AlignmentViewPanel avp)
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+      
+      @Override
+      public List<String> getChainNames()
+      {
+        // TODO Auto-generated method stub
+        return null;
+      }
+      
+      @Override
+      protected void colourBySequence(
+              StructureMappingcommandSet[] colourBySequenceCommands)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void colourByCharge()
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void colourByChain()
+      {
+        // TODO Auto-generated method stub
+        
+      }
+    };
+    String[][] chains = binder.getChains();
+    assertFalse(chains == null || chains[0] == null,
+            "No chains discovered by binding");
+    assertEquals(2, chains[0].length);
+    assertEquals("A", chains[0][0]);
+    assertEquals("B", chains[0][1]);
+  }
   AAStructureBindingModel testee;
 
   AlignmentI al = null;
index 40737ca..c559966 100644 (file)
@@ -47,33 +47,26 @@ public class EBIFetchClientTest
     /*
      * EMBL
      */
-    assertEquals("http://www.ebi.ac.uk/ena/data/view/x53838&display=xml",
+    assertEquals("https://www.ebi.ac.uk/ena/data/view/x53838&display=xml",
             EBIFetchClient.buildUrl("X53838", "EMBL", "display=xml"));
 
     /*
      * EMBLCDS
      */
-    assertEquals("http://www.ebi.ac.uk/ena/data/view/caa37824&display=xml",
+    assertEquals("https://www.ebi.ac.uk/ena/data/view/caa37824&display=xml",
             EBIFetchClient.buildUrl("CAA37824", "EMBL", "display=xml"));
 
     /*
-     * Uniprot
-     */
-    assertEquals(
-            "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/uniprot/p00340/uniprotxml",
-            EBIFetchClient.buildUrl("P00340", "UNIPROT", "uniprotxml"));
-
-    /*
      * PDB / pdb
      */
-    assertEquals("http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/pdb/3a6s/pdb",
+    assertEquals("https://www.ebi.ac.uk/Tools/dbfetch/dbfetch/pdb/3a6s/pdb",
             EBIFetchClient.buildUrl("3A6S", "PDB", "pdb"));
 
     /*
      * PDB / mmCIF
      */
     assertEquals(
-            "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/pdb/3a6s/mmCIF",
+            "https://www.ebi.ac.uk/Tools/dbfetch/dbfetch/pdb/3a6s/mmCIF",
             EBIFetchClient.buildUrl("3A6S", "PDB", "mmCIF"));
   }
 
index 557700a..abe9d4b 100755 (executable)
@@ -1471,7 +1471,7 @@ and any path to a file to save to the file]]></string>
                                                                <boolean>true</boolean>
                                                        </property>
                                                        <property name="destinationName">
-                                                               <string><![CDATA[min-jabaws-client-2.1.0.jar]]></string>
+                                                               <string><![CDATA[min-jabaws-client-2.2.0.jar]]></string>
                                                        </property>
                                                        <property name="fileSize">
                                                                <long>601804</long>
index ac9e260..122b8d0 100644 (file)
     <!-- 
        Suppress check of externally sourced code 
     --> 
-    <suppress checks="[a-zA-Z0-9]*" files="com[\\/]*"/>
-    <suppress checks="[a-zA-Z0-9]*" files="ext[\\/]*"/>
-    <suppress checks="[a-zA-Z0-9]*" files="org[\\/]*"/>
-    <suppress checks="[a-zA-Z0-9]*" files="uk[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]com[\\/]github*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]com[\\/]stevesoft*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]ext[\\/]edu*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]ext[\\/]vamsas*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]org[\\/]jibble*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="[\\/]uk[\\/]ac*"/>
     
     <!-- 
        ImportControl can only handle one top level package
index b41aab3..c47aaec 100644 (file)
                <subpackage name="datamodel">
                <disallow pkg="jalview.gui"/>
                <allow pkg="fr.orsay.lri.varna"/>
-                       <subpackage name="xdb">
-                               <subpackage name="embl">
-                               <allow pkg="org.exolab.castor"/>
-                           </subpackage>
+                       <subpackage name="xdb.embl">
+                       <allow pkg="org.exolab.castor"/>
                    </subpackage>
            </subpackage>
                
+               <subpackage name="ext">
+                       <subpackage name="ensembl">
+                       <allow pkg="javax.ws"/>
+                       <allow pkg="org.json"/>
+                       </subpackage>
+                       <subpackage name="htsjdk">
+                       <allow pkg="htsjdk"/>
+                       </subpackage>
+                       <subpackage name="jmol">
+                       <allow pkg="MCview"/>
+                       <allow pkg="org.jmol"/>
+                       </subpackage>
+                       <subpackage name="paradise">
+                       <allow pkg="org.apache"/>
+                       <allow pkg="org.json"/>
+                       </subpackage>
+                       <subpackage name="rbvi">
+                       <allow pkg="ext.edu.ucsf"/>
+                       <allow pkg="javax.servlet"/>
+                       </subpackage>
+                       <subpackage name="so">
+                       <allow pkg="org.biojava"/>
+                       </subpackage>
+                       <subpackage name="varna">
+                       <allow pkg="fr.orsay"/>
+                       </subpackage>
+           </subpackage>
+               
                <subpackage name="fts">
                <allow pkg="javax.swing"/>
                <allow pkg="javax.ws"/>
                <allow pkg="javax.servlet"/>
                </subpackage>
 
+               <subpackage name="schemes">
+                       <allow pkg="org.exolab.castor" class="jalview.schemes.ColourSchemeLoader"/>
+               </subpackage>
+
                <subpackage name="structure">
                <allow pkg="MCview"/>
                </subpackage>
+               
+               <subpackage name="urls">
+                       <allow pkg="javax.swing" class="jalview.urls.UrlLinkTableModel"/>
+                       <allow pkg="org.json"/>
+               </subpackage>
 
                <subpackage name="util">
                <allow pkg="javax.swing"/>