<classpathentry kind="lib" path="lib/miglayout-4.0-swing.jar"/>
<classpathentry kind="lib" path="lib/jswingreader-0.3.jar" sourcepath="/jswingreader"/>
<classpathentry kind="lib" path="lib/commons-codec-1.3.jar"/>
- <classpathentry kind="lib" path="lib/jdas-1.0.4.jar"/>
<classpathentry kind="lib" path="lib/spring-core-3.0.5.RELEASE.jar"/>
<classpathentry kind="lib" path="lib/spring-web-3.0.5.RELEASE.jar"/>
<classpathentry kind="lib" path="lib/jabaws-min-client-2.2.0.jar" sourcepath="/clustengine"/>
<classpathentry kind="lib" path="lib/VARNAv3-93.jar"/>
<classpathentry kind="lib" path="lib/jfreesvg-2.1.jar"/>
<classpathentry kind="lib" path="lib/quaqua-filechooser-only-8.0.jar"/>
- <classpathentry kind="lib" path="lib/htsjdk-1.133.jar"/>
+ <classpathentry kind="lib" path="lib/VAqua5-patch.jar"/>
+ <classpathentry kind="lib" path="utils/classgraph-4.1.6.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/plugin"/>
<classpathentry kind="lib" path="lib/xml-apis.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Plugin.jar"/>
<classpathentry kind="lib" path="lib/jersey-client-1.19.jar"/>
<classpathentry kind="lib" path="lib/jersey-core-1.19.jar"/>
<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
<classpathentry kind="lib" path="lib/biojava-core-4.1.0.jar"/>
<classpathentry kind="lib" path="lib/biojava-ontology-4.1.0.jar"/>
+ <classpathentry kind="lib" path="lib/htsjdk-2.12.0.jar"/>
<classpathentry kind="lib" path="lib/groovy-all-2.4.12-indy.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="output" path="classes"/>
</classpath>
.project
/dist
+/clover
/classes
/tests
/test-reports
TESTNG
/jalviewApplet.jar
/benchmarking/lib
-*.class
\ No newline at end of file
+*.class
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=52
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_modifiers=false
sp_cleanup.remove_redundant_type_arguments=true
sp_cleanup.remove_trailing_whitespaces=false
sp_cleanup.remove_trailing_whitespaces_all=true
The people listed below are 'The Jalview Authors', who collectively
own the copyright to the Jalview source code and permit it to be released under GPL.
-This is the authoritative list. It was correct on 23rd November 2016.
+This is the authoritative list: it was correct on 5th September 2018 (or the last commit date!)
+
If you are releasing a version of Jalview, please make sure any
statement of authorship in the GUI reflects the list shown here.
In particular, check the resources/authors.props file !
Jim Procter
Mungo Carstairs
-Tochukwu 'Charles' Ofoegbu
+Ben Soares
Kira Mourao
+Tochukwu 'Charles' Ofoegbu
Andrew Waterhouse
Jan Engelhardt
Lauren Lui
##################
-To run application:
+To run application...
+[ NOTE: when using the -classpath option with the '*' wildcard, the argument must be quoted to avoid shell expansion of the wildcard,
+ ALSO, the wildcard MUST be as DIR/* and not DIR/*.jar etc or it will not be interpreted correctly ]
-java -Djava.ext.dirs=JALVIEW_HOME/lib -cp JALVIEW_HOME/jalview.jar jalview.bin.Jalview
+on Windows use:
+ java -classpath "JALVIEW_HOME/lib/*;JALVIEW_HOME/jalview.jar" jalview.bin.Jalview
+and on MacOS or Linux:
+ java -classpath "JALVIEW_HOME/lib/*:JALVIEW_HOME/jalview.jar" jalview.bin.Jalview
Replace JALVIEW_HOME with the full path to Jalview Installation Directory. If building from source:
-java -Djava.ext.dirs=JALVIEW_BUILD/dist -cp JALVIEW_BUILD/dist/jalview.jar jalview.bin.Jalview
+ java -classpath "JALVIEW_BUILD/dist/*" jalview.bin.Jalview
##################
-jalview.release=releases/Release_2_10_3_Branch
-jalview.version=2.10.3
+jalview.release=releases/Release_2_11_Branch
+jalview.version=2.11.0
jalview.ext.android includes code taken from the Android Open Source Project (https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/util).
The Apache 2.0 Licence (http://www.apache.org/licenses/LICENSE-2.0) is acknowledged in the source code.
+ org.stackoverflowusers.file.WindowsShortcuts was downloaded from http://github.com/codebling/WindowsShortcuts via https://stackoverflow.com/questions/309495/windows-shortcut-lnk-parser-in-java
Licensing information for each library is given below:
httpcore-4.0.1.jar
httpmime-4.0.3.jar
jaxrpc.jar
-jdas-1.0.4.jar : Apache License - built from http://code.google.com/p/jdas/ (29th Feb 2012)
jhall.jar
jswingreader-0.3.jar : Apache license - built from http://jswingreader.sourceforge.net/ svn/trunk v12
log4j-1.2.8.jar
min-jaba-client.jar
regex.jar
saaj.jar
-spring-core-3.0.5.RELEASE.jar : Apache License: jdas runtime dependencies retrieved via maven
-spring-web-3.0.5.RELEASE.jar : Apache License: jdas runtime dependencies retrieved via maven
+spring-core-3.0.5.RELEASE.jar : Apache License: jdas runtime dependencies retrieved via maven - TODO: JAL-3035 remove if no longer needed ?
+spring-web-3.0.5.RELEASE.jar : Apache License: jdas runtime dependencies retrieved via maven - TODO: JAL-3035 remove if no longer needed ?
vamsas-client.jar
wsdl4j.jar
xercesImpl.jar
quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/
-lib/htsjdk-1.120-SNAPSHOT.jar: (currently not required for 2.10) built from maven master at https://github.com/samtools/htsjdk MIT License to Broad Institute
+vaqua5-patch: This is a patched version of VAqua v5 (latest stable) by Alan Snyder et al. GPLv3 with Classpath exception, also includes contributions from Quaqua: http://violetlib.org/vaqua/overview.html - see doc/patching-vaqua.txt for patch details, and http://issues.jalview.org/browse/JAL-2988 for details of the bug that the patch addresses.
+
+lib/htsjdk-2.12.jar: built from maven master at https://github.com/samtools/htsjdk MIT License to Broad Institute
lib/biojava-core-4.1.0.jar LGPLv2.1 - latest license at https://github.com/biojava/biojava/blob/master/LICENSE
lib/biojava-ontology-4.1.0.jar LGPLv2.1 - latest license at https://github.com/biojava/biojava/blob/master/LICENSE
+Libraries for Test Suite
+
+utils/classgraph-4.1.6.jar: BSD License - allows recovery of classpath for programmatic construction of a Java command line to launch Jalview
+ version 4.1.6 downloaded from https://mvnrepository.com/artifact/io.github.classgraph/classgraph/4.1.6
+
+
Additional dependencies
examples/javascript/deployJava.js : http://java.com/js/deployJava.js
This builds a jalview.jar file and puts it into dist/
+
2. Make a lib directory in benchmarking/ if not already present and cd into this directory.
+
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
+ To run a specific benchmark file use:
+ java -jar target/benchmarks.jar <Benchmark class name>
+
+ JSON output can be viewed quickly by drag-dropping on http://jmh.morethan.io/
+
+ To get help use the standard -h option:
+ java -jar target/benchmarks.jar -h
+
+ More information here:
+ http://openjdk.java.net/projects/code-tools/jmh/
+ http://java-performance.info/jmh/
+
+
+ 6. If you make changes to the Jalview code everything will need to be refreshed, by performing steps 3-5 again.
+
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package 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.infra.Blackhole;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Param;
+
+import java.util.Iterator;
+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 HiddenColsIteratorsBenchmark {
+ /*
+ * 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 benchStartIterator(HiddenColsAndStartState tstate)
+ {
+ int res = 0;
+ int startx = tstate.visibleColumn;
+ Iterator<Integer> it = tstate.h.getStartRegionIterator(startx,
+ startx+60);
+ while (it.hasNext())
+ {
+ res = it.next() - startx;
+ Blackhole.consumeCPU(5);
+ }
+ return res;
+ }
+
+ @Benchmark
+ @BenchmarkMode({Mode.Throughput})
+ public int benchBoundedIterator(HiddenColsAndStartState tstate)
+ {
+ int startx = tstate.visibleColumn;
+ int blockStart = startx;
+ int blockEnd;
+ int screenY = 0;
+ Iterator<int[]> it = tstate.h.getBoundedIterator(startx,
+ startx+60);
+ while (it.hasNext())
+ {
+ int[] region = it.next();
+
+ blockEnd = Math.min(region[0] - 1, blockStart + 60 - screenY);
+
+ screenY += blockEnd - blockStart + 1;
+ blockStart = region[1] + 1;
+
+ Blackhole.consumeCPU(5);
+ }
+ return blockStart;
+ }
+}
@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()
+{
+ /*
+ * State with multiple hidden columns and a start position set
+ */
+ @State(Scope.Thread)
+ public static class HiddenColsAndStartState
+ {
+ @Param({"100", "1000", "10000", "100000", "1000000"})
+ 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.visibleToAbsoluteColumn(tstate.visibleColumn);
+ }
+
+ @Benchmark
+ @BenchmarkMode({Mode.Throughput})
+ public int benchFindColumnPosition(HiddenColsAndStartState tstate)
+ {
+ return tstate.h.absoluteToVisibleColumn(tstate.visibleColumn);
+ }
+
+ @Benchmark
+ @BenchmarkMode({Mode.Throughput})
+ public int benchGetSize(HiddenColsAndStartState tstate)
{
- 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());
+ return tstate.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;
- }
+ @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
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package org.jalview;
+
+import org.jalview.HiddenColumnsBenchmark.HiddenColsAndStartState;
+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.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
+/*
+ * 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 SeqWidthBenchmark {
+
+ /*
+ * State with multiple hidden columns and a start position set
+ */
+ @State(Scope.Thread)
+ public static class AlignmentState
+ {
+ @Param({"100", "1000", "10000", "100000"})
+ public int numSeqs;
+
+ Random rand = new Random();
+
+ AlignmentI al;
+
+ @Setup
+ public void setup()
+ {
+ rand.setSeed(1234);
+
+ SequenceI[] seqs = new Sequence[numSeqs];
+ for (int i = 0; i < numSeqs; i++)
+ {
+ int count = rand.nextInt(10000);
+ StringBuilder aas = new StringBuilder();
+ for (int j=0; j<count; j++)
+ {
+ aas.append("a");
+ }
+
+ seqs[i] = new Sequence("Sequence" + i, aas.toString());
+ }
+ al = new Alignment(seqs);
+ }
+ }
+
+
+ @Benchmark
+ @BenchmarkMode({Mode.Throughput})
+ public int benchSeqGetWidth(AlignmentState tstate)
+ {
+ return tstate.al.getWidth();
+ }
+
+}
* 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.
-->
-<project name="jalviewX" default="usage" basedir=".">
+<project name="jalviewX" default="usage" basedir="."
+ xmlns:if="ant:if"
+ xmlns:unless="ant:unless">
+ <taskdef classpath="${clover.jar}" resource="cloverlib.xml" if:set="clover.jar"/>
+ <clover-env if:set="clover.jar"/>
+
<target name="help" depends="usage" />
<target name="usage" depends="init">
<echo message="~~~Jalview Ant build.xml Usage~~~~" />
<echo message="testng - run jalview's tests via testNG. Default group is '${testng-groups}'" />
<echo message=" you can specify particular test groups as a list via -Dtestng-groups=" />
<echo message="See docs/building.html and the comments in build file for other targets." />
- <echo message="note: compile and makeApplet require the property java118.home to be set to point to a java 1.1.8 jdk." />
+ <echo message="note: compile and makeApplet optionally compile/obfuscate applet against a different Java version by specifying -Djava118.home=PathtoJDK/lib which is the lib directory in the JDK install that contains rt.jar " />
<echo message="Useful -D flags: -Ddonotobfuscate will prevent applet obfuscation" />
+ <echo message="Useful -D flags: -Dclover.jar to specify path to openclover for testng coverage report" />
</target>
<!-- default TestNG groups to run -->
<property name="testng-groups" value="Functional" />
+ <!-- Java 9 JVM args -->
+ <condition property="java9">
+ <equals arg1="${ant.java.version}" arg2="9"/>
+ </condition>
<!-- Don't change anything below here unless you know what you are doing! -->
<!-- Url path for WebStart in JNLP file -->
<!-- Anne's version needs 1.7 - should rebuild VARNA to java 1.6 for release -->
<property name="j2sev" value="1.7+" />
<!-- Java Compilation settings - source and target javac version -->
- <property name="javac.source" value="1.7" />
- <property name="javac.target" value="1.7" />
+ <property name="javac.source" value="1.8" />
+ <property name="javac.target" value="1.8" />
<!-- Permissions for running Java applets and applications. -->
<!-- Defaults are those suitable for deploying jalview webstart www.jalview.org -->
<property name="docDir" value="doc" />
<property name="sourceDir" value="src" />
<property name="schemaDir" value="schemas" />
- <property name="outputDir" value="classes" />
+ <property name="outputDir" value="classes" unless:set="clover.jar"/>
+ <property name="outputDir" value="cloverclasses" if:set="clover.jar"/>
<property name="packageDir" value="dist" />
<property name="outputJar" value="jalview.jar" />
<!-- Jalview Applet JMol Jar Dependency -->
</path>
<property name="source.dist.name" value="${basedir}/jalview-src.tar.gz" />
<!-- The Location of the java 1.1.8 jdk -->
- <!--<property name="java118.home" value="C:\Sun\jdk1.1.8" /> -->
<property name="java118.home" value="${java.home}" />
- <!-- <property name="applet.jre.tools" value="${java118.home}/lib/classes.zip" />
- -->
<!-- jre for 1.4 version -->
- <property name="applet.jre.tools" value="${java.home}/lib/rt.jar" />
+ <property name="applet.jre.tools" value="${java118.home}/lib/rt.jar" />
<!-- the classpath for building the 1.1 applet -->
<path id="jalviewlite.deps">
<fileset dir="${java118.home}">
- <include name="lib/classes.zip" />
+ <include name="lib/rt.jar" />
</fileset>
<fileset dir="${java.home}/lib">
<include name="plugin.jar" />
verbose="2">
<classpath>
<pathelement location="${testOutputDir}" />
+ <pathelement location="${clover.jar}" if:set="clover.jar"/>
<path refid="test.classpath" />
</classpath>
+ <jvmarg value="--add-modules=java.se.ee" if:set="java9"/>
+ <jvmarg value="--illegal-access=warn" if:set="java9"/>
<classfileset dir="${testOutputDir}" includes="**/*.class" />
</testng>
</target>
<target name="buildindices" depends="init, prepare" unless="help.uptodate">
+ <replace value="${JALVIEW_VERSION}">
+ <replacetoken><![CDATA[$$Version-Rel$$]]></replacetoken>
+ <fileset dir="${outputDir}/${helpDir}">
+ <include name="help.jhm" />
+ </fileset>
+ </replace>
+
<java classname="com.sun.java.help.search.Indexer" classpathref="build.classpath" fork="true" dir="${outputDir}/${helpDir}">
<arg line="html" />
</java>
</jar>
<antcall target="writejnlpf">
- <param name="jnlpFile" value="${packageDir}/jalview.jnlp" />
+ <param name="jnlpFile" value="${packageDir}/jalview_256M.jnlp" />
<param name="inih" value="10M" />
<param name="maxh" value="256M" />
</antcall>
+ <antcall target="writejnlpf">
+ <param name="jnlpFile" value="${packageDir}/jalview.jnlp" />
+ <param name="inih" value="800M" />
+ <param name="maxh" value="1024M" />
+ </antcall>
<antcall target="writejnlpf">
<param name="jnlpFile" value="${packageDir}/jalview_1G.jnlp" />
<antcall target="writejnlpf">
<param name="jnlpFile" value="${packageDir}/jalview_2G.jnlp" />
- <param name="inih" value="256M" />
+ <param name="inih" value="800M" />
<param name="maxh" value="1024M" />
</antcall>
<association mime-type="application-x/ext-file" extensions="jar"/>-->
</target>
- <target name="-jarsignwithtsa" depends="makedist,preparejnlp" if="timestamp">
+ <target name="-jarsignwithtsa" depends="makedist,preparejnlp" if="timestamp" unless="nosign">
<signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="${jalview.keyalg}" digestalg="${jalview.keydig}"
tsaproxyhost="${proxyHost}" tsaproxyport="${proxyPort}" tsaurl="${jalview.tsaurl}">
<fileset dir="${packageDir}">
</fileset>
</signjar>
</target>
- <target name="-jarsignnotsa" depends="makedist,preparejnlp" unless="timestamp">
+ <target name="-jarsignnotsa" depends="makedist,preparejnlp" if:blank="timestamp" unless="nosign">
<signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="${jalview.keyalg}" digestalg="${jalview.keydig}">
<fileset dir="${packageDir}">
<include name="*.jar" />
<offline_allowed />
</information>
<resources>
- <j2se version="1.7+" />
+ <j2se version="1.8+" />
<jar main="true" href="jalview.jar"/>
<fileset dir="${packageDir}">
<exclude name="jalview.jar" />
<include name="*.jar" />
<include name="*_*.jar" />
- <exclude name="*jnilib.jar" />
+ <exclude name="*quaqua*.jar" />
</fileset>
<property name="jalview.version" value="${JALVIEW_VERSION}" />
</resources>
<resources os="Mac OS X">
<fileset dir="${packageDir}">
- <include name="*quaqua*.jnilib.jar" />
+ <include name="quaqua-filechooser-only-8.0.jar"/>
+ <include name="*quaqua64*.jnilib.jar" />
</fileset>
</resources>
<jnlpf toFile="${jnlpFile}" />
<!-- add the add-modules j2se attribute for java 9 -->
- <replace file="${jnlpFile}" value="j2se version="1.7+" initial-heap-size="${inih}" max-heap-size="${maxh}" java-vm-args="--add-modules=java.se.ee --illegal-access=warn"">
- <replacetoken>j2se version="1.7+"</replacetoken>
-
- </replace>
+ <replace file="${jnlpFile}" value="j2se version="1.8+" initial-heap-size="${inih}" max-heap-size="${maxh}" java-vm-args="--add-modules=java.se.ee --illegal-access=warn"">
+ <replacetoken>j2se version="1.8+"</replacetoken>
+ </replace>
</target>
<target name="-dofakejnlpfileassoc" depends="-generatejnlpf" if="nojnlpfileassocs">
</target>
<target name="makedist" depends="build, buildPropertiesFile, linkcheck, buildindices">
+ <fail if="clover.jar">
+ Ignoring request to build jalview distribution with clover-instrumented classes
+ </fail>
<!-- make the package jar if not already existing -->
<mkdir dir="${packageDir}" />
<!-- clean dir if it already existed -->
</target>
<target name="packageApplet" depends="compileApplet, buildPropertiesFile">
- <copy file="${resourceDir}/images/idwidth.gif" toFile="${outputDir}/images/idwidth.gif" />
<copy file="${resourceDir}/images/link.gif" toFile="${outputDir}/images/link.gif" />
<copy todir="${outputDir}/lang">
<fileset dir="${resourceDir}/lang">
<include name="MCview/**" />
<include name="jalview/**" />
<include name=".build_properties" />
- <include name="images/idwidth.gif" />
<include name="images/link.gif" />
<include name="lang/**" />
</fileset>
<include name="plugin.jar" />
</fileset>
</path>
- <taskdef resource="proguard/ant/task.properties" classpath="utils/proguard.jar" />
+ <taskdef resource="proguard/ant/task.properties" classpath="utils/proguard_5.3.3.jar" />
<proguard verbose="true" >
<injar file="in.jar" />
<include name="ap_${jsonSimple}" />
</fileset>
</target>
-<target name="-signappletnotsa" unless="timestamp" depends="-signapplet">
+<target name="-signappletnotsa" if:blank="timestamp" depends="-signapplet" unless="nosign">
<signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false">
<fileset refid="signappletjarset" />
</signjar>
</target>
-<target name="-signapplettsa" if="timestamp" depends="-signapplet">
+<target name="-signapplettsa" if="timestamp" depends="-signapplet" unless="nosign">
<signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" tsaproxyhost="${proxyHost}" tsaproxyport="${proxyPort}" tsaurl="${jalview.tsaurl}">
<fileset refid="signappletjarset" />
</signjar>
--- /dev/null
+VAqua5-patched.jar - how the patch was created
+
+1. Download VAqua5 source from https://violetlib.org/release/vaqua/5/VAqua5Source.zip
+2. Unzip to a directory and apply this patch
+
+diff --git a/src/org/violetlib/aqua/fc/AquaFileChooserUI.java b/src/org/violetlib/aqua/fc/AquaFileChooserUI.java
+index 833366d..61f66e5 100644
+--- a/src/org/violetlib/aqua/fc/AquaFileChooserUI.java
++++ b/src/org/violetlib/aqua/fc/AquaFileChooserUI.java
+@@ -1171,7 +1171,8 @@ public class AquaFileChooserUI extends BasicFileChooserUI {
+ goToFolderCancelButtonText = getString("FileChooser.goToFolderCancelButtonText", l, "Cancel");
+ goToFolderAcceptButtonText = getString("FileChooser.goToFolderAcceptButtonText", l, "Accept");
+ goToFolderErrorText = getString("FileChooser.goToFolderErrorText", l, "The folder can\u2019t be found.");
+- defaultInitialSaveFileName = getString("FileChooser.defaultSaveFileName", l, "Untitled");
++ // Don't set an initial filename for saving (or loading) !
++ // defaultInitialSaveFileName = getString("FileChooser.defaultSaveFileName", l, "Untitled");
+ }
+
+ /**
+
+3. Ensure XCode is installed, along with command line tools and the OSX developer packs
+ - you should have /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
+
+4. Download the VAqua rendering library from violetlib.org and save to the VAqua source's lib folder as lib/VAquaRendering.jar
+
+5. change to the release directory and execute 'ant' - a few warnings are generated but providing a final jar is created, all is good!
+
ST-MOTIF ac25a1
kdHydrophobicity ccffcc|333300|-3.9|4.5|above|-2.0
+STARTFILTERS
+GAMMA-TURN-INVERSE Label Contains PDB
+kdHydrophobicity (Score LT 1.5) OR (Score GE 2.8)
+ENDFILTERS
+
STARTGROUP uniprot
<html><a href="http://pfam.xfam.org/family/PF00111">Pfam family</a></html> FER_CAPAA -1 0 0 Pfam
Iron-sulfur (2Fe-2S) FER_CAPAA -1 39 39 METAL
--- /dev/null
+# STOCKHOLM 1.0
+#=GF ID RNA.SS.TEST
+#=GF TP RNA;
+Test.sequence GUACAAAAAAAAAA
+#=GC SS_cons <(EHBheb(E)e)>
+//
--- /dev/null
+HEADER TRANSFERASE/TRANSFERASE INHIBITOR 01-JAN-13 4IM2
+TITLE STRUCTURE OF TANK-BINDING KINASE 1 (Truncated test file)
+ATOM 3510 N LEU A 468 76.337 90.332 -7.628 1.00168.53 N
+ANISOU 3510 N LEU A 468 19760 15191 29082 5189 1248 -1702 N
+ATOM 3511 CA LEU A 468 75.576 90.788 -6.476 1.00181.60 C
+ANISOU 3511 CA LEU A 468 21073 16927 30998 5158 1421 -2051 C
+ATOM 3512 C LEU A 468 76.285 91.971 -5.836 1.00196.57 C
+ANISOU 3512 C LEU A 468 23029 18636 33021 5053 1667 -2229 C
+ATOM 3513 O LEU A 468 75.727 93.067 -5.733 1.00197.97 O
+ANISOU 3513 O LEU A 468 23115 18581 33523 5166 1662 -2304 O
+ATOM 3514 CB LEU A 468 75.409 89.671 -5.449 1.00173.72 C
+ANISOU 3514 CB LEU A 468 19829 16340 29836 4981 1593 -2304 C
+ATOM 3515 CG LEU A 468 74.099 88.882 -5.420 1.00170.58 C
+ANISOU 3515 CG LEU A 468 19142 16142 29529 5074 1449 -2345 C
+ATOM 3516 CD1 LEU A 468 74.023 87.940 -6.581 1.00167.98 C
+ANISOU 3516 CD1 LEU A 468 18951 15858 29015 5180 1156 -2025 C
+ATOM 3517 CD2 LEU A 468 73.988 88.096 -4.145 1.00165.16 C
+ANISOU 3517 CD2 LEU A 468 18217 15818 28720 4865 1706 -2656 C
+ATOM 3518 N ASP A 469 77.529 91.753 -5.429 1.00208.80 N
+ANISOU 3518 N ASP A 469 24731 20282 34322 4836 1875 -2296 N
+ATOM 3519 CA ASP A 469 78.267 92.785 -4.720 1.00223.11 C
+ANISOU 3519 CA ASP A 469 26577 21960 36233 4701 2123 -2500 C
+ATOM 3520 C ASP A 469 78.653 93.973 -5.599 1.00231.96 C
+ANISOU 3520 C ASP A 469 27954 22654 37525 4817 2037 -2283 C
+ATOM 3521 O ASP A 469 78.718 95.100 -5.118 1.00235.71 O
+ANISOU 3521 O ASP A 469 28377 22940 38242 4798 2175 -2449 O
+ATOM 3522 CB ASP A 469 79.506 92.197 -4.057 1.00224.50 C
+ANISOU 3522 CB ASP A 469 26841 22370 36089 4433 2350 -2633 C
+ATOM 3523 CG ASP A 469 79.748 92.767 -2.679 1.00229.51 C
+ANISOU 3523 CG ASP A 469 27303 23107 36794 4254 2637 -3018 C
+ATOM 3524 OD1 ASP A 469 79.958 93.992 -2.564 1.00232.36 O
+ANISOU 3524 OD1 ASP A 469 27695 23203 37387 4262 2718 -3093 O
+ATOM 3525 OD2 ASP A 469 79.751 91.979 -1.709 1.00229.48 O
+ANISOU 3525 OD2 ASP A 469 27145 23450 36598 4098 2779 -3242 O
+ATOM 3526 N PHE A 470 78.904 93.735 -6.882 1.00233.88 N
+ANISOU 3526 N PHE A 470 28481 22742 37641 4931 1813 -1912 N
+ATOM 3527 CA PHE A 470 79.292 94.831 -7.766 1.00237.73 C
+ANISOU 3527 CA PHE A 470 29252 22819 38256 5033 1733 -1677 C
+ATOM 3528 C PHE A 470 78.103 95.470 -8.467 1.00232.15 C
+ANISOU 3528 C PHE A 470 28512 21868 37828 5322 1470 -1512 C
+ATOM 3529 O PHE A 470 78.021 96.691 -8.532 1.00230.69 O
+ANISOU 3529 O PHE A 470 28371 21372 37909 5402 1493 -1517 O
+ATOM 3530 CB PHE A 470 80.344 94.379 -8.784 1.00242.99 C
+ANISOU 3530 CB PHE A 470 30297 23410 38616 4976 1661 -1357 C
+ATOM 3531 CG PHE A 470 80.663 95.388 -9.839 1.00251.53 C
+ANISOU 3531 CG PHE A 470 31709 24074 39788 5089 1550 -1064 C
+ATOM 3532 CD1 PHE A 470 81.658 96.315 -9.620 1.00252.90 C
+ANISOU 3532 CD1 PHE A 470 32021 24036 40032 4942 1771 -1133 C
+ATOM 3533 CD2 PHE A 470 80.005 95.389 -11.059 1.00255.02 C
+ANISOU 3533 CD2 PHE A 470 32335 24339 40221 5330 1225 -715 C
+ATOM 3534 CE1 PHE A 470 81.981 97.242 -10.575 1.00254.75 C
+ANISOU 3534 CE1 PHE A 470 32569 23879 40344 5028 1688 -862 C
+ATOM 3535 CE2 PHE A 470 80.321 96.320 -12.027 1.00256.76 C
+ANISOU 3535 CE2 PHE A 470 32894 24173 40491 5427 1126 -433 C
+ATOM 3536 CZ PHE A 470 81.313 97.248 -11.784 1.00256.57 C
+ANISOU 3536 CZ PHE A 470 33006 23929 40550 5272 1365 -504 C
+ATOM 3537 N CYS A 471 77.190 94.665 -8.997 1.00176.88 N
+ANISOU 3537 N CYS A 471 20955 21812 24441 2225 -3821 -3711 N
+ATOM 3538 CA CYS A 471 76.124 95.233 -9.815 1.00176.41 C
+ANISOU 3538 CA CYS A 471 20820 21906 24301 2124 -3576 -3614 C
+ATOM 3539 C CYS A 471 74.868 95.631 -9.050 1.00176.82 C
+ANISOU 3539 C CYS A 471 21026 22206 23952 2247 -3588 -3734 C
+ATOM 3540 O CYS A 471 74.632 96.811 -8.854 1.00178.66 O
+ANISOU 3540 O CYS A 471 21175 22393 24314 2353 -3749 -3873 O
+ATOM 3541 CB CYS A 471 75.805 94.346 -11.019 1.00173.95 C
+ANISOU 3541 CB CYS A 471 20521 21694 23877 1925 -3217 -3359 C
+ATOM 3542 SG CYS A 471 76.954 94.571 -12.398 1.00273.04 S
+ANISOU 3542 SG CYS A 471 32850 33934 36957 1863 -3075 -3146 S
+ATOM 3543 N ILE A 472 74.068 94.670 -8.603 1.00173.50 N
+ANISOU 3543 N ILE A 472 20813 22023 23085 2253 -3402 -3662 N
+ATOM 3544 CA ILE A 472 72.771 95.033 -8.022 1.00171.09 C
+ANISOU 3544 CA ILE A 472 20616 21936 22453 2374 -3307 -3694 C
+ATOM 3545 C ILE A 472 72.832 96.022 -6.874 1.00177.82 C
+ANISOU 3545 C ILE A 472 21591 22750 23222 2698 -3611 -3931 C
+ATOM 3546 O ILE A 472 71.992 96.914 -6.776 1.00182.92 O
+ANISOU 3546 O ILE A 472 22220 23491 23792 2778 -3598 -3985 O
+ATOM 3547 CB ILE A 472 71.979 93.843 -7.518 1.00159.41 C
+ANISOU 3547 CB ILE A 472 19318 20653 20599 2393 -3038 -3546 C
+ATOM 3548 CG1 ILE A 472 70.708 93.667 -8.341 1.00147.27 C
+ANISOU 3548 CG1 ILE A 472 17653 19253 19051 2196 -2745 -3384 C
+ATOM 3549 CG2 ILE A 472 71.526 94.090 -6.105 1.00155.95 C
+ANISOU 3549 CG2 ILE A 472 19129 20312 19812 2752 -3085 -3637 C
+ATOM 3550 CD1 ILE A 472 70.927 92.915 -9.606 1.00135.92 C
+ANISOU 3550 CD1 ILE A 472 16097 17752 17794 1929 -2643 -3254 C
+ATOM 3551 N ARG A 473 73.812 95.865 -5.996 1.00180.33 N
+ANISOU 3551 N ARG A 473 22055 22917 23544 2920 -3920 -4092 N
+ATOM 3552 CA ARG A 473 73.860 96.762 -4.877 1.00189.65 C
+ANISOU 3552 CA ARG A 473 23415 24034 24610 3307 -4283 -4357 C
+ATOM 3553 C ARG A 473 74.328 98.021 -5.558 1.00185.98 C
+ANISOU 3553 C ARG A 473 22628 23344 24692 3195 -4530 -4477 C
+ATOM 3554 O ARG A 473 73.519 98.885 -5.866 1.00181.76 O
+ANISOU 3554 O ARG A 473 22002 22904 24153 3165 -4446 -4474 O
+ATOM 3555 CB ARG A 473 74.803 96.287 -3.768 1.00205.24 C
+ANISOU 3555 CB ARG A 473 25661 25862 26460 3635 -4629 -4545 C
+ATOM 3556 CG ARG A 473 74.468 96.921 -2.433 1.00220.50 C
+ANISOU 3556 CG ARG A 473 27955 27814 28011 4171 -4923 -4787 C
+ATOM 3557 CD ARG A 473 75.337 96.433 -1.295 1.00232.58 C
+ANISOU 3557 CD ARG A 473 29837 29192 29341 4591 -5300 -5003 C
+ATOM 3558 NE ARG A 473 76.763 96.602 -1.549 1.00237.46 N
+ANISOU 3558 NE ARG A 473 30220 29440 30564 4489 -5773 -5205 N
+ATOM 3559 CZ ARG A 473 77.716 95.991 -0.861 1.00240.32 C
+ANISOU 3559 CZ ARG A 473 30786 29623 30903 4725 -6098 -5371 C
+ATOM 3560 NH1 ARG A 473 77.388 95.172 0.115 1.00241.12 N
+ANISOU 3560 NH1 ARG A 473 31370 29900 30344 5100 -5978 -5355 N
+ATOM 3561 NH2 ARG A 473 78.988 96.195 -1.159 1.00241.54 N
+ANISOU 3561 NH2 ARG A 473 30651 29398 31724 4605 -6518 -5533 N
+ATOM 3562 N ASN A 474 75.608 98.073 -5.901 1.00188.74 N
+ANISOU 3562 N ASN A 474 22768 23381 25563 3107 -4772 -4534 N
+ATOM 3563 CA ASN A 474 76.168 99.264 -6.526 1.00188.61 C
+ANISOU 3563 CA ASN A 474 22395 23075 26194 3026 -4977 -4605 C
+ATOM 3564 C ASN A 474 75.420 99.892 -7.729 1.00173.98 C
+ANISOU 3564 C ASN A 474 20312 21326 24467 2781 -4623 -4414 C
+ATOM 3565 O ASN A 474 75.482 101.107 -7.891 1.00176.08 O
+ANISOU 3565 O ASN A 474 20374 21426 25104 2827 -4803 -4518 O
+ATOM 3566 CB ASN A 474 77.650 99.066 -6.857 1.00199.45 C
+ANISOU 3566 CB ASN A 474 23514 24060 28207 2939 -5170 -4595 C
+ATOM 3567 CG ASN A 474 78.504 98.809 -5.625 1.00210.23 C
+ANISOU 3567 CG ASN A 474 25062 25219 29597 3243 -5689 -4883 C
+ATOM 3568 OD1 ASN A 474 78.174 99.240 -4.527 1.00215.26 O
+ANISOU 3568 OD1 ASN A 474 25969 25891 29928 3596 -6043 -5160 O
+ATOM 3569 ND2 ASN A 474 79.613 98.103 -5.810 1.00212.07 N
+ANISOU 3569 ND2 ASN A 474 25176 25222 30179 3148 -5748 -4822 N
+ATOM 3570 N ILE A 475 74.722 99.114 -8.562 1.00161.86 N
+ANISOU 3570 N ILE A 475 18813 20033 22652 2556 -4165 -4158 N
+ATOM 3571 CA ILE A 475 74.022 99.727 -9.709 1.00154.84 C
+ANISOU 3571 CA ILE A 475 17755 19216 21861 2390 -3885 -4015 C
+ATOM 3572 C ILE A 475 72.785 100.520 -9.312 1.00159.27 C
+ANISOU 3572 C ILE A 475 18401 19995 22121 2490 -3891 -4125 C
+ATOM 3573 O ILE A 475 72.662 101.687 -9.663 1.00162.60 O
+ANISOU 3573 O ILE A 475 18651 20327 22804 2505 -3962 -4186 O
+ATOM 3574 CB ILE A 475 73.600 98.727 -10.818 1.00214.93 C
+ANISOU 3574 CB ILE A 475 25397 26975 29293 2173 -3475 -3753 C
+ATOM 3575 CG1 ILE A 475 74.808 98.227 -11.613 1.00218.74 C
+ANISOU 3575 CG1 ILE A 475 25753 27211 30145 2083 -3390 -3585 C
+ATOM 3576 CG2 ILE A 475 72.618 99.379 -11.789 1.00210.37 C
+ANISOU 3576 CG2 ILE A 475 24743 26509 28681 2097 -3256 -3677 C
+ATOM 3577 CD1 ILE A 475 74.446 97.201 -12.664 1.00218.15 C
+ANISOU 3577 CD1 ILE A 475 25777 27260 29850 1946 -3056 -3359 C
+ATOM 3578 N GLU A 476 71.856 99.893 -8.600 1.00156.45 N
+ANISOU 3578 N GLU A 476 18293 19907 21245 2571 -3778 -4120 N
+ATOM 3579 CA GLU A 476 70.623 100.594 -8.252 1.00142.72 C
+ANISOU 3579 CA GLU A 476 16627 18370 19231 2677 -3720 -4176 C
+ATOM 3580 C GLU A 476 70.845 101.560 -7.094 1.00144.41 C
+ANISOU 3580 C GLU A 476 16959 18500 19412 3012 -4114 -4440 C
+ATOM 3581 O GLU A 476 70.012 102.417 -6.811 1.00142.58 O
+ANISOU 3581 O GLU A 476 16768 18380 19024 3141 -4136 -4517 O
+ATOM 3582 CB GLU A 476 69.486 99.616 -7.958 1.00128.68 C
+ANISOU 3582 CB GLU A 476 15020 16860 17012 2665 -3395 -4018 C
+ATOM 3583 CG GLU A 476 69.562 98.905 -6.628 1.00128.73 C
+ANISOU 3583 CG GLU A 476 15321 16930 16662 2941 -3433 -4041 C
+ATOM 3584 CD GLU A 476 68.465 97.866 -6.484 1.00133.35 C
+ANISOU 3584 CD GLU A 476 15992 17719 16955 2900 -3026 -3806 C
+ATOM 3585 OE1 GLU A 476 68.285 97.061 -7.422 1.00132.30 O
+ANISOU 3585 OE1 GLU A 476 15710 17598 16962 2603 -2816 -3643 O
+ATOM 3586 OE2 GLU A 476 67.768 97.860 -5.448 1.00136.37 O
+ANISOU 3586 OE2 GLU A 476 16588 18223 17003 3196 -2912 -3773 O
+ATOM 3587 N LYS A 477 71.990 101.424 -6.439 1.00148.46 N
+ANISOU 3587 N LYS A 477 17534 18788 20087 3179 -4467 -4596 N
+ATOM 3588 CA LYS A 477 72.399 102.365 -5.405 1.00154.25 C
+ANISOU 3588 CA LYS A 477 18378 19348 20882 3544 -4976 -4907 C
+ATOM 3589 C LYS A 477 72.634 103.732 -5.994 1.00159.76 C
+ANISOU 3589 C LYS A 477 18754 19833 22117 3467 -5183 -5014 C
+ATOM 3590 O LYS A 477 72.568 104.742 -5.292 1.00158.01 O
+ANISOU 3590 O LYS A 477 18598 19516 21921 3749 -5568 -5266 O
+ATOM 3591 CB LYS A 477 73.667 101.883 -4.706 1.00154.03 C
+ANISOU 3591 CB LYS A 477 18446 19057 21022 3730 -5372 -5076 C
+ATOM 3592 CG LYS A 477 73.367 100.787 -3.750 1.00149.76 C
+ANISOU 3592 CG LYS A 477 18324 18717 19861 3975 -5258 -5042 C
+ATOM 3593 CD LYS A 477 74.437 100.554 -2.740 1.00143.39 C
+ANISOU 3593 CD LYS A 477 17737 17664 19082 4327 -5762 -5306 C
+ATOM 3594 CE LYS A 477 73.739 100.087 -1.488 1.00145.72 C
+ANISOU 3594 CE LYS A 477 18569 18186 18613 4805 -5697 -5337 C
+ATOM 3595 NZ LYS A 477 74.661 99.556 -0.469 1.00149.42 N
+ANISOU 3595 NZ LYS A 477 19366 18470 18936 5206 -6108 -5561 N
+ATOM 3596 N THR A 478 72.908 103.757 -7.293 1.00166.45 N
+ANISOU 3596 N THR A 478 19271 20589 23384 3124 -4918 -4810 N
+ATOM 3597 CA THR A 478 73.186 105.012 -7.968 1.00170.99 C
+ANISOU 3597 CA THR A 478 19509 20929 24531 3052 -5023 -4844 C
+ATOM 3598 C THR A 478 71.905 105.733 -8.391 1.00172.33 C
+ANISOU 3598 C THR A 478 19686 21358 24435 2999 -4780 -4796 C
+ATOM 3599 O THR A 478 71.021 105.170 -9.046 1.00163.10 O
+ANISOU 3599 O THR A 478 18581 20461 22928 2823 -4356 -4594 O
+ATOM 3600 CB THR A 478 74.217 104.856 -9.128 1.00146.93 C
+ANISOU 3600 CB THR A 478 16115 17589 22125 2815 -4843 -4626 C
+ATOM 3601 OG1 THR A 478 74.873 106.106 -9.369 1.00147.15 O
+ANISOU 3601 OG1 THR A 478 15790 17239 22881 2857 -5085 -4705 O
+ATOM 3602 CG2 THR A 478 73.562 104.391 -10.425 1.00144.32 C
+ANISOU 3602 CG2 THR A 478 15764 17473 21597 2570 -4282 -4318 C
+ATOM 3603 N VAL A 479 71.809 106.979 -7.944 1.00177.73 N
+ANISOU 3603 N VAL A 479 20309 21929 25291 3181 -5110 -5014 N
+ATOM 3604 CA VAL A 479 70.674 107.838 -8.218 1.00175.65 C
+ANISOU 3604 CA VAL A 479 20044 21875 24819 3171 -4959 -5013 C
+ATOM 3605 C VAL A 479 71.176 109.077 -8.939 1.00177.67 C
+ANISOU 3605 C VAL A 479 19928 21830 25749 3101 -5069 -5035 C
+ATOM 3606 O VAL A 479 72.353 109.417 -8.840 1.00179.02 O
+ANISOU 3606 O VAL A 479 19865 21600 26555 3150 -5387 -5121 O
+ATOM 3607 CB VAL A 479 69.983 108.266 -6.909 1.00168.37 C
+ANISOU 3607 CB VAL A 479 19442 21113 23418 3524 -5243 -5249 C
+ATOM 3608 CG1 VAL A 479 69.008 109.403 -7.169 1.00162.23 C
+ANISOU 3608 CG1 VAL A 479 18603 20470 22565 3531 -5176 -5285 C
+ATOM 3609 CG2 VAL A 479 69.288 107.080 -6.256 1.00163.89 C
+ANISOU 3609 CG2 VAL A 479 19236 20856 22180 3624 -4991 -5142 C
+ATOM 3610 N MET A 486 57.931 103.433 -6.150 1.00 92.00 N
+ANISOU 3610 N MET A 486 10154 13425 11375 3371 -1523 -3283 N
+ATOM 3611 CA MET A 486 56.824 104.104 -5.482 1.00110.61 C
+ANISOU 3611 CA MET A 486 12558 15882 13585 3644 -1287 -3161 C
+ATOM 3612 C MET A 486 56.182 105.150 -6.389 1.00111.38 C
+ANISOU 3612 C MET A 486 12428 16016 13877 3424 -1416 -3308 C
+ATOM 3613 O MET A 486 56.000 106.305 -6.002 1.00120.35 O
+ANISOU 3613 O MET A 486 13691 17243 14794 3639 -1526 -3430 O
+ATOM 3614 CB MET A 486 57.288 104.743 -4.170 1.00120.60 C
+ANISOU 3614 CB MET A 486 14253 17221 14347 4174 -1395 -3243 C
+ATOM 3615 CG MET A 486 58.405 105.768 -4.316 1.00126.87 C
+ANISOU 3615 CG MET A 486 15171 17987 15047 4196 -1944 -3629 C
+ATOM 3616 SD MET A 486 58.150 107.169 -3.210 1.00146.78 S
+ANISOU 3616 SD MET A 486 18044 20597 17128 4757 -2124 -3782 S
+ATOM 3617 CE MET A 486 58.003 106.326 -1.640 1.00102.35 C
+ANISOU 3617 CE MET A 486 12883 15002 11003 5391 -1797 -3524 C
+ATOM 3618 N GLY A 496 57.154 99.412 -2.065 1.00157.62 N
+ANISOU 3618 N GLY A 496 19150 21656 19083 4616 82 -2024 N
+ATOM 3619 CA GLY A 496 57.031 99.217 -3.498 1.00158.07 C
+ANISOU 3619 CA GLY A 496 18749 21636 19677 3991 -116 -2141 C
+ATOM 3620 C GLY A 496 57.664 97.914 -3.942 1.00163.71 C
+ANISOU 3620 C GLY A 496 19349 22235 20619 3709 -140 -2093 C
+ATOM 3621 O GLY A 496 58.040 97.090 -3.111 1.00167.17 O
+ANISOU 3621 O GLY A 496 20009 22652 20858 3970 79 -1915 O
+ATOM 3622 N GLU A 497 57.778 97.722 -5.254 1.00166.67 N
+ANISOU 3622 N GLU A 497 19413 22530 21383 3222 -403 -2250 N
+ATOM 3623 CA GLU A 497 58.431 96.534 -5.792 1.00170.73 C
+ANISOU 3623 CA GLU A 497 19840 22933 22098 2955 -485 -2239 C
+ATOM 3624 C GLU A 497 59.931 96.621 -5.556 1.00172.64 C
+ANISOU 3624 C GLU A 497 20403 23228 21965 3043 -809 -2472 C
+ATOM 3625 O GLU A 497 60.589 95.609 -5.311 1.00173.01 O
+ANISOU 3625 O GLU A 497 20547 23223 21965 3047 -764 -2395 O
+ATOM 3626 CB GLU A 497 58.173 96.394 -7.290 1.00169.62 C
+ANISOU 3626 CB GLU A 497 19361 22681 22408 2505 -727 -2374 C
+ATOM 3627 CG GLU A 497 56.882 97.012 -7.777 1.00173.11 C
+ANISOU 3627 CG GLU A 497 19518 23086 23171 2413 -663 -2350 C
+ATOM 3628 CD GLU A 497 56.703 96.840 -9.270 1.00173.61 C
+ANISOU 3628 CD GLU A 497 19329 23013 23621 2054 -974 -2531 C
+ATOM 3629 OE1 GLU A 497 57.597 96.241 -9.908 1.00170.78 O
+ANISOU 3629 OE1 GLU A 497 19040 22600 23250 1901 -1202 -2647 O
+ATOM 3630 OE2 GLU A 497 55.672 97.300 -9.805 1.00174.73 O
+ANISOU 3630 OE2 GLU A 497 19233 23093 24064 1967 -999 -2559 O
+ATOM 3631 N ILE A 498 60.466 97.836 -5.652 1.00171.44 N
+ANISOU 3631 N ILE A 498 20381 23149 21608 3107 -1147 -2757 N
+ATOM 3632 CA ILE A 498 61.883 98.078 -5.403 1.00167.93 C
+ANISOU 3632 CA ILE A 498 20186 22695 20926 3210 -1503 -2995 C
+ATOM 3633 C ILE A 498 62.251 97.620 -4.004 1.00173.82 C
+ANISOU 3633 C ILE A 498 21298 23465 21280 3659 -1379 -2903 C
+ATOM 3634 O ILE A 498 63.315 97.034 -3.789 1.00168.12 O
+ANISOU 3634 O ILE A 498 20732 22684 20462 3692 -1544 -2980 O
+ATOM 3635 CB ILE A 498 62.227 99.564 -5.520 1.00165.53 C
+ANISOU 3635 CB ILE A 498 19934 22420 20540 3287 -1855 -3283 C
+ATOM 3636 CG1 ILE A 498 61.848 100.100 -6.901 1.00171.37 C
+ANISOU 3636 CG1 ILE A 498 20360 23137 21618 2911 -1947 -3365 C
+ATOM 3637 CG2 ILE A 498 63.706 99.798 -5.239 1.00153.61 C
+ANISOU 3637 CG2 ILE A 498 18613 20820 18931 3398 -2256 -3525 C
+ATOM 3638 CD1 ILE A 498 61.891 101.605 -6.996 1.00174.73 C
+ANISOU 3638 CD1 ILE A 498 20793 23594 22004 2996 -2195 -3587 C
+ATOM 3639 N SER A 499 61.362 97.890 -3.054 1.00187.32 N
+ANISOU 3639 N SER A 499 23169 25252 22753 4049 -1074 -2727 N
+ATOM 3640 CA SER A 499 61.558 97.444 -1.683 1.00198.47 C
+ANISOU 3640 CA SER A 499 24999 26682 23729 4594 -880 -2593 C
+ATOM 3641 C SER A 499 61.611 95.926 -1.651 1.00206.95 C
+ANISOU 3641 C SER A 499 26003 27687 24943 4481 -548 -2315 C
+ATOM 3642 O SER A 499 62.302 95.334 -0.823 1.00211.11 O
+ANISOU 3642 O SER A 499 26867 28195 25151 4806 -533 -2293 O
+ATOM 3643 CB SER A 499 60.435 97.952 -0.780 1.00200.16 C
+ANISOU 3643 CB SER A 499 25385 26976 23690 5064 -498 -2368 C
+ATOM 3644 OG SER A 499 60.635 97.541 0.556 1.00203.12 O
+ANISOU 3644 OG SER A 499 26244 27359 23574 5697 -286 -2224 O
+ATOM 3645 N ASP A 500 60.877 95.300 -2.564 1.00209.43 N
+ANISOU 3645 N ASP A 500 25883 27938 25751 4040 -320 -2123 N
+ATOM 3646 CA ASP A 500 60.862 93.851 -2.655 1.00212.36 C
+ANISOU 3646 CA ASP A 500 26120 28207 26361 3883 -39 -1865 C
+ATOM 3647 C ASP A 500 62.097 93.307 -3.366 1.00203.21 C
+ANISOU 3647 C ASP A 500 24946 26999 25265 3557 -426 -2093 C
+ATOM 3648 O ASP A 500 62.511 92.195 -3.092 1.00204.96 O
+ANISOU 3648 O ASP A 500 25238 27165 25472 3573 -286 -1954 O
+ATOM 3649 CB ASP A 500 59.580 93.355 -3.335 1.00221.23 C
+ANISOU 3649 CB ASP A 500 26765 29217 28075 3573 287 -1593 C
+ATOM 3650 CG ASP A 500 58.346 93.583 -2.486 1.00233.55 C
+ANISOU 3650 CG ASP A 500 28310 30773 29657 3938 816 -1243 C
+ATOM 3651 OD1 ASP A 500 58.502 93.807 -1.272 1.00239.09 O
+ANISOU 3651 OD1 ASP A 500 29432 31558 29852 4492 1029 -1137 O
+ATOM 3652 OD2 ASP A 500 57.226 93.532 -3.034 1.00237.24 O
+ANISOU 3652 OD2 ASP A 500 28355 31128 30656 3709 1011 -1072 O
+ATOM 3653 N ILE A 501 62.692 94.094 -4.258 1.00192.67 N
+ANISOU 3653 N ILE A 501 23525 25673 24008 3292 -875 -2413 N
+ATOM 3654 CA ILE A 501 63.864 93.633 -5.007 1.00181.71 C
+ANISOU 3654 CA ILE A 501 22108 24215 22719 3006 -1195 -2587 C
+ATOM 3655 C ILE A 501 65.165 93.699 -4.196 1.00170.68 C
+ANISOU 3655 C ILE A 501 21064 22814 20972 3287 -1450 -2764 C
+ATOM 3656 O ILE A 501 65.940 92.735 -4.173 1.00164.70 O
+ANISOU 3656 O ILE A 501 20376 21999 20202 3222 -1476 -2736 O
+ATOM 3657 CB ILE A 501 64.023 94.385 -6.353 1.00138.03 C
+ANISOU 3657 CB ILE A 501 16341 18649 17453 2657 -1507 -2802 C
+ATOM 3658 CG1 ILE A 501 63.385 93.589 -7.491 1.00130.33 C
+ANISOU 3658 CG1 ILE A 501 15061 17587 16872 2296 -1411 -2683 C
+ATOM 3659 CG2 ILE A 501 65.491 94.642 -6.682 1.00137.98 C
+ANISOU 3659 CG2 ILE A 501 16437 18581 17410 2596 -1883 -3037 C
+ATOM 3660 CD1 ILE A 501 61.877 93.516 -7.426 1.00127.50 C
+ANISOU 3660 CD1 ILE A 501 14480 17217 16748 2292 -1111 -2482 C
+ATOM 3661 N HIS A 502 65.396 94.829 -3.532 1.00164.00 N
+ANISOU 3661 N HIS A 502 20439 22007 19869 3613 -1676 -2964 N
+ATOM 3662 CA HIS A 502 66.603 95.022 -2.737 1.00157.69 C
+ANISOU 3662 CA HIS A 502 19968 21147 18800 3931 -2029 -3195 C
+ATOM 3663 C HIS A 502 66.627 94.018 -1.594 1.00162.64 C
+ANISOU 3663 C HIS A 502 20933 21795 19069 4322 -1761 -3012 C
+ATOM 3664 O HIS A 502 67.677 93.496 -1.229 1.00164.35 O
+ANISOU 3664 O HIS A 502 21348 21935 19163 4433 -1971 -3125 O
+ATOM 3665 CB HIS A 502 66.654 96.452 -2.195 1.00150.83 C
+ANISOU 3665 CB HIS A 502 19272 20282 17755 4264 -2351 -3452 C
+ATOM 3666 CG HIS A 502 67.989 97.117 -2.348 1.00143.78 C
+ANISOU 3666 CG HIS A 502 18387 19223 17019 4248 -2929 -3804 C
+ATOM 3667 ND1 HIS A 502 68.672 97.155 -3.544 1.00137.00 N
+ANISOU 3667 ND1 HIS A 502 17193 18253 16609 3785 -3096 -3872 N
+ATOM 3668 CD2 HIS A 502 68.759 97.787 -1.457 1.00140.15 C
+ANISOU 3668 CD2 HIS A 502 18217 18647 16387 4674 -3387 -4099 C
+ATOM 3669 CE1 HIS A 502 69.807 97.814 -3.383 1.00131.33 C
+ANISOU 3669 CE1 HIS A 502 16503 17343 16055 3893 -3583 -4155 C
+ATOM 3670 NE2 HIS A 502 69.883 98.208 -2.125 1.00130.34 N
+ANISOU 3670 NE2 HIS A 502 16741 17200 15583 4416 -3815 -4326 N
+ATOM 3671 N THR A 503 65.450 93.751 -1.039 1.00163.37 N
+ANISOU 3671 N THR A 503 21080 21971 19022 4552 -1268 -2705 N
+ATOM 3672 CA THR A 503 65.295 92.771 0.033 1.00163.31 C
+ANISOU 3672 CA THR A 503 21384 21972 18696 4974 -872 -2437 C
+ATOM 3673 C THR A 503 65.393 91.327 -0.475 1.00151.49 C
+ANISOU 3673 C THR A 503 19659 20415 17484 4610 -614 -2206 C
+ATOM 3674 O THR A 503 65.955 90.464 0.198 1.00146.11 O
+ANISOU 3674 O THR A 503 19247 19705 16563 4853 -520 -2130 O
+ATOM 3675 CB THR A 503 63.956 92.972 0.783 1.00170.09 C
+ANISOU 3675 CB THR A 503 22342 22899 19387 5379 -334 -2106 C
+ATOM 3676 OG1 THR A 503 64.026 94.162 1.576 1.00176.61 O
+ANISOU 3676 OG1 THR A 503 23551 23775 19778 5902 -585 -2325 O
+ATOM 3677 CG2 THR A 503 63.645 91.790 1.693 1.00171.53 C
+ANISOU 3677 CG2 THR A 503 22747 23054 19374 5760 235 -1707 C
+ATOM 3678 N LYS A 504 64.865 91.071 -1.669 1.00141.41 N
+ANISOU 3678 N LYS A 504 17911 19106 16711 4058 -541 -2117 N
+ATOM 3679 CA LYS A 504 64.918 89.730 -2.251 1.00138.96 C
+ANISOU 3679 CA LYS A 504 17368 18711 16719 3706 -369 -1930 C
+ATOM 3680 C LYS A 504 66.335 89.382 -2.646 1.00142.04 C
+ANISOU 3680 C LYS A 504 17848 19062 17058 3520 -779 -2178 C
+ATOM 3681 O LYS A 504 66.762 88.230 -2.559 1.00134.46 O
+ANISOU 3681 O LYS A 504 16927 18053 16108 3463 -666 -2057 O
+ATOM 3682 CB LYS A 504 64.010 89.614 -3.477 1.00129.82 C
+ANISOU 3682 CB LYS A 504 15721 17488 16116 3223 -303 -1839 C
+ATOM 3683 CG LYS A 504 62.585 89.222 -3.164 1.00130.75 C
+ANISOU 3683 CG LYS A 504 15616 17544 16518 3307 225 -1458 C
+ATOM 3684 N LEU A 505 67.053 90.395 -3.100 1.00138.41 N
+ANISOU 3684 N LEU A 505 17394 18602 16593 3427 -1237 -2505 N
+ATOM 3685 CA LEU A 505 68.435 90.224 -3.458 1.00120.29 C
+ANISOU 3685 CA LEU A 505 15154 16230 14322 3285 -1619 -2726 C
+ATOM 3686 C LEU A 505 69.260 89.889 -2.223 1.00124.70 C
+ANISOU 3686 C LEU A 505 16126 16770 14484 3724 -1710 -2800 C
+ATOM 3687 O LEU A 505 70.166 89.052 -2.259 1.00124.02 O
+ANISOU 3687 O LEU A 505 16106 16619 14396 3643 -1808 -2823 O
+ATOM 3688 CB LEU A 505 68.966 91.499 -4.066 1.00109.42 C
+ANISOU 3688 CB LEU A 505 13673 14807 13094 3171 -2036 -3016 C
+ATOM 3689 CG LEU A 505 70.386 91.097 -4.404 1.00128.61 C
+ANISOU 3689 CG LEU A 505 16120 17111 15635 3034 -2336 -3157 C
+ATOM 3690 CD1 LEU A 505 70.509 91.048 -5.920 1.00141.22 C
+ANISOU 3690 CD1 LEU A 505 17393 18648 17616 2580 -2370 -3131 C
+ATOM 3691 CD2 LEU A 505 71.441 91.946 -3.655 1.00114.58 C
+ANISOU 3691 CD2 LEU A 505 14554 15224 13758 3350 -2784 -3462 C
+ATOM 3692 N LEU A 506 68.951 90.579 -1.132 1.00130.40 N
+ANISOU 3692 N LEU A 506 17159 17539 14847 4233 -1705 -2854 N
+ATOM 3693 CA LEU A 506 69.612 90.336 0.139 1.00131.63 C
+ANISOU 3693 CA LEU A 506 17798 17665 14549 4786 -1814 -2947 C
+ATOM 3694 C LEU A 506 69.501 88.865 0.507 1.00144.65 C
+ANISOU 3694 C LEU A 506 19548 19330 16080 4841 -1380 -2638 C
+ATOM 3695 O LEU A 506 70.448 88.287 1.024 1.00156.36 O
+ANISOU 3695 O LEU A 506 21304 20754 17351 5038 -1550 -2741 O
+ATOM 3696 CB LEU A 506 69.008 91.206 1.240 1.00120.17 C
+ANISOU 3696 CB LEU A 506 16713 16270 12675 5409 -1772 -2980 C
+ATOM 3697 N ARG A 507 68.351 88.260 0.214 1.00146.01 N
+ANISOU 3697 N ARG A 507 19470 19552 16453 4658 -839 -2263 N
+ATOM 3698 CA ARG A 507 68.159 86.831 0.443 1.00152.26 C
+ANISOU 3698 CA ARG A 507 20261 20320 17271 4649 -394 -1930 C
+ATOM 3699 C ARG A 507 69.164 86.004 -0.360 1.00145.14 C
+ANISOU 3699 C ARG A 507 19199 19352 16597 4200 -653 -2042 C
+ATOM 3700 O ARG A 507 69.471 84.873 0.007 1.00142.95 O
+ANISOU 3700 O ARG A 507 19044 19045 16224 4273 -450 -1882 O
+ATOM 3701 CB ARG A 507 66.724 86.401 0.111 1.00161.16 C
+ANISOU 3701 CB ARG A 507 21023 21434 18777 4463 165 -1523 C
+ATOM 3702 CG ARG A 507 65.661 86.975 1.046 1.00177.63 C
+ANISOU 3702 CG ARG A 507 23283 23565 20645 4978 585 -1290 C
+ATOM 3703 CD ARG A 507 64.263 86.468 0.696 1.00187.68 C
+ANISOU 3703 CD ARG A 507 24111 24757 22442 4769 1148 -857 C
+ATOM 3704 NE ARG A 507 63.229 87.082 1.527 1.00198.88 N
+ANISOU 3704 NE ARG A 507 25661 26202 23704 5259 1588 -600 N
+ATOM 3705 CZ ARG A 507 61.923 86.883 1.368 1.00205.71 C
+ANISOU 3705 CZ ARG A 507 26137 26967 25058 5169 2095 -210 C
+ATOM 3706 NH1 ARG A 507 61.484 86.084 0.406 1.00207.33 N
+ANISOU 3706 NH1 ARG A 507 25797 27020 25959 4610 2159 -75 N
+ATOM 3707 NH2 ARG A 507 61.055 87.485 2.171 1.00208.11 N
+ANISOU 3707 NH2 ARG A 507 26596 27293 25185 5668 2517 41 N
+ATOM 3708 N LEU A 508 69.681 86.579 -1.445 1.00134.19 N
+ANISOU 3708 N LEU A 508 17555 17933 15496 3776 -1072 -2294 N
+ATOM 3709 CA LEU A 508 70.654 85.888 -2.287 1.00125.06 C
+ANISOU 3709 CA LEU A 508 16259 16704 14555 3385 -1304 -2382 C
+ATOM 3710 C LEU A 508 72.070 85.983 -1.730 1.00133.75 C
+ANISOU 3710 C LEU A 508 17660 17739 15419 3609 -1705 -2655 C
+ATOM 3711 O LEU A 508 72.775 84.975 -1.650 1.00132.42 O
+ANISOU 3711 O LEU A 508 17581 17530 15202 3562 -1700 -2615 O
+ATOM 3712 CB LEU A 508 70.606 86.404 -3.726 1.00112.64 C
+ANISOU 3712 CB LEU A 508 14312 15095 13392 2907 -1513 -2482 C
+ATOM 3713 CG LEU A 508 69.271 86.186 -4.436 1.00113.17 C
+ANISOU 3713 CG LEU A 508 14056 15174 13769 2653 -1215 -2260 C
+ATOM 3714 CD1 LEU A 508 69.459 86.184 -5.945 1.00106.22 C
+ANISOU 3714 CD1 LEU A 508 12898 14225 13237 2216 -1432 -2343 C
+ATOM 3715 CD2 LEU A 508 68.613 84.894 -3.968 1.00117.32 C
+ANISOU 3715 CD2 LEU A 508 14560 15678 14341 2703 -779 -1932 C
+ATOM 3716 N SER A 509 72.491 87.188 -1.355 1.00130.72 N
+ANISOU 3716 N SER A 509 17414 17317 14936 3856 -2085 -2944 N
+ATOM 3717 CA SER A 509 73.767 87.347 -0.663 1.00136.66 C
+ANISOU 3717 CA SER A 509 18457 17948 15519 4156 -2531 -3236 C
+ATOM 3718 C SER A 509 73.698 86.583 0.646 1.00143.40 C
+ANISOU 3718 C SER A 509 19773 18845 15866 4687 -2319 -3138 C
+ATOM 3719 O SER A 509 74.680 85.977 1.082 1.00138.35 O
+ANISOU 3719 O SER A 509 19358 18121 15090 4839 -2521 -3256 O
+ATOM 3720 CB SER A 509 74.089 88.820 -0.410 1.00130.15 C
+ANISOU 3720 CB SER A 509 17685 17028 14738 4382 -3008 -3572 C
+ATOM 3721 OG SER A 509 74.991 89.319 -1.384 1.00125.27 O
+ANISOU 3721 OG SER A 509 16739 16248 14609 4003 -3376 -3749 O
+ATOM 3722 N SER A 510 72.520 86.615 1.263 1.00144.65 N
+ANISOU 3722 N SER A 510 20078 19123 15761 4999 -1878 -2899 N
+ATOM 3723 CA SER A 510 72.236 85.777 2.417 1.00148.97 C
+ANISOU 3723 CA SER A 510 21044 19713 15846 5526 -1487 -2677 C
+ATOM 3724 C SER A 510 72.424 84.315 2.046 1.00145.48 C
+ANISOU 3724 C SER A 510 20455 19266 15554 5204 -1182 -2426 C
+ATOM 3725 O SER A 510 73.001 83.552 2.811 1.00140.49 O
+ANISOU 3725 O SER A 510 20177 18606 14598 5539 -1145 -2415 O
+ATOM 3726 CB SER A 510 70.807 85.999 2.911 1.00149.05 C
+ANISOU 3726 CB SER A 510 21111 19824 15699 5832 -930 -2348 C
+ATOM 3727 OG SER A 510 70.346 84.882 3.643 1.00147.27 O
+ANISOU 3727 OG SER A 510 21097 19617 15240 6154 -337 -1962 O
+ATOM 3728 N SER A 511 71.946 83.946 0.858 1.00139.39 N
+ANISOU 3728 N SER A 511 19184 18508 15269 4583 -1004 -2249 N
+ATOM 3729 CA SER A 511 72.011 82.573 0.365 1.00129.68 C
+ANISOU 3729 CA SER A 511 17763 17254 14255 4236 -745 -2013 C
+ATOM 3730 C SER A 511 73.437 82.171 0.006 1.00129.30 C
+ANISOU 3730 C SER A 511 17762 17135 14232 4035 -1175 -2258 C
+ATOM 3731 O SER A 511 73.792 80.991 0.047 1.00109.17 O
+ANISOU 3731 O SER A 511 15254 14565 11659 3957 -1019 -2119 O
+ATOM 3732 CB SER A 511 71.108 82.416 -0.862 1.00125.40 C
+ANISOU 3732 CB SER A 511 16701 16703 14243 3684 -564 -1828 C
+ATOM 3733 OG SER A 511 71.167 81.106 -1.394 1.00137.08 O
+ANISOU 3733 OG SER A 511 17990 18125 15969 3359 -392 -1635 O
+ATOM 3734 N GLN A 512 74.247 83.164 -0.347 1.00131.12 N
+ANISOU 3734 N GLN A 512 17958 17304 14560 3957 -1699 -2603 N
+ATOM 3735 CA GLN A 512 75.621 82.941 -0.774 1.00120.52 C
+ANISOU 3735 CA GLN A 512 16587 15845 13361 3755 -2110 -2821 C
+ATOM 3736 C GLN A 512 76.508 82.796 0.431 1.00123.24 C
+ANISOU 3736 C GLN A 512 17385 16120 13322 4264 -2359 -3023 C
+ATOM 3737 O GLN A 512 77.569 82.174 0.385 1.00128.94 O
+ANISOU 3737 O GLN A 512 18162 16749 14081 4188 -2573 -3124 O
+ATOM 3738 CB GLN A 512 76.096 84.150 -1.546 1.00118.44 C
+ANISOU 3738 CB GLN A 512 16077 15483 13440 3537 -2531 -3073 C
+ATOM 3739 CG GLN A 512 76.798 83.822 -2.807 1.00125.91 C
+ANISOU 3739 CG GLN A 512 16711 16343 14787 3048 -2644 -3057 C
+ATOM 3740 CD GLN A 512 76.915 85.020 -3.690 1.00137.22 C
+ANISOU 3740 CD GLN A 512 17859 17690 16589 2843 -2877 -3186 C
+ATOM 3741 OE1 GLN A 512 77.456 86.052 -3.281 1.00153.03 O
+ANISOU 3741 OE1 GLN A 512 19904 19568 18672 3053 -3245 -3442 O
+ATOM 3742 NE2 GLN A 512 76.353 84.922 -4.897 1.00128.62 N
+ANISOU 3742 NE2 GLN A 512 16487 16643 15739 2470 -2678 -3017 N
+ATOM 3743 N GLY A 513 76.073 83.422 1.510 1.00128.93 N
+ANISOU 3743 N GLY A 513 18453 16869 13665 4826 -2362 -3100 N
+ATOM 3744 CA GLY A 513 76.767 83.309 2.761 1.00135.31 C
+ANISOU 3744 CA GLY A 513 19790 17602 14021 5449 -2610 -3308 C
+ATOM 3745 C GLY A 513 76.597 81.908 3.295 1.00133.10 C
+ANISOU 3745 C GLY A 513 19748 17398 13425 5620 -2132 -3010 C
+ATOM 3746 O GLY A 513 77.464 81.407 3.988 1.00135.48 O
+ANISOU 3746 O GLY A 513 20407 17622 13448 5952 -2344 -3163 O
+ATOM 3747 N THR A 514 75.478 81.270 2.971 1.00130.00 N
+ANISOU 3747 N THR A 514 19139 17128 13128 5402 -1499 -2584 N
+ATOM 3748 CA THR A 514 75.252 79.899 3.409 1.00136.05 C
+ANISOU 3748 CA THR A 514 20053 17932 13707 5525 -990 -2248 C
+ATOM 3749 C THR A 514 76.125 78.980 2.571 1.00136.91 C
+ANISOU 3749 C THR A 514 19914 17993 14111 4991 -1151 -2279 C
+ATOM 3750 O THR A 514 76.451 77.859 2.971 1.00136.85 O
+ANISOU 3750 O THR A 514 20093 17981 13923 5102 -944 -2139 O
+ATOM 3751 CB THR A 514 73.784 79.475 3.234 1.00141.83 C
+ANISOU 3751 CB THR A 514 20522 18734 14631 5408 -287 -1768 C
+ATOM 3752 OG1 THR A 514 73.591 78.921 1.927 1.00142.93 O
+ANISOU 3752 OG1 THR A 514 20113 18858 15336 4676 -233 -1640 O
+ATOM 3753 CG2 THR A 514 72.861 80.659 3.413 1.00145.09 C
+ANISOU 3753 CG2 THR A 514 20916 19192 15018 5620 -214 -1761 C
+ATOM 3754 N ILE A 515 76.491 79.473 1.394 1.00129.08 N
+ANISOU 3754 N ILE A 515 18518 16960 13565 4442 -1494 -2442 N
+ATOM 3755 CA ILE A 515 77.327 78.735 0.468 1.00119.39 C
+ANISOU 3755 CA ILE A 515 17053 15677 12633 3951 -1657 -2465 C
+ATOM 3756 C ILE A 515 78.787 78.796 0.895 1.00127.05 C
+ANISOU 3756 C ILE A 515 18275 16524 13475 4143 -2161 -2798 C
+ATOM 3757 O ILE A 515 79.482 77.778 0.906 1.00128.44 O
+ANISOU 3757 O ILE A 515 18530 16671 13600 4065 -2153 -2760 O
+ATOM 3758 CB ILE A 515 77.220 79.308 -0.945 1.00110.42 C
+ANISOU 3758 CB ILE A 515 15452 14516 11987 3401 -1815 -2500 C
+ATOM 3759 CG1 ILE A 515 75.801 79.150 -1.481 1.00109.39 C
+ANISOU 3759 CG1 ILE A 515 15038 14466 12060 3177 -1388 -2203 C
+ATOM 3760 CG2 ILE A 515 78.168 78.587 -1.861 1.00112.80 C
+ANISOU 3760 CG2 ILE A 515 15581 14743 12533 2997 -1979 -2516 C
+ATOM 3761 CD1 ILE A 515 75.570 79.879 -2.780 1.00110.01 C
+ANISOU 3761 CD1 ILE A 515 14740 14519 12538 2759 -1561 -2268 C
+ATOM 3762 N GLU A 516 79.240 79.996 1.247 1.00122.76 N
+ANISOU 3762 N GLU A 516 17837 15878 12927 4400 -2627 -3132 N
+ATOM 3763 CA GLU A 516 80.636 80.218 1.589 1.00124.18 C
+ANISOU 3763 CA GLU A 516 18172 15860 13149 4571 -3208 -3493 C
+ATOM 3764 C GLU A 516 81.099 79.274 2.681 1.00126.09 C
+ANISOU 3764 C GLU A 516 18894 16095 12918 5029 -3183 -3522 C
+ATOM 3765 O GLU A 516 82.117 78.595 2.539 1.00116.84 O
+ANISOU 3765 O GLU A 516 17721 14825 11848 4893 -3381 -3605 O
+ATOM 3766 CB GLU A 516 80.863 81.656 2.046 1.00135.21 C
+ANISOU 3766 CB GLU A 516 19658 17112 14603 4907 -3722 -3854 C
+ATOM 3767 CG GLU A 516 82.315 82.045 1.962 1.00146.41 C
+ANISOU 3767 CG GLU A 516 20992 18238 16400 4885 -4381 -4215 C
+ATOM 3768 CD GLU A 516 82.865 81.775 0.582 1.00151.28 C
+ANISOU 3768 CD GLU A 516 21100 18789 17590 4220 -4329 -4073 C
+ATOM 3769 OE1 GLU A 516 82.373 82.413 -0.367 1.00146.52 O
+ANISOU 3769 OE1 GLU A 516 20133 18221 17316 3867 -4198 -3957 O
+ATOM 3770 OE2 GLU A 516 83.763 80.917 0.441 1.00154.24 O
+ANISOU 3770 OE2 GLU A 516 21471 19078 18055 4089 -4397 -4065 O
+END
--- /dev/null
+TITLE STRUCTURE OF TANK-BINDING KINASE 1 (Truncated test file)
+ATOM 3510 N LEU A 468 76.337 90.332 -7.628 1.00168.53 N
+ANISOU 3510 N LEU A 468 19760 15191 29082 5189 1248 -1702 N
+ATOM 3511 CA LEU A 468 75.576 90.788 -6.476 1.00181.60 C
+ANISOU 3511 CA LEU A 468 21073 16927 30998 5158 1421 -2051 C
+ATOM 3512 C LEU A 468 76.285 91.971 -5.836 1.00196.57 C
+ANISOU 3512 C LEU A 468 23029 18636 33021 5053 1667 -2229 C
+ATOM 3513 O LEU A 468 75.727 93.067 -5.733 1.00197.97 O
+ANISOU 3513 O LEU A 468 23115 18581 33523 5166 1662 -2304 O
+ATOM 3514 CB LEU A 468 75.409 89.671 -5.449 1.00173.72 C
+ANISOU 3514 CB LEU A 468 19829 16340 29836 4981 1593 -2304 C
+ATOM 3515 CG LEU A 468 74.099 88.882 -5.420 1.00170.58 C
+ANISOU 3515 CG LEU A 468 19142 16142 29529 5074 1449 -2345 C
+ATOM 3516 CD1 LEU A 468 74.023 87.940 -6.581 1.00167.98 C
+ANISOU 3516 CD1 LEU A 468 18951 15858 29015 5180 1156 -2025 C
+ATOM 3517 CD2 LEU A 468 73.988 88.096 -4.145 1.00165.16 C
+ANISOU 3517 CD2 LEU A 468 18217 15818 28720 4865 1706 -2656 C
+ATOM 3518 N ASP A 469 77.529 91.753 -5.429 1.00208.80 N
+ANISOU 3518 N ASP A 469 24731 20282 34322 4836 1875 -2296 N
+ATOM 3519 CA ASP A 469 78.267 92.785 -4.720 1.00223.11 C
+ANISOU 3519 CA ASP A 469 26577 21960 36233 4701 2123 -2500 C
+ATOM 3520 C ASP A 469 78.653 93.973 -5.599 1.00231.96 C
+ANISOU 3520 C ASP A 469 27954 22654 37525 4817 2037 -2283 C
+ATOM 3521 O ASP A 469 78.718 95.100 -5.118 1.00235.71 O
+ANISOU 3521 O ASP A 469 28377 22940 38242 4798 2175 -2449 O
+ATOM 3522 CB ASP A 469 79.506 92.197 -4.057 1.00224.50 C
+ANISOU 3522 CB ASP A 469 26841 22370 36089 4433 2350 -2633 C
+ATOM 3523 CG ASP A 469 79.748 92.767 -2.679 1.00229.51 C
+ANISOU 3523 CG ASP A 469 27303 23107 36794 4254 2637 -3018 C
+ATOM 3524 OD1 ASP A 469 79.958 93.992 -2.564 1.00232.36 O
+ANISOU 3524 OD1 ASP A 469 27695 23203 37387 4262 2718 -3093 O
+ATOM 3525 OD2 ASP A 469 79.751 91.979 -1.709 1.00229.48 O
+ANISOU 3525 OD2 ASP A 469 27145 23450 36598 4098 2779 -3242 O
+ATOM 3526 N PHE A 470 78.904 93.735 -6.882 1.00233.88 N
+ANISOU 3526 N PHE A 470 28481 22742 37641 4931 1813 -1912 N
+ATOM 3527 CA PHE A 470 79.292 94.831 -7.766 1.00237.73 C
+ANISOU 3527 CA PHE A 470 29252 22819 38256 5033 1733 -1677 C
+ATOM 3528 C PHE A 470 78.103 95.470 -8.467 1.00232.15 C
+ANISOU 3528 C PHE A 470 28512 21868 37828 5322 1470 -1512 C
+ATOM 3529 O PHE A 470 78.021 96.691 -8.532 1.00230.69 O
+ANISOU 3529 O PHE A 470 28371 21372 37909 5402 1493 -1517 O
+ATOM 3530 CB PHE A 470 80.344 94.379 -8.784 1.00242.99 C
+ANISOU 3530 CB PHE A 470 30297 23410 38616 4976 1661 -1357 C
+ATOM 3531 CG PHE A 470 80.663 95.388 -9.839 1.00251.53 C
+ANISOU 3531 CG PHE A 470 31709 24074 39788 5089 1550 -1064 C
+ATOM 3532 CD1 PHE A 470 81.658 96.315 -9.620 1.00252.90 C
+ANISOU 3532 CD1 PHE A 470 32021 24036 40032 4942 1771 -1133 C
+ATOM 3533 CD2 PHE A 470 80.005 95.389 -11.059 1.00255.02 C
+ANISOU 3533 CD2 PHE A 470 32335 24339 40221 5330 1225 -715 C
+ATOM 3534 CE1 PHE A 470 81.981 97.242 -10.575 1.00254.75 C
+ANISOU 3534 CE1 PHE A 470 32569 23879 40344 5028 1688 -862 C
+ATOM 3535 CE2 PHE A 470 80.321 96.320 -12.027 1.00256.76 C
+ANISOU 3535 CE2 PHE A 470 32894 24173 40491 5427 1126 -433 C
+ATOM 3536 CZ PHE A 470 81.313 97.248 -11.784 1.00256.57 C
+ANISOU 3536 CZ PHE A 470 33006 23929 40550 5272 1365 -504 C
+ATOM 3537 N CYS A 471 77.190 94.665 -8.997 1.00176.88 N
+ANISOU 3537 N CYS A 471 20955 21812 24441 2225 -3821 -3711 N
+ATOM 3538 CA CYS A 471 76.124 95.233 -9.815 1.00176.41 C
+ANISOU 3538 CA CYS A 471 20820 21906 24301 2124 -3576 -3614 C
+ATOM 3539 C CYS A 471 74.868 95.631 -9.050 1.00176.82 C
+ANISOU 3539 C CYS A 471 21026 22206 23952 2247 -3588 -3734 C
+ATOM 3540 O CYS A 471 74.632 96.811 -8.854 1.00178.66 O
+ANISOU 3540 O CYS A 471 21175 22393 24314 2353 -3749 -3873 O
+ATOM 3541 CB CYS A 471 75.805 94.346 -11.019 1.00173.95 C
+ANISOU 3541 CB CYS A 471 20521 21694 23877 1925 -3217 -3359 C
+ATOM 3542 SG CYS A 471 76.954 94.571 -12.398 1.00273.04 S
+ANISOU 3542 SG CYS A 471 32850 33934 36957 1863 -3075 -3146 S
+ATOM 3543 N ILE A 472 74.068 94.670 -8.603 1.00173.50 N
+ANISOU 3543 N ILE A 472 20813 22023 23085 2253 -3402 -3662 N
+ATOM 3544 CA ILE A 472 72.771 95.033 -8.022 1.00171.09 C
+ANISOU 3544 CA ILE A 472 20616 21936 22453 2374 -3307 -3694 C
+ATOM 3545 C ILE A 472 72.832 96.022 -6.874 1.00177.82 C
+ANISOU 3545 C ILE A 472 21591 22750 23222 2698 -3611 -3931 C
+ATOM 3546 O ILE A 472 71.992 96.914 -6.776 1.00182.92 O
+ANISOU 3546 O ILE A 472 22220 23491 23792 2778 -3598 -3985 O
+ATOM 3547 CB ILE A 472 71.979 93.843 -7.518 1.00159.41 C
+ANISOU 3547 CB ILE A 472 19318 20653 20599 2393 -3038 -3546 C
+ATOM 3548 CG1 ILE A 472 70.708 93.667 -8.341 1.00147.27 C
+ANISOU 3548 CG1 ILE A 472 17653 19253 19051 2196 -2745 -3384 C
+ATOM 3549 CG2 ILE A 472 71.526 94.090 -6.105 1.00155.95 C
+ANISOU 3549 CG2 ILE A 472 19129 20312 19812 2752 -3085 -3637 C
+ATOM 3550 CD1 ILE A 472 70.927 92.915 -9.606 1.00135.92 C
+ANISOU 3550 CD1 ILE A 472 16097 17752 17794 1929 -2643 -3254 C
+ATOM 3551 N ARG A 473 73.812 95.865 -5.996 1.00180.33 N
+ANISOU 3551 N ARG A 473 22055 22917 23544 2920 -3920 -4092 N
+ATOM 3552 CA ARG A 473 73.860 96.762 -4.877 1.00189.65 C
+ANISOU 3552 CA ARG A 473 23415 24034 24610 3307 -4283 -4357 C
+ATOM 3553 C ARG A 473 74.328 98.021 -5.558 1.00185.98 C
+ANISOU 3553 C ARG A 473 22628 23344 24692 3195 -4530 -4477 C
+ATOM 3554 O ARG A 473 73.519 98.885 -5.866 1.00181.76 O
+ANISOU 3554 O ARG A 473 22002 22904 24153 3165 -4446 -4474 O
+ATOM 3555 CB ARG A 473 74.803 96.287 -3.768 1.00205.24 C
+ANISOU 3555 CB ARG A 473 25661 25862 26460 3635 -4629 -4545 C
+ATOM 3556 CG ARG A 473 74.468 96.921 -2.433 1.00220.50 C
+ANISOU 3556 CG ARG A 473 27955 27814 28011 4171 -4923 -4787 C
+ATOM 3557 CD ARG A 473 75.337 96.433 -1.295 1.00232.58 C
+ANISOU 3557 CD ARG A 473 29837 29192 29341 4591 -5300 -5003 C
+ATOM 3558 NE ARG A 473 76.763 96.602 -1.549 1.00237.46 N
+ANISOU 3558 NE ARG A 473 30220 29440 30564 4489 -5773 -5205 N
+ATOM 3559 CZ ARG A 473 77.716 95.991 -0.861 1.00240.32 C
+ANISOU 3559 CZ ARG A 473 30786 29623 30903 4725 -6098 -5371 C
+ATOM 3560 NH1 ARG A 473 77.388 95.172 0.115 1.00241.12 N
+ANISOU 3560 NH1 ARG A 473 31370 29900 30344 5100 -5978 -5355 N
+ATOM 3561 NH2 ARG A 473 78.988 96.195 -1.159 1.00241.54 N
+ANISOU 3561 NH2 ARG A 473 30651 29398 31724 4605 -6518 -5533 N
+ATOM 3562 N ASN A 474 75.608 98.073 -5.901 1.00188.74 N
+ANISOU 3562 N ASN A 474 22768 23381 25563 3107 -4772 -4534 N
+ATOM 3563 CA ASN A 474 76.168 99.264 -6.526 1.00188.61 C
+ANISOU 3563 CA ASN A 474 22395 23075 26194 3026 -4977 -4605 C
+ATOM 3564 C ASN A 474 75.420 99.892 -7.729 1.00173.98 C
+ANISOU 3564 C ASN A 474 20312 21326 24467 2781 -4623 -4414 C
+ATOM 3565 O ASN A 474 75.482 101.107 -7.891 1.00176.08 O
+ANISOU 3565 O ASN A 474 20374 21426 25104 2827 -4803 -4518 O
+ATOM 3566 CB ASN A 474 77.650 99.066 -6.857 1.00199.45 C
+ANISOU 3566 CB ASN A 474 23514 24060 28207 2939 -5170 -4595 C
+ATOM 3567 CG ASN A 474 78.504 98.809 -5.625 1.00210.23 C
+ANISOU 3567 CG ASN A 474 25062 25219 29597 3243 -5689 -4883 C
+ATOM 3568 OD1 ASN A 474 78.174 99.240 -4.527 1.00215.26 O
+ANISOU 3568 OD1 ASN A 474 25969 25891 29928 3596 -6043 -5160 O
+ATOM 3569 ND2 ASN A 474 79.613 98.103 -5.810 1.00212.07 N
+ANISOU 3569 ND2 ASN A 474 25176 25222 30179 3148 -5748 -4822 N
+ATOM 3570 N ILE A 475 74.722 99.114 -8.562 1.00161.86 N
+ANISOU 3570 N ILE A 475 18813 20033 22652 2556 -4165 -4158 N
+ATOM 3571 CA ILE A 475 74.022 99.727 -9.709 1.00154.84 C
+ANISOU 3571 CA ILE A 475 17755 19216 21861 2390 -3885 -4015 C
+ATOM 3572 C ILE A 475 72.785 100.520 -9.312 1.00159.27 C
+ANISOU 3572 C ILE A 475 18401 19995 22121 2490 -3891 -4125 C
+ATOM 3573 O ILE A 475 72.662 101.687 -9.663 1.00162.60 O
+ANISOU 3573 O ILE A 475 18651 20327 22804 2505 -3962 -4186 O
+ATOM 3574 CB ILE A 475 73.600 98.727 -10.818 1.00214.93 C
+ANISOU 3574 CB ILE A 475 25397 26975 29293 2173 -3475 -3753 C
+ATOM 3575 CG1 ILE A 475 74.808 98.227 -11.613 1.00218.74 C
+ANISOU 3575 CG1 ILE A 475 25753 27211 30145 2083 -3390 -3585 C
+ATOM 3576 CG2 ILE A 475 72.618 99.379 -11.789 1.00210.37 C
+ANISOU 3576 CG2 ILE A 475 24743 26509 28681 2097 -3256 -3677 C
+ATOM 3577 CD1 ILE A 475 74.446 97.201 -12.664 1.00218.15 C
+ANISOU 3577 CD1 ILE A 475 25777 27260 29850 1946 -3056 -3359 C
+ATOM 3578 N GLU A 476 71.856 99.893 -8.600 1.00156.45 N
+ANISOU 3578 N GLU A 476 18293 19907 21245 2571 -3778 -4120 N
+ATOM 3579 CA GLU A 476 70.623 100.594 -8.252 1.00142.72 C
+ANISOU 3579 CA GLU A 476 16627 18370 19231 2677 -3720 -4176 C
+ATOM 3580 C GLU A 476 70.845 101.560 -7.094 1.00144.41 C
+ANISOU 3580 C GLU A 476 16959 18500 19412 3012 -4114 -4440 C
+ATOM 3581 O GLU A 476 70.012 102.417 -6.811 1.00142.58 O
+ANISOU 3581 O GLU A 476 16768 18380 19024 3141 -4136 -4517 O
+ATOM 3582 CB GLU A 476 69.486 99.616 -7.958 1.00128.68 C
+ANISOU 3582 CB GLU A 476 15020 16860 17012 2665 -3395 -4018 C
+ATOM 3583 CG GLU A 476 69.562 98.905 -6.628 1.00128.73 C
+ANISOU 3583 CG GLU A 476 15321 16930 16662 2941 -3433 -4041 C
+ATOM 3584 CD GLU A 476 68.465 97.866 -6.484 1.00133.35 C
+ANISOU 3584 CD GLU A 476 15992 17719 16955 2900 -3026 -3806 C
+ATOM 3585 OE1 GLU A 476 68.285 97.061 -7.422 1.00132.30 O
+ANISOU 3585 OE1 GLU A 476 15710 17598 16962 2603 -2816 -3643 O
+ATOM 3586 OE2 GLU A 476 67.768 97.860 -5.448 1.00136.37 O
+ANISOU 3586 OE2 GLU A 476 16588 18223 17003 3196 -2912 -3773 O
+ATOM 3587 N LYS A 477 71.990 101.424 -6.439 1.00148.46 N
+ANISOU 3587 N LYS A 477 17534 18788 20087 3179 -4467 -4596 N
+ATOM 3588 CA LYS A 477 72.399 102.365 -5.405 1.00154.25 C
+ANISOU 3588 CA LYS A 477 18378 19348 20882 3544 -4976 -4907 C
+ATOM 3589 C LYS A 477 72.634 103.732 -5.994 1.00159.76 C
+ANISOU 3589 C LYS A 477 18754 19833 22117 3467 -5183 -5014 C
+ATOM 3590 O LYS A 477 72.568 104.742 -5.292 1.00158.01 O
+ANISOU 3590 O LYS A 477 18598 19516 21921 3749 -5568 -5266 O
+ATOM 3591 CB LYS A 477 73.667 101.883 -4.706 1.00154.03 C
+ANISOU 3591 CB LYS A 477 18446 19057 21022 3730 -5372 -5076 C
+ATOM 3592 CG LYS A 477 73.367 100.787 -3.750 1.00149.76 C
+ANISOU 3592 CG LYS A 477 18324 18717 19861 3975 -5258 -5042 C
+ATOM 3593 CD LYS A 477 74.437 100.554 -2.740 1.00143.39 C
+ANISOU 3593 CD LYS A 477 17737 17664 19082 4327 -5762 -5306 C
+ATOM 3594 CE LYS A 477 73.739 100.087 -1.488 1.00145.72 C
+ANISOU 3594 CE LYS A 477 18569 18186 18613 4805 -5697 -5337 C
+ATOM 3595 NZ LYS A 477 74.661 99.556 -0.469 1.00149.42 N
+ANISOU 3595 NZ LYS A 477 19366 18470 18936 5206 -6108 -5561 N
+ATOM 3596 N THR A 478 72.908 103.757 -7.293 1.00166.45 N
+ANISOU 3596 N THR A 478 19271 20589 23384 3124 -4918 -4810 N
+ATOM 3597 CA THR A 478 73.186 105.012 -7.968 1.00170.99 C
+ANISOU 3597 CA THR A 478 19509 20929 24531 3052 -5023 -4844 C
+ATOM 3598 C THR A 478 71.905 105.733 -8.391 1.00172.33 C
+ANISOU 3598 C THR A 478 19686 21358 24435 2999 -4780 -4796 C
+ATOM 3599 O THR A 478 71.021 105.170 -9.046 1.00163.10 O
+ANISOU 3599 O THR A 478 18581 20461 22928 2823 -4356 -4594 O
+ATOM 3600 CB THR A 478 74.217 104.856 -9.128 1.00146.93 C
+ANISOU 3600 CB THR A 478 16115 17589 22125 2815 -4843 -4626 C
+ATOM 3601 OG1 THR A 478 74.873 106.106 -9.369 1.00147.15 O
+ANISOU 3601 OG1 THR A 478 15790 17239 22881 2857 -5085 -4705 O
+ATOM 3602 CG2 THR A 478 73.562 104.391 -10.425 1.00144.32 C
+ANISOU 3602 CG2 THR A 478 15764 17473 21597 2570 -4282 -4318 C
+ATOM 3603 N VAL A 479 71.809 106.979 -7.944 1.00177.73 N
+ANISOU 3603 N VAL A 479 20309 21929 25291 3181 -5110 -5014 N
+ATOM 3604 CA VAL A 479 70.674 107.838 -8.218 1.00175.65 C
+ANISOU 3604 CA VAL A 479 20044 21875 24819 3171 -4959 -5013 C
+ATOM 3605 C VAL A 479 71.176 109.077 -8.939 1.00177.67 C
+ANISOU 3605 C VAL A 479 19928 21830 25749 3101 -5069 -5035 C
+ATOM 3606 O VAL A 479 72.353 109.417 -8.840 1.00179.02 O
+ANISOU 3606 O VAL A 479 19865 21600 26555 3150 -5387 -5121 O
+ATOM 3607 CB VAL A 479 69.983 108.266 -6.909 1.00168.37 C
+ANISOU 3607 CB VAL A 479 19442 21113 23418 3524 -5243 -5249 C
+ATOM 3608 CG1 VAL A 479 69.008 109.403 -7.169 1.00162.23 C
+ANISOU 3608 CG1 VAL A 479 18603 20470 22565 3531 -5176 -5285 C
+ATOM 3609 CG2 VAL A 479 69.288 107.080 -6.256 1.00163.89 C
+ANISOU 3609 CG2 VAL A 479 19236 20856 22180 3624 -4991 -5142 C
+ATOM 3610 N MET A 486 57.931 103.433 -6.150 1.00 92.00 N
+ANISOU 3610 N MET A 486 10154 13425 11375 3371 -1523 -3283 N
+ATOM 3611 CA MET A 486 56.824 104.104 -5.482 1.00110.61 C
+ANISOU 3611 CA MET A 486 12558 15882 13585 3644 -1287 -3161 C
+ATOM 3612 C MET A 486 56.182 105.150 -6.389 1.00111.38 C
+ANISOU 3612 C MET A 486 12428 16016 13877 3424 -1416 -3308 C
+ATOM 3613 O MET A 486 56.000 106.305 -6.002 1.00120.35 O
+ANISOU 3613 O MET A 486 13691 17243 14794 3639 -1526 -3430 O
+ATOM 3614 CB MET A 486 57.288 104.743 -4.170 1.00120.60 C
+ANISOU 3614 CB MET A 486 14253 17221 14347 4174 -1395 -3243 C
+ATOM 3615 CG MET A 486 58.405 105.768 -4.316 1.00126.87 C
+ANISOU 3615 CG MET A 486 15171 17987 15047 4196 -1944 -3629 C
+ATOM 3616 SD MET A 486 58.150 107.169 -3.210 1.00146.78 S
+ANISOU 3616 SD MET A 486 18044 20597 17128 4757 -2124 -3782 S
+ATOM 3617 CE MET A 486 58.003 106.326 -1.640 1.00102.35 C
+ANISOU 3617 CE MET A 486 12883 15002 11003 5391 -1797 -3524 C
+ATOM 3618 N GLY A 496 57.154 99.412 -2.065 1.00157.62 N
+ANISOU 3618 N GLY A 496 19150 21656 19083 4616 82 -2024 N
+ATOM 3619 CA GLY A 496 57.031 99.217 -3.498 1.00158.07 C
+ANISOU 3619 CA GLY A 496 18749 21636 19677 3991 -116 -2141 C
+ATOM 3620 C GLY A 496 57.664 97.914 -3.942 1.00163.71 C
+ANISOU 3620 C GLY A 496 19349 22235 20619 3709 -140 -2093 C
+ATOM 3621 O GLY A 496 58.040 97.090 -3.111 1.00167.17 O
+ANISOU 3621 O GLY A 496 20009 22652 20858 3970 79 -1915 O
+ATOM 3622 N GLU A 497 57.778 97.722 -5.254 1.00166.67 N
+ANISOU 3622 N GLU A 497 19413 22530 21383 3222 -403 -2250 N
+ATOM 3623 CA GLU A 497 58.431 96.534 -5.792 1.00170.73 C
+ANISOU 3623 CA GLU A 497 19840 22933 22098 2955 -485 -2239 C
+ATOM 3624 C GLU A 497 59.931 96.621 -5.556 1.00172.64 C
+ANISOU 3624 C GLU A 497 20403 23228 21965 3043 -809 -2472 C
+ATOM 3625 O GLU A 497 60.589 95.609 -5.311 1.00173.01 O
+ANISOU 3625 O GLU A 497 20547 23223 21965 3047 -764 -2395 O
+ATOM 3626 CB GLU A 497 58.173 96.394 -7.290 1.00169.62 C
+ANISOU 3626 CB GLU A 497 19361 22681 22408 2505 -727 -2374 C
+ATOM 3627 CG GLU A 497 56.882 97.012 -7.777 1.00173.11 C
+ANISOU 3627 CG GLU A 497 19518 23086 23171 2413 -663 -2350 C
+ATOM 3628 CD GLU A 497 56.703 96.840 -9.270 1.00173.61 C
+ANISOU 3628 CD GLU A 497 19329 23013 23621 2054 -974 -2531 C
+ATOM 3629 OE1 GLU A 497 57.597 96.241 -9.908 1.00170.78 O
+ANISOU 3629 OE1 GLU A 497 19040 22600 23250 1901 -1202 -2647 O
+ATOM 3630 OE2 GLU A 497 55.672 97.300 -9.805 1.00174.73 O
+ANISOU 3630 OE2 GLU A 497 19233 23093 24064 1967 -999 -2559 O
+ATOM 3631 N ILE A 498 60.466 97.836 -5.652 1.00171.44 N
+ANISOU 3631 N ILE A 498 20381 23149 21608 3107 -1147 -2757 N
+ATOM 3632 CA ILE A 498 61.883 98.078 -5.403 1.00167.93 C
+ANISOU 3632 CA ILE A 498 20186 22695 20926 3210 -1503 -2995 C
+ATOM 3633 C ILE A 498 62.251 97.620 -4.004 1.00173.82 C
+ANISOU 3633 C ILE A 498 21298 23465 21280 3659 -1379 -2903 C
+ATOM 3634 O ILE A 498 63.315 97.034 -3.789 1.00168.12 O
+ANISOU 3634 O ILE A 498 20732 22684 20462 3692 -1544 -2980 O
+ATOM 3635 CB ILE A 498 62.227 99.564 -5.520 1.00165.53 C
+ANISOU 3635 CB ILE A 498 19934 22420 20540 3287 -1855 -3283 C
+ATOM 3636 CG1 ILE A 498 61.848 100.100 -6.901 1.00171.37 C
+ANISOU 3636 CG1 ILE A 498 20360 23137 21618 2911 -1947 -3365 C
+ATOM 3637 CG2 ILE A 498 63.706 99.798 -5.239 1.00153.61 C
+ANISOU 3637 CG2 ILE A 498 18613 20820 18931 3398 -2256 -3525 C
+ATOM 3638 CD1 ILE A 498 61.891 101.605 -6.996 1.00174.73 C
+ANISOU 3638 CD1 ILE A 498 20793 23594 22004 2996 -2195 -3587 C
+ATOM 3639 N SER A 499 61.362 97.890 -3.054 1.00187.32 N
+ANISOU 3639 N SER A 499 23169 25252 22753 4049 -1074 -2727 N
+ATOM 3640 CA SER A 499 61.558 97.444 -1.683 1.00198.47 C
+ANISOU 3640 CA SER A 499 24999 26682 23729 4594 -880 -2593 C
+ATOM 3641 C SER A 499 61.611 95.926 -1.651 1.00206.95 C
+ANISOU 3641 C SER A 499 26003 27687 24943 4481 -548 -2315 C
+ATOM 3642 O SER A 499 62.302 95.334 -0.823 1.00211.11 O
+ANISOU 3642 O SER A 499 26867 28195 25151 4806 -533 -2293 O
+ATOM 3643 CB SER A 499 60.435 97.952 -0.780 1.00200.16 C
+ANISOU 3643 CB SER A 499 25385 26976 23690 5064 -498 -2368 C
+ATOM 3644 OG SER A 499 60.635 97.541 0.556 1.00203.12 O
+ANISOU 3644 OG SER A 499 26244 27359 23574 5697 -286 -2224 O
+ATOM 3645 N ASP A 500 60.877 95.300 -2.564 1.00209.43 N
+ANISOU 3645 N ASP A 500 25883 27938 25751 4040 -320 -2123 N
+ATOM 3646 CA ASP A 500 60.862 93.851 -2.655 1.00212.36 C
+ANISOU 3646 CA ASP A 500 26120 28207 26361 3883 -39 -1865 C
+ATOM 3647 C ASP A 500 62.097 93.307 -3.366 1.00203.21 C
+ANISOU 3647 C ASP A 500 24946 26999 25265 3557 -426 -2093 C
+ATOM 3648 O ASP A 500 62.511 92.195 -3.092 1.00204.96 O
+ANISOU 3648 O ASP A 500 25238 27165 25472 3573 -286 -1954 O
+ATOM 3649 CB ASP A 500 59.580 93.355 -3.335 1.00221.23 C
+ANISOU 3649 CB ASP A 500 26765 29217 28075 3573 287 -1593 C
+ATOM 3650 CG ASP A 500 58.346 93.583 -2.486 1.00233.55 C
+ANISOU 3650 CG ASP A 500 28310 30773 29657 3938 816 -1243 C
+ATOM 3651 OD1 ASP A 500 58.502 93.807 -1.272 1.00239.09 O
+ANISOU 3651 OD1 ASP A 500 29432 31558 29852 4492 1029 -1137 O
+ATOM 3652 OD2 ASP A 500 57.226 93.532 -3.034 1.00237.24 O
+ANISOU 3652 OD2 ASP A 500 28355 31128 30656 3709 1011 -1072 O
+ATOM 3653 N ILE A 501 62.692 94.094 -4.258 1.00192.67 N
+ANISOU 3653 N ILE A 501 23525 25673 24008 3292 -875 -2413 N
+ATOM 3654 CA ILE A 501 63.864 93.633 -5.007 1.00181.71 C
+ANISOU 3654 CA ILE A 501 22108 24215 22719 3006 -1195 -2587 C
+ATOM 3655 C ILE A 501 65.165 93.699 -4.196 1.00170.68 C
+ANISOU 3655 C ILE A 501 21064 22814 20972 3287 -1450 -2764 C
+ATOM 3656 O ILE A 501 65.940 92.735 -4.173 1.00164.70 O
+ANISOU 3656 O ILE A 501 20376 21999 20202 3222 -1476 -2736 O
+ATOM 3657 CB ILE A 501 64.023 94.385 -6.353 1.00138.03 C
+ANISOU 3657 CB ILE A 501 16341 18649 17453 2657 -1507 -2802 C
+ATOM 3658 CG1 ILE A 501 63.385 93.589 -7.491 1.00130.33 C
+ANISOU 3658 CG1 ILE A 501 15061 17587 16872 2296 -1411 -2683 C
+ATOM 3659 CG2 ILE A 501 65.491 94.642 -6.682 1.00137.98 C
+ANISOU 3659 CG2 ILE A 501 16437 18581 17410 2596 -1883 -3037 C
+ATOM 3660 CD1 ILE A 501 61.877 93.516 -7.426 1.00127.50 C
+ANISOU 3660 CD1 ILE A 501 14480 17217 16748 2292 -1111 -2482 C
+ATOM 3661 N HIS A 502 65.396 94.829 -3.532 1.00164.00 N
+ANISOU 3661 N HIS A 502 20439 22007 19869 3613 -1676 -2964 N
+ATOM 3662 CA HIS A 502 66.603 95.022 -2.737 1.00157.69 C
+ANISOU 3662 CA HIS A 502 19968 21147 18800 3931 -2029 -3195 C
+ATOM 3663 C HIS A 502 66.627 94.018 -1.594 1.00162.64 C
+ANISOU 3663 C HIS A 502 20933 21795 19069 4322 -1761 -3012 C
+ATOM 3664 O HIS A 502 67.677 93.496 -1.229 1.00164.35 O
+ANISOU 3664 O HIS A 502 21348 21935 19163 4433 -1971 -3125 O
+ATOM 3665 CB HIS A 502 66.654 96.452 -2.195 1.00150.83 C
+ANISOU 3665 CB HIS A 502 19272 20282 17755 4264 -2351 -3452 C
+ATOM 3666 CG HIS A 502 67.989 97.117 -2.348 1.00143.78 C
+ANISOU 3666 CG HIS A 502 18387 19223 17019 4248 -2929 -3804 C
+ATOM 3667 ND1 HIS A 502 68.672 97.155 -3.544 1.00137.00 N
+ANISOU 3667 ND1 HIS A 502 17193 18253 16609 3785 -3096 -3872 N
+ATOM 3668 CD2 HIS A 502 68.759 97.787 -1.457 1.00140.15 C
+ANISOU 3668 CD2 HIS A 502 18217 18647 16387 4674 -3387 -4099 C
+ATOM 3669 CE1 HIS A 502 69.807 97.814 -3.383 1.00131.33 C
+ANISOU 3669 CE1 HIS A 502 16503 17343 16055 3893 -3583 -4155 C
+ATOM 3670 NE2 HIS A 502 69.883 98.208 -2.125 1.00130.34 N
+ANISOU 3670 NE2 HIS A 502 16741 17200 15583 4416 -3815 -4326 N
+ATOM 3671 N THR A 503 65.450 93.751 -1.039 1.00163.37 N
+ANISOU 3671 N THR A 503 21080 21971 19022 4552 -1268 -2705 N
+ATOM 3672 CA THR A 503 65.295 92.771 0.033 1.00163.31 C
+ANISOU 3672 CA THR A 503 21384 21972 18696 4974 -872 -2437 C
+ATOM 3673 C THR A 503 65.393 91.327 -0.475 1.00151.49 C
+ANISOU 3673 C THR A 503 19659 20415 17484 4610 -614 -2206 C
+ATOM 3674 O THR A 503 65.955 90.464 0.198 1.00146.11 O
+ANISOU 3674 O THR A 503 19247 19705 16563 4853 -520 -2130 O
+ATOM 3675 CB THR A 503 63.956 92.972 0.783 1.00170.09 C
+ANISOU 3675 CB THR A 503 22342 22899 19387 5379 -334 -2106 C
+ATOM 3676 OG1 THR A 503 64.026 94.162 1.576 1.00176.61 O
+ANISOU 3676 OG1 THR A 503 23551 23775 19778 5902 -585 -2325 O
+ATOM 3677 CG2 THR A 503 63.645 91.790 1.693 1.00171.53 C
+ANISOU 3677 CG2 THR A 503 22747 23054 19374 5760 235 -1707 C
+ATOM 3678 N LYS A 504 64.865 91.071 -1.669 1.00141.41 N
+ANISOU 3678 N LYS A 504 17911 19106 16711 4058 -541 -2117 N
+ATOM 3679 CA LYS A 504 64.918 89.730 -2.251 1.00138.96 C
+ANISOU 3679 CA LYS A 504 17368 18711 16719 3706 -369 -1930 C
+ATOM 3680 C LYS A 504 66.335 89.382 -2.646 1.00142.04 C
+ANISOU 3680 C LYS A 504 17848 19062 17058 3520 -779 -2178 C
+ATOM 3681 O LYS A 504 66.762 88.230 -2.559 1.00134.46 O
+ANISOU 3681 O LYS A 504 16927 18053 16108 3463 -666 -2057 O
+ATOM 3682 CB LYS A 504 64.010 89.614 -3.477 1.00129.82 C
+ANISOU 3682 CB LYS A 504 15721 17488 16116 3223 -303 -1839 C
+ATOM 3683 CG LYS A 504 62.585 89.222 -3.164 1.00130.75 C
+ANISOU 3683 CG LYS A 504 15616 17544 16518 3307 225 -1458 C
+ATOM 3684 N LEU A 505 67.053 90.395 -3.100 1.00138.41 N
+ANISOU 3684 N LEU A 505 17394 18602 16593 3427 -1237 -2505 N
+ATOM 3685 CA LEU A 505 68.435 90.224 -3.458 1.00120.29 C
+ANISOU 3685 CA LEU A 505 15154 16230 14322 3285 -1619 -2726 C
+ATOM 3686 C LEU A 505 69.260 89.889 -2.223 1.00124.70 C
+ANISOU 3686 C LEU A 505 16126 16770 14484 3724 -1710 -2800 C
+ATOM 3687 O LEU A 505 70.166 89.052 -2.259 1.00124.02 O
+ANISOU 3687 O LEU A 505 16106 16619 14396 3643 -1808 -2823 O
+ATOM 3688 CB LEU A 505 68.966 91.499 -4.066 1.00109.42 C
+ANISOU 3688 CB LEU A 505 13673 14807 13094 3171 -2036 -3016 C
+ATOM 3689 CG LEU A 505 70.386 91.097 -4.404 1.00128.61 C
+ANISOU 3689 CG LEU A 505 16120 17111 15635 3034 -2336 -3157 C
+ATOM 3690 CD1 LEU A 505 70.509 91.048 -5.920 1.00141.22 C
+ANISOU 3690 CD1 LEU A 505 17393 18648 17616 2580 -2370 -3131 C
+ATOM 3691 CD2 LEU A 505 71.441 91.946 -3.655 1.00114.58 C
+ANISOU 3691 CD2 LEU A 505 14554 15224 13758 3350 -2784 -3462 C
+ATOM 3692 N LEU A 506 68.951 90.579 -1.132 1.00130.40 N
+ANISOU 3692 N LEU A 506 17159 17539 14847 4233 -1705 -2854 N
+ATOM 3693 CA LEU A 506 69.612 90.336 0.139 1.00131.63 C
+ANISOU 3693 CA LEU A 506 17798 17665 14549 4786 -1814 -2947 C
+ATOM 3694 C LEU A 506 69.501 88.865 0.507 1.00144.65 C
+ANISOU 3694 C LEU A 506 19548 19330 16080 4841 -1380 -2638 C
+ATOM 3695 O LEU A 506 70.448 88.287 1.024 1.00156.36 O
+ANISOU 3695 O LEU A 506 21304 20754 17351 5038 -1550 -2741 O
+ATOM 3696 CB LEU A 506 69.008 91.206 1.240 1.00120.17 C
+ANISOU 3696 CB LEU A 506 16713 16270 12675 5409 -1772 -2980 C
+ATOM 3697 N ARG A 507 68.351 88.260 0.214 1.00146.01 N
+ANISOU 3697 N ARG A 507 19470 19552 16453 4658 -839 -2263 N
+ATOM 3698 CA ARG A 507 68.159 86.831 0.443 1.00152.26 C
+ANISOU 3698 CA ARG A 507 20261 20320 17271 4649 -394 -1930 C
+ATOM 3699 C ARG A 507 69.164 86.004 -0.360 1.00145.14 C
+ANISOU 3699 C ARG A 507 19199 19352 16597 4200 -653 -2042 C
+ATOM 3700 O ARG A 507 69.471 84.873 0.007 1.00142.95 O
+ANISOU 3700 O ARG A 507 19044 19045 16224 4273 -450 -1882 O
+ATOM 3701 CB ARG A 507 66.724 86.401 0.111 1.00161.16 C
+ANISOU 3701 CB ARG A 507 21023 21434 18777 4463 165 -1523 C
+ATOM 3702 CG ARG A 507 65.661 86.975 1.046 1.00177.63 C
+ANISOU 3702 CG ARG A 507 23283 23565 20645 4978 585 -1290 C
+ATOM 3703 CD ARG A 507 64.263 86.468 0.696 1.00187.68 C
+ANISOU 3703 CD ARG A 507 24111 24757 22442 4769 1148 -857 C
+ATOM 3704 NE ARG A 507 63.229 87.082 1.527 1.00198.88 N
+ANISOU 3704 NE ARG A 507 25661 26202 23704 5259 1588 -600 N
+ATOM 3705 CZ ARG A 507 61.923 86.883 1.368 1.00205.71 C
+ANISOU 3705 CZ ARG A 507 26137 26967 25058 5169 2095 -210 C
+ATOM 3706 NH1 ARG A 507 61.484 86.084 0.406 1.00207.33 N
+ANISOU 3706 NH1 ARG A 507 25797 27020 25959 4610 2159 -75 N
+ATOM 3707 NH2 ARG A 507 61.055 87.485 2.171 1.00208.11 N
+ANISOU 3707 NH2 ARG A 507 26596 27293 25185 5668 2517 41 N
+ATOM 3708 N LEU A 508 69.681 86.579 -1.445 1.00134.19 N
+ANISOU 3708 N LEU A 508 17555 17933 15496 3776 -1072 -2294 N
+ATOM 3709 CA LEU A 508 70.654 85.888 -2.287 1.00125.06 C
+ANISOU 3709 CA LEU A 508 16259 16704 14555 3385 -1304 -2382 C
+ATOM 3710 C LEU A 508 72.070 85.983 -1.730 1.00133.75 C
+ANISOU 3710 C LEU A 508 17660 17739 15419 3609 -1705 -2655 C
+ATOM 3711 O LEU A 508 72.775 84.975 -1.650 1.00132.42 O
+ANISOU 3711 O LEU A 508 17581 17530 15202 3562 -1700 -2615 O
+ATOM 3712 CB LEU A 508 70.606 86.404 -3.726 1.00112.64 C
+ANISOU 3712 CB LEU A 508 14312 15095 13392 2907 -1513 -2482 C
+ATOM 3713 CG LEU A 508 69.271 86.186 -4.436 1.00113.17 C
+ANISOU 3713 CG LEU A 508 14056 15174 13769 2653 -1215 -2260 C
+ATOM 3714 CD1 LEU A 508 69.459 86.184 -5.945 1.00106.22 C
+ANISOU 3714 CD1 LEU A 508 12898 14225 13237 2216 -1432 -2343 C
+ATOM 3715 CD2 LEU A 508 68.613 84.894 -3.968 1.00117.32 C
+ANISOU 3715 CD2 LEU A 508 14560 15678 14341 2703 -779 -1932 C
+ATOM 3716 N SER A 509 72.491 87.188 -1.355 1.00130.72 N
+ANISOU 3716 N SER A 509 17414 17317 14936 3856 -2085 -2944 N
+ATOM 3717 CA SER A 509 73.767 87.347 -0.663 1.00136.66 C
+ANISOU 3717 CA SER A 509 18457 17948 15519 4156 -2531 -3236 C
+ATOM 3718 C SER A 509 73.698 86.583 0.646 1.00143.40 C
+ANISOU 3718 C SER A 509 19773 18845 15866 4687 -2319 -3138 C
+ATOM 3719 O SER A 509 74.680 85.977 1.082 1.00138.35 O
+ANISOU 3719 O SER A 509 19358 18121 15090 4839 -2521 -3256 O
+ATOM 3720 CB SER A 509 74.089 88.820 -0.410 1.00130.15 C
+ANISOU 3720 CB SER A 509 17685 17028 14738 4382 -3008 -3572 C
+ATOM 3721 OG SER A 509 74.991 89.319 -1.384 1.00125.27 O
+ANISOU 3721 OG SER A 509 16739 16248 14609 4003 -3376 -3749 O
+ATOM 3722 N SER A 510 72.520 86.615 1.263 1.00144.65 N
+ANISOU 3722 N SER A 510 20078 19123 15761 4999 -1878 -2899 N
+ATOM 3723 CA SER A 510 72.236 85.777 2.417 1.00148.97 C
+ANISOU 3723 CA SER A 510 21044 19713 15846 5526 -1487 -2677 C
+ATOM 3724 C SER A 510 72.424 84.315 2.046 1.00145.48 C
+ANISOU 3724 C SER A 510 20455 19266 15554 5204 -1182 -2426 C
+ATOM 3725 O SER A 510 73.001 83.552 2.811 1.00140.49 O
+ANISOU 3725 O SER A 510 20177 18606 14598 5539 -1145 -2415 O
+ATOM 3726 CB SER A 510 70.807 85.999 2.911 1.00149.05 C
+ANISOU 3726 CB SER A 510 21111 19824 15699 5832 -930 -2348 C
+ATOM 3727 OG SER A 510 70.346 84.882 3.643 1.00147.27 O
+ANISOU 3727 OG SER A 510 21097 19617 15240 6154 -337 -1962 O
+ATOM 3728 N SER A 511 71.946 83.946 0.858 1.00139.39 N
+ANISOU 3728 N SER A 511 19184 18508 15269 4583 -1004 -2249 N
+ATOM 3729 CA SER A 511 72.011 82.573 0.365 1.00129.68 C
+ANISOU 3729 CA SER A 511 17763 17254 14255 4236 -745 -2013 C
+ATOM 3730 C SER A 511 73.437 82.171 0.006 1.00129.30 C
+ANISOU 3730 C SER A 511 17762 17135 14232 4035 -1175 -2258 C
+ATOM 3731 O SER A 511 73.792 80.991 0.047 1.00109.17 O
+ANISOU 3731 O SER A 511 15254 14565 11659 3957 -1019 -2119 O
+ATOM 3732 CB SER A 511 71.108 82.416 -0.862 1.00125.40 C
+ANISOU 3732 CB SER A 511 16701 16703 14243 3684 -564 -1828 C
+ATOM 3733 OG SER A 511 71.167 81.106 -1.394 1.00137.08 O
+ANISOU 3733 OG SER A 511 17990 18125 15969 3359 -392 -1635 O
+ATOM 3734 N GLN A 512 74.247 83.164 -0.347 1.00131.12 N
+ANISOU 3734 N GLN A 512 17958 17304 14560 3957 -1699 -2603 N
+ATOM 3735 CA GLN A 512 75.621 82.941 -0.774 1.00120.52 C
+ANISOU 3735 CA GLN A 512 16587 15845 13361 3755 -2110 -2821 C
+ATOM 3736 C GLN A 512 76.508 82.796 0.431 1.00123.24 C
+ANISOU 3736 C GLN A 512 17385 16120 13322 4264 -2359 -3023 C
+ATOM 3737 O GLN A 512 77.569 82.174 0.385 1.00128.94 O
+ANISOU 3737 O GLN A 512 18162 16749 14081 4188 -2573 -3124 O
+ATOM 3738 CB GLN A 512 76.096 84.150 -1.546 1.00118.44 C
+ANISOU 3738 CB GLN A 512 16077 15483 13440 3537 -2531 -3073 C
+ATOM 3739 CG GLN A 512 76.798 83.822 -2.807 1.00125.91 C
+ANISOU 3739 CG GLN A 512 16711 16343 14787 3048 -2644 -3057 C
+ATOM 3740 CD GLN A 512 76.915 85.020 -3.690 1.00137.22 C
+ANISOU 3740 CD GLN A 512 17859 17690 16589 2843 -2877 -3186 C
+ATOM 3741 OE1 GLN A 512 77.456 86.052 -3.281 1.00153.03 O
+ANISOU 3741 OE1 GLN A 512 19904 19568 18672 3053 -3245 -3442 O
+ATOM 3742 NE2 GLN A 512 76.353 84.922 -4.897 1.00128.62 N
+ANISOU 3742 NE2 GLN A 512 16487 16643 15739 2470 -2678 -3017 N
+ATOM 3743 N GLY A 513 76.073 83.422 1.510 1.00128.93 N
+ANISOU 3743 N GLY A 513 18453 16869 13665 4826 -2362 -3100 N
+ATOM 3744 CA GLY A 513 76.767 83.309 2.761 1.00135.31 C
+ANISOU 3744 CA GLY A 513 19790 17602 14021 5449 -2610 -3308 C
+ATOM 3745 C GLY A 513 76.597 81.908 3.295 1.00133.10 C
+ANISOU 3745 C GLY A 513 19748 17398 13425 5620 -2132 -3010 C
+ATOM 3746 O GLY A 513 77.464 81.407 3.988 1.00135.48 O
+ANISOU 3746 O GLY A 513 20407 17622 13448 5952 -2344 -3163 O
+ATOM 3747 N THR A 514 75.478 81.270 2.971 1.00130.00 N
+ANISOU 3747 N THR A 514 19139 17128 13128 5402 -1499 -2584 N
+ATOM 3748 CA THR A 514 75.252 79.899 3.409 1.00136.05 C
+ANISOU 3748 CA THR A 514 20053 17932 13707 5525 -990 -2248 C
+ATOM 3749 C THR A 514 76.125 78.980 2.571 1.00136.91 C
+ANISOU 3749 C THR A 514 19914 17993 14111 4991 -1151 -2279 C
+ATOM 3750 O THR A 514 76.451 77.859 2.971 1.00136.85 O
+ANISOU 3750 O THR A 514 20093 17981 13923 5102 -944 -2139 O
+ATOM 3751 CB THR A 514 73.784 79.475 3.234 1.00141.83 C
+ANISOU 3751 CB THR A 514 20522 18734 14631 5408 -287 -1768 C
+ATOM 3752 OG1 THR A 514 73.591 78.921 1.927 1.00142.93 O
+ANISOU 3752 OG1 THR A 514 20113 18858 15336 4676 -233 -1640 O
+ATOM 3753 CG2 THR A 514 72.861 80.659 3.413 1.00145.09 C
+ANISOU 3753 CG2 THR A 514 20916 19192 15018 5620 -214 -1761 C
+ATOM 3754 N ILE A 515 76.491 79.473 1.394 1.00129.08 N
+ANISOU 3754 N ILE A 515 18518 16960 13565 4442 -1494 -2442 N
+ATOM 3755 CA ILE A 515 77.327 78.735 0.468 1.00119.39 C
+ANISOU 3755 CA ILE A 515 17053 15677 12633 3951 -1657 -2465 C
+ATOM 3756 C ILE A 515 78.787 78.796 0.895 1.00127.05 C
+ANISOU 3756 C ILE A 515 18275 16524 13475 4143 -2161 -2798 C
+ATOM 3757 O ILE A 515 79.482 77.778 0.906 1.00128.44 O
+ANISOU 3757 O ILE A 515 18530 16671 13600 4065 -2153 -2760 O
+ATOM 3758 CB ILE A 515 77.220 79.308 -0.945 1.00110.42 C
+ANISOU 3758 CB ILE A 515 15452 14516 11987 3401 -1815 -2500 C
+ATOM 3759 CG1 ILE A 515 75.801 79.150 -1.481 1.00109.39 C
+ANISOU 3759 CG1 ILE A 515 15038 14466 12060 3177 -1388 -2203 C
+ATOM 3760 CG2 ILE A 515 78.168 78.587 -1.861 1.00112.80 C
+ANISOU 3760 CG2 ILE A 515 15581 14743 12533 2997 -1979 -2516 C
+ATOM 3761 CD1 ILE A 515 75.570 79.879 -2.780 1.00110.01 C
+ANISOU 3761 CD1 ILE A 515 14740 14519 12538 2759 -1561 -2268 C
+ATOM 3762 N GLU A 516 79.240 79.996 1.247 1.00122.76 N
+ANISOU 3762 N GLU A 516 17837 15878 12927 4400 -2627 -3132 N
+ATOM 3763 CA GLU A 516 80.636 80.218 1.589 1.00124.18 C
+ANISOU 3763 CA GLU A 516 18172 15860 13149 4571 -3208 -3493 C
+ATOM 3764 C GLU A 516 81.099 79.274 2.681 1.00126.09 C
+ANISOU 3764 C GLU A 516 18894 16095 12918 5029 -3183 -3522 C
+ATOM 3765 O GLU A 516 82.117 78.595 2.539 1.00116.84 O
+ANISOU 3765 O GLU A 516 17721 14825 11848 4893 -3381 -3605 O
+ATOM 3766 CB GLU A 516 80.863 81.656 2.046 1.00135.21 C
+ANISOU 3766 CB GLU A 516 19658 17112 14603 4907 -3722 -3854 C
+ATOM 3767 CG GLU A 516 82.315 82.045 1.962 1.00146.41 C
+ANISOU 3767 CG GLU A 516 20992 18238 16400 4885 -4381 -4215 C
+ATOM 3768 CD GLU A 516 82.865 81.775 0.582 1.00151.28 C
+ANISOU 3768 CD GLU A 516 21100 18789 17590 4220 -4329 -4073 C
+ATOM 3769 OE1 GLU A 516 82.373 82.413 -0.367 1.00146.52 O
+ANISOU 3769 OE1 GLU A 516 20133 18221 17316 3867 -4198 -3957 O
+ATOM 3770 OE2 GLU A 516 83.763 80.917 0.441 1.00154.24 O
+ANISOU 3770 OE2 GLU A 516 21471 19078 18055 4089 -4397 -4065 O
+END
--- /dev/null
+HEADER TRANSFERASE/TRANSFERASE INHIBITOR 01-JAN-13 4IM2
+TITLE STRUCTURE OF TANK-BINDING KINASE 1 (Truncated test file)
+DBREF 4IM2 A 1 657 UNP Q9UHD2 TBK1_HUMAN 1 657
+SEQADV 4IM2 GLY A -5 UNP Q9UHD2 EXPRESSION TAG
+SEQADV 4IM2 SER A -4 UNP Q9UHD2 EXPRESSION TAG
+SEQADV 4IM2 GLY A -3 UNP Q9UHD2 EXPRESSION TAG
+SEQADV 4IM2 SER A -2 UNP Q9UHD2 EXPRESSION TAG
+SEQADV 4IM2 GLY A -1 UNP Q9UHD2 EXPRESSION TAG
+SEQADV 4IM2 SER A 0 UNP Q9UHD2 EXPRESSION TAG
+SEQRES 1 A 663 GLY SER GLY SER GLY SER MET GLN SER THR SER ASN HIS
+ATOM 1 N GLY A -1 126.784 4.226 -23.353 1.00158.13 N
+ANISOU 1 N GLY A -1 19370 17517 23197 6628 1162 2075 N
+ATOM 2 CA GLY A -1 125.521 4.306 -24.062 1.00150.94 C
+ANISOU 2 CA GLY A -1 18746 16231 22374 6153 1277 1996 C
+ATOM 3 C GLY A -1 125.742 4.361 -25.557 1.00146.29 C
+ANISOU 3 C GLY A -1 18187 15453 21943 5900 1405 1498 C
+ATOM 4 O GLY A -1 126.691 4.980 -26.029 1.00150.85 O
+ANISOU 4 O GLY A -1 18536 16366 22413 5906 1385 1160 O
+ATOM 5 N SER A 0 124.869 3.710 -26.313 1.00137.36 N
+ANISOU 5 N SER A 0 17328 13796 21068 5675 1550 1432 N
+ATOM 6 CA SER A 0 125.052 3.672 -27.755 1.00139.44 C
+ANISOU 6 CA SER A 0 17634 13884 21461 5464 1674 953 C
+ATOM 7 C SER A 0 123.846 4.104 -28.574 1.00137.43 C
+ANISOU 7 C SER A 0 17591 13478 21149 4975 1714 755 C
+ATOM 8 O SER A 0 122.737 4.275 -28.071 1.00128.25 O
+ANISOU 8 O SER A 0 16566 12244 19921 4780 1667 988 O
+ATOM 9 CB SER A 0 125.578 2.312 -28.214 1.00155.09 C
+ANISOU 9 CB SER A 0 19671 15395 23862 5752 1827 887 C
+ATOM 10 OG SER A 0 126.993 2.281 -28.131 1.00164.59 O
+ANISOU 10 OG SER A 0 20608 16866 25062 6113 1802 781 O
+ATOM 11 N MET A 1 124.096 4.270 -29.861 1.00134.87 N
+ANISOU 11 N MET A 1 17283 13123 20839 4799 1805 311 N
+ATOM 12 CA MET A 1 123.214 5.039 -30.698 1.00125.22 C
+ANISOU 12 CA MET A 1 16193 11958 19428 4369 1804 70 C
+ATOM 13 C MET A 1 122.885 4.351 -32.006 1.00124.69 C
+ANISOU 13 C MET A 1 16293 11510 19572 4225 1942 -293 C
+ATOM 14 O MET A 1 123.723 3.686 -32.606 1.00129.61 O
+ANISOU 14 O MET A 1 16868 11984 20394 4414 2057 -519 O
+ATOM 15 CB MET A 1 123.867 6.392 -30.970 1.00122.51 C
+ANISOU 15 CB MET A 1 15675 12140 18732 4254 1762 -132 C
+ATOM 16 CG MET A 1 125.074 6.368 -31.866 1.00120.74 C
+ANISOU 16 CG MET A 1 15318 12013 18544 4369 1884 -495 C
+ATOM 17 SD MET A 1 125.834 7.982 -31.850 1.00196.33 S
+ANISOU 17 SD MET A 1 24655 22193 27747 4246 1861 -642 S
+ATOM 18 CE MET A 1 126.785 7.896 -30.345 1.00132.53 C
+ANISOU 18 CE MET A 1 16264 14397 19693 4639 1728 -355 C
+ATOM 19 N GLN A 2 121.643 4.496 -32.440 1.00123.78 N
+ANISOU 19 N GLN A 2 16363 11253 19416 3898 1925 -369 N
+ATOM 20 CA GLN A 2 121.313 4.161 -33.809 1.00128.51 C
+ANISOU 20 CA GLN A 2 17093 11643 20094 3714 2020 -799 C
+ATOM 21 C GLN A 2 121.639 5.396 -34.617 1.00121.06 C
+ANISOU 21 C GLN A 2 16105 11138 18752 3541 2004 -1065 C
+ATOM 22 O GLN A 2 121.959 6.442 -34.059 1.00107.32 O
+ANISOU 22 O GLN A 2 14247 9790 16739 3528 1928 -906 O
+ATOM 23 CB GLN A 2 119.832 3.845 -33.965 1.00136.11 C
+ANISOU 23 CB GLN A 2 18240 12314 21161 3439 1994 -809 C
+ATOM 24 CG GLN A 2 119.171 3.277 -32.740 1.00148.45 C
+ANISOU 24 CG GLN A 2 19841 13613 22949 3500 1973 -376 C
+ATOM 25 CD GLN A 2 117.773 2.799 -33.042 1.00158.28 C
+ANISOU 25 CD GLN A 2 21243 14511 24385 3221 1993 -473 C
+ATOM 26 OE1 GLN A 2 116.827 3.097 -32.313 1.00163.28 O
+ANISOU 26 OE1 GLN A 2 21915 15160 24966 3070 1921 -211 O
+ATOM 27 NE2 GLN A 2 117.631 2.057 -34.134 1.00155.02 N
+ANISOU 27 NE2 GLN A 2 20902 13797 24200 3144 2095 -885 N
+ATOM 28 N SER A 3 121.547 5.280 -35.931 1.00124.66 N
+ANISOU 28 N SER A 3 16661 11530 19175 3410 2090 -1474 N
+ATOM 29 CA SER A 3 121.742 6.432 -36.781 1.00120.35 C
+ANISOU 29 CA SER A 3 16121 11369 18236 3242 2107 -1703 C
+ATOM 30 C SER A 3 121.190 6.186 -38.161 1.00125.27 C
+ANISOU 30 C SER A 3 16914 11882 18801 3073 2165 -2108 C
+ATOM 31 O SER A 3 120.746 5.090 -38.489 1.00135.86 O
+ANISOU 31 O SER A 3 18337 12848 20436 3082 2197 -2268 O
+ATOM 32 CB SER A 3 123.217 6.751 -36.923 1.00116.70 C
+ANISOU 32 CB SER A 3 15475 11153 17711 3435 2220 -1807 C
+ATOM 33 OG SER A 3 123.770 5.974 -37.974 1.00112.78 O
+ANISOU 33 OG SER A 3 15005 10478 17367 3528 2375 -2175 O
+ATOM 34 N THR A 4 121.244 7.232 -38.972 1.00116.48 N
+ANISOU 34 N THR A 4 15849 11109 17301 2928 2191 -2281 N
+ATOM 35 CA THR A 4 120.978 7.130 -40.394 1.00113.12 C
+ANISOU 35 CA THR A 4 15568 10691 16723 2823 2262 -2692 C
+ATOM 36 C THR A 4 122.118 7.839 -41.119 1.00116.32 C
+ANISOU 36 C THR A 4 15918 11410 16867 2884 2432 -2867 C
+ATOM 37 O THR A 4 123.106 8.236 -40.495 1.00117.17 O
+ANISOU 37 O THR A 4 15851 11671 16998 3007 2493 -2706 O
+ATOM 38 CB THR A 4 119.615 7.756 -40.775 1.00106.20 C
+ANISOU 38 CB THR A 4 14854 9927 15568 2568 2121 -2713 C
+ATOM 39 OG1 THR A 4 119.774 9.154 -41.043 1.00107.14 O
+ANISOU 39 OG1 THR A 4 15001 10451 15258 2480 2138 -2644 O
+ATOM 40 CG2 THR A 4 118.597 7.567 -39.657 1.00 99.42 C
+ANISOU 40 CG2 THR A 4 13990 8889 14896 2483 1956 -2396 C
+ATOM 41 N SER A 5 121.981 7.982 -42.432 1.00116.70 N
+ANISOU 41 N SER A 5 16106 11564 16670 2803 2517 -3210 N
+ATOM 42 CA SER A 5 122.975 8.671 -43.247 1.00122.60 C
+ANISOU 42 CA SER A 5 16837 12604 17144 2839 2721 -3385 C
+ATOM 43 C SER A 5 123.317 10.064 -42.713 1.00128.43 C
+ANISOU 43 C SER A 5 17501 13666 17630 2768 2748 -3105 C
+ATOM 44 O SER A 5 124.481 10.467 -42.712 1.00133.01 O
+ANISOU 44 O SER A 5 17934 14410 18193 2852 2925 -3133 O
+ATOM 45 CB SER A 5 122.473 8.779 -44.687 1.00127.34 C
+ANISOU 45 CB SER A 5 17646 13318 17418 2741 2774 -3729 C
+ATOM 46 OG SER A 5 121.108 9.163 -44.712 1.00135.31 O
+ANISOU 46 OG SER A 5 18807 14370 18235 2568 2576 -3643 O
+ATOM 47 N ASN A 6 122.303 10.783 -42.240 1.00122.78 N
+ANISOU 47 N ASN A 6 16868 13033 16750 2608 2581 -2859 N
+ATOM 48 CA ASN A 6 122.460 12.194 -41.897 1.00114.44 C
+ANISOU 48 CA ASN A 6 15777 12275 15429 2507 2620 -2639 C
+ATOM 49 C ASN A 6 122.348 12.537 -40.412 1.00108.55 C
+ANISOU 49 C ASN A 6 14870 11544 14832 2498 2474 -2282 C
+ATOM 50 O ASN A 6 122.712 13.640 -40.004 1.00110.16 O
+ANISOU 50 O ASN A 6 14983 11984 14890 2435 2531 -2135 O
+ATOM 51 CB ASN A 6 121.461 13.034 -42.695 1.00113.00 C
+ANISOU 51 CB ASN A 6 15832 12254 14850 2339 2583 -2658 C
+ATOM 52 CG ASN A 6 121.646 12.886 -44.191 1.00118.14 C
+ANISOU 52 CG ASN A 6 16648 12982 15257 2366 2743 -2999 C
+ATOM 53 OD1 ASN A 6 122.765 12.952 -44.698 1.00122.16 O
+ANISOU 53 OD1 ASN A 6 17097 13580 15737 2449 2985 -3154 O
+ATOM 54 ND2 ASN A 6 120.546 12.672 -44.905 1.00118.96 N
+ANISOU 54 ND2 ASN A 6 16946 13074 15179 2302 2609 -3139 N
+ATOM 55 N HIS A 7 121.845 11.605 -39.608 1.00100.48 N
+ANISOU 55 N HIS A 7 13810 10269 14098 2560 2305 -2149 N
+ATOM 56 CA HIS A 7 121.657 11.871 -38.183 1.00 91.49 C
+ANISOU 56 CA HIS A 7 12535 9160 13066 2569 2162 -1799 C
+ATOM 57 C HIS A 7 122.134 10.725 -37.300 1.00 97.74 C
+ANISOU 57 C HIS A 7 13180 9725 14232 2793 2117 -1685 C
+ATOM 58 O HIS A 7 122.456 9.647 -37.791 1.00101.23 O
+ANISOU 58 O HIS A 7 13643 9923 14898 2924 2188 -1876 O
+ATOM 59 CB HIS A 7 120.189 12.175 -37.884 1.00 86.30 C
+ANISOU 59 CB HIS A 7 12021 8464 12306 2383 1977 -1628 C
+ATOM 60 CG HIS A 7 119.634 13.303 -38.694 1.00101.46 C
+ANISOU 60 CG HIS A 7 14094 10603 13853 2201 2000 -1699 C
+ATOM 61 ND1 HIS A 7 119.265 13.157 -40.015 1.00 99.83 N
+ANISOU 61 ND1 HIS A 7 14076 10384 13472 2153 2049 -1976 N
+ATOM 62 CD2 HIS A 7 119.401 14.600 -38.379 1.00 89.60 C
+ANISOU 62 CD2 HIS A 7 12588 9342 12114 2078 1988 -1527 C
+ATOM 63 CE1 HIS A 7 118.823 14.314 -40.476 1.00 97.86 C
+ANISOU 63 CE1 HIS A 7 13944 10363 12875 2029 2062 -1939 C
+ATOM 64 NE2 HIS A 7 118.896 15.206 -39.503 1.00 93.14 N
+ANISOU 64 NE2 HIS A 7 13235 9899 12253 1975 2035 -1667 N
+END
SEQUENCE_GROUP Group_B 1 351 2-5
SEQUENCE_GROUP Group_C 12 14 -1 seq1 seq2 seq3
PROPERTIES Group_A description=This is the description colour=Helix Propensity pidThreshold=0 outlineColour=red displayBoxes=true displayText=false colourText=false textCol1=black textCol2=black textColThreshold=0
-PROPERTIES Group_B outlineColour=red colour=None
+PROPERTIES Group_B outlineColour=green colour=None
PROPERTIES Group_C colour=Clustal
CLUSTAL
-FER_CAPAA/1-97 -----------------------------------------------------------A
-FER_CAPAN/1-144 MA------SVSATMISTSFMPRKPAVTSL-KPIPNVGE--ALFGLKS-A--NGGKVTCMA
-FER1_SOLLC/1-144 MA------SISGTMISTSFLPRKPAVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMA
-Q93XJ9_SOLTU/1-144 MA------SISGTMISTSFLPRKPVVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMA
-FER1_PEA/1-149 MATT---PALYGTAVSTSFLRTQPMPMSV-TTTKAFSN--GFLGLKT-SLKRGDLAVAMA
-Q7XA98_TRIPR/1-152 MATT---PALYGTAVSTSFMRRQPVPMSV-ATTTTTKAFPSGFGLKSVSTKRGDLAVAMA
-FER1_MESCR/1-148 MAAT--TAALSGATMSTAFAPK--TPPMTAALPTNVGR--ALFGLKS-SASR-GRVTAMA
-FER1_SPIOL/1-147 MAAT--TTTMMG--MATTFVPKPQAPPMMAALPSNTGR--SLFGLKT-GSR--GGRMTMA
-FER3_RAPSA/1-96 -----------------------------------------------------------A
-FER1_ARATH/1-148 MAST----ALSSAIVGTSFIRRSPAPISLRSLPSANTQ--SLFGLKS-GTARGGRVTAMA
-FER_BRANA/1-96 -----------------------------------------------------------A
-FER2_ARATH/1-148 MAST----ALSSAIVSTSFLRRQQTPISLRSLPFANTQ--SLFGLKS-STARGGRVTAMA
-Q93Z60_ARATH/1-118 MAST----ALSSAIVSTSFLRRQQTPISLRSLPFANTQ--SLFGLKS-STARGGRVTAMA
-FER1_MAIZE/1-150 MATVLGSPRAPAFFFSSSSLRAAPAPTAV--ALPAAKV--GIMGRSA-SSRR--RLRAQA
-O80429_MAIZE/1-140 MAAT---------ALSMSILR---APPPCFSSPLRLRV--AVAKPLA-APMRRQLLRAQA
-1A70|/1-97 -----------------------------------------------------------A
-
-FER_CAPAA/1-97 SYKVKLITPDGPIEFDCPDDVYILDQAEEAGHDLPYSCRAGSCSSCAGKIAGGAVDQTDG
-FER_CAPAN/1-144 SYKVKLITPDGPIEFDCPDNVYILDQAEEAGHDLPYSCRAGSCSSCAGKIAGGAVDQTDG
-FER1_SOLLC/1-144 SYKVKLITPEGPIEFECPDDVYILDQAEEEGHDLPYSCRAGSCSSCAGKVTAGSVDQSDG
-Q93XJ9_SOLTU/1-144 SYKVKLITPDGPIEFECPDDVYILDQAEEEGHDLPYSCRAGSCSSCAGKVTAGTVDQSDG
-FER1_PEA/1-149 SYKVKLVTPDGTQEFECPSDVYILDHAEEVGIDLPYSCRAGSCSSCAGKVVGGEVDQSDG
-Q7XA98_TRIPR/1-152 TYKVKLITPEGPQEFDCPDDVYILDHAEEVGIELPYSCRAGSCSSCAGKVVNGNVNQEDG
-FER1_MESCR/1-148 AYKVTLVTPEGKQELECPDDVYILDAAEEAGIDLPYSCRAGSCSSCAGKVTSGSVNQDDG
-FER1_SPIOL/1-147 AYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQ
-FER3_RAPSA/1-96 TYKVKFITPEGEQEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQ
-FER1_ARATH/1-148 TYKVKFITPEGELEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQ
-FER_BRANA/1-96 TYKVKFITPEGEQEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDE
-FER2_ARATH/1-148 TYKVKFITPEGEQEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQ
-Q93Z60_ARATH/1-118 TYKVKFITPEGEQEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQ
-FER1_MAIZE/1-150 TYNVKLITPEGEVELQVPDDVYILDQAEEDGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQ
-O80429_MAIZE/1-140 TYNVKLITPEGEVELQVPDDVYILDFAEEEGIDLPFSCRAGSCSSCAGKVVSGSVDQSDQ
-1A70|/1-97 AYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQ
-
-FER_CAPAA/1-97 NFLDDDQLEEGWVLTCVAYPQSDVTIETHKEAELVG-
-FER_CAPAN/1-144 NFLDDDQLEEGWVLTCVAYPQSDVTIETHKEAELVG-
-FER1_SOLLC/1-144 NFLDEDQEAAGFVLTCVAYPKGDVTIETHKEEELTA-
-Q93XJ9_SOLTU/1-144 KFLDDDQEAAGFVLTCVAYPKCDVTIETHKEEELTA-
-FER1_PEA/1-149 SFLDDEQIEAGFVLTCVAYPTSDVVIETHKEEDLTA-
-Q7XA98_TRIPR/1-152 SFLDDEQIEGGWVLTCVAFPTSDVTIETHKEEELTA-
-FER1_MESCR/1-148 SFLDDDQIKEGWVLTCVAYPTGDVTIETHKEEELTA-
-FER1_SPIOL/1-147 SFLDDDQIDEGWVLTCAAYPVSDVTIETHKEEELTA-
-FER3_RAPSA/1-96 SFLDDDQIAEGFVLTCAAYPTSDVTIETHREEDMV--
-FER1_ARATH/1-148 SFLDDEQIGEGFVLTCAAYPTSDVTIETHKEEDIV--
-FER_BRANA/1-96 SFLDDDQIAEGFVLTCAAYPTSDVTIETHKEEELV--
-FER2_ARATH/1-148 SFLDDEQMSEGYVLTCVAYPTSDVVIETHKEEAIM--
-Q93Z60_ARATH/1-118 SFLDD--------------------------------
-FER1_MAIZE/1-150 SYLDDGQIADGWVLTCHAYPTSDVVIETHKEEELTGA
-O80429_MAIZE/1-140 SFLNDNQVADGWVLTCAAYPTSDVVIETHKEDDLL--
-1A70|/1-97 SFLDDDQIDEGWVLTCAAYPVSDVTIETHKKEELTA
-
+FER_CAPAA/1-97 -----------------------------------------------------------A 1
+FER_CAPAN/1-144 MA------SVSATMISTSFMPRKPAVTSL-KPIPNVGE--ALFGLKS-A--NGGKVTCMA 48
+FER1_SOLLC/1-144 MA------SISGTMISTSFLPRKPAVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMA 48
+Q93XJ9_SOLTU/1-144 MA------SISGTMISTSFLPRKPVVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMA 48
+FER1_PEA/1-149 MATT---PALYGTAVSTSFLRTQPMPMSV-TTTKAFSN--GFLGLKT-SLKRGDLAVAMA 53
+
+FER_CAPAA/1-97 SYKVKLI 8
+FER_CAPAN/1-144 SYKVKLI 55
+FER1_SOLLC/1-144 SYKVKLI 55
+Q93XJ9_SOLTU/1-144 SYKVKLI 55
+FER1_PEA/1-149 SYKVKLV 60
<mapID target="home" url="html/index.html" />
<mapID target="new" url="html/whatsNew.html"/>
- <mapID target="release" url="html/releases.html#Jalview.2.10.3"/>
+ <mapID target="release" url="html/releases.html#Jalview.$$Version-Rel$$"/>
<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="pdbmcviewer" url="html/features/pdbviewer.html"/>
<mapID target="pdbjmol" url="html/features/jmol.html"/>
<mapID target="chimera" url="html/features/chimera.html"/>
+ <mapID target="chimera.annotxfer" url="html/features/chimera.html#annotxfer"/>
<mapID target="varna" url="html/features/varna.html"/>
<mapID target="xsspannotation" url="html/features/xsspannotation.html"/>
<mapID target="preferences" url="html/features/preferences.html"/>
<mapID target="annotations.fileformat" url="html/features/annotationsFormat.html"/>
<mapID target="features.fileformat" url="html/features/featuresFormat.html"/>
<mapID target="features.featureschemes" url="html/features/featureschemes.html"/>
- <mapID target="das.settings" url="html/features/dassettings.html"/>
- <mapID target="das.viewing" url="html/features/dasfeatures.html"/>
<mapID target="edit" url="html/editing/index.html"/>
<mapID target="jalarchive" url="html/features/jalarchive.html"/>
<mapID target="multipleviews" url="html/features/multipleViews.html"/>
<tocitem text="Jalview Documentation" target="home" expand="true">
<tocitem text="What's new" target="new" expand="true">
<tocitem text="Latest Release Notes" target="release"/>
+ <tocitem text="Structure Chooser" target="pdbchooser"/>
+ <tocitem text="Chimera Annotation Exchange" target="chimera.annotxfer"/>
</tocitem>
<tocitem text="Editing Alignments" target="edit" />
<tocitem text="Feature Colourschemes" target="features.featureschemes" />
<tocitem text="User Defined Sequence Features" target="seqfeatcreat" />
<tocitem text="Editing Sequence Features" target="seqfeatedit" />
- <tocitem text="DAS Feature Retrieval" target="das.viewing" />
- <tocitem text="DAS Feature Settings" target="das.settings" />
<tocitem text="HTML annotation report" target="io.seqreport" />
</tocitem>
<tocitem text="Alignment Conservation Analysis" target="aacon" />
<tocitem text="Multi-Harmony Alignment Analysis" target="shmrws" />
<tocitem text="Sequence Retrieval" target="seqfetch" />
- <tocitem text="Database Reference Retrieval" target="dbreffetcher" />
- <tocitem text="DAS Feature Retrieval" target="das.viewing" />
+ <tocitem text="Database Reference Retrieval" target="dbreffetcher" />
</tocitem>
<tocitem text="Colour Schemes" target="colours" expand="false">
<em>Undo / redo</em> - editing of sequences (insertion/removal of
gaps, removal of sequences, trimming sequences etc) may be undone or
redone at any time using the appropriate menu items from the edit
- menu. The undo history list only allows a maximum of 10 actions.
+ menu.
<p>
<em>Trimming alignment</em> - First select a column by clicking the
scale indicator (above the sequences) The alignment may then be
structure in the alignment. The regions used to calculate
the superposition will be highlighted using the 'Cartoon'
rendering style, and the remaining data shown as a chain
- trace.<br/><br/>
+ trace.<br />
+ <br />
</em></li>
- <li><strong><a name="experimental">EXPERIMENTAL FEATURES</a></strong><br/>
- <em>
- These are only available if the <strong>Tools→Enable
- Experimental Features</strong> option is enabled. (Since Jalview 2.10.2)</em>
- <ul>
- <li><strong>Write Jalview features</strong><br /> <em>Selecting
- this option will create new residue attributes for any
- features currently visible in the associated alignment
- views, allowing those positions to be selected and
- analysed with via Chimera's 'Render by Attribute' tool
- (found in the Tools submenu called Structure Analysis).<br />
- <br />If you use this option, please remember to select
- the <em>Refresh Menus</em> option in Chimera's Render by
- Attribute dialog box in order to see the attributes
- derived from Jalview sequence features.
- </em><br />
- <a href="https://issues.jalview.org/browse/JAL-2295">View
- this function's issue in Jalview's bug tracker</a></li>
- <li><strong>Fetch Chimera Attributes</strong><br /> <em>This
- submenu lists available Chimera residue attributes that
- can be imported as Jalview features on associated
- sequences.<br />This is particularly useful for
- transferring quantitative positional annotation. For
- example, structure similarity for an alignment can be
- visualised by transferring the local RMSD attributes
- generated by Chimera's Match->Align tool onto aligned
- sequences and displayed with a <a
- href="featureschemes.html">Graduated feature colour
- scheme</a>.
- </em><a href="https://issues.jalview.org/browse/JAL-2296">View
- this function's issue in Jalview's bug tracker</a></li>
- </ul></li>
- <li><strong>Help<br>
+ <li><a name="annotxfer"><strong>Write Jalview
+ features</strong></a><br /> <em>Selecting this option will create
+ new residue attributes for any features currently visible in
+ the associated alignment views, allowing those positions to
+ be selected and analysed with via Chimera's 'Render by
+ Attribute' tool (found in the Tools submenu called Structure
+ Analysis).<br /> <br />If you use this option, please
+ remember to select the <em>Refresh Menus</em> option in
+ Chimera's Render by Attribute dialog box in order to see the
+ attributes derived from Jalview sequence features.
+ </em></li>
+ <li><strong>Fetch Chimera Attributes</strong><br /> <em>This
+ submenu lists available Chimera residue attributes that can
+ be imported as Jalview features on associated sequences.<br />This
+ is particularly useful for transferring quantitative
+ positional annotation. For example, structure similarity for
+ an alignment can be visualised by transferring the local
+ RMSD attributes generated by Chimera's Match->Align tool
+ onto aligned sequences and displayed with a <a
+ href="featureschemes.html">Graduated feature colour
+ scheme</a>. </li>
+ </ul></li>
+ <li><strong>Help<br>
</strong>
<ul>
<li><strong>Chimera Help<br>
</tr>
<tr>
<td>
- <div align="center">-dasserver nickname=URL</div>
- <td>
- <div align="left">
- Add and enable a <a href="dassettings.html">DAS server</a>
- with given nickname (alphanumeric or underscores only) for
- retrieval of features for all alignments<br> Sources that
- also support the sequence command may be specified by
- prepending the URL with 'sequence:'<br> <em>e.g.</em>
- sequence:http://localdas.somewhere.org/das/source
- </div>
- </td>
- </tr>
- <tr>
- <td>
- <div align="center">-fetchfrom nickname</div>
- <td>
- <div align="left">
- Query a <a href="dassettings.html">DAS source</a> called
- nickname for features for the alignments and display them
- </div>
- </td>
- </tr>
- <tr>
- <td>
<div align="center">-groovy FILE/URL</div>
<td>
<div align="left">Execute groovy script in FILE (where
provided by InstallAnywhere any output from the application will be
sent to output.txt, not standard out.<br> The Jalview
application also requires a number of additional libraries on the
- class path. The command line below adds the Jalview installation's
- 'lib' directory to the list of directories that are searched for
- jars to be added to the classpath:
+ class path. The command line below adds all the jar files in the
+ Jalview installation's 'lib' directory to the classpath, as well as
+ the Jalview application jar file:
</p>
- <pre>java -Djava.ext.dirs=$INSTALL_DIR$/lib -cp $INSTALL_DIR$/jalview.jar jalview.bin.Jalview -open [FILE] </pre>
+ <pre>java -classpath "$INSTALL_DIR$/lib/*:$INSTALL_DIR$/jalview.jar" jalview.bin.Jalview -open [FILE] </pre>
<p>
Use '-help' to get more information on the <a
href="clarguments.html">command line arguments</a> that
+++ /dev/null
-<html>
-<!--
- * 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.
- -->
-<head>
-<title>DAS Features</title>
-</head>
-
-<body>
- <p>
- <strong>DAS Sequence Feature Retrieval</strong>
- </p>
- <p>Jalview includes a client for retrieving sequences and their
- features via the Distributed Annotation System.</p>
- <ol>
- <li>Open the Feature Settings panel by selecting "View
- -> Feature Settings..."</li>
- <li>Click on the "<a href="dassettings.html">DAS
- Settings</a>" tabbed pane.
- </li>
- <li>Select the sources to use for DAS feature retrieval, then
- click the "Fetch DAS Features" button.
- <ul>
- <li>Cancelling Feature Retrieval<br> Press the <strong>Cancel
- Fetch</strong> button to immediately stop feature retrieval. This
- will not remove any features already added to the alignment,
- but will halt any outstanding DAS requests.<em>The cancel
- fetch button is of particular use when one or more DAS
- annotation servers are not responding!</em>
- </ul>
- </li>
- </ol>
- <p>
- If your DAS source selection contains sources which use UniProt
- accession ids, you will be asked whether Jalview should find UniProt
- Accession ids for the given sequence names. It is important to
- realise that many DAS sources only use UniProt accession ids, rather
- than Swissprot/UniProt sequence names.<br> The <a
- href="../webServices/dbreffetcher.html">database
- reference fetcher</a> documentation describes how Jalview discovers
- what database references are appropriate for the sequences in the
- alignment.
- <ul>
- <li><em>Note</em><br> Please remember to save your
- alignment if either the start/end numbering, or the sequence IDs
- were updated during the ID retrieval process.</li>
- </ul>
- <p>
- <p>
- <em>DAS support was introduced in Jalview Version 2.1.</em>
- </p>
- <br />
- <p>
- <em>The DAS registry at http://www.dasregistry.org was
- decommissioned early in 2015. An unmaintained mirror is currently
- hosted at http://www.ebi.ac.uk/das-srv/registry/.</em>
- </p>
- <p>
-</body>
-</html>
+++ /dev/null
-<html>
-<!--
- * 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.
- -->
-<head>
-<title>DAS Settings</title>
-</head>
-
-<body>
- <p>
- <strong>DAS Settings</strong>
- </p>
- <p>
- Jalview can retrieve sequences and features from many <a
- href="http://biodas.org/">DAS</a> sources. The DAS sources
- that it uses are discovered and selected <em>via</em> the DAS
- settings panel, opened either from the <a
- href="featuresettings.html">View→Feature Settings</a> dialog
- box from the alignment window's menu bar, or the <a
- href="featuresettings.html">Tools→Preferences</a>
- dialog box opened from the Desktop menu bar.
- </p>
- <p>
- <img src="das.gif">
- <p>The available sources are listed in the table using each
- source's Nickname as its identifier. Clicking on a source's entry in
- the table reveals more information about that service in the panel
- to the right. Select the tickbox in the "Use Source"
- column for a source to add it to the set Jalview queries for
- alignment and sequence features.</p>
- <p>You can filter the visible DAS sources by authority, type and
- "label". You should read the DAS documentation to
- understand more about these values.
- <p>
- <strong>Updating the list of sources</strong>
- </p>
- <p>
- When the DAS Settings panel is first opened, and when the <strong>'Refresh
- source'</strong> buton is pressed, a list of DAS sources is retrieved from
- the DAS registry URL. Note that the registry hosted at
- http://www.dasregistry.org/das/ was retired at the start of 2015. An
- alternative service is currently hosted at
- http://www.ebi.ac.uk/das-srv/registry/das/. To connect to this
- service, ensure your .jalview_properties file includes the following
- line:<br> <b>DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/</b>
- </p>
- <p>
- <strong>Adding your own DAS Sources</strong>
- </p>
- <p>You can add your own DAS source to the list by clicking the
- "Add Local Source" button. Enter the URL and nickname of
- your additional service. It should be noted that Jalview 2.1 will
- not query additional sources for more information, but this will be
- implemented in future editions.
- <p>
-</body>
-</html>
contains tab separated text fields. <strong>No comments are
allowed</strong>.
</p>
- <p>The first set of lines contain type definitions:
+ <p>
+ <strong>Feature Colours</strong>
+ </p>
+ <p>The first set of lines contain feature type definitions and their colours:
<pre>
<strong><em>Feature label</em>	<em>Feature Colour</em>
<!-- 	<em>Feature links</em> --></strong>
<ul>
<li>A single colour specified as either a red,green,blue 24 bit
triplet in hexadecimal (eg. 00ff00) or as comma separated numbers
- (ranging from 0 to 255))</li>
+ (ranging from 0 to 255))<br>
+ (For help with colour values, see <a href="https://www.w3schools.com/colors/colors_converter.asp">https://www.w3schools.com/colors/colors_converter.asp</a>.)</li>
<li>A <a href="featureschemes.html">graduated colourscheme</a>
specified as a "|" separated list of fields: <pre>
-[label|]<mincolor>|<maxcolor>|[absolute|]<minvalue>|<maxvalue>[|<thresholdtype>|[<threshold value>]]
+[label <em>or</em> score<em> or</em> attribute|attName|]<mincolor>|<maxcolor>|[absolute|]<minvalue>|<maxvalue>[|<novalue>][|<thresholdtype>|[<threshold value>]]
</pre> The fields are as follows:
<ul>
- <li><em>label</em><br> Indicate that the feature
+ <li><em>label</em><br> Indicates that the feature
description should be used to create a colour for features of
this type.<br> <em>Note: if no threshold value is
- needed then the final '|' may be omitted.<br> This
+ needed then only 'label' is required.<br> This
keyword was added in Jalview 2.6
</em></li>
+ <li><em>score</em><br> Indicates that the feature
+ score should be used to create a graduated colour for features of
+ this type, in conjunction with mincolor, maxcolor.<br><em>This keyword was added in Jalview 2.11.
+ It may be omitted (score is the default) if mincolor and maxcolor are specified.
+ </em></li>
+
+ <li><em>attribute|attName</em><br> Indicates that the value of feature
+ attribute 'attName' should be used to create a colour for features of
+ this type.
+ <br>For example, <em>attribute|clinical_significance</em> to colour by clinical_significance.
+ <br>To colour by range of a numeric attribute, include <em>mincolor</em> and <em>maxcolor</em>, or omit to colour by text (category).
+ <br>(Note: the value of the attribute used for colouring will also be shown in the tooltip as you mouse over features.)
+ <br>A sub-attribute should be written as, for example, CSQ:IMPACT.
+ <br><em>This keyword was added in Jalview 2.11</em></li>
+
<li><em>mincolor</em> and <em>maxcolor</em><br> Colour
triplets specified as hexadecimal or comma separated values
(may be left blank for a <em>label</em> style colourscheme,
<li><em>minvalue</em> and <em>maxvalue</em><br>
Minimum and maximum values defining the range of scores for
- which the colour range will be defined over. If minvalue is
+ which the colour range will be defined over.<br>If minvalue is
greater than maxvalue then the linear mapping will have
negative gradient.</li>
+ <li><em>novalue</em> <br>
+ Specifies the colour to use if colouring by attribute, when the attribute is absent.
+ Valid options are <em>novaluemin, novaluemax, novaluenone</em>, to use mincolor, maxcolor, or no colour.
+ <br>If not specified this will default to novaluemin.</li>
+
<li><em>thresholdtype</em><br> Either
"none", "below", or "above". <em>below</em>
and <em>above</em> require an additional <em>threshold
</ul>
</p>
+ <p>
+ <strong>Feature Filters</strong>
+ </p>
+ <p>This section is optional, and allows one or more filters to be defined for each feature type.
+ <br>Only features that satisfy the filter conditions will be displayed.
+ <br>Begin with a line which is just STARTFILTERS, and end with a line which is just ENDFILTERS.
+ <br>Each line has the format:
+ <pre>featureType <em><tab></em> (filtercondition1) [and|or] (filtercondition2) [and|or]...<br></pre>
+ The parentheses are not needed if there is only one condition.
+ Combine multiple conditions with either <em>and</em> or <em>or</em> (but not a mixture).
+ <br>Each condition is written as:
+ <pre>Label <em>or</em> Score <em>or</em> AttributeName condition [value]</pre>
+ where either the label (description), (numeric) score, or (text or numeric) attribute is tested against the condition.
+ <br><em>condition</em> is not case sensitive, and should be one of
+ <ul>
+ <li><em>Contains</em> - description (or attribute) should contain the given value (not case sensitive); example <em>clinical_significance contains Pathogenic</em></li>
+ <li><em>NotContains</em> - description (or attribute) should not contain the given value</li>
+ <li><em>Matches</em> - description (or attribute) should match the given value (not case sensitive)</li>
+ <li><em>NotMatches</em> - description (or attribute) should not match the given value (not case sensitive)</li>
+ <li><em>Present</em> - attribute is present on the feature (no value required); example <em>CSQ:SIFT present</em></li>
+ <li><em>NotPresent</em> - attribute is not present on the feature (no value required)</li>
+ <li><em>EQ</em> - feature score, or specified attribute, is equal to the (numeric) value</li>
+ <li><em>NE, LT, LE, GT, GE</em> - tests for not equal to / less than / less than or equal to / greater than / greater than or equal to the value</li>
+ </ul>
+ A non-numeric value always fails a numeric test.<br>If either attribute name, or value to compare, contains spaces, then enclose in single quotes:
+ <em>'mutagenesis site' contains 'decreased affinity'</em>
+ <br>Tip: some examples of filter syntax are given below; or to see more, first configure colours and filters in Jalview, then <em>File | Export Features</em> to Textbox in Jalview Format.
+ <br><em>Feature filters were added in Jalview 2.11</em>
+ </p>
+
+ <p>
+ <strong>Feature Instances</strong>
+ </p>
+
<p>The remaining lines in the file are the sequence annotation
definitions, where the now defined features are attached to regions
on particular sequences. Each feature can optionally include some
descriptive text which is displayed in a tooltip when the mouse is
- near the feature on that sequence (and can also be used to generate
- a colour the feature).</p>
+ near the feature on that sequence (and may also be used to generate
+ a colour for the feature).</p>
<p>
If your sequence annotation is already available in <a href="http://gmod.org/wiki/GFF2">GFF2</a> (http://gmod.org/wiki/GFF2) or
helix	ff0000
strand	00ff00
coil	cccccc
+kdHydrophobicity	ccffcc|333300|-3.9|4.5|above|-2.0
+
+STARTFILTERS
+metal ion-binding site	Label Contains sulfur
+kdHydrophobicity	(Score LT 1.5) OR (Score GE 2.8)
+ENDFILTERS
+
Your Own description here	FER_CAPAA	-1	3	93	domain
Your Own description here	FER_CAPAN	-1	48	144	chain
Your Own description here	FER_CAPAN	-1	50	140	domain
Your Own description here	FER1_LYCES	-1	1	47	transit peptide
Your Own description here	Q93XJ9_SOLTU	-1	1	48	signal peptide
Your Own description here	Q93XJ9_SOLTU	-1	49	144	chain
-startgroup	secondarystucture
+
+STARTGROUP	secondarystucture
PDB secondary structure annotation	FER1_SPIOL	-1	52	59	strand
PDB secondary structure annotation	FER1_SPIOL	-1	74	80	helix
-endgroup	secondarystructure
+ENDGROUP	secondarystructure
+
+STARTGROUP	kd
+Hydrophobicity score by kD Q93XJ9_SOLTU -1 48 48 kdHydrophobicity 1.8
+ENDGROUP	kd
+
GFF
FER_CAPAA	GffGroup	domain	3	93	.	.
</pre>
</p> -->
<p>
<a name="align"><strong>Superposing structures based on
- their aligned sequences</strong></a><br> If several structures are
- available on the alignment, you may add additional structures to an
- existing Jmol view by selecting their entry in the appropriate
- pop-up menu. Jalview will ask you if you wish to add the structure
- to the existing alignment, and if you do, it will import and
- superimpose the new PDB file using the corresponding positions from
- the alignment. If the alignment is subsequently edited, you can use
- the <a href="#sAlign"><em>Jmol→Align</em></a> menu option from
- the menu bar of the structure view window to superpose the
- structures using the updated alignment.<br> <em>Sequence
+ their aligned sequences</strong></a><br> If several structures are shown
+ in a view, you can superimpose them using the corresponding
+ positions from the alignment via the <a href="#sAlign"><em>Jmol→Align</em></a>
+ menu option from the menu bar of the structure view window. <br> <em>Sequence
based structure superposition was added in Jalview 2.6</em>
</p>
<p>
Preferences</a> tab contains settings affecting the export of
sequence alignments and EPS files.
</li>
- <li>The <a href="dassettings.html"><strong>"DAS
- Settings"</strong> Preferences</a> tab allows you to select which DAS
- sources to use when fetching DAS Features.
- </li>
<li>The <a href="../webServices/webServicesPrefs.html"><strong>"Web
Service"</strong> Preferences</a> tab allows you to configure the <a
href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS</a>
and PDB file association (if available). The Jalview id/start-end
option is ignored if Modeller output is selected.
<p>
- <a name="editing"><strong>e"Editinge" Preferences tab</strong></a>
+ <a name="editing"><strong>"Editing" Preferences tab</strong></a>
</p>
<p>There are currently three options available which can be
selected / deselected.</p>
<p>The search history keeps up to 99 queries by default. To clear
the history, or modify the size of the history, right-click the text
box.</p>
- <img src="searchclearhist.png" width="402" height="121" align="left" />
+ <img src="searchclearhist.png" width="402" height="127" align="left" />
<p>
<strong>Other dialogs that provide a query history</strong>
</p>
href="featuresettings.html">Sequence Feature Settings</a>
dialog box. Feature colour schemes and display parameters are unique
to a particular alignment, so it is possible to colour the same
- sequence features differently in different alignment views.<br>
- Since Jalview 2.1, it is possible to add <a href="dassettings.html">DAS
- features</a> to an alignment via the DAS tabbed pane of the feature
- settings window.
+ sequence features differently in different alignment views.
</p>
<p>
<strong>View→Sequence ID Tooltip→Show
<p>
<strong>Sequence Fetcher</strong>
</p>
- <p>
- Jalview can retrieve sequences from certain databases using either
- the DBFetch service provided by the EMBL European Bioinformatics
- Institute, or, since Jalview 2.4, DAS servers capable of the <em>sequence</em>
- command (configured in <a href="dassettings.html">DAS settings</a>).
- </p>
- <p>The Sequence Fetcher can be opened via the "File"
+ <p>Jalview can retrieve sequences from a range of sequence, 3D
+ structure, genomic and domain family databases provided by EMBL-EBI.</p>
+ <p>The Sequence Fetcher can be opened via the "File"
menu on the main desktop in order to retrieve sequences as a new
alignment, or opened via the "File" menu of an existing
alignment to import additional sequences. There may be a short delay
- when the sequence fetcher is first opened, whilst Jalview compiles
- the list of available sequence datasources from the currently
- defined DAS server registry.</p>
+ when the sequence fetcher is first opened, whilst Jalview contacts each database's web API.</p>
<p>
Every time a new fetcher is opened, you will need to <strong>select
the database you want to retrieve sequences</strong> from the database
tooltips are shown if you mouse over some sources, explaining what
the database will retrieve. You can select one by using the up/down
arrow keys and hitting return, or by double clicking with the mouse.
- <br />
- <em>If you have DAS sources enabled, then you may have several
- sources for the same type of sequence identifier, and these will
- be grouped together in a sub-branch branch labeled with the
- identifier.</em>
</p>
<p>Once you have selected a sequence database, its fetcher dialog
will open. Jalview provides two types of dialog:</p>
currently selected database into the retrieval box. Finally, press
"OK" to initiate the retrieval.</li>
</ol>
- <p>
- <strong>Only retrieving part of a sequence</strong>
- </p>
- <p>
- When using DAS sources (indicated by a "<em>(DAS)</em>"),
- you can append a range in addition to a sequence ID. For example, to
- retrieve 50 residues starting at position 35 in UNIPROT sequence
- P73137 using the UNIPROT DAS server, you would enter
- "'P73137:35,84'.<br /> <em>Full support for DAS range
- queries was introduced in Jalview 2.8</em>
- </p>
<p>If you use the WSDBFetch sequence fetcher services (EMBL,
UniProt, PFAM, and RFAM) in work for publication, please cite:</p>
or <strong>"View→Nucleotide"</strong> (in the protein panel)
allows you to show or hide one or other of the linked alignment
panels.</li>
- <li>Panel heights are adjusted dragging the divider between
+ <li>Panel heights are adjusted by dragging the divider between
them using the mouse</li>
<li><a href="../menus/alwview.html"><strong>"View→New
View / Expand Views / Gather Views"</strong></a> behave as for a normal
<body>
<p>
- <strong>Structure Chooser</strong>
+ <strong>Structure Chooser Dialog Box</strong>
</p>
<p>
- The Structure Chooser interface allows you to interactively select
- which PDB structures to view for the currently selected set of
+ The Structure Chooser allows you to select
+ 3D structures to view for the currently selected set of
sequences. It is opened by selecting the <strong>"3D
- Structure Data.."</strong> option from the Sequence ID panel's <a
+ Structure Data..."</strong> option from the Sequence ID panel's <a
href="../menus/popupMenu.html">pop-up menu</a>. The dialog
provides:
</p>
<p>
<strong>Selecting and Viewing Structures</strong>
</p>
+ <p>The drop-down menu offers different options for structure
+ discovery; the 'Cached' view is shown automatically if existing
+ structure data has been imported for the selected sequences, and if
+ none is available, the import PDB/mmCIF file options are shown.</p>
<p>
Once one or more structures have been selected, pressing the <strong>View</strong>
- button will import them into <a
+ or <strong>Add</strong> button will import them <a
href="viewingpdbs.html#afterviewbutton">a new or existing
- structure view</a>.
+ structure view</a>. When multiple views are available, use the
+ drop-down menu to pick the target viewer for the structures.
</p>
<p>
<strong>Automated discovery of structure data</strong>
criteria (e.g. worst quality rather than best).</p>
<p>
- <img src="schooser_main.png" style="width: 464px; height: 369px;">
+ <img src="schooser_main.png" style="width: 499px; height: 437px;">
<!-- <p><img src="schooser_config.png" style="width: 463px; height: 369px; ">
<p><img src="schooser_drop-down.png" style="width: 464px; height: 368px; ">
<p><img src="schooser_enter-id.png" style="width: 467px; height: 373px; ">
<p><img src="schooser_from-file.png" style="width: 468px; height: 370px; ">
<p><img src="schooser_cached.png"> -->
- <br>The screenshot above shows the Structure Chooser interface
- along with the meta-data of auto-discovered structures for the
- sample alignment. If no structures were
- auto-discovered, options for manually associating PDB records will be shown (see below).
- <p>
+ <br>The screenshot above shows the Structure Chooser displayed after
+ selecting all the sequences in the Jalview example project. If no
+ structures were auto-discovered, options for manually associating
+ PDB records will be shown (see below).<p>
<strong>Exploration of meta-data for available structures</strong>
</p>
<p>Information on each structure available is displayed in columns
Columns' tab and tick the columns which you want to see.</p>
<p>
<img src="schooser_enter-id.png"
- style="width: 464px; height: 369px;">
+ style="width: 464px; height: 173px;">
<br/>
<strong>Manual selection/association of PDB files with
Sequences</strong>
provided it is installed and can be launched by Jalview. The default
viewer can be configured in the <a href="preferences.html#structure">Structure
tab</a> in the <strong>Tools→Preferences</strong> dialog box.
+
<p>
Structure data imported into Jalview can also be processed to
display secondary structure and temperature factor annotation. See
for more information.
</p>
<p>
- <strong><a name="afterviewbutton">After pressing the
- 'View' button in the Structure Chooser</a></strong><br /> The behaviour of
- the 'View' button depends on the number of structures selected, and
- whether structure views already exist for the selected structures or
- aligned sequences.
+ <img src="schooser_viewbutton.png"
+ style="width: 465px; height: 81px" /><br/> <strong><a
+ name="afterviewbutton">Controlling where the new structures
+ will be shown</a></strong>
+ <br />The Structure Chooser offers several options
+ for viewing a structure. <br/><strong>New View</strong> will open a new
+ structure viewer for the selected structures, but if there are views
+ already open, you can select which one to use, and press the <strong>Add</strong>
+ button. Jalview can automatically superimpose new structures based
+ on the linked alignments - but if this is not desirable, simple
+ un-tick the <strong>Superpose Structures</strong> checkbox.
+
</p>
- <p>If multiple structures are selected, then Jalview will always
- create a new structure view. The selected structures will be
- imported into this view, and superposed with the matched positions
- from the aligned sequences. A message in the structure viewer's
- status bar will be shown if not enough aligned columns were
- available to perform a superposition.</p>
<p>
- If a <strong>single</strong> PDB structure is selected, one of the
- following will happen:
+ <em>Superposing structures</em><br/>Jalview superposes structures using
+ the visible portions of any associated sequence alignments. A
+ message in the structure viewer's status bar will be shown if not
+ enough aligned columns were available to perform a superposition.
</p>
-
- <ul>
- <li>If no structures are open, then an interactive display of
- the structure will be opened in a new window.</li>
-
- <li>If another structure is already shown for the current
- alignment, then you will be asked if you want to add and <a
- href="jmol.html#align"></a> to the structure in the existing view.
- (<em>new feature in Jalview 2.6</em>).
- </li>
-
- <li>If the structure is already shown, then you will be
- prompted to associate the sequence with an existing view of the
- selected structure. This is useful when working with multi-domain
- or multi-chain PDB files.</li>
-
- <li style="list-style: none">See the <a href="jmol.html">Jmol
- </a> and <a href="chimera.html">Chimera</a> PDB viewer help pages for
- more information about the display.
- </li>
- </ul>
-
+ <p>
+ See the <a href="jmol.html">Jmol
+ </a> and <a href="chimera.html">Chimera</a> help pages for
+ more information about their capabilities.</p>
+
<p>
<strong>Retrieving sequences from the PDB</strong><br>You can
! <string>-Xms2M</string>
! <string>-Xmx64M</string>
</array>
-</pre> Exchange the above two string tags for : <pre>
+</pre>Exchange the above two string tags for : <pre>
<string>-Xms500M</string>
<string>-Xmx1000M</string>
</pre>
the file and try to start Jalview in the normal way. If it doesn't
start, see below...</li>
</ul>
+ <p>
+ <em>Please Note:</em> We do modify the default memory settings in
+ Jalview from time to time, so you may find different numbers to
+ those shown in the examples above.
+ </p>
<font size="3"><em>Jalview doesn't start... What do the
memory settings mean ?<a name="memsetting"></a>
</em></font>
enlighten us if you know better!). Our experiments found 1000m to be
the biggest setting that could be used on a 1GB machine. Just try
reducing the sizes until Jalview starts up properly!</p>
+ <p>
+ We increased the default memory in Jalview 2.10.5 to 1G. To launch
+ Jalview with the pre 2.10.5 default memory allocation, use the <a
+ href="http://www.jalview.org/webstart/jalview_256MB.jnlp">Jalview
+ 256MB JNLP</a>.
+ </p>
<p> </p>
</body>
</html>
href="../features/featuresettings.html">Sequence
Feature Settings...</a> </strong><br> <em>Opens the
Sequence Feature Settings dialog box to control the colour
- and display of sequence features on the alignment, and
- configure and retrieve features from DAS annotation
- servers.</em></li>
+ and display of sequence features on the alignment.</em></li>
<li><strong>Sequence ID Tooltip</strong><em>
(application only) <br>This submenu's options allow the
inclusion or exclusion of non-positional sequence features
is dynamic, and may contain user-defined web service entries in
addition to any of the following ones:</em>
<ul>
- <li><strong>Fetch DB References</strong><br> <em>This
- submenu contains options for accessing any of the database
- services that Jalview is aware of (e.g. DAS sequence servers
- and the WSDBFetch service provided by the EBI) to verify
- sequence start/end positions and retrieve all database cross
- references and PDB ids associated with all or just the
- selected sequences in the alignment.
- <ul>
- <li>'Trim Retrieved Sequences' - when checked, Jalview
- will discard any additional sequence data for accessions
- associated with sequences in the alignment. <br> <strong>Note:
- Disabling this could cause out of memory errors when
- working with genomic sequence records !</strong><br> <strong>Added
- in Jalview 2.8.1</strong>
- </li>
- <li>'Standard Databases' will check sequences against
- the EBI databases plus any active DAS sequence sources</li>
- </ul> Other sub-menus allow you to pick a specific source to query
- - sources are listed alphabetically according to their
- nickname.
- </em><br></li>
- </ul>
+ <li><strong>Fetch DB References</strong><br> <em>This
+ submenu contains options for accessing any of the database
+ services that Jalview is aware of (e.g. those provided by
+ EMBL-EBI) to verify sequence start/end positions and retrieve all
+ database cross references and PDB ids associated with all or just
+ the selected sequences in the alignment.
+ <ul>
+ <li>'Trim Retrieved Sequences' - when checked, Jalview will
+ discard any additional sequence data for accessions associated
+ with sequences in the alignment. <br> <strong>Note:
+ Disabling this could cause out of memory errors when working
+ with genomic sequence records !</strong><br> <strong>Added
+ in Jalview 2.8.1</strong>
+ </li>
+ <li>'Standard Databases' will check sequences against the
+ EBI databases.</li>
+ </ul> Other sub-menus allow you to pick a specific source to query -
+ sources are listed alphabetically according to their nickname.
+ </em><br></li>
+ </ul>
<p>Selecting items from the following submenus will start a
remote service on compute facilities at the University of Dundee,
or elsewhere. You need a continuous network connection in order to
<li><strong><a href="../features/featuresettings.html">Sequence
Feature Settings...</a></strong><em><br> Opens the Sequence
Feature Settings dialog box to control the colour and display of
- sequence features on the alignment, and configure and retrieve
- features from DAS annotation servers.</em></li>
+ sequence features on the alignment.</em></li>
<li><strong>Sequence ID Tooltip</strong><em> (application
only) <br>This submenu's options allow the inclusion or
exclusion of non-positional sequence features or database cross
the <a href="../features/groovy.html">Groovy Console</a> for
interactive scripting.
</em><strong><br></strong></li>
- <li><strong>Enable Experimental Features</strong> <em>Enable or disable <a href="../whatsNew.html#experimental">features still under development</a> in Jalview's user interface. This setting is remembered in your preferences.</em>
+ <!-- <li><strong>Enable Experimental Features</strong> <em>Enable or disable <a href="../whatsNew.html#experimental">features still under development</a> in Jalview's user interface. This setting is remembered in your preferences.</em> -->
</ul></li>
<li><strong>Vamsas</strong> <em>For more details, read the
dynamic, and may contain user-defined web service entries in
addition to any of the following ones:</em>
<ul>
- <li><strong>Fetch DB References</strong><br> <em>This
- submenu contains options for accessing any of the database
- services that Jalview is aware of (e.g. DAS sequence servers and
- the WSDBFetch service provided by the EBI) to verify sequence
- start/end positions and retrieve all database cross references
- and PDB ids associated with all or just the selected sequences
- in the alignment.
- <ul>
+ <li><strong>Fetch DB References</strong><br> <em>This submenu
+ contains options for accessing any of the database services that
+ Jalview is aware of (e.g services provided by the EBI) to verify
+ sequence start/end positions and retrieve all database cross
+ references and PDB ids associated with all or just the selected
+ sequences in the alignment.
+ <ul>
<li>'Retrieve full Sequence' - when checked, Jalview will
retrieve the full sequence for any accessions associated
with sequences in the alignment. <br> <strong>Note:
in Jalview 2.8.1</strong>
</li>
<li>'Standard Databases' will check sequences against the
- EBI databases plus any active DAS sequence sources<</li>
+ EBI databases</li>
</ul> Other submenus allow you to pick a specific source to query -
sources are listed alphabetically according to their nickname.
</em></li>
</div>
</td>
</tr>
+
+ <td width="60" nowrap>
+ <div align="center">
+ <strong><a name="Jalview.2.11.0">2.11.0</a><br />
+ <em>29/01/2019</em></strong>
+ </div>
+ </td>
+ <td><div align="left">
+ <em>Deprecations</em>
+ <ul>
+ <li>
+ <!-- JAL-3035 -->DAS sequence retrieval and annotation
+ capabilities removed from the Jalview Desktop
+ </li>
+ </ul>
+ <em>Release Processes</em>
+ <ul>
+ <li>Atlassian Bamboo continuous integration server for unattended Test Suite execution</li>
+ <li><!-- JAL-2864 -->Memory test suite to detect leaks in common operations</li>
+ </ul>
+ </div></td>
+ <td><div align="left">
+ <em></em>
+ <ul>
+ <li>
+ <!-- JAL-2865 -->Jalview hangs when closing windows
+ or the overview updates with large alignments.
+ </li>
+ <li>
+ <!-- JAL-2865 -->Tree and PCA calculation fails for selected
+ region if columns were selected by dragging right-to-left
+ and the mouse moved to the left of the first column.
+ </li>
+ </ul>
+ <em>Editing</em>
+ <ul>
+ <li>
+ <!-- JAL-2822 -->Start and End should be updated when
+ sequence data at beginning or end of alignment added/removed
+ via 'Edit' sequence
+ </li>
+ <li>
+ <!-- JAL-2541 -->Delete/Cut selection doesn't relocate
+ sequence features correctly when start of sequence is
+ removed (Known defect since 2.10)
+ </li>
+ <li>
+ <!-- JAL- -->
+ </li>
+ </ul>
+ </div></td>
+ </tr>
+ <tr>
+ <td width="60" nowrap>
+ <div align="center">
+ <strong><a name="Jalview.2.10.5">2.10.5</a><br /> <em>10/09/2018</em></strong>
+ </div>
+ </td>
+ <td><div align="left">
+ <em></em>
+ <ul>
+ <li>
+ <!-- JAL-3101 -->Default memory for Jalview webstart and
+ InstallAnywhere increased to 1G.
+ </li>
+ <li>
+ <!-- JAL-247 -->Hidden sequence markers and representative
+ sequence bolding included when exporting alignment as EPS,
+ SVG, PNG or HTML. <em>Display is configured via the
+ Format menu, or for command-line use via a jalview
+ properties file.</em>
+ </li>
+ <li>
+ <!-- JAL-3076 -->Ensembl client updated to Version 7 REST
+ API and sequence data now imported as JSON.
+ </li>
+ <li>
+ <!-- JAL-3065 -->Change in recommended way of starting
+ Jalview via a Java command line: add jars in lib directory
+ to CLASSPATH, rather than via the deprecated java.ext.dirs
+ property.
+ </li>
+ </ul>
+ <em>Development</em>
+ <ul>
+ <li>
+ <!-- JAL-3047 -->Support added to execute test suite
+ instrumented with <a href="http://openclover.org/">Open
+ Clover</a>
+ </li>
+ </ul>
+ </div></td>
+ <td><div align="left">
+ <em></em>
+ <ul>
+ <li>
+ <!-- JAL-3104 -->Poorly scaled bar in quality annotation
+ row shown in Feredoxin Structure alignment view of example
+ alignment.
+ </li>
+ <li>
+ <!-- JAL-2854 -->Annotation obscures sequences if lots of
+ annotation displayed.
+ </li>
+ <li>
+ <!-- JAL-3107 -->Group conservation/consensus not shown
+ for newly created group when 'Apply to all groups'
+ selected
+ </li>
+ <li>
+ <!-- JAL-3087 -->Corrupted display when switching to
+ wrapped mode when sequence panel's vertical scrollbar is
+ visible.
+ </li>
+ <li>
+ <!-- JAL-3003 -->Alignment is black in exported EPS file
+ when sequences are selected in exported view.</em>
+ </li>
+ <li>
+ <!-- JAL-3059 -->Groups with different coloured borders
+ aren't rendered with correct colour.
+ </li>
+ <li>
+ <!-- JAL-3092 -->Jalview could hang when importing certain
+ types of knotted RNA secondary structure.
+ </li>
+ <li>
+ <!-- JAL-3095 -->Sequence highlight and selection in
+ trimmed VARNA 2D structure is incorrect for sequences that
+ do not start at 1.
+ </li>
+ <li>
+ <!-- JAL-3061 -->'.' inserted into RNA secondary structure
+ annotation when columns are inserted into an alignment,
+ and when exporting as Stockholm flatfile.
+ </li>
+ <li>
+ <!-- JAL-3053 -->Jalview annotation rows containing upper
+ and lower-case 'E' and 'H' do not automatically get
+ treated as RNA secondary structure.
+ </li>
+ <li>
+ <!-- JAL-3106 -->.jvp should be used as default extension
+ (not .jar) when saving a jalview project file.
+ </li>
+ <li>
+ <!-- JAL-3105 -->Mac Users: closing a window correctly
+ transfers focus to previous window on OSX
+ </li>
+ </ul>
+ <em>Java 10 Issues Resolved</em>
+ <ul>
+ <li>
+ <!-- JAL-2988 -->OSX - Can't save new files via the File
+ or export menus by typing in a name into the Save dialog
+ box.
+ </li>
+ <li>
+ <!-- JAL-2988 JAL-2968 -->Jalview now uses patched version
+ of the <a href="https://violetlib.org/vaqua/overview.html">VAqua5</a>
+ 'look and feel' which has improved compatibility with the
+ latest version of OSX.
+ </li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td width="60" nowrap>
+ <div align="center">
+ <strong><a name="Jalview.2.10.4b1">2.10.4b1</a><br />
+ <em>7/06/2018</em></strong>
+ </div>
+ </td>
+ <td><div align="left">
+ <em></em>
+ <ul>
+ <li>
+ <!-- JAL-2920 -->Use HGVS nomenclature for variant
+ annotation retrieved from Uniprot
+ </li>
+ <li>
+ <!-- JAL-1460 -->Windows File Shortcuts can be dragged
+ onto the Jalview Desktop
+ </li>
+ </ul>
+ </div></td>
+ <td><div align="left">
+ <em></em>
+ <ul>
+ <li>
+ <!-- JAL-3017 -->Cannot import features with multiple
+ variant elements (blocks import of some Uniprot records)
+ </li>
+ <li>
+ <!-- JAL-2997 -->Clustal files with sequence positions in
+ right-hand column parsed correctly
+ </li>
+ <li>
+ <!-- JAL-2991 -->Wrap view - export to SVG - IDs shown but
+ not alignment area in exported graphic
+ </li>
+ <li>
+ <!-- JAL-2993 -->F2/Keyboard mode edits work when Overview
+ window has input focus
+ </li>
+ <li>
+ <!-- JAL-2992 -->Annotation panel set too high when
+ annotation added to view (Windows)
+ </li>
+ <li>
+ <!-- JAL-3009 -->Jalview Desktop is slow to start up when
+ network connectivity is poor
+ </li>
+ <li>
+ <!-- JAL-1460 -->Drag URL from chrome, firefox, IE to
+ Jalview desktop on Windows doesn't open file<br /> <em>Dragging
+ the currently open URL and links from a page viewed in
+ Firefox or Chrome on Windows is now fully supported. If
+ you are using Edge, only links in the page can be
+ dragged, and with Internet Explorer, only the currently
+ open URL in the browser can be dropped onto Jalview.</em>
+ </li>
+ </ul>
+ </div></td>
+ </tr>
+ <tr>
+ <td width="60" nowrap>
+ <div align="center">
+ <strong><a name="Jalview.2.10.4">2.10.4</a><br /> <em>10/05/2018</em></strong>
+ </div>
+ </td>
+ <td><div align="left">
+ <em></em>
+ <ul>
+ <li>
+ <!-- JAL-1847 JAL-2944 -->New Structure Chooser control
+ for disabling automatic superposition of multiple
+ structures and open structures in existing views
+ </li>
+ <li>
+ <!-- JAL-984 -->Mouse cursor changes to indicate Sequence
+ ID and annotation area margins can be click-dragged to
+ adjust them.
+ </li>
+ <li>
+ <!-- JAL-2885 -->Jalview uses HTTPS for Uniprot, Xfam and
+ Ensembl services
+ </li>
+ <li>
+ <!-- JAL-2759 -->Improved performance for large alignments
+ and lots of hidden columns
+ </li>
+ <li>
+ <!-- JAL-2593 -->Improved performance when rendering lots
+ of features (particularly when transparency is disabled)
+ </li>
+ </ul>
+ </div>
+ </td>
+ <td><div align="left">
+ <ul>
+ <li>
+ <!-- JAL-2899 -->Structure and Overview aren't updated
+ when Colour By Annotation threshold slider is adjusted
+ </li>
+ <li>
+ <!-- JAL-2778 -->Slow redraw when Overview panel shown
+ overlapping alignment panel
+ </li>
+ <li>
+ <!-- JAL-2929 -->Overview doesn't show end of unpadded
+ sequence as gaps
+ </li>
+ <li>
+ <!-- JAL-2789, JAL-2893 -->Cross-reference handling
+ improved: CDS not handled correctly if transcript has no
+ UTR
+ </li>
+ <li>
+ <!-- JAL-2321 -->Secondary structure and temperature
+ factor annotation not added to sequence when local PDB
+ file associated with it by drag'n'drop or structure
+ chooser
+ </li>
+ <li>
+ <!-- JAL-2984 -->Answering 'No' to PDB Autoassociate
+ dialog doesn't import PDB files dropped on an alignment
+ </li>
+ <li>
+ <!-- JAL-2666 -->Linked scrolling via protein horizontal
+ scroll bar doesn't work for some CDS/Protein views
+ </li>
+ <li>
+ <!-- JAL-2930 -->Trackpad scrolling is broken on OSX on
+ Java 1.8u153 onwards and Java 1.9u4+.
+ </li>
+ <li>
+ <!-- JAL-2924 -->Tooltip shouldn't be displayed for empty
+ columns in annotation row
+ </li>
+ <li>
+ <!-- JAL-2913 -->Preferences panel's ID Width control is not
+ honored in batch mode
+ </li>
+ <li>
+ <!-- JAL-2945 -->Linked sequence highlighting doesn't work
+ for structures added to existing Jmol view
+ </li>
+ <li>
+ <!-- JAL-2223 -->'View Mappings' includes duplicate
+ entries after importing project with multiple views
+ </li>
+ <li>
+ <!-- JAL-2781 JAL-2780 -->Viewing or annotating Uniprot
+ protein sequences via SIFTS from associated PDB entries
+ with negative residue numbers or missing residues fails
+ </li>
+ <li>
+ <!-- JAL-2952 -->Exception when shading sequence with negative
+ Temperature Factor values from annotated PDB files (e.g.
+ as generated by CONSURF)
+ </li>
+ <li>
+ <!-- JAL-2920 -->Uniprot 'sequence variant' features
+ tooltip doesn't include a text description of mutation
+ </li>
+ <li>
+ <!-- JAL-2922 -->Invert displayed features very slow when
+ structure and/or overview windows are also shown
+ </li>
+ <li>
+ <!-- JAL-2954 -->Selecting columns from highlighted regions
+ very slow for alignments with large numbers of sequences
+ </li>
+ <li>
+ <!-- JAL-2925 -->Copy Consensus fails for group consensus
+ with 'StringIndexOutOfBounds'
+ </li>
+ <li>
+ <!-- JAL-2976 -->VAqua(4) provided as fallback Look and Feel for OSX
+ platforms running Java 10
+ </li>
+ <li>
+ <!-- JAL-2960 -->Adding a structure to existing structure
+ view appears to do nothing because the view is hidden behind the alignment view
+ </li>
+ </ul>
+ <em>Applet</em>
+ <ul>
+ <li>
+ <!-- JAL-2926 -->Copy consensus sequence option in applet
+ should copy the group consensus when popup is opened on it
+ </li>
+ </ul>
+ <em>Batch Mode</em>
+ <ul>
+ <li>
+ <!-- JAL-2913 -->Fixed ID width preference is not respected
+ </li>
+ </ul>
+ <em>New Known Defects</em>
+ <ul>
+ <li>
+ <!-- JAL-2973 --> Exceptions occasionally raised when
+ editing a large alignment and overview is displayed
+ </li>
+ <li>
+ <!-- JAL-2974 -->'Overview updating' progress bar is shown
+ repeatedly after a series of edits even when the overview
+ is no longer reflecting updates
+ </li>
+ <li>
+ <!-- JAL-2946 -->'SIFTS Mapping Error' when viewing
+ structures for protein subsequence (if 'Trim Retrieved
+ Sequences' enabled) or Ensembl isoforms (Workaround in
+ 2.10.4 is to fail back to N&W mapping)
+ </li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td width="60" nowrap>
+ <div align="center">
+ <strong><a name="Jalview.2.10.3b1">2.10.3b1</a><br /> <em>24/1/2018</em></strong>
+ </div>
+ </td>
+ <td><div align="left">
+ <ul><li>Updated Certum Codesigning Certificate
+ (Valid till 30th November 2018)</li></ul></div></td>
+ <td><div align="left">
+ <em>Desktop</em><ul>
+ <ul>
+ <li><!-- JAL-2859-->Only one structure is loaded when several sequences and structures are selected for viewing/superposing</li>
+ <li><!-- JAL-2851-->Alignment doesn't appear to scroll vertically via trackpad and scrollwheel</li>
+ <li><!-- JAL-2842-->Jalview hangs if up/down arrows pressed in cursor mode when cursor lies in hidden region at start of alignment</li>
+ <li><!-- JAL-2827-->Helix annotation has 'notches' when scrolled into view if columns are hidden</li>
+ <li><!-- JAL-2740-->Annotation column filter can be slow to reset (ie after hitting cancel) for large numbers of hidden columns</li>
+ <li><!-- JAL-2849-->User preference for disabling inclusion of sequence limits when exporting as flat file has no effect</li>
+ <li><!-- JAL-2679-->Reproducible cross-reference relationships when retrieving sequences from EnsemblGenomes</li>
+ </ul>
+ </div>
+ </td>
+ </tr>
<tr>
<td width="60" nowrap>
<div align="center">
- <strong><a name="Jalview.2.10.3">2.10.3</a><br />
- <em>17/11/2017</em></strong>
+ <strong><a name="Jalview.2.10.3">2.10.3</a><br /> <em>17/11/2017</em></strong>
</div>
</td>
<td><div align="left">
<!-- JAL-2773 -->Structure views don't get updated unless
their colours have changed
</li>
- <li><!-- JAL-2495 -->All linked sequences are highlighted for a structure mousover (Jmol) or selection (Chimera)</li>
- <li><!-- JAL-2790 -->'Cancel' button in progress bar for JABAWS AACon, RNAAliFold and Disorder prediction jobs
+ <li>
+ <!-- JAL-2495 -->All linked sequences are highlighted for
+ a structure mousover (Jmol) or selection (Chimera)
+ </li>
+ <li>
+ <!-- JAL-2790 -->'Cancel' button in progress bar for
+ JABAWS AACon, RNAAliFold and Disorder prediction jobs
+ </li>
+ <li>
+ <!-- JAL-2617 -->Stop codons are excluded in CDS/Protein
+ view from Ensembl locus cross-references
+ </li>
+ <li>
+ <!-- JAL-2685 -->Start/End limits are shown in Pairwise
+ Alignment report
+ </li>
+ <li>
+ <!-- JAL-2810 -->Sequence fetcher's Free text 'autosearch'
+ feature can be disabled
+ </li>
+ <li>
+ <!-- JAL-2810 -->Retrieve IDs tab added for UniProt and
+ PDB easier retrieval of sequences for lists of IDs
+ </li>
+ <li>
+ <!-- JAL-2758 -->Short names for sequences retrieved from
+ Uniprot
</li>
-
- <li><!-- JAL-2617 -->Stop codons are excluded in CDS/Protein view from Ensembl locus cross-references</li>
- <li><!-- JAL-2685 -->Start/End limits are shown in Pairwise Alignment report</li>
- <li><!-- JAL-2810 -->Sequence fetcher's Free text 'autosearch' feature can be disabled</li>
- <li><!-- JAL-2810 -->Retrieve IDs tab added for UniProt and PDB easier retrieval of sequences for lists of IDs</li>
- <li><!-- JAL-2758 -->Short names for sequences retrieved from Uniprot</li>
</ul>
<em>Scripting</em>
<ul>
<li>Groovy interpreter updated to 2.4.12</li>
- <li>Example groovy script for generating a matrix of percent identity scores for current alignment.</li>
+ <li>Example groovy script for generating a matrix of
+ percent identity scores for current alignment.</li>
</ul>
<em>Testing and Deployment</em>
<ul>
- <li><!-- JAL-2727 -->Test to catch memory leaks in Jalview UI</li>
+ <li>
+ <!-- JAL-2727 -->Test to catch memory leaks in Jalview UI
+ </li>
</ul>
- </div>
- </td>
+ </div></td>
<td><div align="left">
<em>General</em>
<ul>
- <li><!-- JAL-2643 -->Pressing tab after updating the colour threshold text field doesn't trigger an update to the alignment view</li>
- <li><!-- JAL-2682 -->Race condition when parsing sequence ID strings in parallel</li>
- <li><!-- JAL-2608 -->Overview windows are also closed when alignment window is closed</li>
- <li><!-- JAL-2548 -->Export of features doesn't always respect group visibility</li>
- <li><!-- JAL-2831 -->Jumping from column 1 to column 100,000 takes a long time in Cursor mode</li>
+ <li>
+ <!-- JAL-2643 -->Pressing tab after updating the colour
+ threshold text field doesn't trigger an update to the
+ alignment view
+ </li>
+ <li>
+ <!-- JAL-2682 -->Race condition when parsing sequence ID
+ strings in parallel
+ </li>
+ <li>
+ <!-- JAL-2608 -->Overview windows are also closed when
+ alignment window is closed
+ </li>
+ <li>
+ <!-- JAL-2548 -->Export of features doesn't always respect
+ group visibility
+ </li>
+ <li>
+ <!-- JAL-2831 -->Jumping from column 1 to column 100,000
+ takes a long time in Cursor mode
+ </li>
</ul>
<em>Desktop</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>
- <li><!-- JAL-2529 -->Revised Ensembl REST API CDNA query</li>
- <li><!-- JAL-2739 -->Hidden column marker in last column not rendered when switching back from Wrapped to normal view</li>
- <li><!-- JAL-2768 -->Annotation display corrupted when scrolling right in unwapped alignment view</li>
- <li><!-- JAL-2542 -->Existing features on subsequence incorrectly relocated when full sequence retrieved from database</li>
- <li><!-- JAL-2733 -->Last reported memory still shown when Desktop->Show Memory is unticked (OSX only)</li>
- <li><!-- JAL-2658 -->Amend Features dialog doesn't allow features of same type and group to be selected for amending</li>
- <li><!-- JAL-2524 -->Jalview becomes sluggish in wide alignments when hidden columns are present</li>
- <li><!-- JAL-2392 -->Jalview freezes when loading and displaying several structures</li>
- <li><!-- JAL-2732 -->Black outlines left after resizing or moving a window</li>
- <li><!-- JAL-1900,JAL-1625 -->Unable to minimise windows within the Jalview desktop on OSX</li>
- <li><!-- JAL-2667 -->Mouse wheel doesn't scroll vertically when in wrapped alignment mode</li>
- <li><!-- JAL-2636 -->Scale mark not shown when close to right hand end of alignment</li>
- <li><!-- JAL-2684 -->Pairwise alignment of selected regions of each selected sequence do not have correct start/end positions</li>
- <li><!-- JAL-2793 -->Alignment ruler height set incorrectly after canceling the Alignment Window's Font dialog</li>
- <li><!-- JAL-2036 -->Show cross-references not enabled after restoring project until a new view is created</li>
- <li><!-- JAL-2756 -->Warning popup about use of SEQUENCE_ID in URL links appears when only default EMBL-EBI link is configured (since 2.10.2b2)</li>
- <li><!-- JAL-2775 -->Overview redraws whole window when box position is adjusted</li>
- <li><!-- JAL-2225 -->Structure viewer doesn't map all chains in a multi-chain structure when viewing alignment involving more than one chain (since 2.10)</li>
- <li><!-- JAL-2811 -->Double residue highlights in cursor mode if new selection moves alignment window</li>
- <li><!-- JAL-2837,JAL-2840 -->Alignment vanishes when using arrow key in cursor mode to pass hidden column marker</li>
- <li><!-- JAL-2679 -->Ensembl Genomes example ID changed to one that produces correctly annotated transcripts and products</li>
- <li><!-- JAL-2776 -->Toggling a feature group after first time doesn't update associated structure view</li>
- </ul>
- ><em>Applet</em><br/>
- <ul>
- <li><!-- JAL-2687 -->Concurrent modification exception when closing alignment panel</li>
+ <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>
+ <li>
+ <!-- JAL-2529 -->Revised Ensembl REST API CDNA query
+ </li>
+ <li>
+ <!-- JAL-2739 -->Hidden column marker in last column not
+ rendered when switching back from Wrapped to normal view
+ </li>
+ <li>
+ <!-- JAL-2768 -->Annotation display corrupted when
+ scrolling right in unwapped alignment view
+ </li>
+ <li>
+ <!-- JAL-2542 -->Existing features on subsequence
+ incorrectly relocated when full sequence retrieved from
+ database
+ </li>
+ <li>
+ <!-- JAL-2733 -->Last reported memory still shown when
+ Desktop->Show Memory is unticked (OSX only)
+ </li>
+ <li>
+ <!-- JAL-2658 -->Amend Features dialog doesn't allow
+ features of same type and group to be selected for
+ amending
+ </li>
+ <li>
+ <!-- JAL-2524 -->Jalview becomes sluggish in wide
+ alignments when hidden columns are present
+ </li>
+ <li>
+ <!-- JAL-2392 -->Jalview freezes when loading and
+ displaying several structures
+ </li>
+ <li>
+ <!-- JAL-2732 -->Black outlines left after resizing or
+ moving a window
+ </li>
+ <li>
+ <!-- JAL-1900,JAL-1625 -->Unable to minimise windows
+ within the Jalview desktop on OSX
+ </li>
+ <li>
+ <!-- JAL-2667 -->Mouse wheel doesn't scroll vertically
+ when in wrapped alignment mode
+ </li>
+ <li>
+ <!-- JAL-2636 -->Scale mark not shown when close to right
+ hand end of alignment
+ </li>
+ <li>
+ <!-- JAL-2684 -->Pairwise alignment of selected regions of
+ each selected sequence do not have correct start/end
+ positions
+ </li>
+ <li>
+ <!-- JAL-2793 -->Alignment ruler height set incorrectly
+ after canceling the Alignment Window's Font dialog
+ </li>
+ <li>
+ <!-- JAL-2036 -->Show cross-references not enabled after
+ restoring project until a new view is created
+ </li>
+ <li>
+ <!-- JAL-2756 -->Warning popup about use of SEQUENCE_ID in
+ URL links appears when only default EMBL-EBI link is
+ configured (since 2.10.2b2)
+ </li>
+ <li>
+ <!-- JAL-2775 -->Overview redraws whole window when box
+ position is adjusted
+ </li>
+ <li>
+ <!-- JAL-2225 -->Structure viewer doesn't map all chains
+ in a multi-chain structure when viewing alignment
+ involving more than one chain (since 2.10)
+ </li>
+ <li>
+ <!-- JAL-2811 -->Double residue highlights in cursor mode
+ if new selection moves alignment window
+ </li>
+ <li>
+ <!-- JAL-2837,JAL-2840 -->Alignment vanishes when using
+ arrow key in cursor mode to pass hidden column marker
+ </li>
+ <li>
+ <!-- JAL-2679 -->Ensembl Genomes example ID changed to one
+ that produces correctly annotated transcripts and products
+ </li>
+ <li>
+ <!-- JAL-2776 -->Toggling a feature group after first time
+ doesn't update associated structure view
+ </li>
</ul>
- <em>BioJSON</em><br/>
+ <em>Applet</em><br />
<ul>
- <li>
- <!-- JAL-2546 -->BioJSON export does not preserve non-positional features
- </li>
+ <li>
+ <!-- JAL-2687 -->Concurrent modification exception when
+ closing alignment panel
+ </li>
</ul>
- <strong>New Known Issues</strong>
+ <em>BioJSON</em><br />
<ul>
- <li><!-- JAL-2541 -->Delete/Cut selection doesn't relocate sequence features correctly (for many previous versions of Jalview)</li>
- <li><!-- JAL-2841 -->Cursor mode unexpectedly scrolls when using cursor in wrapped panel other than top</li>
- <li><!-- JAL-2791 -->Select columns containing feature ignores graduated colour threshold</li>
- <li><!-- JAL-2822,JAL-2823 -->Edit sequence operation doesn't always preserve numbering and sequence features</li>
+ <li>
+ <!-- JAL-2546 -->BioJSON export does not preserve
+ non-positional features
+ </li>
</ul>
- <strong>Known Java 9 Issues</strong>
+ <em>New Known Issues</em>
<ul>
- <li><!-- JAL-2902 -->Groovy Console very slow to open and is
- not responsive when entering characters (Webstart, Java 9.01,
- OSX 10.10)
+ <li>
+ <!-- JAL-2541 -->Delete/Cut selection doesn't relocate
+ sequence features correctly (for many previous versions of
+ Jalview)
+ </li>
+ <li>
+ <!-- JAL-2841 -->Cursor mode unexpectedly scrolls when
+ using cursor in wrapped panel other than top
+ </li>
+ <li>
+ <!-- JAL-2791 -->Select columns containing feature ignores
+ graduated colour threshold
+ </li>
+ <li>
+ <!-- JAL-2822,JAL-2823 -->Edit sequence operation doesn't
+ always preserve numbering and sequence features
</li>
</ul>
- </div>
- </td>
+ <em>Known Java 9 Issues</em>
+ <ul>
+ <li>
+ <!-- JAL-2902 -->Groovy Console very slow to open and is
+ not responsive when entering characters (Webstart, Java
+ 9.01, OSX 10.10)
+ </li>
+ </ul>
+ </div></td>
</tr>
<tr>
<td width="60" nowrap>
ID, and can be viewed in full via the
<a href="../io/exportseqreport.html">Sequence Details</a> window. .
Jalview also uses references for the retrieval of
- <a href="../features/viewingpdbs.html">PDB structures</a> and <a
- href="../features/dasfeatures.html">DAS features</a>, and for
+ <a href="../features/viewingpdbs.html">PDB structures</a>, and for
retrieving sequence cross-references such as the protein products of a
DNA sequence.
</p>
application provides three ways to access the retrieval function.
Either:
<ul>
- <li>select the <strong>Discover PDB IDs</strong> option from the
- structure submenu of the sequence's popup menu
- </li>
- <li>Choose one of the options from the 'Fetch DB Refs' submenu in
+ <li>select the <strong>Structure Chooser...</strong> option from
+ the Sequence ID popup menu.
+ </li>
+ <li>Choose one of the options from the 'Fetch DB Refs' submenu in
the alignment window's <strong>Web Services</strong> menu:
<ul>
- <li><em>Standard Databases</em> will fetch references from
- the EBI databases plus currently selected DAS sources</li>
- <li>The other entries submenus leading to lists of individual
+ <li><em>Standard Databases</em> will fetch references from EBI
+ databases appropriate for the sequence type (Nucleotide or Protein)</li>
+ <li>The other entries submenus leading to lists of individual
database sources that Jalview can access.</li>
</ul>
</li>
- <li>Answer 'Yes' when asked if you wish to retrieve database
- references for your sequences after initiating a DAS Sequence
- Feature fetch.</li>
</ul>
<p>Jalview discovers references for a sequence by generating a set
of ID queries from the ID string of each sequence in the alignment. It
Institute (EBI) and Distributed Annotation System servers that are
capable of serving sequences.
</li>
- <li>The <a href="../features/dasfeatures.html">DAS Feature
- Fetcher</a> enables the retrieval and visualization of features from
- DAS annotation sources
- </li>
- <li>The <a href="dbreffetcher.html">Database Reference
- Fetcher</a> transfers database references from records available
- from DAS or the public sequence databases.
- </li>
- <li>The <strong>Web Services</strong> menu in each alignment
+ <li>The <a href="dbreffetcher.html">Database Reference
+ Fetcher</a> transfers database references and annotation from the public
+ sequence databases.
+ </li>
+ <li>The <strong>Web Services</strong> menu in each alignment
window also provides access to the following:
<ul>
<li>Programs for <a href="msaclient.html">multiple
</head>
<body>
<p>
- <strong>What's new in Jalview 2.10.3 ?</strong>
- </p>
- <p>
- Version 2.10.3 was released in November 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.
+ <strong>What's new in Jalview 2.10.5 ?</strong>
</p>
+ <p>Jalview 2.10.5 is a minor release that includes critical
+ patches for users working with Ensembl, RNA secondary structure
+ annotation, and those running Jalview on OSX with Java 10.</p>
<ul>
- <li>Faster and more responsive UI when importing and working
- with wide alignments and handling hundreds and thousands of
- sequence features</li>
- <li>Improved usability with <a
- href="features/pdbsequencefetcher.html">PDB</a> and <a
- href="features/uniprotsequencefetcher.html">UniProt</a> Free Text
- Search dialog, and new tab for retrieval of sequences for lists of
- IDs.
+ <li>Jalview's default memory limit increased to 1G. <br/>If you have
+ problems starting Jalview 2.10.5 and you have 1G or less
+ physical memory on your machine, you will need to <a
+ href="memory.html#memsetting">reduce the memory</a> allocated to
+ Jalview.
+ </li>
+ <li>EPS, PNG and SVG export now includes hidden sequence
+ markers, and representative sequences are marked in bold.</li>
+ <li>Ensembl Client updated for Ensembl Rest API v7.<br />The
+ latest Ensembl API is not backwards compatible with earlier
+ versions of Jalview, so if you require Ensembl functionality you
+ will need to install this release.
</li>
- <li>Short names assigned to sequences retrieved from UniProt</li>
+ <li>Improved support for VIENNA extended dot-bracket notation
+ for RNA secondary structure.</li>
+ <li>Positional and selected region highlighting in VARNA
+ 'trimmed sequence' view made more reliable.</li>
</ul>
<p>
- <strong><a name="experimental">Experimental Features</a></strong>
+ The full list of bugs fixed in this release can be found in the <a
+ href="releases.html#Jalview.2.10.5">2.10.5 Release Notes</a>. The
+ majority of bug fixes and improvements in 2.10.5 are due to Jalview users
+ contacting us via the jalview-discuss email list. Thanks to everyone
+ who took the time to help make Jalview better !
</p>
<p>
- Remember, please enable the <em>Experimental Features</em> option in
- the Jalview Desktop's <em>Tools</em> menu, and then restart Jalview
- if you want to try out features below:
+ <strong>Jalview and Java 10</strong>
</p>
+ <p>This release addresses a critical bug for OSX users who are
+ running Jalview with Java 10 which can prevent files being saved
+ correctly through the 'Save As' dialog box.</p>
+ <em>Known Issues</em>
<ul>
- <li><em>Annotation transfer between Chimera and Jalview</em><br />Two
- <a href="features/chimera.html#experimental">new entries in
- the Chimera viewer's Chimera menu</a> allow positional annotation to
- be exchanged between Chimera and Jalview.</li>
+ <li>OSX: The 'Open File' dialog for Jalview's Groovy Console
+ appears with the title 'Save As', and attempting to select a file to load yields a FileNotFound exception.</br>The workaround is to first clear the 'Untitled' filename before selecting the file you wish to load.
+ </li>
+ <li>OSX: Links don't open when clicked on or via the Sequence or Alignment window popup menu.</li>
+ <li>OSX (Webstart): Jalview only displays old news feed items</li>
</ul>
-
</body>
</html>
* 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.
-->
-<!--
+
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
-YEAR=2016
-AUTHORS=J Procter, M Carstairs, TC Ofoegbu, K Mourao, AM Waterhouse, J Engelhardt, LM Lui, A Menard, D Barton, N Sherstnev, D Roldan-Martinez, M Clamp, S Searle, G Barton
-AUTHORFNAMES=Jim Procter, Mungo Carstairs, Tochukwu 'Charles' Ofoegbu, Kira Mourao, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Anne Menard, Daniel Barton, Natasha Sherstnev, David Roldan-Martinez, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
+YEAR=2018
+AUTHORS=J Procter, M Carstairs, B Soares, K Mourao, TC Ofoegbu, AM Waterhouse, J Engelhardt, LM Lui, A Menard, D Barton, N Sherstnev, D Roldan-Martinez, M Clamp, S Searle, G Barton
+AUTHORFNAMES=Jim Procter, Mungo Carstairs, Ben Soares, Kira Mourao, Tochukwu 'Charles' Ofoegbu, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Anne Menard, Daniel Barton, Natasha Sherstnev, David Roldan-Martinez, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
\ No newline at end of file
label.about = About...
label.show_sequence_limits = Show Sequence Limits
action.feature_settings = Feature Settings...
-label.feature_settings = Feature Settings
label.all_columns = All Columns
label.all_sequences = All Sequences
label.selected_columns = Selected Columns
label.autoadd_secstr = Add secondary structure annotation to alignment
label.autoadd_temp = Add Temperature Factor annotation to alignment
label.structure_viewer = Default structure viewer
+label.double_click_to_browse = Double-click to browse for file
label.chimera_path = Path to Chimera program
label.chimera_path_tip = Jalview will first try any path entered here, else standard installation locations.<br>Double-click to browse for file.
label.invalid_chimera_path = Chimera path not found or not executable
label.chimera_failed = Error opening Chimera - is it installed?\nCheck path in Preferences, Structure
label.min_colour = Minimum Colour
label.max_colour = Maximum Colour
+label.no_colour = No Colour
label.use_original_colours = Use Original Colours
label.threshold_minmax = Threshold is min/max
label.represent_group_with = Represent Group with {0}
label.group_colour = Group Colour
label.sequence = Sequence
label.view_pdb_structure = View PDB Structure
-label.min = Min:
-label.max = Max:
-label.colour_by_label = Colour by label
+label.min_value = Min value
+label.max_value = Max value
+label.no_value = No value
label.new_feature = New Feature
label.match_case = Match Case
label.view_alignment_editor = View in alignment editor
label.seq_sort_by_score = Sequence sort by Score
label.load_colours = Load Colours
label.save_colours = Save Colours
+label.load_colours_tooltip = Load feature colours and filters from file
+label.save_colours_tooltip = Save feature colours and filters to file
label.fetch_das_features = Fetch DAS Features
label.selected_database_to_fetch_from = Selected {0} database {1} to fetch from {2}
label.database_param = Database: {0}
label.enter_view_name = Enter View Name
label.enter_label = Enter label
label.enter_label_for_the_structure = Enter a label for the structure
-label.pdb_entry_is_already_displayed = {0} is already displayed.\nDo you want to re-use this viewer ?
-label.map_sequences_to_visible_window = Map Sequences to Visible Window: {0}
-label.add_pdbentry_to_view = Do you want to add {0} to the view called\n{1}\n
-label.align_to_existing_structure_view = Align to existing structure view
label.pdb_entries_couldnt_be_retrieved = The following pdb entries could not be retrieved from the PDB\:\n{0}\nPlease retry, or try downloading them manually.
label.couldnt_load_file = Couldn't load file
label.couldnt_find_pdb_id_in_file = Couldn't find a PDB id in the file supplied. Please enter an Id to identify this structure.
label.view_full_application = View in Full Application
label.load_associated_tree = Load Associated Tree...
label.load_features_annotations = Load Features/Annotations...
+label.load_vcf = Load SNP variants from plain text or indexed VCF data
+label.load_vcf_file = Load VCF File
+label.searching_vcf = Loading VCF variants...
+label.added_vcf = Added {0} VCF variants to {1} sequence(s)
label.export_features = Export Features...
label.export_annotations = Export Annotations...
label.to_upper_case = To Upper Case
label.threshold_feature_below_threshold = Below Threshold
label.adjust_threshold = Adjust threshold
label.toggle_absolute_relative_display_threshold = Toggle between absolute and relative display threshold.
-label.display_features_same_type_different_label_using_different_colour = Display features of the same type with a different label using a different colour. (e.g. domain features)
label.select_colour_minimum_value = Select Colour for Minimum Value
label.select_colour_maximum_value = Select Colour for Maximum Value
label.open_url_param = Open URL {0}
label.2d_rna_sequence_name = 2D RNA - {0}
label.edit_name_and_description_current_group = Edit name and description of current group
label.from_file = From File
-label.enter_pdb_id = Enter PDB Id (or pdbid:chaincode)
+label.enter_pdb_id = Enter PDB Id
+label.enter_pdb_id_tip = Enter PDB Id (or pdbid:chaincode)
label.text_colour = Text Colour...
label.structure = Structure
label.show_pdbstruct_dialog = 3D Structure Data...
label.original_data_for_params = Original Data for {0}
label.points_for_params = Points for {0}
label.transformed_points_for_params = Transformed points for {0}
-label.graduated_color_for_params = Graduated Feature Colour for {0}
+label.variable_color_for = Variable Feature Colour for {0}
label.select_background_colour = Select Background Colour
label.invalid_font = Invalid Font
label.separate_multiple_accession_ids = Enter one or more accession IDs separated by a semi-colon ";"
label.service_called_is_not_seq_search_service = The Service called \n{0}\nis not a \nSequence Search Service\!
label.seq_search_service_is_unknown = The Sequence Search Service named {0} is unknown
label.feature_type = Feature Type
-label.display = Display
+label.show = Show
label.service_url = Service URL
label.copied_sequences = Copied sequences
label.cut_sequences = Cut Sequences
label.result = result
label.results = results
label.structure_chooser = Structure Chooser
-label.select = Select :
label.invert = Invert
label.select_pdb_file = Select PDB File
info.select_filter_option = Select Filter Option/Manual Entry
label.overview = Overview
label.reset_to_defaults = Reset to defaults
label.oview_calc = Recalculating overview...
-option.enable_disable_autosearch = When ticked, search is performed automatically.
+label.feature_details = Feature details
+label.matchCondition_contains = Contains
+label.matchCondition_notcontains = Does not contain
+label.matchCondition_matches = Matches
+label.matchCondition_notmatches = Does not match
+label.matchCondition_present = Is present
+label.matchCondition_notpresent = Is not present
+label.matchCondition_eq = =
+label.matchCondition_ne = not =
+label.matchCondition_lt = <
+label.matchCondition_le = <=
+label.matchCondition_gt = >
+label.matchCondition_ge = >=
+label.numeric_required = The value should be numeric
+label.filter = Filter
+label.filters = Filters
+label.join_conditions = Join conditions with
+label.score = Score
+label.colour_by_label = Colour by label
+label.variable_colour = Variable colour...
+label.select_colour = Select colour
+option.enable_disable_autosearch = When ticked, search is performed automatically
option.autosearch = Autosearch
-label.retrieve_ids = Retrieve IDs
\ No newline at end of file
+label.retrieve_ids = Retrieve IDs
+label.display_settings_for = Display settings for {0} features
+label.simple = Simple
+label.simple_colour = Simple Colour
+label.colour_by_text = Colour by text
+label.graduated_colour = Graduated Colour
+label.by_text_of = By text of
+label.by_range_of = By range of
+label.filters_tooltip = Click to set or amend filters
+label.or = Or
+label.and = And
+label.sequence_feature_colours = Sequence Feature Colours
+label.best_quality = Best Quality
+label.best_resolution = Best Resolution
+label.most_protein_chain = Most Protein Chain
+label.most_bound_molecules = Most Bound Molecules
+label.most_polymer_residues = Most Polymer Residues
+label.cached_structures = Cached Structures
+label.free_text_search = Free Text Search
label.documentation = Documentación
label.about = Acerca de...
label.show_sequence_limits = Mostrar los lÃmites de la secuencia
-label.feature_settings = Ajustar funciones...
label.all_columns = Todas las columnas
label.all_sequences = Todas las secuencias
label.selected_columns = Columnas seleccionadas
label.autocalculated_annotation = Anotación autocalculada
label.min_colour = Color mÃnimo
label.max_colour = Color máximo
+label.no_colour = Sin color
label.use_original_colours = Usar colores originales
label.threshold_minmax = El umbral es mÃn/máx
label.represent_group_with = Representar al grupo con
label.group_colour = Color del grupo
label.sequence = Secuencia
label.view_pdb_structure = Ver estructura PDB
-label.min = MÃn:
-label.max = Máx:
+label.max_value = Valor máximo
+label.min_value = Valor mÃnimo
+label.no_value = Sin valor
label.colour_by_label = Color por etiquetas
label.new_feature = Nueva función
label.match_case = Hacer corresponder mayúsculas y minúsculas
label.seq_sort_by_score = Ordenar las secuencias por puntuación
label.load_colours = Cargar colores
label.save_colours = Guardar colores
+label.load_colours_tooltip = Cargar colores y filtros desde fichero
+label.save_colours_tooltip = Guardar colores y filtros en fichero
label.fetch_das_features = Recuperar funciones DAS
label.selected_database_to_fetch_from = Seleccionada {0} Base de datos {1} para buscar de {2}
label.database_param = Base de datos: {0}
label.enter_view_name = Introduzca un nombre para la vista
label.enter_label = Introducir etiqueta
label.enter_label_for_the_structure = Introducir una etiqueta para la estructura
-label.pdb_entry_is_already_displayed = {0} Ya est\u00E1 mostrado.\nQuieres volver a usar este visor?
-label.map_sequences_to_visible_window = Mapa de secuencias en ventana visible: {0}
-label.add_pdbentry_to_view = Quieres a\u00F1adir {0} a la vista llamada\n{1}\n
-label.align_to_existing_structure_view = Alinear a una estructura ya existente
label.pdb_entries_couldnt_be_retrieved = Las siguientes entradas pdb no pueden ser extra\u00EDdas del PDB\:\n{0}\nPor favor, prueba descarg\u00E1ndolas manualmente.
label.couldnt_load_file = No se pudo cargar el fichero
label.couldnt_find_pdb_id_in_file = No se pudo encontrar un Id PDB en el fichero suministrado. Por favor, introduzca un Id para identificar esta estructura.
label.view_full_application = Ver en la aplicación completa
label.load_associated_tree = Cargar árbol asociado ...
label.load_features_annotations = Cargar caracterÃsticas/anotaciones ...
+label.load_vcf = Cargar variantes SNP desde fichero VCF texto o tab-indexado
+label.load_vcf_file = Cargar fichero VCF
+label.searching_vcf = Cargando variantes VCF...
+label.added_vcf= {0} variantes VCF añadidas a {1} secuencia(s)
label.export_features = Exportar caracterÃsticas...
label.export_annotations = Exportar anotaciones ...
label.to_upper_case = Pasar a mayúsculas
label.threshold_feature_below_threshold = Por debajo del umbral
label.adjust_threshold = Ajustar umbral
label.toggle_absolute_relative_display_threshold = Cambiar entre mostrar el umbral absoluto y el relativo.
-label.display_features_same_type_different_label_using_different_colour = Mostrar las caracterÃsticas del mismo tipo con una etiqueta diferente y empleando un color distinto (p.e. caracterÃsticas del dominio)
label.select_colour_minimum_value = Seleccionar el color para el valor mÃnimo
label.select_colour_maximum_value = Seleccionar el color para el valor máximo
label.open_url_param = Abrir URL {0}
label.edit_name_and_description_current_group = Editar el nombre y la descripción del grupo actual
label.from_file = desde fichero
label.enter_pdb_id = Introducir PDB Id
+label.enter_pdb_id_tip = Introducir PDB Id (o pdbid:chaincode)
label.text_colour = Color de texto...
label.structure = Estructura
label.create_sequence_details_report_annotation_for = Anotación para {0}
label.original_data_for_params = Datos originales de {0}
label.points_for_params = Puntos de {0}
label.transformed_points_for_params = Puntos transformados de {0}
-label.graduated_color_for_params = Color graduado para la caracterÃstica de {0}
+label.variable_color_for = Color variable para la caracterÃstica de {0}
label.select_background_colour = Seleccionar color de fondo
label.invalid_font = Fuente no válida
label.separate_multiple_accession_ids = Separar los accession id con un punto y coma ";"
label.service_called_is_not_seq_search_service = El Servicio llamando \n{0}\nno es un \nServicio de B\u00FAsqueda de Secuencias\!
label.seq_search_service_is_unknown = El Servicio de Búsqueda de Sencuencias llamado {0} es desconocido
label.feature_type = Tipo de caracterÃstisca
-label.display = Representación
+label.show = Mostrar
label.service_url = URL del servicio
label.copied_sequences = Secuencias copiadas
label.cut_sequences = Cortar secuencias
label.scale_protein_to_cdna=Adaptar proteÃna a cDNA
label.scale_protein_to_cdna_tip=Hacer a los residuos de proteÃnas de la misma anchura que los codones en ventanas divididas
status.loading_cached_pdb_entries=Cargando Entradas PDB en Caché
-label.select=Seleccionar :
label.select_by_annotation=Seleccionar/Ocultar Columnas por Anotación
action.select_by_annotation=Seleccionar/Ocultar Columnas por Anotación...
action.export_features=Exportar CaracterÃsticas
error.invalid_regex=Expresión regular inválida
label.autoadd_temp=Añadir anotación factor de temperatura al alineamiento
+label.double_click_to_browse = Haga doble clic para buscar fichero
label.chimera_path_tip=Jalview intentará primero las rutas introducidas aquÃ, Y si no las rutas usuales de instalación
label.structure_chooser=Selector de Estructuras
label.structure_chooser_manual_association=Selector de Estructuras - asociación manual
label.aacon_calculations=cálculos AACon
label.pdb_web-service_error=Error de servicio web PDB
exception.unable_to_detect_internet_connection=Jalview no puede detectar una conexión a Internet
-label.chimera_path=Ruta de acceso a programa Chimera
+label.chimera_path=Ruta de acceso a Chimera
warn.delete_all=<html>Borrar todas las secuencias cerrará la ventana del alineamiento.<br>Confirmar o Cancelar.
label.select_all=Seleccionar Todos
label.alpha_helix=Hélice Alfa
label.chimera_help=Ayuda para Chimera
label.find_tip=Buscar alineamiento, selección o IDs de secuencia para una subsecuencia (sin huecos)
-label.structure_viewer=Visualizador de estructura por defecto
+label.structure_viewer=Visualizador por defecto
label.embbed_biojson=Incrustar BioJSON al exportar HTML
label.transparency_tip=Ajustar la transparencia a "ver a través" los colores de las caracterÃsticas.
label.choose_annotations=Escoja anotaciones
label.overview = Resumen
label.reset_to_defaults = Restablecen a los predeterminados
label.oview_calc = Recalculando resumen
+label.feature_details = Detalles de caracterÃstica
+label.matchCondition_contains = Contiene
+label.matchCondition_notcontains = No contiene
+label.matchCondition_matches = Es igual a
+label.matchCondition_notmatches = No es igual a
+label.matchCondition_present = Está presente
+label.matchCondition_notpresent = No está presente
+label.matchCondition_eq = =
+label.matchCondition_ne = not =
+label.matchCondition_lt = <
+label.matchCondition_le = <=
+label.matchCondition_gt = >
+label.matchCondition_ge = >=
+label.numeric_required = Valor numérico requerido
+label.filter = Filtro
+label.filters = Filtros
+label.join_conditions = Combinar condiciones con
+label.score = Puntuación
+label.colour_by_label = Colorear por texto
+label.variable_colour = Color variable...
+label.select_colour = Seleccionar color
+option.enable_disable_autosearch = Marcar para buscar automáticamente
+option.autosearch = Auto búsqueda
+label.retrieve_ids = Recuperar IDs
+label.display_settings_for = Visualización de caracterÃsticas {0}
+label.simple = Simple
+label.simple_colour = Color simple
+label.colour_by_text = Colorear por texto
+label.graduated_colour = Color graduado
+label.by_text_of = Por texto de
+label.by_range_of = Por rango de
+label.filters_tooltip = Haga clic para configurar o modificar los filtros
+label.or = O
+label.and = Y
+label.sequence_feature_colours = Colores de caracterÃsticas de las secuencias
+label.best_quality = Mejor Calidad
+label.best_resolution = Mejor Resolución
+label.most_protein_chain = Más Cadena de ProteÃna
+label.most_bound_molecules = Más Moléculas Ligadas
+label.most_polymer_residues = Más Residuos de PolÃmeros
+label.cached_structures = Estructuras en Caché
+label.free_text_search = Búsqueda de texto libre
* The Jalview Authors are detailed in the 'AUTHORS' file.
-->
<mapping>
+ <!-- see https://www.uniprot.org/docs/uniprot.xsd for latest Uniprot XML schema -->
<class name="jalview.datamodel.xdb.uniprot.UniprotFile">
<map-to xml="uniprot"/>
<field name="UniprotEntries" type="jalview.datamodel.xdb.uniprot.UniprotEntry" collection="vector">
</field>
<field name="position">
<bind-xml name="position" node="attribute" location="location/position"/>
- </field>
+ </field>
<field name="begin">
<bind-xml name="position" node="attribute" location="location/begin"/>
- </field>
- <field name="end">
- <bind-xml name="position" node="attribute" location="location/end"/>
- </field>
+ </field>
+ <field name="end">
+ <bind-xml name="position" node="attribute" location="location/end"/>
+ </field>
+ <field name="variation" collection="vector" type="string">
+ <bind-xml name="variation"/>
+ </field>
+ <field name="original">
+ <bind-xml name="original"/>
+ </field>
</class>
<class name="jalview.datamodel.xdb.uniprot.UniprotSequence">
You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
-->
-<!-- edited with XMLSpy v2005 rel. 3 U (http://www.altova.com) by lj (jl) -->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="www.jalview.org/colours">
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jalview="www.jalview.org/colours" targetNamespace="www.jalview.org/colours">
<xs:complexType name="JalviewUserColours">
<xs:sequence>
<xs:element name="Version" maxOccurs="1" minOccurs="0" type="xs:string">
</xs:element>
<xs:element name="colour" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
- <xs:attribute name="Name" type="xs:string"/>
+ <xs:sequence>
+ <xs:element name="attributeName" type="xs:string" minOccurs="0" maxOccurs="2">
+ <xs:annotation>
+ <xs:documentation>name of feature attribute to colour by, or attribute and sub-attribute</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="Name" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>Single letter residue code for an alignment colour scheme, or feature type for a feature colour scheme</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
<xs:attribute name="RGB" type="xs:string" use="required"/>
<xs:attribute name="minRGB" type="xs:string" use="optional"/>
- <xs:attribute name="threshType" type="xs:string" use="optional">
- <xs:annotation>
- <xs:documentation>loosely specified enumeration: NONE,ABOVE, or BELOW</xs:documentation>
- </xs:annotation>
+ <xs:attribute name="noValueColour" use="optional" type="jalview:NoValueColour" default="Min" />
+ <xs:attribute name="threshType" use="optional">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="NONE" />
+ <xs:enumeration value="ABOVE" />
+ <xs:enumeration value="BELOW" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:attribute>
<xs:attribute name="threshold" type="xs:float" use="optional"/>
<xs:attribute name="max" type="xs:float" use="optional"/>
<xs:attribute name="autoScale" type="xs:boolean" use="optional"/>
</xs:complexType>
</xs:element>
+ <xs:element name="filter" maxOccurs="unbounded" minOccurs="0" >
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="matcherSet" type="jalview:FeatureMatcherSet" />
+ </xs:sequence>
+ <xs:attribute name="featureType" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
</xs:sequence>
<xs:attribute name="schemeName" type="xs:string" use="optional"/>
</xs:complexType>
+
+ <xs:complexType name="FeatureMatcherSet">
+ <xs:annotation>
+ <xs:documentation>A feature match condition, which may be simple or compound</xs:documentation>
+ </xs:annotation>
+ <xs:choice>
+ <xs:element name="matchCondition" type="jalview:FeatureMatcher" />
+ <xs:element name="compoundMatcher">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="matcherSet" minOccurs="2" maxOccurs="2" type="jalview:FeatureMatcherSet" />
+ </xs:sequence>
+ <xs:attribute name="and" type="xs:boolean" use="required">
+ <xs:annotation>
+ <xs:documentation>If true, matchers are AND-ed, if false they are OR-ed</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+
+ <xs:complexType name="FeatureMatcher">
+ <xs:sequence>
+ <xs:element name="attributeName" type="xs:string" minOccurs="0" maxOccurs="2">
+ <xs:annotation>
+ <xs:documentation>name of feature attribute to filter on, or attribute and sub-attribute</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="condition" type="xs:string" />
+ <xs:element name="value" type="xs:string" />
+ </xs:sequence>
+ <xs:attribute name="by">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="byLabel" />
+ <xs:enumeration value="byScore" />
+ <xs:enumeration value="byAttribute" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:simpleType name="NoValueColour">
+ <xs:annotation>
+ <xs:documentation>Graduated feature colour if no score (or attribute) value</xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="None" />
+ <xs:enumeration value="Min" />
+ <xs:enumeration value="Max" />
+ </xs:restriction>
+ </xs:simpleType>
</xs:schema>
<xs:sequence>
<xs:element name="setting" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
+ <xs:sequence>
+ <xs:element name="attributeName" type="xs:string" minOccurs="0" maxOccurs="2">
+ <xs:annotation>
+ <xs:documentation>name of feature attribute to colour by, or attribute and sub-attribute</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="matcherSet" minOccurs="0" type="jalview:FeatureMatcherSet">
+ <xs:annotation>
+ <xs:documentation>optional filter(s) applied to the feature type</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
<xs:attribute name="type" type="xs:string" use="required" />
<xs:attribute name="colour" type="xs:int" use="required" />
<xs:attribute name="display" type="xs:boolean"
</xs:documentation>
</xs:annotation>
</xs:attribute>
+ <xs:attribute name="noValueColour" use="optional" type="jalview:NoValueColour" default="Min" />
<xs:attribute name="threshold" type="xs:float"
use="optional">
<xs:annotation>
<xs:element name="otherData" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="key" type="xs:string" use="required" />
+ <xs:attribute name="key2" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>key2 may be used for a sub-attribute of key</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
<xs:attribute name="value" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
public String id;
- public Vector<Bond> bonds = new Vector<Bond>();
+ public Vector<Bond> bonds = new Vector<>();
- public Vector<Atom> atoms = new Vector<Atom>();
+ public Vector<Atom> atoms = new Vector<>();
- public Vector<Residue> residues = new Vector<Residue>();
+ public Vector<Residue> residues = new Vector<>();
public int offset;
}
/**
+ * Annotate the residues with their corresponding positions in s1 using the
+ * alignment in as NOTE: This clears all atom.alignmentMapping values on the
+ * structure.
+ *
+ * @param as
+ * @param s1
+ */
+ public void makeExactMapping(StructureMapping mapping, SequenceI s1)
+ {
+ // first clear out any old alignmentMapping values:
+ for (Atom atom : atoms)
+ {
+ atom.alignmentMapping = -1;
+ }
+ SequenceI ds = s1;
+ while (ds.getDatasetSequence() != null)
+ {
+ ds = ds.getDatasetSequence();
+ }
+ int pdboffset = 0;
+ for (Residue res : residues)
+ {
+ // res.number isn't set correctly for discontinuous/mismapped residues
+ int seqpos = mapping.getSeqPos(res.atoms.get(0).resNumber);
+ char strchar = sequence.getCharAt(pdboffset++);
+ if (seqpos == StructureMapping.UNASSIGNED_VALUE)
+ {
+ continue;
+ }
+ char seqchar = ds.getCharAt(seqpos - ds.getStart());
+
+ boolean sameResidue = Comparison.isSameResidue(
+ seqchar, strchar, false);
+ if (sameResidue)
+ {
+ for (Atom atom : res.atoms)
+ {
+ atom.alignmentMapping = seqpos - 1;
+ }
+ }
+ }
+ }
+
+ /**
* Copies over the RESNUM seqfeatures from the internal chain sequence to the
* mapped sequence
*
boolean deoxyn = false;
boolean nucleotide = false;
StringBuilder seq = new StringBuilder(256);
- Vector<SequenceFeature> resFeatures = new Vector<SequenceFeature>();
- Vector<Annotation> resAnnotation = new Vector<Annotation>();
- int i, iSize = atoms.size() - 1;
+ Vector<SequenceFeature> resFeatures = new Vector<>();
+ Vector<Annotation> resAnnotation = new Vector<>();
+ int iSize = atoms.size() - 1;
int resNumber = -1;
char insCode = ' ';
- for (i = 0; i <= iSize; i++)
+
+ for (int i = 0; i <= iSize; i++)
{
Atom tmp = atoms.elementAt(i);
resNumber = tmp.resNumber;
offset = resNumber;
}
- Vector<Atom> resAtoms = new Vector<Atom>();
+ Vector<Atom> resAtoms = new Vector<>();
// Add atoms to a vector while the residue number
// remains the same as the first atom's resNumber (res)
while ((resNumber == res) && (ins == insCode) && (i < atoms.size()))
if (StructureImportSettings.isShowSeqFeatures())
{
- for (i = 0, iSize = resFeatures.size(); i < iSize; i++)
+ iSize = resFeatures.size();
+ for (int i = 0; i < iSize; i++)
{
sequence.addSequenceFeature(resFeatures.elementAt(i));
resFeatures.setElementAt(null, i);
if (visibleChainAnnotation)
{
Annotation[] annots = new Annotation[resAnnotation.size()];
- float max = 0;
- for (i = 0, iSize = annots.length; i < iSize; i++)
+ float max = 0f;
+ float min = 0f;
+ iSize = annots.length;
+ for (int i = 0; i < iSize; i++)
{
annots[i] = resAnnotation.elementAt(i);
- if (annots[i].value > max)
- {
- max = annots[i].value;
- }
+ max = Math.max(max, annots[i].value);
+ min = Math.min(min, annots[i].value);
resAnnotation.setElementAt(null, i);
}
AlignmentAnnotation tfactorann = new AlignmentAnnotation(
"Temperature Factor", "Temperature Factor for " + pdbid + id,
- annots, 0, max, AlignmentAnnotation.LINE_GRAPH);
+ annots, min, max, AlignmentAnnotation.LINE_GRAPH);
tfactorann.setSequenceRef(sequence);
sequence.addAlignmentAnnotation(tfactorann);
}
{
SequenceI sq = mapping.getSequence();
SequenceI dsq = sq;
+ if (sqmpping == null)
+ {
+ // SIFTS mappings are recorded in the StructureMapping object...
+
+ sqmpping = mapping.getSeqToPdbMapping();
+ }
if (sq != null)
{
while (dsq.getDatasetSequence() != null)
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
this.structureManager = structureManager;
chimera = null;
chimeraListenerThread = null;
- currentModelsMap = new HashMap<Integer, ChimeraModel>();
+ currentModelsMap = new HashMap<>();
}
public List<ChimeraModel> getChimeraModels(String modelName,
ModelType modelType)
{
- List<ChimeraModel> models = new ArrayList<ChimeraModel>();
+ List<ChimeraModel> models = new ArrayList<>();
for (ChimeraModel model : currentModelsMap.values())
{
if (modelName.equals(model.getModelName())
public Map<String, List<ChimeraModel>> getChimeraModelsMap()
{
- Map<String, List<ChimeraModel>> models = new HashMap<String, List<ChimeraModel>>();
+ Map<String, List<ChimeraModel>> models = new HashMap<>();
for (ChimeraModel model : currentModelsMap.values())
{
String modelName = model.getModelName();
public Map<Integer, ChimeraModel> getSelectedModels()
{
- Map<Integer, ChimeraModel> selectedModelsMap = new HashMap<Integer, ChimeraModel>();
+ Map<Integer, ChimeraModel> selectedModelsMap = new HashMap<>();
List<String> chimeraReply = sendChimeraCommand(
"list selection level molecule", true);
if (chimeraReply != null)
*/
public List<String> getSelectedResidueSpecs()
{
- List<String> selectedResidues = new ArrayList<String>();
+ List<String> selectedResidues = new ArrayList<>();
List<String> chimeraReply = sendChimeraCommand(
"list selection level residue", true);
if (chimeraReply != null)
// TODO: [Optional] Handle smiles names in a better way in Chimera?
public List<ChimeraModel> getModelList()
{
- List<ChimeraModel> modelList = new ArrayList<ChimeraModel>();
+ List<ChimeraModel> modelList = new ArrayList<>();
List<String> list = sendChimeraCommand("list models type molecule",
true);
if (list != null)
*/
public List<String> getPresets()
{
- ArrayList<String> presetList = new ArrayList<String>();
+ ArrayList<String> presetList = new ArrayList<>();
List<String> output = sendChimeraCommand("preset list", true);
if (output != null)
{
// iterate over possible paths for starting Chimera
for (String chimeraPath : chimeraPaths)
{
- File path = new File(chimeraPath);
- // uncomment the next line to simulate Chimera not installed
- // path = new File(chimeraPath + "x");
- if (!path.canExecute())
- {
- error += "File '" + path + "' does not exist.\n";
- continue;
- }
try
{
- List<String> args = new ArrayList<String>();
+ // ensure symbolic links are resolved
+ chimeraPath = Paths.get(chimeraPath).toRealPath().toString();
+ File path = new File(chimeraPath);
+ // uncomment the next line to simulate Chimera not installed
+ // path = new File(chimeraPath + "x");
+ if (!path.canExecute())
+ {
+ error += "File '" + path + "' does not exist.\n";
+ continue;
+ }
+ List<String> args = new ArrayList<>();
args.add(chimeraPath);
// shows Chimera output window but suppresses REST responses:
// args.add("--debug");
break;
} catch (Exception e)
{
- // Chimera could not be started
+ // Chimera could not be started using this path
error += e.getMessage();
}
}
public List<String> getAttrList()
{
- List<String> attributes = new ArrayList<String>();
+ List<String> attributes = new ArrayList<>();
final List<String> reply = sendChimeraCommand("list resattr", true);
if (reply != null)
{
public Map<ChimeraResidue, Object> getAttrValues(String aCommand,
ChimeraModel model)
{
- Map<ChimeraResidue, Object> values = new HashMap<ChimeraResidue, Object>();
+ Map<ChimeraResidue, Object> values = new HashMap<>();
final List<String> reply = sendChimeraCommand("list residue spec "
+ model.toSpec() + " attribute " + aCommand, true);
if (reply != null)
protected List<String> sendRestCommand(String command)
{
String restUrl = "http://127.0.0.1:" + this.chimeraRestPort + "/run";
- List<NameValuePair> commands = new ArrayList<NameValuePair>(1);
+ List<NameValuePair> commands = new ArrayList<>(1);
commands.add(new BasicNameValuePair("command", command));
- List<String> reply = new ArrayList<String>();
+ List<String> reply = new ArrayList<>();
BufferedReader response = null;
try
{
this.haveGUI = haveGUI;
// Create the Chimera interface
chimeraManager = new ChimeraManager(this);
- chimSelectionList = new ArrayList<ChimeraStructuralObject>();
+ chimSelectionList = new ArrayList<>();
pathProps = new Properties();
}
ModelType type)
{
// new models
- Map<String, List<ChimeraModel>> newModels = new HashMap<String, List<ChimeraModel>>();
+ Map<String, List<ChimeraModel>> newModels = new HashMap<>();
if (chimObjNames.size() > 0)
{
List<String> names = chimObjNames.iterator().next();
// alDialog.dispose();
// }
// System.out.println("launch align dialog");
- List<ChimeraStructuralObject> chimObjectList = new ArrayList<ChimeraStructuralObject>();
+ List<ChimeraStructuralObject> chimObjectList = new ArrayList<>();
for (ChimeraModel model : chimeraManager.getChimeraModels())
{
if (useChains)
public List<String> getAllChimeraResidueAttributes()
{
- List<String> attributes = new ArrayList<String>();
+ List<String> attributes = new ArrayList<>();
// attributes.addAll(rinManager.getResAttrs());
attributes.addAll(chimeraManager.getAttrList());
return attributes;
// TODO: [Optional] Change priority of Chimera paths
public static List<String> getChimeraPaths()
{
- List<String> pathList = new ArrayList<String>();
+ List<String> pathList = new ArrayList<>();
// if no network is available and the settings have been modified by the
// user, check for a
}
else if (os.startsWith("Windows"))
{
- pathList.add("\\Program Files\\Chimera\\bin\\chimera");
- pathList.add("C:\\Program Files\\Chimera\\bin\\chimera.exe");
+ for (String root : new String[] { "\\Program Files",
+ "C:\\Program Files", "\\Program Files (x86)",
+ "C:\\Program Files (x86)" })
+ {
+ for (String version : new String[] { "1.11", "1.11.1", "1.11.2",
+ "1.12", "1.12.1", "1.12.2", "1.13" })
+ {
+ pathList.add(root + "\\Chimera " + version + "\\bin\\chimera");
+ pathList.add(
+ root + "\\Chimera " + version + "\\bin\\chimera.exe");
+ }
+ }
}
else if (os.startsWith("Mac"))
{
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.GeneLociI;
import jalview.datamodel.IncompleteCodonException;
import jalview.datamodel.Mapping;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.datamodel.features.SequenceFeatures;
+import jalview.io.gff.Gff3Helper;
import jalview.io.gff.SequenceOntologyI;
import jalview.schemes.ResidueProperties;
import jalview.util.Comparison;
{
return variant == null ? null : variant.getFeatureGroup();
}
+
+ /**
+ * toString for aid in the debugger only
+ */
+ @Override
+ public String toString()
+ {
+ return base + ":" + (variant == null ? "" : variant.getDescription());
+ }
}
/**
*/
public static AlignmentI expandContext(AlignmentI core, int flankSize)
{
- List<SequenceI> sq = new ArrayList<SequenceI>();
+ List<SequenceI> sq = new ArrayList<>();
int maxoffset = 0;
for (SequenceI s : core.getSequences())
{
public static Map<String, List<SequenceI>> getSequencesByName(
AlignmentI al)
{
- Map<String, List<SequenceI>> theMap = new LinkedHashMap<String, List<SequenceI>>();
+ Map<String, List<SequenceI>> theMap = new LinkedHashMap<>();
for (SequenceI seq : al.getSequences())
{
String name = seq.getName();
List<SequenceI> seqs = theMap.get(name);
if (seqs == null)
{
- seqs = new ArrayList<SequenceI>();
+ seqs = new ArrayList<>();
theMap.put(name, seqs);
}
seqs.add(seq);
return false;
}
- Set<SequenceI> mappedDna = new HashSet<SequenceI>();
- Set<SequenceI> mappedProtein = new HashSet<SequenceI>();
+ Set<SequenceI> mappedDna = new HashSet<>();
+ Set<SequenceI> mappedProtein = new HashSet<>();
/*
* First pass - map sequences where cross-references exist. This include
* Answers true if the mappings include one between the given (dataset)
* sequences.
*/
- public static boolean mappingExists(List<AlignedCodonFrame> mappings,
+ protected static boolean mappingExists(List<AlignedCodonFrame> mappings,
SequenceI aaSeq, SequenceI cdnaSeq)
{
if (mappings != null)
{
String lastCodon = String.valueOf(cdnaSeqChars,
cdnaLength - CODON_LENGTH, CODON_LENGTH).toUpperCase();
- for (String stop : ResidueProperties.STOP)
+ for (String stop : ResidueProperties.STOP_CODONS)
{
if (lastCodon.equals(stop))
{
* allow * in protein to match untranslatable in dna
*/
final char aaRes = aaSeqChars[aaPos];
- if ((translated == null || "STOP".equals(translated)) && aaRes == '*')
+ if ((translated == null || ResidueProperties.STOP.equals(translated))
+ && aaRes == '*')
{
continue;
}
if (dnaPos == cdnaSeqChars.length - CODON_LENGTH)
{
String codon = String.valueOf(cdnaSeqChars, dnaPos, CODON_LENGTH);
- if ("STOP".equals(ResidueProperties.codonTranslate(codon)))
+ if (ResidueProperties.STOP
+ .equals(ResidueProperties.codonTranslate(codon)))
{
return true;
}
System.err.println("Wrong alignment type in alignProteinAsDna");
return 0;
}
- List<SequenceI> unmappedProtein = new ArrayList<SequenceI>();
+ List<SequenceI> unmappedProtein = new ArrayList<>();
Map<AlignedCodon, Map<SequenceI, AlignedCodon>> alignedCodons = buildCodonColumnsMap(
protein, dna, unmappedProtein);
return alignProteinAs(protein, alignedCodons, unmappedProtein);
* {dnaSequence, {proteinSequence, codonProduct}} at that position. The
* comparator keeps the codon positions ordered.
*/
- Map<AlignedCodon, Map<SequenceI, AlignedCodon>> alignedCodons = new TreeMap<AlignedCodon, Map<SequenceI, AlignedCodon>>(
+ Map<AlignedCodon, Map<SequenceI, AlignedCodon>> alignedCodons = new TreeMap<>(
new CodonComparator());
for (SequenceI dnaSeq : dna.getSequences())
// TODO delete this ugly hack once JAL-2022 is resolved
// i.e. we can model startPhase > 0 (incomplete start codon)
- List<SequenceI> sequencesChecked = new ArrayList<SequenceI>();
+ List<SequenceI> sequencesChecked = new ArrayList<>();
AlignedCodon lastCodon = null;
- Map<SequenceI, AlignedCodon> toAdd = new HashMap<SequenceI, AlignedCodon>();
+ Map<SequenceI, AlignedCodon> toAdd = new HashMap<>();
for (Entry<AlignedCodon, Map<SequenceI, AlignedCodon>> entry : alignedCodons
.entrySet())
Map<SequenceI, AlignedCodon> seqProduct = alignedCodons.get(codon);
if (seqProduct == null)
{
- seqProduct = new HashMap<SequenceI, AlignedCodon>();
+ seqProduct = new HashMap<>();
alignedCodons.put(codon, seqProduct);
}
seqProduct.put(protein, codon);
{
continue;
}
- final List<AlignmentAnnotation> result = new ArrayList<AlignmentAnnotation>();
+ final List<AlignmentAnnotation> result = new ArrayList<>();
for (AlignmentAnnotation dsann : datasetAnnotations)
{
/*
throw new IllegalArgumentException(
"IMPLEMENTATION ERROR: dataset.getDataset() must be null!");
}
- List<SequenceI> foundSeqs = new ArrayList<SequenceI>();
- List<SequenceI> cdsSeqs = new ArrayList<SequenceI>();
+ List<SequenceI> foundSeqs = new ArrayList<>();
+ List<SequenceI> cdsSeqs = new ArrayList<>();
List<AlignedCodonFrame> mappings = dataset.getCodonFrames();
HashSet<SequenceI> productSeqs = null;
if (products != null)
{
- productSeqs = new HashSet<SequenceI>();
+ productSeqs = new HashSet<>();
for (SequenceI seq : products)
{
- productSeqs.add(seq.getDatasetSequence() == null ? seq
- : seq.getDatasetSequence());
+ productSeqs.add(seq.getDatasetSequence() == null ? seq : seq
+ .getDatasetSequence());
}
}
/*
* add a mapping from CDS to the (unchanged) mapped to range
*/
- List<int[]> cdsRange = Collections
- .singletonList(new int[]
- { 1, cdsSeq.getLength() });
+ List<int[]> cdsRange = Collections.singletonList(new int[] { 1,
+ cdsSeq.getLength() });
MapList cdsToProteinMap = new MapList(cdsRange,
mapList.getToRanges(), mapList.getFromRatio(),
mapList.getToRatio());
* add another mapping from original 'from' range to CDS
*/
AlignedCodonFrame dnaToCdsMapping = new AlignedCodonFrame();
- MapList dnaToCdsMap = new MapList(mapList.getFromRanges(),
+ final MapList dnaToCdsMap = new MapList(mapList.getFromRanges(),
cdsRange, 1, 1);
dnaToCdsMapping.addMap(dnaSeq.getDatasetSequence(), cdsSeqDss,
dnaToCdsMap);
}
/*
+ * transfer dna chromosomal loci (if known) to the CDS
+ * sequence (via the mapping)
+ */
+ final MapList cdsToDnaMap = dnaToCdsMap.getInverse();
+ transferGeneLoci(dnaSeq, cdsToDnaMap, cdsSeq);
+
+ /*
* add DBRef with mapping from protein to CDS
* (this enables Get Cross-References from protein alignment)
* This is tricky because we can't have two DBRefs with the
for (DBRefEntry primRef : dnaDss.getPrimaryDBRefs())
{
- // creates a complementary cross-reference to the source sequence's
- // primary reference.
-
- DBRefEntry cdsCrossRef = new DBRefEntry(primRef.getSource(),
- primRef.getSource() + ":" + primRef.getVersion(),
- primRef.getAccessionId());
- cdsCrossRef
- .setMap(new Mapping(dnaDss, new MapList(dnaToCdsMap)));
+ /*
+ * create a cross-reference from CDS to the source sequence's
+ * primary reference and vice versa
+ */
+ String source = primRef.getSource();
+ String version = primRef.getVersion();
+ DBRefEntry cdsCrossRef = new DBRefEntry(source, source + ":"
+ + version, primRef.getAccessionId());
+ cdsCrossRef.setMap(new Mapping(dnaDss, new MapList(cdsToDnaMap)));
cdsSeqDss.addDBRef(cdsCrossRef);
+ dnaSeq.addDBRef(new DBRefEntry(source, version, cdsSeq
+ .getName(), new Mapping(cdsSeqDss, dnaToCdsMap)));
+
// problem here is that the cross-reference is synthesized -
// cdsSeq.getName() may be like 'CDS|dnaaccession' or
// 'CDS|emblcdsacc'
// assuming cds version same as dna ?!?
- DBRefEntry proteinToCdsRef = new DBRefEntry(primRef.getSource(),
- primRef.getVersion(), cdsSeq.getName());
+ DBRefEntry proteinToCdsRef = new DBRefEntry(source, version,
+ cdsSeq.getName());
//
- proteinToCdsRef.setMap(
- new Mapping(cdsSeqDss, cdsToProteinMap.getInverse()));
+ proteinToCdsRef.setMap(new Mapping(cdsSeqDss, cdsToProteinMap
+ .getInverse()));
proteinProduct.addDBRef(proteinToCdsRef);
}
}
}
- AlignmentI cds = new Alignment(
- cdsSeqs.toArray(new SequenceI[cdsSeqs.size()]));
+ AlignmentI cds = new Alignment(cdsSeqs.toArray(new SequenceI[cdsSeqs
+ .size()]));
cds.setDataset(dataset);
return cds;
}
/**
+ * Tries to transfer gene loci (dbref to chromosome positions) from fromSeq to
+ * toSeq, mediated by the given mapping between the sequences
+ *
+ * @param fromSeq
+ * @param targetToFrom
+ * Map
+ * @param targetSeq
+ */
+ protected static void transferGeneLoci(SequenceI fromSeq,
+ MapList targetToFrom, SequenceI targetSeq)
+ {
+ if (targetSeq.getGeneLoci() != null)
+ {
+ // already have - don't override
+ return;
+ }
+ GeneLociI fromLoci = fromSeq.getGeneLoci();
+ if (fromLoci == null)
+ {
+ return;
+ }
+
+ MapList newMap = targetToFrom.traverse(fromLoci.getMap());
+
+ if (newMap != null)
+ {
+ targetSeq.setGeneLoci(fromLoci.getSpeciesId(),
+ fromLoci.getAssemblyId(), fromLoci.getChromosomeId(), newMap);
+ }
+ }
+
+ /**
* A helper method that finds a CDS sequence in the alignment dataset that is
* mapped to the given protein sequence, and either is, or has a mapping from,
* the given dna sequence.
* @param seqMappings
* the set of mappings involving dnaSeq
* @param aMapping
- * an initial candidate from seqMappings
+ * a transcript-to-peptide mapping
* @return
*/
static SequenceI findCdsForProtein(List<AlignedCodonFrame> mappings,
if (mappedFromLength == dnaLength
|| mappedFromLength == dnaLength - CODON_LENGTH)
{
- return seqDss;
+ /*
+ * if sequence has CDS features, this is a transcript with no UTR
+ * - do not take this as the CDS sequence! (JAL-2789)
+ */
+ if (seqDss.getFeatures().getFeaturesByOntology(SequenceOntologyI.CDS)
+ .isEmpty())
+ {
+ return seqDss;
+ }
}
/*
{
/*
* found a 3:1 mapping to the protein product which covers
- * the whole dna sequence i.e. is from CDS; finally check it
- * is from the dna start sequence
+ * the whole dna sequence i.e. is from CDS; finally check the CDS
+ * is mapped from the given dna start sequence
*/
SequenceI cdsSeq = map.getFromSeq();
+ // todo this test is weak if seqMappings contains multiple mappings;
+ // we get away with it if transcript:cds relationship is 1:1
List<AlignedCodonFrame> dnaToCdsMaps = MappingUtils
.findMappingsForSequence(cdsSeq, seqMappings);
if (!dnaToCdsMaps.isEmpty())
}
/**
- * add any DBRefEntrys to cdsSeq from contig that have a Mapping congruent to
+ * Adds any DBRefEntrys to cdsSeq from contig that have a Mapping congruent to
* the given mapping.
*
* @param cdsSeq
* @param contig
+ * @param proteinProduct
* @param mapping
- * @return list of DBRefEntrys added.
+ * @return list of DBRefEntrys added
*/
- public static List<DBRefEntry> propagateDBRefsToCDS(SequenceI cdsSeq,
+ protected static List<DBRefEntry> propagateDBRefsToCDS(SequenceI cdsSeq,
SequenceI contig, SequenceI proteinProduct, Mapping mapping)
{
- // gather direct refs from contig congrent with mapping
- List<DBRefEntry> direct = new ArrayList<DBRefEntry>();
- HashSet<String> directSources = new HashSet<String>();
+ // gather direct refs from contig congruent with mapping
+ List<DBRefEntry> direct = new ArrayList<>();
+ HashSet<String> directSources = new HashSet<>();
+
if (contig.getDBRefs() != null)
{
for (DBRefEntry dbr : contig.getDBRefs())
DBRefEntry[] onSource = DBRefUtils.selectRefs(
proteinProduct.getDBRefs(),
directSources.toArray(new String[0]));
- List<DBRefEntry> propagated = new ArrayList<DBRefEntry>();
+ List<DBRefEntry> propagated = new ArrayList<>();
// and generate appropriate mappings
for (DBRefEntry cdsref : direct)
* subtypes in the Sequence Ontology)
* @param omitting
*/
- public static int transferFeatures(SequenceI fromSeq, SequenceI toSeq,
+ protected static int transferFeatures(SequenceI fromSeq, SequenceI toSeq,
MapList mapping, String select, String... omitting)
{
SequenceI copyTo = toSeq;
int mappedDnaLength = MappingUtils.getLength(ranges);
/*
- * if not a whole number of codons, something is wrong,
- * abort mapping
+ * if not a whole number of codons, truncate mapping
*/
- if (mappedDnaLength % CODON_LENGTH > 0)
+ int codonRemainder = mappedDnaLength % CODON_LENGTH;
+ if (codonRemainder > 0)
{
- return null;
+ mappedDnaLength -= codonRemainder;
+ MappingUtils.removeEndPositions(codonRemainder, ranges);
}
int proteinLength = proteinSeq.getLength();
proteinStart++;
proteinLength--;
}
- List<int[]> proteinRange = new ArrayList<int[]>();
+ List<int[]> proteinRange = new ArrayList<>();
/*
* dna length should map to protein (or protein plus stop codon)
* @param dnaSeq
* @return
*/
- public static List<int[]> findCdsPositions(SequenceI dnaSeq)
+ protected static List<int[]> findCdsPositions(SequenceI dnaSeq)
{
- List<int[]> result = new ArrayList<int[]>();
+ List<int[]> result = new ArrayList<>();
List<SequenceFeature> sfs = dnaSeq.getFeatures().getFeaturesByOntology(
SequenceOntologyI.CDS);
{
if (var.variant != null)
{
- String alleles = (String) var.variant.getValue("alleles");
+ String alleles = (String) var.variant.getValue(Gff3Helper.ALLELES);
if (alleles != null)
{
for (String base : alleles.split(","))
{
- String codon = base + base2 + base3;
- if (addPeptideVariant(peptide, peptidePos, residue, var, codon))
+ if (!base1.equalsIgnoreCase(base))
{
- count++;
+ String codon = base.toUpperCase() + base2.toLowerCase()
+ + base3.toLowerCase();
+ String canonical = base1.toUpperCase() + base2.toLowerCase()
+ + base3.toLowerCase();
+ if (addPeptideVariant(peptide, peptidePos, residue, var,
+ codon, canonical))
+ {
+ count++;
+ }
}
}
}
{
if (var.variant != null)
{
- String alleles = (String) var.variant.getValue("alleles");
+ String alleles = (String) var.variant.getValue(Gff3Helper.ALLELES);
if (alleles != null)
{
for (String base : alleles.split(","))
{
- String codon = base1 + base + base3;
- if (addPeptideVariant(peptide, peptidePos, residue, var, codon))
+ if (!base2.equalsIgnoreCase(base))
{
- count++;
+ String codon = base1.toLowerCase() + base.toUpperCase()
+ + base3.toLowerCase();
+ String canonical = base1.toLowerCase() + base2.toUpperCase()
+ + base3.toLowerCase();
+ if (addPeptideVariant(peptide, peptidePos, residue, var,
+ codon, canonical))
+ {
+ count++;
+ }
}
}
}
{
if (var.variant != null)
{
- String alleles = (String) var.variant.getValue("alleles");
+ String alleles = (String) var.variant.getValue(Gff3Helper.ALLELES);
if (alleles != null)
{
for (String base : alleles.split(","))
{
- String codon = base1 + base2 + base;
- if (addPeptideVariant(peptide, peptidePos, residue, var, codon))
+ if (!base3.equalsIgnoreCase(base))
{
- count++;
+ String codon = base1.toLowerCase() + base2.toLowerCase()
+ + base.toUpperCase();
+ String canonical = base1.toLowerCase() + base2.toLowerCase()
+ + base3.toUpperCase();
+ if (addPeptideVariant(peptide, peptidePos, residue, var,
+ codon, canonical))
+ {
+ count++;
+ }
}
}
}
}
/**
- * Helper method that adds a peptide variant feature, provided the given codon
- * translates to a value different to the current residue (is a non-synonymous
- * variant). ID and clinical_significance attributes of the dna variant (if
- * present) are copied to the new feature.
+ * Helper method that adds a peptide variant feature. ID and
+ * clinical_significance attributes of the dna variant (if present) are copied
+ * to the new feature.
*
* @param peptide
* @param peptidePos
* @param residue
* @param var
* @param codon
+ * the variant codon e.g. aCg
+ * @param canonical
+ * the 'normal' codon e.g. aTg
* @return true if a feature was added, else false
*/
static boolean addPeptideVariant(SequenceI peptide, int peptidePos,
- String residue, DnaVariant var, String codon)
+ String residue, DnaVariant var, String codon, String canonical)
{
/*
* get peptide translation of codon e.g. GAT -> D
* e.g. multibase variants or HGMD_MUTATION etc
* are currently ignored here
*/
- String trans = codon.contains("-") ? "-"
+ String trans = codon.contains("-") ? null
: (codon.length() > CODON_LENGTH ? null
: ResidueProperties.codonTranslate(codon));
- if (trans != null && !trans.equals(residue))
+ if (trans == null)
+ {
+ return false;
+ }
+ String desc = canonical + "/" + codon;
+ String featureType = "";
+ if (trans.equals(residue))
+ {
+ featureType = SequenceOntologyI.SYNONYMOUS_VARIANT;
+ }
+ else if (ResidueProperties.STOP.equals(trans))
+ {
+ featureType = SequenceOntologyI.STOP_GAINED;
+ }
+ else
{
String residue3Char = StringUtils
.toSentenceCase(ResidueProperties.aa2Triplet.get(residue));
String trans3Char = StringUtils
.toSentenceCase(ResidueProperties.aa2Triplet.get(trans));
- String desc = "p." + residue3Char + peptidePos + trans3Char;
- SequenceFeature sf = new SequenceFeature(
- SequenceOntologyI.SEQUENCE_VARIANT, desc, peptidePos,
- peptidePos, var.getSource());
- StringBuilder attributes = new StringBuilder(32);
- String id = (String) var.variant.getValue(ID);
- if (id != null)
- {
- if (id.startsWith(SEQUENCE_VARIANT))
- {
- id = id.substring(SEQUENCE_VARIANT.length());
- }
- sf.setValue(ID, id);
- attributes.append(ID).append("=").append(id);
- // TODO handle other species variants JAL-2064
- StringBuilder link = new StringBuilder(32);
- try
- {
- link.append(desc).append(" ").append(id).append(
- "|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=")
- .append(URLEncoder.encode(id, "UTF-8"));
- sf.addLink(link.toString());
- } catch (UnsupportedEncodingException e)
- {
- // as if
- }
- }
- String clinSig = (String) var.variant.getValue(CLINICAL_SIGNIFICANCE);
- if (clinSig != null)
+ desc = "p." + residue3Char + peptidePos + trans3Char;
+ featureType = SequenceOntologyI.NONSYNONYMOUS_VARIANT;
+ }
+ SequenceFeature sf = new SequenceFeature(featureType, desc, peptidePos,
+ peptidePos, var.getSource());
+
+ StringBuilder attributes = new StringBuilder(32);
+ String id = (String) var.variant.getValue(ID);
+ if (id != null)
+ {
+ if (id.startsWith(SEQUENCE_VARIANT))
{
- sf.setValue(CLINICAL_SIGNIFICANCE, clinSig);
- attributes.append(";").append(CLINICAL_SIGNIFICANCE).append("=")
- .append(clinSig);
+ id = id.substring(SEQUENCE_VARIANT.length());
}
- peptide.addSequenceFeature(sf);
- if (attributes.length() > 0)
+ sf.setValue(ID, id);
+ attributes.append(ID).append("=").append(id);
+ // TODO handle other species variants JAL-2064
+ StringBuilder link = new StringBuilder(32);
+ try
+ {
+ link.append(desc).append(" ").append(id).append(
+ "|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=")
+ .append(URLEncoder.encode(id, "UTF-8"));
+ sf.addLink(link.toString());
+ } catch (UnsupportedEncodingException e)
{
- sf.setAttributes(attributes.toString());
+ // as if
}
- return true;
}
- return false;
+ String clinSig = (String) var.variant.getValue(CLINICAL_SIGNIFICANCE);
+ if (clinSig != null)
+ {
+ sf.setValue(CLINICAL_SIGNIFICANCE, clinSig);
+ attributes.append(";").append(CLINICAL_SIGNIFICANCE).append("=")
+ .append(clinSig);
+ }
+ peptide.addSequenceFeature(sf);
+ if (attributes.length() > 0)
+ {
+ sf.setAttributes(attributes.toString());
+ }
+ return true;
}
/**
* Builds a map whose key is position in the protein sequence, and value is a
- * list of the base and all variants for each corresponding codon position
+ * list of the base and all variants for each corresponding codon position.
+ * <p>
+ * This depends on dna variants being held as a comma-separated list as
+ * property "alleles" on variant features.
*
* @param dnaSeq
* @param dnaToProtein
* map from peptide position to all variants of the codon which codes for it
* LinkedHashMap ensures we keep the peptide features in sequence order
*/
- LinkedHashMap<Integer, List<DnaVariant>[]> variants = new LinkedHashMap<Integer, List<DnaVariant>[]>();
+ LinkedHashMap<Integer, List<DnaVariant>[]> variants = new LinkedHashMap<>();
List<SequenceFeature> dnaFeatures = dnaSeq.getFeatures()
.getFeaturesByOntology(SequenceOntologyI.SEQUENCE_VARIANT);
// not handling multi-locus variant features
continue;
}
+
+ /*
+ * ignore variant if not a SNP
+ */
+ String alls = (String) sf.getValue(Gff3Helper.ALLELES);
+ if (alls == null)
+ {
+ continue; // non-SNP VCF variant perhaps - can't process this
+ }
+
+ String[] alleles = alls.toUpperCase().split(",");
+ boolean isSnp = true;
+ for (String allele : alleles)
+ {
+ if (allele.trim().length() > 1)
+ {
+ isSnp = false;
+ }
+ }
+ if (!isSnp)
+ {
+ continue;
+ }
+
int[] mapsTo = dnaToProtein.locateInTo(dnaCol, dnaCol);
if (mapsTo == null)
{
if (codonVariants == null)
{
codonVariants = new ArrayList[CODON_LENGTH];
- codonVariants[0] = new ArrayList<DnaVariant>();
- codonVariants[1] = new ArrayList<DnaVariant>();
- codonVariants[2] = new ArrayList<DnaVariant>();
+ codonVariants[0] = new ArrayList<>();
+ codonVariants[1] = new ArrayList<>();
+ codonVariants[2] = new ArrayList<>();
variants.put(peptidePosition, codonVariants);
}
/*
- * extract dna variants to a string array
- */
- String alls = (String) sf.getValue("alleles");
- if (alls == null)
- {
- continue;
- }
- String[] alleles = alls.toUpperCase().split(",");
- int i = 0;
- for (String allele : alleles)
- {
- alleles[i++] = allele.trim(); // lose any space characters "A, G"
- }
-
- /*
* get this peptide's codon positions e.g. [3, 4, 5] or [4, 7, 10]
*/
int[] codon = peptidePosition == lastPeptidePostion ? lastCodon
/*
* fancy case - aligning via mappings between sequences
*/
- List<SequenceI> unmapped = new ArrayList<SequenceI>();
+ List<SequenceI> unmapped = new ArrayList<>();
Map<Integer, Map<SequenceI, Character>> columnMap = buildMappedColumnsMap(
unaligned, aligned, unmapped);
int width = columnMap.size();
}
// map from dataset sequence to alignment sequence(s)
- Map<SequenceI, List<SequenceI>> alignedDatasets = new HashMap<SequenceI, List<SequenceI>>();
+ Map<SequenceI, List<SequenceI>> alignedDatasets = new HashMap<>();
for (SequenceI seq : aligned.getSequences())
{
SequenceI ds = seq.getDatasetSequence();
* {unalignedSequence, characterPerSequence} at that position.
* TreeMap keeps the entries in ascending column order.
*/
- SortedMap<Integer, Map<SequenceI, Character>> map = new TreeMap<Integer, Map<SequenceI, Character>>();
+ SortedMap<Integer, Map<SequenceI, Character>> map = new TreeMap<>();
/*
* record any sequences that have no mapping so can't be realigned
Map<SequenceI, Character> seqsMap = map.get(fromCol);
if (seqsMap == null)
{
- seqsMap = new HashMap<SequenceI, Character>();
+ seqsMap = new HashMap<>();
map.put(fromCol, seqsMap);
}
seqsMap.put(seq, seq.getCharAt(mappedCharPos - toStart));
* or not conserved (-1)
* Using TreeMap means properties are displayed in alphabetical order
*/
- SortedMap<String, Integer> resultHash = new TreeMap<String, Integer>();
+ SortedMap<String, Integer> resultHash = new TreeMap<>();
SymbolCounts symbolCounts = values.getSymbolCounts();
char[] symbols = symbolCounts.symbols;
int[] counts = symbolCounts.values;
*/
private void percentIdentity(ScoreMatrix sm)
{
- seqNums = new Vector<int[]>();
+ seqNums = new Vector<>();
int i = 0, iSize = sequences.length;
// Do we need to calculate this again?
for (i = 0; i < iSize; i++)
protected void findQuality(int startCol, int endCol,
ScoreMatrix scoreMatrix)
{
- quality = new Vector<Double>();
+ quality = new Vector<>();
double max = -Double.MAX_VALUE;
float[][] scores = scoreMatrix.getMatrix();
/**
* Complete the given consensus and quuality annotation rows. Note: currently
- * this method will enlarge the given annotation row if it is too small,
- * otherwise will leave its length unchanged.
+ * this method will reallocate the given annotation row if it is different to
+ * the calculated width, otherwise will leave its length unchanged.
*
* @param conservation
* conservation annotation row
float qmax = 0f;
if (conservation != null && conservation.annotations != null
- && conservation.annotations.length < alWidth)
+ && conservation.annotations.length != alWidth)
{
conservation.annotations = new Annotation[alWidth];
}
{
quality2.graphMax = (float) qualityMaximum;
if (quality2.annotations != null
- && quality2.annotations.length < alWidth)
+ && quality2.annotations.length != alWidth)
{
quality2.annotations = new Annotation[alWidth];
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
public class Dna
* 'final' variables describe the inputs to the translation, which should not
* be modified.
*/
- final private List<SequenceI> selection;
+ private final List<SequenceI> selection;
- final private String[] seqstring;
+ private final String[] seqstring;
- final private int[] contigs;
+ private final Iterator<int[]> contigs;
- final private char gapChar;
+ private final char gapChar;
- final private AlignmentAnnotation[] annotations;
+ private final AlignmentAnnotation[] annotations;
- final private int dnaWidth;
+ private final int dnaWidth;
- final private AlignmentI dataset;
+ private final AlignmentI dataset;
+
+ private ShiftList vismapping;
+
+ private int[] startcontigs;
/*
* Working variables for the translation.
* @param viewport
* @param visibleContigs
*/
- public Dna(AlignViewportI viewport, int[] visibleContigs)
+ public Dna(AlignViewportI viewport, Iterator<int[]> visibleContigs)
{
this.selection = Arrays.asList(viewport.getSequenceSelection());
this.seqstring = viewport.getViewAsString(true);
this.annotations = viewport.getAlignment().getAlignmentAnnotation();
this.dnaWidth = viewport.getAlignment().getWidth();
this.dataset = viewport.getAlignment().getDataset();
+ initContigs();
+ }
+
+ /**
+ * Initialise contigs used as starting point for translateCodingRegion
+ */
+ private void initContigs()
+ {
+ vismapping = new ShiftList(); // map from viscontigs to seqstring
+ // intervals
+
+ int npos = 0;
+ int[] lastregion = null;
+ ArrayList<Integer> tempcontigs = new ArrayList<>();
+ while (contigs.hasNext())
+ {
+ int[] region = contigs.next();
+ if (lastregion == null)
+ {
+ vismapping.addShift(npos, region[0]);
+ }
+ else
+ {
+ // hidden region
+ vismapping.addShift(npos, region[0] - lastregion[1] + 1);
+ }
+ lastregion = region;
+ tempcontigs.add(region[0]);
+ tempcontigs.add(region[1]);
+ }
+
+ startcontigs = new int[tempcontigs.size()];
+ int i = 0;
+ for (Integer val : tempcontigs)
+ {
+ startcontigs[i] = val;
+ i++;
+ }
+ tempcontigs = null;
}
/**
int s;
int sSize = selection.size();
- List<SequenceI> pepseqs = new ArrayList<SequenceI>();
+ List<SequenceI> pepseqs = new ArrayList<>();
for (s = 0; s < sSize; s++)
{
SequenceI newseq = translateCodingRegion(selection.get(s),
if (dnarefs != null)
{
// intersect with pep
- List<DBRefEntry> mappedrefs = new ArrayList<DBRefEntry>();
+ List<DBRefEntry> mappedrefs = new ArrayList<>();
DBRefEntry[] refs = dna.getDBRefs();
for (int d = 0; d < refs.length; d++)
{
String seqstring, AlignedCodonFrame acf,
List<SequenceI> proteinSeqs)
{
- List<int[]> skip = new ArrayList<int[]>();
- int skipint[] = null;
- ShiftList vismapping = new ShiftList(); // map from viscontigs to seqstring
- // intervals
- int vc;
- int[] scontigs = new int[contigs.length];
+ List<int[]> skip = new ArrayList<>();
+ int[] skipint = null;
+
int npos = 0;
- for (vc = 0; vc < contigs.length; vc += 2)
- {
- if (vc == 0)
- {
- vismapping.addShift(npos, contigs[vc]);
- }
- else
- {
- // hidden region
- vismapping.addShift(npos, contigs[vc] - contigs[vc - 1] + 1);
- }
- scontigs[vc] = contigs[vc];
- scontigs[vc + 1] = contigs[vc + 1];
- }
+ int vc = 0;
+
+ int[] scontigs = new int[startcontigs.length];
+ System.arraycopy(startcontigs, 0, scontigs, 0, startcontigs.length);
// allocate a roughly sized buffer for the protein sequence
StringBuilder protein = new StringBuilder(seqstring.length() / 2);
skip.add(skipint);
skipint = null;
}
- if (aa.equals("STOP"))
+ if (aa.equals(ResidueProperties.STOP))
{
aa = STOP_ASTERIX;
}
public AlignmentI reverseCdna(boolean complement)
{
int sSize = selection.size();
- List<SequenceI> reversed = new ArrayList<SequenceI>();
+ List<SequenceI> reversed = new ArrayList<>();
for (int s = 0; s < sSize; s++)
{
SequenceI newseq = reverseSequence(selection.get(s).getName(),
}
/**
+ * Answers the reverse complement of the input string
+ *
+ * @see #getComplement(char)
+ * @param s
+ * @return
+ */
+ public static String reverseComplement(String s)
+ {
+ StringBuilder sb = new StringBuilder(s.length());
+ for (int i = s.length() - 1; i >= 0; i--)
+ {
+ sb.append(Dna.getComplement(s.charAt(i)));
+ }
+ return sb.toString();
+ }
+
+ /**
* Returns dna complement (preserving case) for aAcCgGtTuU. Ambiguity codes
* are treated as on http://reverse-complement.com/. Anything else is left
* unchanged.
/*
* catch things like <<..<<..>>..<<..>>>> |
*/
- int j = bps.size() - 1;
- while (j >= 0)
+ int j = bps.size();
+ while (--j >= 0)
{
int popen = bps.get(j).getBP5();
break;
}
}
- j -= 1;
}
// Put positions and helix information into the hashtable
Color getMaxColour();
/**
+ * Returns the 'no value' colour (used when a feature lacks score, or the
+ * attribute, being used for colouring)
+ *
+ * @return
+ */
+ Color getNoColour();
+
+ /**
* Answers true if the feature has a single colour, i.e. if isColourByLabel()
* and isGraduatedColour() both answer false
*
boolean isSimpleColour();
/**
- * Answers true if the feature is coloured by label (description)
+ * Answers true if the feature is coloured by label (description) or by text
+ * value of an attribute
*
* @return
*/
void setAboveThreshold(boolean b);
/**
- * Answers true if the threshold is the minimum value (when
- * isAboveThreshold()) or maximum value (when isBelowThreshold()) of the
- * colour range; only applicable when isGraduatedColour and either
- * isAboveThreshold() or isBelowThreshold() answers true
- *
- * @return
- */
- boolean isThresholdMinMax();
-
- void setThresholdMinMax(boolean b);
-
- /**
* Returns the threshold value (if any), else zero
*
* @return
Color getColor(SequenceFeature feature);
/**
- * Update the min-max range for a graduated colour scheme
+ * Update the min-max range for a graduated colour scheme. Note that the
+ * colour scheme may be configured to colour by feature score, or a
+ * (numeric-valued) attribute - the caller should ensure that the correct
+ * range is being set.
*
* @param min
* @param max
* @return
*/
String toJalviewFormat(String featureType);
+
+ /**
+ * Answers true if colour is by attribute text or numerical value
+ *
+ * @return
+ */
+ boolean isColourByAttribute();
+
+ /**
+ * Answers the name of the attribute (and optional sub-attribute...) used for
+ * colouring if any, or null
+ *
+ * @return
+ */
+ String[] getAttributeName();
+
+ /**
+ * Sets the name of the attribute (and optional sub-attribute...) used for
+ * colouring if any, or null to remove this property
+ *
+ * @return
+ */
+ void setAttributeName(String... name);
}
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
import java.awt.Color;
import java.awt.Graphics;
List<String> getGroups(boolean visible);
/**
- * change visibility for a range of groups
+ * Set visibility for a list of groups
*
* @param toset
* @param visible
void setGroupVisibility(List<String> toset, boolean visible);
/**
- * change visibiilty of given group
+ * Set visibility of the given feature group
*
* @param group
* @param visible
void setGroupVisibility(String group, boolean visible);
/**
- * Returns features at the specified aligned column on the given sequence.
- * Non-positional features are not included. If the column has a gap, then
- * enclosing features are included (but not contact features).
+ * Returns visible features at the specified aligned column on the given
+ * sequence. Non-positional features are not included. If the column has a gap,
+ * then enclosing features are included (but not contact features).
*
* @param sequence
* @param column
*/
float getTransparency();
+ /**
+ * Answers the filters applied to the given feature type, or null if none is
+ * set
+ *
+ * @param featureType
+ * @return
+ */
+ FeatureMatcherSetI getFeatureFilter(String featureType);
+
+ /**
+ * Answers the feature filters map
+ *
+ * @return
+ */
+ public Map<String, FeatureMatcherSetI> getFeatureFilters();
+
+ /**
+ * Sets the filters for the feature type, or removes them if a null or empty
+ * filter is passed
+ *
+ * @param featureType
+ * @param filter
+ */
+ void setFeatureFilter(String featureType, FeatureMatcherSetI filter);
+
+ /**
+ * Replaces all feature filters with the given map
+ *
+ * @param filters
+ */
+ void setFeatureFilters(Map<String, FeatureMatcherSetI> filters);
+
+ /**
+ * Returns the colour for a particular feature instance. This includes
+ * calculation of 'colour by label', or of a graduated score colour, if
+ * applicable.
+ * <p>
+ * Returns null if
+ * <ul>
+ * <li>feature type is not visible, or</li>
+ * <li>feature group is not visible, or</li>
+ * <li>feature values lie outside any colour threshold, or</li>
+ * <li>feature is excluded by filter conditions</li>
+ * </ul>
+ *
+ * @param feature
+ * @return
+ */
+ Color getColour(SequenceFeature feature);
}
*/
package jalview.api.structures;
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
import jalview.schemes.ColourSchemeI;
import jalview.structures.models.AAStructureBindingModel;
*/
void setJalviewColourScheme(ColourSchemeI colourScheme);
+ /**
+ *
+ * @return true if all background sequence/structure binding threads have
+ * completed for this viewer instance
+ */
+ boolean hasMapping();
+
+ /**
+ * Checks if the PDB file is already loaded in this viewer, if so just adds
+ * mappings as necessary and answers true, else answers false. This supports
+ * the use case of adding additional chains of the same structure to a viewer.
+ *
+ * @param seq
+ * @param chains
+ * @param apanel
+ * @param pdbId
+ * @return
+ */
+ boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains,
+ AlignmentViewPanel apanel, String pdbId);
+
+ /**
+ * Adds one or more chains (sequences) of a PDB structure to this structure
+ * viewer
+ *
+ * @param pdbentry
+ * @param seq
+ * @param chains
+ * @param apanel
+ * @param pdbId
+ * @return
+ */
+ void addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq,
+ String[] chains, AlignmentViewPanel apanel, String pdbId);
+
+ /**
+ * refresh GUI after reconfiguring structure(s) and alignment panels
+ */
+ void updateTitleAndMenus();
+
+ /**
+ * Answers true if the viewer should attempt to align any added structures,
+ * else false
+ *
+ * @return
+ */
+ boolean isAlignAddedStructures();
+
+ /**
+ * Sets the flag for whether added structures should be aligned
+ *
+ * @param alignAdded
+ */
+ void setAlignAddedStructures(boolean alignAdded);
+
+ /**
+ * Raise the panel to the top of the stack...
+ */
+ void raiseViewer();
+
}
.formatMessage("label.annotation_for_displayid", new Object[]
{ seq.getDisplayId(true) }));
new SequenceAnnotationReport(null).createSequenceAnnotationReport(
- contents, seq, true, true,
- (ap.seqPanel.seqCanvas.fr != null)
- ? ap.seqPanel.seqCanvas.fr.getMinMax()
- : null);
+ contents, seq, true, true, ap.seqPanel.seqCanvas.fr);
contents.append("</p>");
}
Frame frame = new Frame();
FeaturesFile formatter = new FeaturesFile();
if (format.equalsIgnoreCase("Jalview"))
{
- features = formatter.printJalviewFormat(viewport.getAlignment()
- .getSequencesArray(), getDisplayedFeatureCols(),
- getDisplayedFeatureGroups(), true);
+ features = formatter.printJalviewFormat(
+ viewport.getAlignment().getSequencesArray(),
+ getDisplayedFeatureCols(), null, getDisplayedFeatureGroups(),
+ true);
}
else
{
static StringBuffer copiedSequences;
- static Vector<int[]> copiedHiddenColumns;
+ static HiddenColumns copiedHiddenColumns;
protected void copy_actionPerformed()
{
if (viewport.hasHiddenColumns() && viewport.getSelectionGroup() != null)
{
- copiedHiddenColumns = new Vector<>(viewport.getAlignment()
- .getHiddenColumns().getHiddenColumnsCopy());
int hiddenOffset = viewport.getSelectionGroup().getStartRes();
- for (int[] region : copiedHiddenColumns)
- {
- region[0] = region[0] - hiddenOffset;
- region[1] = region[1] - hiddenOffset;
- }
+ int hiddenCutoff = viewport.getSelectionGroup().getEndRes();
+
+ // create new HiddenColumns object with copy of hidden regions
+ // between startRes and endRes, offset by startRes
+ copiedHiddenColumns = new HiddenColumns(
+ viewport.getAlignment().getHiddenColumns(), hiddenOffset,
+ hiddenCutoff, hiddenOffset);
}
else
{
{
try
{
-
if (copiedSequences == null)
{
return;
}
- StringTokenizer st = new StringTokenizer(copiedSequences.toString());
+ StringTokenizer st = new StringTokenizer(copiedSequences.toString(),
+ "\t");
Vector seqs = new Vector();
while (st.hasMoreElements())
{
}
AlignFrame af = new AlignFrame(new Alignment(newSeqs),
viewport.applet, newtitle, false);
- if (copiedHiddenColumns != null)
- {
- for (int i = 0; i < copiedHiddenColumns.size(); i++)
- {
- int[] region = copiedHiddenColumns.elementAt(i);
- af.viewport.hideColumns(region[0], region[1]);
- }
- }
+ af.viewport.setHiddenColumns(copiedHiddenColumns);
jalview.bin.JalviewLite.addFrame(af, newtitle, frameWidth,
frameHeight);
if (av.hasHiddenColumns())
{
AlignmentI al = av.getAlignment();
- start = al.getHiddenColumns().findColumnPosition(ostart);
- end = al.getHiddenColumns().findColumnPosition(end);
+ start = al.getHiddenColumns().absoluteToVisibleColumn(ostart);
+ end = al.getHiddenColumns().absoluteToVisibleColumn(end);
if (start == end)
{
if (!scrollToNearest && !al.getHiddenColumns().isVisible(ostart))
if (av.hasHiddenColumns())
{
width = av.getAlignment().getHiddenColumns()
- .findColumnPosition(width);
+ .absoluteToVisibleColumn(width);
}
if (x < 0)
{
import java.awt.event.MouseListener;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;
-import java.util.ArrayList;
import java.util.Vector;
//import javax.swing.JPanel;
{
HiddenColumns oldHidden = av.getAnnotationColumnSelectionState()
.getOldHiddenColumns();
- if (oldHidden != null)
- {
- ArrayList<int[]> regions = oldHidden.getHiddenColumnsCopy();
- for (int[] positions : regions)
- {
- av.hideColumns(positions[0], positions[1]);
- }
- }
- // TODO not clear why we need to hide all the columns (above) if we are
- // going to copy the hidden columns over wholesale anyway
av.getAlignment().setHiddenColumns(oldHidden);
}
av.sendSelection();
import jalview.analysis.AlignmentUtils;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.util.MessageManager;
import java.awt.Checkbox;
import java.awt.CheckboxMenuItem;
import java.awt.Color;
+import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.event.MouseMotionListener;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Vector;
public class AnnotationLabels extends Panel
implements ActionListener, MouseListener, MouseMotionListener
{
Image image;
+ /**
+ * width in pixels within which height adjuster arrows are shown and active
+ */
+ private static final int HEIGHT_ADJUSTER_WIDTH = 50;
+
+ /**
+ * height in pixels for allowing height adjuster to be active
+ */
+ private static int HEIGHT_ADJUSTER_HEIGHT = 10;
+
boolean active = false;
AlignmentPanel ap;
this.ap = ap;
this.av = ap.av;
setLayout(null);
-
- /**
- * this retrieves the adjustable height glyph from resources. we don't use
- * it at the moment. java.net.URL url =
- * getClass().getResource("/images/idwidth.gif"); Image temp = null;
- *
- * if (url != null) { temp =
- * java.awt.Toolkit.getDefaultToolkit().createImage(url); }
- *
- * try { MediaTracker mt = new MediaTracker(this); mt.addImage(temp, 0);
- * mt.waitForID(0); } catch (Exception ex) { }
- *
- * BufferedImage bi = new BufferedImage(temp.getHeight(this),
- * temp.getWidth(this), BufferedImage.TYPE_INT_RGB); Graphics2D g =
- * (Graphics2D) bi.getGraphics(); g.rotate(Math.toRadians(90));
- * g.drawImage(temp, 0, -bi.getWidth(this), this); image = (Image) bi;
- */
addMouseListener(this);
addMouseMotionListener(this);
}
}
else if (evt.getActionCommand().equals(COPYCONS_SEQ))
{
- SequenceI cons = av.getConsensusSeq();
+ SequenceGroup group = aa[selectedRow].groupRef;
+ SequenceI cons = group == null ? av.getConsensusSeq()
+ : group.getConsensusSeq();
if (cons != null)
{
copy_annotseqtoclipboard(cons);
@Override
public void mouseMoved(MouseEvent evt)
{
- resizePanel = evt.getY() < 10 && evt.getX() < 14;
+ resizePanel = evt.getY() < HEIGHT_ADJUSTER_HEIGHT
+ && evt.getX() < HEIGHT_ADJUSTER_WIDTH;
+ setCursor(Cursor.getPredefinedCursor(
+ resizePanel ? Cursor.S_RESIZE_CURSOR : Cursor.DEFAULT_CURSOR));
int row = getSelectedRow(evt.getY() + scrollOffset);
if (row > -1)
resizePanel = false;
dragEvent = null;
dragCancelled = false;
+ setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
repaint();
ap.annotationPanel.repaint();
}
resizePanel = true;
repaint();
}
+ setCursor(Cursor.getPredefinedCursor(
+ resizePanel ? Cursor.S_RESIZE_CURSOR : Cursor.DEFAULT_CURSOR));
}
@Override
+ "\t" + sq.getSequenceAsString() + "\n");
if (av.hasHiddenColumns())
{
- jalview.appletgui.AlignFrame.copiedHiddenColumns = new Vector<>(
- av.getAlignment().getHiddenColumns().getHiddenColumnsCopy());
+ jalview.appletgui.AlignFrame.copiedHiddenColumns = new HiddenColumns(
+ av.getAlignment().getHiddenColumns());
}
}
}
}
g.translate(0, +scrollOffset);
- if (resizePanel)
- {
- g.setColor(Color.red);
- g.setPaintMode();
- g.drawLine(2, 8, 5, 2);
- g.drawLine(5, 2, 8, 8);
- }
- else if (!dragCancelled && dragEvent != null && aa != null)
+
+ if (!resizePanel && !dragCancelled && dragEvent != null && aa != null)
{
g.setColor(Color.lightGray);
g.drawString(aa[selectedRow].label, dragEvent.getX(),
if (av.hasHiddenColumns())
{
column = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(column);
+ .visibleToAbsoluteColumn(column);
}
if (row > -1 && column < aa[row].annotations.length
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.ext.jmol.JalviewJmolBinding;
-import jalview.gui.IProgressIndicator;
import jalview.io.DataSourceType;
import jalview.structure.StructureSelectionManager;
@Override
public int[] resizeInnerPanel(String data)
{
- // TODO Auto-generated method stub
return null;
}
@Override
public Map<String, Object> getJSpecViewProperty(String arg0)
{
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- protected IProgressIndicator getIProgressIndicator()
- {
- // no progress indicators on the applet
return null;
}
}
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.ext.jmol.JalviewJmolBinding;
-import jalview.gui.IProgressIndicator;
import jalview.io.DataSourceType;
import java.awt.Container;
}
@Override
- protected IProgressIndicator getIProgressIndicator()
- {
- // no progress indicators on applet (could access javascript for this)
- return null;
- }
-
- @Override
public void updateColours(Object source)
{
-
- // TODO Auto-generated method stub
-
}
@Override
protected JmolAppConsoleInterface createJmolConsole(
Container consolePanel, String buttonsToShow)
{
- // TODO Auto-generated method stub
return null;
}
@Override
public void releaseReferences(Object svl)
{
- // TODO Auto-generated method stub
-
}
@Override
public Map<String, Object> getJSpecViewProperty(String arg0)
{
- // TODO Auto-generated method stub
return null;
}
*/
private static final int SCALE_FACTOR_1K = 1000;
+ private static final String COLON = ":";
+
private JVDialog frame;
private Frame owner;
slider.addAdjustmentListener(this);
slider.addMouseListener(this);
owner = (af != null) ? af : fs.frame;
- frame = new JVDialog(owner, MessageManager
- .formatMessage("label.graduated_color_for_params", new String[]
- { type }), true, 480, 248);
+ frame = new JVDialog(owner, MessageManager.formatMessage(
+ "label.variable_color_for", new String[] { type }), true, 480,
+ 248);
frame.setMainPanel(this);
validate();
frame.setVisible(true);
private void jbInit() throws Exception
{
- Label minLabel = new Label(MessageManager.getString("label.min")),
- maxLabel = new Label(MessageManager.getString("label.max"));
+ Label minLabel = new Label(
+ MessageManager.getString("label.min_value") + COLON);
+ Label maxLabel = new Label(
+ MessageManager.getString("label.max_value") + COLON);
minLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
maxLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
// minColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceI;
import jalview.util.MessageManager;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
import java.awt.BorderLayout;
import java.awt.Button;
public class FeatureSettings extends Panel
implements ItemListener, MouseListener, MouseMotionListener,
- ActionListener, AdjustmentListener, FeatureSettingsControllerI
+ AdjustmentListener, FeatureSettingsControllerI
{
FeatureRenderer fr;
add(scrollPane, BorderLayout.CENTER);
}
- Button invert = new Button("Invert Selection");
- invert.addActionListener(this);
+ Button invert = new Button(
+ MessageManager.getString("label.invert_selection"));
+ invert.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ invertSelection();
+ }
+ });
Panel lowerPanel = new Panel(new GridLayout(2, 1, 5, 10));
lowerPanel.add(invert);
}
}
- @Override
- public void actionPerformed(ActionEvent evt)
+ protected void invertSelection()
{
for (int i = 0; i < featurePanel.getComponentCount(); i++)
{
{
Component[] comps = featurePanel.getComponents();
int cSize = comps.length;
-
- Object[][] tmp = new Object[cSize][3];
- int tmpSize = 0;
- for (int i = 0; i < cSize; i++)
- {
- MyCheckbox check = (MyCheckbox) comps[i];
- tmp[tmpSize][0] = check.type;
- tmp[tmpSize][1] = fr.getFeatureStyle(check.type);
- tmp[tmpSize][2] = new Boolean(check.getState());
- tmpSize++;
+ FeatureSettingsBean[] rowData = new FeatureSettingsBean[cSize];
+ int i = 0;
+ for (Component comp : comps)
+ {
+ MyCheckbox check = (MyCheckbox) comp;
+ // feature filter set to null as not (yet) offered in applet
+ FeatureColourI colour = fr.getFeatureStyle(check.type);
+ rowData[i] = new FeatureSettingsBean(check.type, colour, null,
+ check.getState());
+ i++;
}
- Object[][] data = new Object[tmpSize][3];
- System.arraycopy(tmp, 0, data, 0, tmpSize);
-
- fr.setFeaturePriority(data);
+ fr.setFeaturePriority(rowData);
ap.paintAlignment(updateOverview, updateOverview);
}
if (av.hasHiddenColumns())
{
maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth) - 1;
+ .absoluteToVisibleColumn(maxwidth) - 1;
}
int annotationHeight = 0;
package jalview.appletgui;
import java.awt.Color;
+import java.awt.Cursor;
import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Image;
import java.awt.Panel;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
int oldX = 0;
- Image image;
-
AlignmentPanel ap;
public IdwidthAdjuster(AlignmentPanel ap)
{
setLayout(null);
this.ap = ap;
- java.net.URL url = getClass().getResource("/images/idwidth.gif");
- if (url != null)
- {
- image = java.awt.Toolkit.getDefaultToolkit().getImage(url);
- }
-
+ setBackground(Color.WHITE);
addMouseListener(this);
addMouseMotionListener(this);
}
+ @Override
public void mousePressed(MouseEvent evt)
{
oldX = evt.getX();
}
+ @Override
public void mouseReleased(MouseEvent evt)
{
active = false;
// }
}
+ @Override
public void mouseEntered(MouseEvent evt)
{
active = true;
+ setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
+
repaint();
}
+ @Override
public void mouseExited(MouseEvent evt)
{
active = false;
+ setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
repaint();
}
+ @Override
public void mouseDragged(MouseEvent evt)
{
active = true;
}
}
+ @Override
public void mouseMoved(MouseEvent evt)
{
}
+ @Override
public void mouseClicked(MouseEvent evt)
{
}
-
- public void paint(Graphics g)
- {
- g.setColor(Color.white);
- g.fillRect(0, 0, getSize().width, getSize().height);
- if (active)
- {
- if (image != null)
- {
- g.drawImage(image, getSize().width - 20, 2, this);
- }
- }
- }
-
}
{
mg.translate(0, od.getSequencesHeight());
or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
- av.getCharWidth(), od.getGraphHeight(),
- od.getColumns(av.getAlignment()));
+ od.getGraphHeight(), od.getColumns(av.getAlignment()));
mg.translate(0, -od.getSequencesHeight());
}
- System.gc();
if (restart)
{
}
}
+ /**
+ * Nulls references to protect against potential memory leaks
+ */
+ void dispose()
+ {
+ od = null;
+ }
+
}
if (!od.isPositionInBox(evt.getX(), evt.getY()))
{
draggingBox = false;
+
+ // display drag cursor at mouse position
+ setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+
od.updateViewportFromMouse(evt.getX(), evt.getY(),
av.getAlignment().getHiddenSequences(),
av.getAlignment().getHiddenColumns());
@Override
public void mouseReleased(MouseEvent evt)
{
+ draggingBox = false;
}
@Override
} finally
{
av = null;
+ if (oviewCanvas != null)
+ {
+ oviewCanvas.dispose();
+ }
oviewCanvas = null;
ap = null;
od = null;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
+import java.util.Iterator;
import java.util.List;
public class ScalePanel extends Panel
if (av.hasHiddenColumns())
{
- res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x);
+ res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(x);
}
else
{
});
pop.add(item);
- if (av.getAlignment().getHiddenColumns().hasManyHiddenColumns())
+ if (av.getAlignment().getHiddenColumns().hasMultiHiddenColumnRegions())
{
item = new MenuItem(MessageManager.getString("action.reveal_all"));
item.addActionListener(new ActionListener()
if (av.hasHiddenColumns())
{
res = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(res);
+ .visibleToAbsoluteColumn(res);
}
if (!stretchingGroup)
int res = (evt.getX() / av.getCharWidth())
+ av.getRanges().getStartRes();
res = Math.max(0, res);
- res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
+ res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(res);
res = Math.min(res, av.getAlignment().getWidth() - 1);
min = Math.min(res, min);
max = Math.max(res, max);
{
if (hidden.isVisible(sel))
{
- sel = hidden.findColumnPosition(sel);
+ sel = hidden.absoluteToVisibleColumn(sel);
}
else
{
if (av.getShowHiddenMarkers())
{
int widthx = 1 + endx - startx;
- List<Integer> positions = hidden.findHiddenRegionPositions();
- for (int pos : positions)
+ Iterator<Integer> it = hidden.getStartRegionIterator(startx,
+ startx + widthx + 1);
+ while (it.hasNext())
{
-
- res = pos - startx;
-
- if (res < 0 || res > widthx)
- {
- continue;
- }
+ res = it.next() - startx;
gg.fillPolygon(
new int[]
- { -1 + res * avCharWidth - avcharHeight / 4,
- -1 + res * avCharWidth + avcharHeight / 4,
- -1 + res * avCharWidth },
- new int[]
- { y, y, y + 2 * yOf }, 3);
+ { -1 + res * avCharWidth - avcharHeight / 4, -1 + res * avCharWidth + avcharHeight / 4,
+ -1 + res * avCharWidth }, new int[]
+ { y, y, y + 2 * yOf }, 3);
}
}
}
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.VisibleContigsIterator;
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
import jalview.viewmodel.AlignmentViewport;
import java.awt.Image;
import java.awt.Panel;
import java.beans.PropertyChangeEvent;
-import java.util.List;
+import java.util.Iterator;
public class SeqCanvas extends Panel implements ViewportListenerI
{
if (av.hasHiddenColumns())
{
startx = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(startx);
+ .visibleToAbsoluteColumn(startx);
endx = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(endx);
+ .visibleToAbsoluteColumn(endx);
}
int maxwidth = av.getAlignment().getWidth();
if (av.hasHiddenColumns())
{
maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth) - 1;
+ .absoluteToVisibleColumn(maxwidth) - 1;
}
// WEST SCALE
if (av.hasHiddenColumns())
{
endx = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(endx);
+ .visibleToAbsoluteColumn(endx);
}
SequenceI seq;
int canvasHeight, int startRes)
{
AlignmentI al = av.getAlignment();
-
+
FontMetrics fm = getFontMetrics(av.getFont());
-
+
LABEL_EAST = 0;
LABEL_WEST = 0;
-
+
if (av.getScaleRightWrapped())
{
LABEL_EAST = fm.stringWidth(getMask());
}
-
+
if (av.getScaleLeftWrapped())
{
LABEL_WEST = fm.stringWidth(getMask());
}
-
+
int hgap = avcharHeight;
if (av.getScaleAboveWrapped())
{
hgap += avcharHeight;
}
-
+
int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / avcharWidth;
int cHeight = av.getAlignment().getHeight() * avcharHeight;
-
+
av.setWrappedWidth(cWidth);
-
+
av.getRanges().setViewportStartAndWidth(startRes, cWidth);
-
+
int endx;
int ypos = hgap;
-
+
int maxwidth = av.getAlignment().getWidth();
-
+
if (av.hasHiddenColumns())
{
maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth);
+ .absoluteToVisibleColumn(maxwidth);
}
-
+
while ((ypos <= canvasHeight) && (startRes < maxwidth))
{
endx = startRes + cWidth - 1;
-
+
if (endx > maxwidth)
{
endx = maxwidth;
}
-
+
g.setColor(Color.black);
-
+
if (av.getScaleLeftWrapped())
{
drawWestScale(g, startRes, endx, ypos);
}
-
+
if (av.getScaleRightWrapped())
{
g.translate(canvasWidth - LABEL_EAST, 0);
drawEastScale(g, startRes, endx, ypos);
g.translate(-(canvasWidth - LABEL_EAST), 0);
}
-
+
g.translate(LABEL_WEST, 0);
-
+
if (av.getScaleAboveWrapped())
{
drawNorthScale(g, startRes, endx, ypos);
HiddenColumns hidden = av.getAlignment().getHiddenColumns();
g.setColor(Color.blue);
int res;
- List<Integer> positions = hidden.findHiddenRegionPositions();
- for (int pos : positions)
+ Iterator<Integer> it = hidden.getStartRegionIterator(startRes,
+ endx + 1);
+ while (it.hasNext())
{
- res = pos - startRes;
-
- if (res < 0 || res > endx - startRes)
- {
- continue;
- }
-
+ res = it.next() - startRes;
gg.fillPolygon(
new int[]
- { res * avcharWidth - avcharHeight / 4,
- res * avcharWidth + avcharHeight / 4,
- res * avcharWidth },
+ { res * avcharWidth - avcharHeight / 4, res * avcharWidth + avcharHeight / 4, res * avcharWidth },
new int[]
- { ypos - (avcharHeight / 2), ypos - (avcharHeight / 2),
- ypos - (avcharHeight / 2) + 8 },
- 3);
-
+ { ypos - (avcharHeight / 2), ypos - (avcharHeight / 2), ypos - (avcharHeight / 2) + 8 }, 3);
}
}
-
+
if (g.getClip() == null)
{
g.setClip(0, 0, cWidth * avcharWidth, canvasHeight);
}
-
+
drawPanel(g, startRes, endx, 0, al.getHeight() - 1, ypos);
g.setClip(null);
-
+
if (av.isShowAnnotation())
{
g.translate(0, cHeight + ypos + 4);
{
annotations = new AnnotationPanel(av);
}
-
+
annotations.drawComponent(g, startRes, endx + 1);
g.translate(0, -cHeight - ypos - 4);
}
g.translate(-LABEL_WEST, 0);
-
+
ypos += cHeight + getAnnotationHeight() + hgap;
-
+
startRes += cWidth;
}
-
+
}
AnnotationPanel annotations;
else
{
int screenY = 0;
- final int screenYMax = endRes - startRes;
- int blockStart = startRes;
- int blockEnd = endRes;
-
- if (av.hasHiddenColumns())
- {
- HiddenColumns hidden = av.getAlignment().getHiddenColumns();
- for (int[] region : hidden.getHiddenColumnsCopy())
- {
- int hideStart = region[0];
- int hideEnd = region[1];
-
- if (hideStart <= blockStart)
- {
- blockStart += (hideEnd - hideStart) + 1;
- continue;
- }
-
- /*
- * draw up to just before the next hidden region, or the end of
- * the visible region, whichever comes first
- */
- blockEnd = Math.min(hideStart - 1, blockStart + screenYMax
- - screenY);
-
- g1.translate(screenY * avcharWidth, 0);
+ int blockStart;
+ int blockEnd;
- draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ VisibleContigsIterator regions = (VisibleContigsIterator) hidden
+ .getVisContigsIterator(startRes, endRes + 1, true);
- /*
- * draw the downline of the hidden column marker (ScalePanel draws the
- * triangle on top) if we reached it
- */
- if (av.getShowHiddenMarkers() && blockEnd == hideStart - 1)
- {
- g1.setColor(Color.blue);
- g1.drawLine((blockEnd - blockStart + 1) * avcharWidth - 1,
- 0 + offset,
- (blockEnd - blockStart + 1) * avcharWidth - 1,
- (endSeq - startSeq + 1) * avcharHeight + offset);
- }
-
- g1.translate(-screenY * avcharWidth, 0);
- screenY += blockEnd - blockStart + 1;
- blockStart = hideEnd + 1;
-
- if (screenY > screenYMax)
- {
- // already rendered last block
- return;
- }
- }
- }
- if (screenY <= screenYMax)
+ while (regions.hasNext())
{
- // remaining visible region to render
- blockEnd = blockStart + (endRes - startRes) - screenY;
+ int[] region = regions.next();
+ blockEnd = region[1];
+ blockStart = region[0];
+
+ /*
+ * draw up to just before the next hidden region, or the end of
+ * the visible region, whichever comes first
+ */
g1.translate(screenY * avcharWidth, 0);
+
draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
+ /*
+ * draw the downline of the hidden column marker (ScalePanel draws the
+ * triangle on top) if we reached it
+ */
+ if (av.getShowHiddenMarkers()
+ && (regions.hasNext() || regions.endsAtHidden()))
+ {
+ g1.setColor(Color.blue);
+ g1.drawLine((blockEnd - blockStart + 1) * avcharWidth - 1,
+ 0 + offset, (blockEnd - blockStart + 1) * avcharWidth - 1,
+ (endSeq - startSeq + 1) * avcharHeight + offset);
+ }
+
g1.translate(-screenY * avcharWidth, 0);
+ screenY += blockEnd - blockStart + 1;
}
}
-
}
// int startRes, int endRes, int startSeq, int endSeq, int x, int y,
if (av.hasHiddenColumns())
{
res = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(res);
+ .visibleToAbsoluteColumn(res);
}
return res;
{
fixedColumns = true;
int y1 = av.getAlignment().getHiddenColumns()
- .getHiddenBoundaryLeft(startres);
+ .getNextHiddenBoundary(true, startres);
int y2 = av.getAlignment().getHiddenColumns()
- .getHiddenBoundaryRight(startres);
+ .getNextHiddenBoundary(false, startres);
if ((insertGap && startres > y1 && lastres < y1)
|| (!insertGap && startres < y2 && lastres > y2))
if (sg.getSize() == av.getAlignment().getHeight())
{
if ((av.hasHiddenColumns() && startres < av.getAlignment()
- .getHiddenColumns().getHiddenBoundaryRight(startres)))
+ .getHiddenColumns()
+ .getNextHiddenBoundary(false, startres)))
{
endEditing();
return;
import jalview.structure.StructureImportSettings;
import jalview.urls.IdOrgSettings;
import jalview.util.ColorUtils;
-import jalview.ws.dbsources.das.api.DasSourceRegistryI;
-import jalview.ws.dbsources.das.datamodel.DasSourceRegistry;
import jalview.ws.sifts.SiftsSettings;
import java.awt.Color;
@Override
public synchronized Enumeration<Object> keys()
{
- return Collections.enumeration(new TreeSet<Object>(super.keySet()));
+ return Collections.enumeration(new TreeSet<>(super.keySet()));
}
};
}
}
- /** Called when Jalview is started */
+ /**
+ * Loads properties from the given properties file. Any existing properties
+ * are first cleared.
+ */
public static void loadProperties(String propsFile)
{
propertiesFile = propsFile;
{
fis = new FileInputStream(propertiesFile);
}
+ applicationProperties.clear();
applicationProperties.load(fis);
// remove any old build properties
* @param obj
* String value of property
*
- * @return String value of property
+ * @return previous value of property (or null)
*/
- public static String setProperty(String key, String obj)
+ public static Object setProperty(String key, String obj)
{
-
+ Object oldValue = null;
try
{
- applicationProperties.setProperty(key, obj);
+ oldValue = applicationProperties.setProperty(key, obj);
if (!propsAreReadOnly)
{
FileOutputStream out = new FileOutputStream(propertiesFile);
System.out.println(
"Error setting property: " + key + " " + obj + "\n" + ex);
}
- return obj;
+ return oldValue;
}
/**
return null;
}
- private static DasSourceRegistryI sourceRegistry = null;
-
- /**
- * initialise and ..
- *
- * @return instance of the das source registry
- */
- public static DasSourceRegistryI getDasSourceRegistry()
- {
- if (sourceRegistry == null)
- {
- sourceRegistry = new DasSourceRegistry();
- }
- return sourceRegistry;
- }
-
/**
* Set the specified value, or remove it if null or empty. Does not save the
* properties file.
*/
package jalview.bin;
-import groovy.lang.Binding;
-import groovy.util.GroovyScriptEngine;
-
import jalview.ext.so.SequenceOntology;
import jalview.gui.AlignFrame;
import jalview.gui.Desktop;
import java.util.Map;
import java.util.Vector;
+import javax.swing.LookAndFeel;
import javax.swing.UIManager;
+import groovy.lang.Binding;
+import groovy.util.GroovyScriptEngine;
+
/**
* Main class for Jalview Application <br>
* <br>
- * start with java -Djava.ext.dirs=$PATH_TO_LIB$ jalview.bin.Jalview
+ * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
+ * jalview.bin.Jalview
+ *
+ * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
+ * jalview.bin.Jalview jalview.bin.Jalview
+ *
+ * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
+ * embellish '*' to e.g. '*.jar')
*
* @author $author$
* @version $Revision$
af.setProgressBar(MessageManager
.getString("status.das_features_being_retrived"), id);
af.featureSettings_actionPerformed(null);
- af.featureSettings.fetchDasFeatures(dasSources, true);
af.setProgressBar(null, id);
synchronized (us)
{
{
error.printStackTrace();
System.out.println("\nEssential logging libraries not found."
- + "\nUse: java -Djava.ext.dirs=$PATH_TO_LIB$ jalview.bin.Jalview");
+ + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
System.exit(0);
}
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex)
{
+ System.err.println("Unexpected Look and Feel Exception");
+ ex.printStackTrace();
}
if (Platform.isAMac())
{
+
+ LookAndFeel lookAndFeel = ch.randelshofer.quaqua.QuaquaManager
+ .getLookAndFeel();
System.setProperty("com.apple.mrj.application.apple.menu.about.name",
"Jalview");
System.setProperty("apple.laf.useScreenMenuBar", "true");
- try
+ if (lookAndFeel != null)
{
- UIManager.setLookAndFeel(
- ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel());
- } catch (Throwable e)
+ try
+ {
+ UIManager.setLookAndFeel(lookAndFeel);
+ } catch (Throwable e)
+ {
+ System.err.println(
+ "Failed to set QuaQua look and feel: " + e.toString());
+ }
+ }
+ if (lookAndFeel == null || !(lookAndFeel.getClass()
+ .isAssignableFrom(UIManager.getLookAndFeel().getClass()))
+ || !UIManager.getLookAndFeel().getClass().toString()
+ .toLowerCase().contains("quaqua"))
{
- System.err.println(
- "Failed to set QuaQua look and feel: " + e.toString());
+ try
+ {
+ System.err.println(
+ "Quaqua LaF not available on this plaform. Using VAqua(4).\nSee https://issues.jalview.org/browse/JAL-2976");
+ UIManager.setLookAndFeel("org.violetlib.aqua.AquaLookAndFeel");
+ } catch (Throwable e)
+ {
+ System.err.println(
+ "Failed to reset look and feel: " + e.toString());
+ }
}
}
}
try
{
- Map<String, Object> vbinding = new HashMap<String, Object>();
+ Map<String, Object> vbinding = new HashMap<>();
vbinding.put("Jalview", this);
if (af != null)
{
+ nickname + "|" + url);
if (source == null)
{
- source = new Vector<String>();
+ source = new Vector<>();
}
source.addElement(nickname);
}
System.out.println("adding source '" + data + "'");
if (source == null)
{
- source = new Vector<String>();
+ source = new Vector<>();
}
source.addElement(data);
}
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
SequenceI rs = sel.getSequenceAt(0);
start = rs.findIndex(start);
end = rs.findIndex(end);
- List<Integer> cs = new ArrayList<Integer>(csel.getSelected());
+ List<Integer> cs = new ArrayList<>(csel.getSelected());
csel.clear();
for (Integer selectedCol : cs)
{
setMouseoverListener(currentAlignFrame, listener);
}
- private Vector<jalview.javascript.JSFunctionExec> javascriptListeners = new Vector<jalview.javascript.JSFunctionExec>();
+ private Vector<jalview.javascript.JSFunctionExec> javascriptListeners = new Vector<>();
/*
* (non-Javadoc)
else
{
param = st.nextToken();
- List<SequenceI> tmp = new ArrayList<SequenceI>();
- List<String> tmp2 = new ArrayList<String>();
+ List<SequenceI> tmp = new ArrayList<>();
+ List<String> tmp2 = new ArrayList<>();
while (st.hasMoreTokens())
{
JnetAnnotationMaker.add_annotation(predictions,
alignFrame.viewport.getAlignment(), 0, false);
// false == do not add sequence profile from concise output
- SequenceI repseq = alignFrame.viewport.getAlignment()
- .getSequenceAt(0);
- alignFrame.viewport.getAlignment().setSeqrep(repseq);
- HiddenColumns cs = new HiddenColumns();
- cs.hideInsertionsFor(repseq);
- alignFrame.viewport.getAlignment().setHiddenColumns(cs);
+
+ alignFrame.viewport.getAlignment().setupJPredAlignment();
+
alignFrame.alignPanel.fontChanged();
alignFrame.alignPanel.setScrollValues(0, 0);
result = true;
// callInitCallback();
}
- private Hashtable<String, long[]> jshashes = new Hashtable<String, long[]>();
+ private Hashtable<String, long[]> jshashes = new Hashtable<>();
- private Hashtable<String, Hashtable<String, String[]>> jsmessages = new Hashtable<String, Hashtable<String, String[]>>();
+ private Hashtable<String, Hashtable<String, String[]>> jsmessages = new Hashtable<>();
public void setJsMessageSet(String messageclass, String viewId,
String[] colcommands)
Hashtable<String, String[]> msgset = jsmessages.get(messageclass);
if (msgset == null)
{
- msgset = new Hashtable<String, String[]>();
+ msgset = new Hashtable<>();
jsmessages.put(messageclass, msgset);
}
msgset.put(viewId, colcommands);
// --------------------------/
/**
- * Field _name.
+ * Single letter residue code for an alignment colour scheme, or feature type
+ * for a feature colour scheme
*/
private java.lang.String _name;
private java.lang.String _minRGB;
/**
- * loosely specified enumeration: NONE,ABOVE, or BELOW
+ * Field _noValueColour.
*/
- private java.lang.String _threshType;
+ private jalview.binding.types.NoValueColour _noValueColour = jalview.binding.types.NoValueColour
+ .valueOf("Min");
+
+ /**
+ * Field _threshType.
+ */
+ private jalview.binding.types.ColourThreshTypeType _threshType;
/**
* Field _threshold.
*/
private boolean _has_autoScale;
+ /**
+ * name of feature attribute to colour by, or attribute and sub-attribute
+ */
+ private java.util.Vector _attributeNameList;
+
// ----------------/
// - Constructors -/
// ----------------/
public Colour()
{
super();
+ setNoValueColour(jalview.binding.types.NoValueColour.valueOf("Min"));
+ this._attributeNameList = new java.util.Vector();
}
// -----------/
// -----------/
/**
- */
+ *
+ *
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.addElement(vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.add(index, vAttributeName);
+ }
+
+ /**
+ */
public void deleteAutoScale()
{
this._has_autoScale = false;
}
/**
- */
+ */
public void deleteColourByLabel()
{
this._has_colourByLabel = false;
}
/**
- */
+ */
public void deleteMax()
{
this._has_max = false;
}
/**
- */
+ */
public void deleteMin()
{
this._has_min = false;
}
/**
- */
+ */
public void deleteThreshold()
{
this._has_threshold = false;
}
/**
+ * Method enumerateAttributeName.
+ *
+ * @return an Enumeration over all java.lang.String elements
+ */
+ public java.util.Enumeration enumerateAttributeName()
+ {
+ return this._attributeNameList.elements();
+ }
+
+ /**
+ * Method getAttributeName.
+ *
+ * @param index
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ * @return the value of the java.lang.String at the given index
+ */
+ public java.lang.String getAttributeName(final int index)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("getAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ return (java.lang.String) _attributeNameList.get(index);
+ }
+
+ /**
+ * Method getAttributeName.Returns the contents of the collection in an Array.
+ * <p>
+ * Note: Just in case the collection contents are changing in another thread,
+ * we pass a 0-length Array of the correct type into the API call. This way we
+ * <i>know</i> that the Array returned is of exactly the correct length.
+ *
+ * @return this collection as an Array
+ */
+ public java.lang.String[] getAttributeName()
+ {
+ java.lang.String[] array = new java.lang.String[0];
+ return (java.lang.String[]) this._attributeNameList.toArray(array);
+ }
+
+ /**
+ * Method getAttributeNameCount.
+ *
+ * @return the size of this collection
+ */
+ public int getAttributeNameCount()
+ {
+ return this._attributeNameList.size();
+ }
+
+ /**
* Returns the value of field 'autoScale'.
*
* @return the value of field 'AutoScale'.
}
/**
- * Returns the value of field 'name'.
+ * Returns the value of field 'name'. The field 'name' has the following
+ * description: Single letter residue code for an alignment colour scheme, or
+ * feature type for a feature colour scheme
*
* @return the value of field 'Name'.
*/
}
/**
+ * Returns the value of field 'noValueColour'.
+ *
+ * @return the value of field 'NoValueColour'.
+ */
+ public jalview.binding.types.NoValueColour getNoValueColour()
+ {
+ return this._noValueColour;
+ }
+
+ /**
* Returns the value of field 'RGB'.
*
* @return the value of field 'RGB'.
}
/**
- * Returns the value of field 'threshType'. The field 'threshType' has the
- * following description: loosely specified enumeration: NONE,ABOVE, or BELOW
+ * Returns the value of field 'threshType'.
*
* @return the value of field 'ThreshType'.
*/
- public java.lang.String getThreshType()
+ public jalview.binding.types.ColourThreshTypeType getThreshType()
{
return this._threshType;
}
}
/**
+ */
+ public void removeAllAttributeName()
+ {
+ this._attributeNameList.clear();
+ }
+
+ /**
+ * Method removeAttributeName.
+ *
+ * @param vAttributeName
+ * @return true if the object was removed from the collection.
+ */
+ public boolean removeAttributeName(final java.lang.String vAttributeName)
+ {
+ boolean removed = _attributeNameList.remove(vAttributeName);
+ return removed;
+ }
+
+ /**
+ * Method removeAttributeNameAt.
+ *
+ * @param index
+ * @return the element removed from the collection
+ */
+ public java.lang.String removeAttributeNameAt(final int index)
+ {
+ java.lang.Object obj = this._attributeNameList.remove(index);
+ return (java.lang.String) obj;
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void setAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("setAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ this._attributeNameList.set(index, vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param vAttributeNameArray
+ */
+ public void setAttributeName(final java.lang.String[] vAttributeNameArray)
+ {
+ // -- copy array
+ _attributeNameList.clear();
+
+ for (int i = 0; i < vAttributeNameArray.length; i++)
+ {
+ this._attributeNameList.add(vAttributeNameArray[i]);
+ }
+ }
+
+ /**
* Sets the value of field 'autoScale'.
*
* @param autoScale
}
/**
- * Sets the value of field 'name'.
+ * Sets the value of field 'name'. The field 'name' has the following
+ * description: Single letter residue code for an alignment colour scheme, or
+ * feature type for a feature colour scheme
*
* @param name
* the value of field 'name'.
}
/**
+ * Sets the value of field 'noValueColour'.
+ *
+ * @param noValueColour
+ * the value of field 'noValueColour'.
+ */
+ public void setNoValueColour(
+ final jalview.binding.types.NoValueColour noValueColour)
+ {
+ this._noValueColour = noValueColour;
+ }
+
+ /**
* Sets the value of field 'RGB'.
*
* @param RGB
}
/**
- * Sets the value of field 'threshType'. The field 'threshType' has the
- * following description: loosely specified enumeration: NONE,ABOVE, or BELOW
+ * Sets the value of field 'threshType'.
*
* @param threshType
* the value of field 'threshType'.
*/
- public void setThreshType(final java.lang.String threshType)
+ public void setThreshType(
+ final jalview.binding.types.ColourThreshTypeType threshType)
{
this._threshType = threshType;
}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.binding;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class CompoundMatcher.
+ *
+ * @version $Revision$ $Date$
+ */
+public class CompoundMatcher implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * If true, matchers are AND-ed, if false they are OR-ed
+ */
+ private boolean _and;
+
+ /**
+ * keeps track of state for field: _and
+ */
+ private boolean _has_and;
+
+ /**
+ * Field _matcherSetList.
+ */
+ private java.util.Vector _matcherSetList;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public CompoundMatcher()
+ {
+ super();
+ this._matcherSetList = new java.util.Vector();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ *
+ *
+ * @param vMatcherSet
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addMatcherSet(final jalview.binding.MatcherSet vMatcherSet)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._matcherSetList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addMatcherSet has a maximum of 2");
+ }
+
+ this._matcherSetList.addElement(vMatcherSet);
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vMatcherSet
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addMatcherSet(final int index,
+ final jalview.binding.MatcherSet vMatcherSet)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._matcherSetList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addMatcherSet has a maximum of 2");
+ }
+
+ this._matcherSetList.add(index, vMatcherSet);
+ }
+
+ /**
+ */
+ public void deleteAnd()
+ {
+ this._has_and = false;
+ }
+
+ /**
+ * Method enumerateMatcherSet.
+ *
+ * @return an Enumeration over all jalview.binding.MatcherSet elements
+ */
+ public java.util.Enumeration enumerateMatcherSet()
+ {
+ return this._matcherSetList.elements();
+ }
+
+ /**
+ * Returns the value of field 'and'. The field 'and' has the following
+ * description: If true, matchers are AND-ed, if false they are OR-ed
+ *
+ * @return the value of field 'And'.
+ */
+ public boolean getAnd()
+ {
+ return this._and;
+ }
+
+ /**
+ * Method getMatcherSet.
+ *
+ * @param index
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ * @return the value of the jalview.binding.MatcherSet at the given index
+ */
+ public jalview.binding.MatcherSet getMatcherSet(final int index)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._matcherSetList.size())
+ {
+ throw new IndexOutOfBoundsException(
+ "getMatcherSet: Index value '" + index + "' not in range [0.."
+ + (this._matcherSetList.size() - 1) + "]");
+ }
+
+ return (jalview.binding.MatcherSet) _matcherSetList.get(index);
+ }
+
+ /**
+ * Method getMatcherSet.Returns the contents of the collection in an Array.
+ * <p>
+ * Note: Just in case the collection contents are changing in another thread,
+ * we pass a 0-length Array of the correct type into the API call. This way we
+ * <i>know</i> that the Array returned is of exactly the correct length.
+ *
+ * @return this collection as an Array
+ */
+ public jalview.binding.MatcherSet[] getMatcherSet()
+ {
+ jalview.binding.MatcherSet[] array = new jalview.binding.MatcherSet[0];
+ return (jalview.binding.MatcherSet[]) this._matcherSetList
+ .toArray(array);
+ }
+
+ /**
+ * Method getMatcherSetCount.
+ *
+ * @return the size of this collection
+ */
+ public int getMatcherSetCount()
+ {
+ return this._matcherSetList.size();
+ }
+
+ /**
+ * Method hasAnd.
+ *
+ * @return true if at least one And has been added
+ */
+ public boolean hasAnd()
+ {
+ return this._has_and;
+ }
+
+ /**
+ * Returns the value of field 'and'. The field 'and' has the following
+ * description: If true, matchers are AND-ed, if false they are OR-ed
+ *
+ * @return the value of field 'And'.
+ */
+ public boolean isAnd()
+ {
+ return this._and;
+ }
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ */
+ public void removeAllMatcherSet()
+ {
+ this._matcherSetList.clear();
+ }
+
+ /**
+ * Method removeMatcherSet.
+ *
+ * @param vMatcherSet
+ * @return true if the object was removed from the collection.
+ */
+ public boolean removeMatcherSet(
+ final jalview.binding.MatcherSet vMatcherSet)
+ {
+ boolean removed = _matcherSetList.remove(vMatcherSet);
+ return removed;
+ }
+
+ /**
+ * Method removeMatcherSetAt.
+ *
+ * @param index
+ * @return the element removed from the collection
+ */
+ public jalview.binding.MatcherSet removeMatcherSetAt(final int index)
+ {
+ java.lang.Object obj = this._matcherSetList.remove(index);
+ return (jalview.binding.MatcherSet) obj;
+ }
+
+ /**
+ * Sets the value of field 'and'. The field 'and' has the following
+ * description: If true, matchers are AND-ed, if false they are OR-ed
+ *
+ * @param and
+ * the value of field 'and'.
+ */
+ public void setAnd(final boolean and)
+ {
+ this._and = and;
+ this._has_and = true;
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vMatcherSet
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void setMatcherSet(final int index,
+ final jalview.binding.MatcherSet vMatcherSet)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._matcherSetList.size())
+ {
+ throw new IndexOutOfBoundsException(
+ "setMatcherSet: Index value '" + index + "' not in range [0.."
+ + (this._matcherSetList.size() - 1) + "]");
+ }
+
+ this._matcherSetList.set(index, vMatcherSet);
+ }
+
+ /**
+ *
+ *
+ * @param vMatcherSetArray
+ */
+ public void setMatcherSet(
+ final jalview.binding.MatcherSet[] vMatcherSetArray)
+ {
+ // -- copy array
+ _matcherSetList.clear();
+
+ for (int i = 0; i < vMatcherSetArray.length; i++)
+ {
+ this._matcherSetList.add(vMatcherSetArray[i]);
+ }
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.binding.CompoundMatcher
+ */
+ public static jalview.binding.CompoundMatcher unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.binding.CompoundMatcher) Unmarshaller
+ .unmarshal(jalview.binding.CompoundMatcher.class, reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.binding;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class FeatureMatcher.
+ *
+ * @version $Revision$ $Date$
+ */
+public class FeatureMatcher implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _by.
+ */
+ private jalview.binding.types.FeatureMatcherByType _by;
+
+ /**
+ * name of feature attribute to filter on, or attribute and sub-attribute
+ */
+ private java.util.Vector _attributeNameList;
+
+ /**
+ * Field _condition.
+ */
+ private java.lang.String _condition;
+
+ /**
+ * Field _value.
+ */
+ private java.lang.String _value;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public FeatureMatcher()
+ {
+ super();
+ this._attributeNameList = new java.util.Vector();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ *
+ *
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.addElement(vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.add(index, vAttributeName);
+ }
+
+ /**
+ * Method enumerateAttributeName.
+ *
+ * @return an Enumeration over all java.lang.String elements
+ */
+ public java.util.Enumeration enumerateAttributeName()
+ {
+ return this._attributeNameList.elements();
+ }
+
+ /**
+ * Method getAttributeName.
+ *
+ * @param index
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ * @return the value of the java.lang.String at the given index
+ */
+ public java.lang.String getAttributeName(final int index)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("getAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ return (java.lang.String) _attributeNameList.get(index);
+ }
+
+ /**
+ * Method getAttributeName.Returns the contents of the collection in an Array.
+ * <p>
+ * Note: Just in case the collection contents are changing in another thread,
+ * we pass a 0-length Array of the correct type into the API call. This way we
+ * <i>know</i> that the Array returned is of exactly the correct length.
+ *
+ * @return this collection as an Array
+ */
+ public java.lang.String[] getAttributeName()
+ {
+ java.lang.String[] array = new java.lang.String[0];
+ return (java.lang.String[]) this._attributeNameList.toArray(array);
+ }
+
+ /**
+ * Method getAttributeNameCount.
+ *
+ * @return the size of this collection
+ */
+ public int getAttributeNameCount()
+ {
+ return this._attributeNameList.size();
+ }
+
+ /**
+ * Returns the value of field 'by'.
+ *
+ * @return the value of field 'By'.
+ */
+ public jalview.binding.types.FeatureMatcherByType getBy()
+ {
+ return this._by;
+ }
+
+ /**
+ * Returns the value of field 'condition'.
+ *
+ * @return the value of field 'Condition'.
+ */
+ public java.lang.String getCondition()
+ {
+ return this._condition;
+ }
+
+ /**
+ * Returns the value of field 'value'.
+ *
+ * @return the value of field 'Value'.
+ */
+ public java.lang.String getValue()
+ {
+ return this._value;
+ }
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ */
+ public void removeAllAttributeName()
+ {
+ this._attributeNameList.clear();
+ }
+
+ /**
+ * Method removeAttributeName.
+ *
+ * @param vAttributeName
+ * @return true if the object was removed from the collection.
+ */
+ public boolean removeAttributeName(final java.lang.String vAttributeName)
+ {
+ boolean removed = _attributeNameList.remove(vAttributeName);
+ return removed;
+ }
+
+ /**
+ * Method removeAttributeNameAt.
+ *
+ * @param index
+ * @return the element removed from the collection
+ */
+ public java.lang.String removeAttributeNameAt(final int index)
+ {
+ java.lang.Object obj = this._attributeNameList.remove(index);
+ return (java.lang.String) obj;
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void setAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("setAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ this._attributeNameList.set(index, vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param vAttributeNameArray
+ */
+ public void setAttributeName(final java.lang.String[] vAttributeNameArray)
+ {
+ // -- copy array
+ _attributeNameList.clear();
+
+ for (int i = 0; i < vAttributeNameArray.length; i++)
+ {
+ this._attributeNameList.add(vAttributeNameArray[i]);
+ }
+ }
+
+ /**
+ * Sets the value of field 'by'.
+ *
+ * @param by
+ * the value of field 'by'.
+ */
+ public void setBy(final jalview.binding.types.FeatureMatcherByType by)
+ {
+ this._by = by;
+ }
+
+ /**
+ * Sets the value of field 'condition'.
+ *
+ * @param condition
+ * the value of field 'condition'.
+ */
+ public void setCondition(final java.lang.String condition)
+ {
+ this._condition = condition;
+ }
+
+ /**
+ * Sets the value of field 'value'.
+ *
+ * @param value
+ * the value of field 'value'.
+ */
+ public void setValue(final java.lang.String value)
+ {
+ this._value = value;
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.binding.FeatureMatcher
+ */
+ public static jalview.binding.FeatureMatcher unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.binding.FeatureMatcher) Unmarshaller
+ .unmarshal(jalview.binding.FeatureMatcher.class, reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.binding;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * A feature match condition, which may be simple or compound
+ *
+ * @version $Revision$ $Date$
+ */
+public class FeatureMatcherSet implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Internal choice value storage
+ */
+ private java.lang.Object _choiceValue;
+
+ /**
+ * Field _matchCondition.
+ */
+ private jalview.binding.MatchCondition _matchCondition;
+
+ /**
+ * Field _compoundMatcher.
+ */
+ private jalview.binding.CompoundMatcher _compoundMatcher;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public FeatureMatcherSet()
+ {
+ super();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Returns the value of field 'choiceValue'. The field 'choiceValue' has the
+ * following description: Internal choice value storage
+ *
+ * @return the value of field 'ChoiceValue'.
+ */
+ public java.lang.Object getChoiceValue()
+ {
+ return this._choiceValue;
+ }
+
+ /**
+ * Returns the value of field 'compoundMatcher'.
+ *
+ * @return the value of field 'CompoundMatcher'.
+ */
+ public jalview.binding.CompoundMatcher getCompoundMatcher()
+ {
+ return this._compoundMatcher;
+ }
+
+ /**
+ * Returns the value of field 'matchCondition'.
+ *
+ * @return the value of field 'MatchCondition'.
+ */
+ public jalview.binding.MatchCondition getMatchCondition()
+ {
+ return this._matchCondition;
+ }
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ * Sets the value of field 'compoundMatcher'.
+ *
+ * @param compoundMatcher
+ * the value of field 'compoundMatcher'.
+ */
+ public void setCompoundMatcher(
+ final jalview.binding.CompoundMatcher compoundMatcher)
+ {
+ this._compoundMatcher = compoundMatcher;
+ this._choiceValue = compoundMatcher;
+ }
+
+ /**
+ * Sets the value of field 'matchCondition'.
+ *
+ * @param matchCondition
+ * the value of field 'matchCondition'.
+ */
+ public void setMatchCondition(
+ final jalview.binding.MatchCondition matchCondition)
+ {
+ this._matchCondition = matchCondition;
+ this._choiceValue = matchCondition;
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.binding.FeatureMatcherSet
+ */
+ public static jalview.binding.FeatureMatcherSet unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.binding.FeatureMatcherSet) Unmarshaller
+ .unmarshal(jalview.binding.FeatureMatcherSet.class, reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.binding;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class Filter.
+ *
+ * @version $Revision$ $Date$
+ */
+public class Filter implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _featureType.
+ */
+ private java.lang.String _featureType;
+
+ /**
+ * Field _matcherSet.
+ */
+ private jalview.binding.MatcherSet _matcherSet;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public Filter()
+ {
+ super();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Returns the value of field 'featureType'.
+ *
+ * @return the value of field 'FeatureType'.
+ */
+ public java.lang.String getFeatureType()
+ {
+ return this._featureType;
+ }
+
+ /**
+ * Returns the value of field 'matcherSet'.
+ *
+ * @return the value of field 'MatcherSet'.
+ */
+ public jalview.binding.MatcherSet getMatcherSet()
+ {
+ return this._matcherSet;
+ }
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ * Sets the value of field 'featureType'.
+ *
+ * @param featureType
+ * the value of field 'featureType'.
+ */
+ public void setFeatureType(final java.lang.String featureType)
+ {
+ this._featureType = featureType;
+ }
+
+ /**
+ * Sets the value of field 'matcherSet'.
+ *
+ * @param matcherSet
+ * the value of field 'matcherSet'.
+ */
+ public void setMatcherSet(final jalview.binding.MatcherSet matcherSet)
+ {
+ this._matcherSet = matcherSet;
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.binding.Filter
+ */
+ public static jalview.binding.Filter unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.binding.Filter) Unmarshaller
+ .unmarshal(jalview.binding.Filter.class, reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
*/
private java.util.Vector _colourList;
+ /**
+ * Field _filterList.
+ */
+ private java.util.Vector _filterList;
+
// ----------------/
// - Constructors -/
// ----------------/
{
super();
this._colourList = new java.util.Vector();
+ this._filterList = new java.util.Vector();
}
// -----------/
}
/**
+ *
+ *
+ * @param vFilter
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addFilter(final Filter vFilter)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ this._filterList.addElement(vFilter);
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vFilter
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addFilter(final int index, final Filter vFilter)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ this._filterList.add(index, vFilter);
+ }
+
+ /**
* Method enumerateColour.
*
* @return an Enumeration over all Colour elements
}
/**
+ * Method enumerateFilter.
+ *
+ * @return an Enumeration over all Filter elements
+ */
+ public java.util.Enumeration enumerateFilter()
+ {
+ return this._filterList.elements();
+ }
+
+ /**
* Method getColour.
*
* @param index
}
/**
+ * Method getFilter.
+ *
+ * @param index
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ * @return the value of the Filter at the given index
+ */
+ public Filter getFilter(final int index)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._filterList.size())
+ {
+ throw new IndexOutOfBoundsException(
+ "getFilter: Index value '" + index + "' not in range [0.."
+ + (this._filterList.size() - 1) + "]");
+ }
+
+ return (Filter) _filterList.get(index);
+ }
+
+ /**
+ * Method getFilter.Returns the contents of the collection in an Array.
+ * <p>
+ * Note: Just in case the collection contents are changing in another thread,
+ * we pass a 0-length Array of the correct type into the API call. This way we
+ * <i>know</i> that the Array returned is of exactly the correct length.
+ *
+ * @return this collection as an Array
+ */
+ public Filter[] getFilter()
+ {
+ Filter[] array = new Filter[0];
+ return (Filter[]) this._filterList.toArray(array);
+ }
+
+ /**
+ * Method getFilterCount.
+ *
+ * @return the size of this collection
+ */
+ public int getFilterCount()
+ {
+ return this._filterList.size();
+ }
+
+ /**
* Returns the value of field 'schemeName'.
*
* @return the value of field 'SchemeName'.
}
/**
- */
+ */
public void removeAllColour()
{
this._colourList.clear();
}
/**
+ */
+ public void removeAllFilter()
+ {
+ this._filterList.clear();
+ }
+
+ /**
* Method removeColour.
*
* @param vColour
}
/**
+ * Method removeFilter.
+ *
+ * @param vFilter
+ * @return true if the object was removed from the collection.
+ */
+ public boolean removeFilter(final Filter vFilter)
+ {
+ boolean removed = _filterList.remove(vFilter);
+ return removed;
+ }
+
+ /**
+ * Method removeFilterAt.
+ *
+ * @param index
+ * @return the element removed from the collection
+ */
+ public Filter removeFilterAt(final int index)
+ {
+ java.lang.Object obj = this._filterList.remove(index);
+ return (Filter) obj;
+ }
+
+ /**
*
*
* @param index
}
/**
+ *
+ *
+ * @param index
+ * @param vFilter
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void setFilter(final int index, final Filter vFilter)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._filterList.size())
+ {
+ throw new IndexOutOfBoundsException(
+ "setFilter: Index value '" + index + "' not in range [0.."
+ + (this._filterList.size() - 1) + "]");
+ }
+
+ this._filterList.set(index, vFilter);
+ }
+
+ /**
+ *
+ *
+ * @param vFilterArray
+ */
+ public void setFilter(final Filter[] vFilterArray)
+ {
+ // -- copy array
+ _filterList.clear();
+
+ for (int i = 0; i < vFilterArray.length; i++)
+ {
+ this._filterList.add(vFilterArray[i]);
+ }
+ }
+
+ /**
* Sets the value of field 'schemeName'.
*
* @param schemeName
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.binding;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class MatchCondition.
+ *
+ * @version $Revision$ $Date$
+ */
+public class MatchCondition extends FeatureMatcher
+ implements java.io.Serializable
+{
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public MatchCondition()
+ {
+ super();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.binding.FeatureMatcher
+ */
+ public static jalview.binding.FeatureMatcher unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.binding.FeatureMatcher) Unmarshaller
+ .unmarshal(jalview.binding.MatchCondition.class, reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.binding;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class MatcherSet.
+ *
+ * @version $Revision$ $Date$
+ */
+public class MatcherSet extends FeatureMatcherSet
+ implements java.io.Serializable
+{
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public MatcherSet()
+ {
+ super();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.binding.FeatureMatcherSet
+ */
+ public static jalview.binding.FeatureMatcherSet unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.binding.FeatureMatcherSet) Unmarshaller
+ .unmarshal(jalview.binding.MatcherSet.class, reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.binding.types;
+
+ //---------------------------------/
+ //- Imported classes and packages -/
+//---------------------------------/
+
+import java.util.Hashtable;
+
+/**
+ * Class ColourThreshTypeType.
+ *
+ * @version $Revision$ $Date$
+ */
+public class ColourThreshTypeType implements java.io.Serializable {
+
+
+ //--------------------------/
+ //- Class/Member Variables -/
+ //--------------------------/
+
+ /**
+ * The NONE type
+ */
+ public static final int NONE_TYPE = 0;
+
+ /**
+ * The instance of the NONE type
+ */
+ public static final ColourThreshTypeType NONE = new ColourThreshTypeType(NONE_TYPE, "NONE");
+
+ /**
+ * The ABOVE type
+ */
+ public static final int ABOVE_TYPE = 1;
+
+ /**
+ * The instance of the ABOVE type
+ */
+ public static final ColourThreshTypeType ABOVE = new ColourThreshTypeType(ABOVE_TYPE, "ABOVE");
+
+ /**
+ * The BELOW type
+ */
+ public static final int BELOW_TYPE = 2;
+
+ /**
+ * The instance of the BELOW type
+ */
+ public static final ColourThreshTypeType BELOW = new ColourThreshTypeType(BELOW_TYPE, "BELOW");
+
+ /**
+ * Field _memberTable.
+ */
+ private static java.util.Hashtable _memberTable = init();
+
+ /**
+ * Field type.
+ */
+ private int type = -1;
+
+ /**
+ * Field stringValue.
+ */
+ private java.lang.String stringValue = null;
+
+
+ //----------------/
+ //- Constructors -/
+ //----------------/
+
+ private ColourThreshTypeType(final int type, final java.lang.String value) {
+ super();
+ this.type = type;
+ this.stringValue = value;
+ }
+
+
+ //-----------/
+ //- Methods -/
+ //-----------/
+
+ /**
+ * Method enumerate.Returns an enumeration of all possible
+ * instances of ColourThreshTypeType
+ *
+ * @return an Enumeration over all possible instances of
+ * ColourThreshTypeType
+ */
+ public static java.util.Enumeration enumerate(
+ ) {
+ return _memberTable.elements();
+ }
+
+ /**
+ * Method getType.Returns the type of this ColourThreshTypeType
+ *
+ * @return the type of this ColourThreshTypeType
+ */
+ public int getType(
+ ) {
+ return this.type;
+ }
+
+ /**
+ * Method init.
+ *
+ * @return the initialized Hashtable for the member table
+ */
+ private static java.util.Hashtable init(
+ ) {
+ Hashtable members = new Hashtable();
+ members.put("NONE", NONE);
+ members.put("ABOVE", ABOVE);
+ members.put("BELOW", BELOW);
+ return members;
+ }
+
+ /**
+ * Method readResolve. will be called during deserialization to
+ * replace the deserialized object with the correct constant
+ * instance.
+ *
+ * @return this deserialized object
+ */
+ private java.lang.Object readResolve(
+ ) {
+ return valueOf(this.stringValue);
+ }
+
+ /**
+ * Method toString.Returns the String representation of this
+ * ColourThreshTypeType
+ *
+ * @return the String representation of this ColourThreshTypeTyp
+ */
+ public java.lang.String toString(
+ ) {
+ return this.stringValue;
+ }
+
+ /**
+ * Method valueOf.Returns a new ColourThreshTypeType based on
+ * the given String value.
+ *
+ * @param string
+ * @return the ColourThreshTypeType value of parameter 'string'
+ */
+ public static jalview.binding.types.ColourThreshTypeType valueOf(
+ final java.lang.String string) {
+ java.lang.Object obj = null;
+ if (string != null) {
+ obj = _memberTable.get(string);
+ }
+ if (obj == null) {
+ String err = "" + string + " is not a valid ColourThreshTypeType";
+ throw new IllegalArgumentException(err);
+ }
+ return (ColourThreshTypeType) obj;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.binding.types;
+
+ //---------------------------------/
+ //- Imported classes and packages -/
+//---------------------------------/
+
+import java.util.Hashtable;
+
+/**
+ * Class FeatureMatcherByType.
+ *
+ * @version $Revision$ $Date$
+ */
+public class FeatureMatcherByType implements java.io.Serializable {
+
+
+ //--------------------------/
+ //- Class/Member Variables -/
+ //--------------------------/
+
+ /**
+ * The byLabel type
+ */
+ public static final int BYLABEL_TYPE = 0;
+
+ /**
+ * The instance of the byLabel type
+ */
+ public static final FeatureMatcherByType BYLABEL = new FeatureMatcherByType(BYLABEL_TYPE, "byLabel");
+
+ /**
+ * The byScore type
+ */
+ public static final int BYSCORE_TYPE = 1;
+
+ /**
+ * The instance of the byScore type
+ */
+ public static final FeatureMatcherByType BYSCORE = new FeatureMatcherByType(BYSCORE_TYPE, "byScore");
+
+ /**
+ * The byAttribute type
+ */
+ public static final int BYATTRIBUTE_TYPE = 2;
+
+ /**
+ * The instance of the byAttribute type
+ */
+ public static final FeatureMatcherByType BYATTRIBUTE = new FeatureMatcherByType(BYATTRIBUTE_TYPE, "byAttribute");
+
+ /**
+ * Field _memberTable.
+ */
+ private static java.util.Hashtable _memberTable = init();
+
+ /**
+ * Field type.
+ */
+ private int type = -1;
+
+ /**
+ * Field stringValue.
+ */
+ private java.lang.String stringValue = null;
+
+
+ //----------------/
+ //- Constructors -/
+ //----------------/
+
+ private FeatureMatcherByType(final int type, final java.lang.String value) {
+ super();
+ this.type = type;
+ this.stringValue = value;
+ }
+
+
+ //-----------/
+ //- Methods -/
+ //-----------/
+
+ /**
+ * Method enumerate.Returns an enumeration of all possible
+ * instances of FeatureMatcherByType
+ *
+ * @return an Enumeration over all possible instances of
+ * FeatureMatcherByType
+ */
+ public static java.util.Enumeration enumerate(
+ ) {
+ return _memberTable.elements();
+ }
+
+ /**
+ * Method getType.Returns the type of this FeatureMatcherByType
+ *
+ * @return the type of this FeatureMatcherByType
+ */
+ public int getType(
+ ) {
+ return this.type;
+ }
+
+ /**
+ * Method init.
+ *
+ * @return the initialized Hashtable for the member table
+ */
+ private static java.util.Hashtable init(
+ ) {
+ Hashtable members = new Hashtable();
+ members.put("byLabel", BYLABEL);
+ members.put("byScore", BYSCORE);
+ members.put("byAttribute", BYATTRIBUTE);
+ return members;
+ }
+
+ /**
+ * Method readResolve. will be called during deserialization to
+ * replace the deserialized object with the correct constant
+ * instance.
+ *
+ * @return this deserialized object
+ */
+ private java.lang.Object readResolve(
+ ) {
+ return valueOf(this.stringValue);
+ }
+
+ /**
+ * Method toString.Returns the String representation of this
+ * FeatureMatcherByType
+ *
+ * @return the String representation of this FeatureMatcherByTyp
+ */
+ public java.lang.String toString(
+ ) {
+ return this.stringValue;
+ }
+
+ /**
+ * Method valueOf.Returns a new FeatureMatcherByType based on
+ * the given String value.
+ *
+ * @param string
+ * @return the FeatureMatcherByType value of parameter 'string'
+ */
+ public static jalview.binding.types.FeatureMatcherByType valueOf(
+ final java.lang.String string) {
+ java.lang.Object obj = null;
+ if (string != null) {
+ obj = _memberTable.get(string);
+ }
+ if (obj == null) {
+ String err = "" + string + " is not a valid FeatureMatcherByType";
+ throw new IllegalArgumentException(err);
+ }
+ return (FeatureMatcherByType) obj;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.binding.types;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import java.util.Hashtable;
+
+/**
+ * Graduated feature colour if no score (or attribute) value
+ *
+ * @version $Revision$ $Date$
+ */
+public class NoValueColour implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * The None type
+ */
+ public static final int NONE_TYPE = 0;
+
+ /**
+ * The instance of the None type
+ */
+ public static final NoValueColour NONE = new NoValueColour(NONE_TYPE,
+ "None");
+
+ /**
+ * The Min type
+ */
+ public static final int MIN_TYPE = 1;
+
+ /**
+ * The instance of the Min type
+ */
+ public static final NoValueColour MIN = new NoValueColour(MIN_TYPE,
+ "Min");
+
+ /**
+ * The Max type
+ */
+ public static final int MAX_TYPE = 2;
+
+ /**
+ * The instance of the Max type
+ */
+ public static final NoValueColour MAX = new NoValueColour(MAX_TYPE,
+ "Max");
+
+ /**
+ * Field _memberTable.
+ */
+ private static java.util.Hashtable _memberTable = init();
+
+ /**
+ * Field type.
+ */
+ private int type = -1;
+
+ /**
+ * Field stringValue.
+ */
+ private java.lang.String stringValue = null;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ private NoValueColour(final int type, final java.lang.String value)
+ {
+ super();
+ this.type = type;
+ this.stringValue = value;
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method enumerate.Returns an enumeration of all possible instances of
+ * NoValueColour
+ *
+ * @return an Enumeration over all possible instances of NoValueColour
+ */
+ public static java.util.Enumeration enumerate()
+ {
+ return _memberTable.elements();
+ }
+
+ /**
+ * Method getType.Returns the type of this NoValueColour
+ *
+ * @return the type of this NoValueColour
+ */
+ public int getType()
+ {
+ return this.type;
+ }
+
+ /**
+ * Method init.
+ *
+ * @return the initialized Hashtable for the member table
+ */
+ private static java.util.Hashtable init()
+ {
+ Hashtable members = new Hashtable();
+ members.put("None", NONE);
+ members.put("Min", MIN);
+ members.put("Max", MAX);
+ return members;
+ }
+
+ /**
+ * Method readResolve. will be called during deserialization to replace the
+ * deserialized object with the correct constant instance.
+ *
+ * @return this deserialized object
+ */
+ private java.lang.Object readResolve()
+ {
+ return valueOf(this.stringValue);
+ }
+
+ /**
+ * Method toString.Returns the String representation of this NoValueColour
+ *
+ * @return the String representation of this NoValueColour
+ */
+ public java.lang.String toString()
+ {
+ return this.stringValue;
+ }
+
+ /**
+ * Method valueOf.Returns a new NoValueColour based on the given String value.
+ *
+ * @param string
+ * @return the NoValueColour value of parameter 'string'
+ */
+ public static jalview.binding.types.NoValueColour valueOf(
+ final java.lang.String string)
+ {
+ java.lang.Object obj = null;
+ if (string != null)
+ {
+ obj = _memberTable.get(string);
+ }
+ if (obj == null)
+ {
+ String err = "" + string + " is not a valid NoValueColour";
+ throw new IllegalArgumentException(err);
+ }
+ return (NoValueColour) obj;
+ }
+
+}
*/
package jalview.commands;
+import jalview.analysis.AlignSeq;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
+import jalview.datamodel.Range;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.SequenceFeaturesI;
+import jalview.util.Comparison;
import jalview.util.ReverseListIterator;
import jalview.util.StringUtils;
public abstract Action getUndoAction();
};
- private List<Edit> edits = new ArrayList<Edit>();
+ private List<Edit> edits = new ArrayList<>();
String description;
int position, int number, AlignmentI al, boolean performEdit,
AlignmentI[] views)
{
- Edit edit = new Edit(command, seqs, position, number,
- al.getGapCharacter());
- if (al.getHeight() == seqs.length)
- {
- edit.al = al;
- edit.fullAlignmentHeight = true;
- }
-
- addEdit(edit);
-
- if (performEdit)
- {
- performEdit(edit, views);
- }
+ Edit edit = new Edit(command, seqs, position, number, al);
+ appendEdit(edit, al, performEdit, views);
}
/**
command.string[i] = sequence.getSequence(command.position,
command.position + command.number);
SequenceI oldds = sequence.getDatasetSequence();
- if (command.oldds != null && command.oldds[i] != null)
- {
- // we are redoing an undone cut.
- sequence.setDatasetSequence(null);
- }
- sequence.deleteChars(command.position,
+ Range cutPositions = sequence.findPositions(command.position + 1,
command.position + command.number);
+ boolean cutIsInternal = cutPositions != null
+ && sequence.getStart() != cutPositions
+ .getBegin() && sequence.getEnd() != cutPositions.getEnd();
+
+ /*
+ * perform the cut; if this results in a new dataset sequence, add
+ * that to the alignment dataset
+ */
+ SequenceI ds = sequence.getDatasetSequence();
+ sequence.deleteChars(command.position, command.position
+ + command.number);
+
if (command.oldds != null && command.oldds[i] != null)
{
- // oldds entry contains the cut dataset sequence.
+ /*
+ * we are Redoing a Cut, or Undoing a Paste - so
+ * oldds entry contains the cut dataset sequence,
+ * with sequence features in expected place
+ */
sequence.setDatasetSequence(command.oldds[i]);
command.oldds[i] = oldds;
}
else
{
- // modify the oldds if necessary
+ /*
+ * new cut operation: save the dataset sequence
+ * so it can be restored in an Undo
+ */
+ if (command.oldds == null)
+ {
+ command.oldds = new SequenceI[command.seqs.length];
+ }
+ command.oldds[i] = oldds;// todo not if !cutIsInternal?
+
+ // do we need to edit sequence features for new sequence ?
if (oldds != sequence.getDatasetSequence()
- || sequence.getFeatures().hasFeatures())
+ || (cutIsInternal
+ && sequence.getFeatures().hasFeatures()))
+ // todo or just test cutIsInternal && cutPositions != null ?
{
- if (command.oldds == null)
+ if (cutPositions != null)
{
- command.oldds = new SequenceI[command.seqs.length];
+ cutFeatures(command, sequence, cutPositions.getBegin(),
+ cutPositions.getEnd(), cutIsInternal);
}
- command.oldds[i] = oldds;
- // FIXME JAL-2541 JAL-2526 get correct positions if on a gap
- adjustFeatures(
- command,
- i,
- sequence.findPosition(command.position),
- sequence.findPosition(command.position + command.number),
- false);
}
}
+ SequenceI newDs = sequence.getDatasetSequence();
+ if (newDs != ds && command.al != null
+ && command.al.getDataset() != null
+ && !command.al.getDataset().getSequences().contains(newDs))
+ {
+ command.al.getDataset().addSequence(newDs);
+ }
}
if (sequence.getLength() < 1)
*/
static void paste(Edit command, AlignmentI[] views)
{
- StringBuffer tmp;
- boolean newDSNeeded;
- boolean newDSWasNeeded;
- int newstart, newend;
boolean seqWasDeleted = false;
- int start = 0, end = 0;
for (int i = 0; i < command.seqs.length; i++)
{
- newDSNeeded = false;
- newDSWasNeeded = command.oldds != null && command.oldds[i] != null;
- if (command.seqs[i].getLength() < 1)
+ boolean newDSNeeded = false;
+ boolean newDSWasNeeded = command.oldds != null
+ && command.oldds[i] != null;
+ SequenceI sequence = command.seqs[i];
+ if (sequence.getLength() < 1)
{
- // ie this sequence was deleted, we need to
- // readd it to the alignment
+ /*
+ * sequence was deleted; re-add it to the alignment
+ */
if (command.alIndex[i] < command.al.getHeight())
{
List<SequenceI> sequences;
{
if (!(command.alIndex[i] < 0))
{
- sequences.add(command.alIndex[i], command.seqs[i]);
+ sequences.add(command.alIndex[i], sequence);
}
}
}
else
{
- command.al.addSequence(command.seqs[i]);
+ command.al.addSequence(sequence);
}
seqWasDeleted = true;
}
- newstart = command.seqs[i].getStart();
- newend = command.seqs[i].getEnd();
+ int newStart = sequence.getStart();
+ int newEnd = sequence.getEnd();
- tmp = new StringBuffer();
- tmp.append(command.seqs[i].getSequence());
+ StringBuilder tmp = new StringBuilder();
+ tmp.append(sequence.getSequence());
// Undo of a delete does not replace original dataset sequence on to
// alignment sequence.
+ int start = 0;
+ int length = 0;
+
if (command.string != null && command.string[i] != null)
{
if (command.position >= tmp.length())
{
// This occurs if padding is on, and residues
// are removed from end of alignment
- int length = command.position - tmp.length();
- while (length > 0)
+ int len = command.position - tmp.length();
+ while (len > 0)
{
tmp.append(command.gapChar);
- length--;
+ len--;
}
}
tmp.insert(command.position, command.string[i]);
for (int s = 0; s < command.string[i].length; s++)
{
- if (jalview.schemes.ResidueProperties.aaIndex[command.string[i][s]] != 23)
+ if (!Comparison.isGap(command.string[i][s]))
{
+ length++;
if (!newDSNeeded)
{
newDSNeeded = true;
- start = command.seqs[i].findPosition(command.position);
- end = command.seqs[i]
- .findPosition(command.position + command.number);
+ start = sequence.findPosition(command.position);
+ // end = sequence
+ // .findPosition(command.position + command.number);
}
- if (command.seqs[i].getStart() == start)
+ if (sequence.getStart() == start)
{
- newstart--;
+ newStart--;
}
else
{
- newend++;
+ newEnd++;
}
}
}
command.string[i] = null;
}
- command.seqs[i].setSequence(tmp.toString());
- command.seqs[i].setStart(newstart);
- command.seqs[i].setEnd(newend);
+ sequence.setSequence(tmp.toString());
+ sequence.setStart(newStart);
+ sequence.setEnd(newEnd);
+
+ /*
+ * command and Undo share the same dataset sequence if cut was
+ * at start or end of sequence
+ */
+ boolean sameDatasetSequence = false;
if (newDSNeeded)
{
- if (command.seqs[i].getDatasetSequence() != null)
+ if (sequence.getDatasetSequence() != null)
{
SequenceI ds;
if (newDSWasNeeded)
{
// make a new DS sequence
// use new ds mechanism here
- ds = new Sequence(command.seqs[i].getName(),
- jalview.analysis.AlignSeq.extractGaps(
- jalview.util.Comparison.GapChars,
- command.seqs[i].getSequenceAsString()),
- command.seqs[i].getStart(), command.seqs[i].getEnd());
- ds.setDescription(command.seqs[i].getDescription());
+ String ungapped = AlignSeq.extractGaps(Comparison.GapChars,
+ sequence.getSequenceAsString());
+ ds = new Sequence(sequence.getName(), ungapped,
+ sequence.getStart(), sequence.getEnd());
+ ds.setDescription(sequence.getDescription());
}
if (command.oldds == null)
{
command.oldds = new SequenceI[command.seqs.length];
}
- command.oldds[i] = command.seqs[i].getDatasetSequence();
- command.seqs[i].setDatasetSequence(ds);
+ command.oldds[i] = sequence.getDatasetSequence();
+ sameDatasetSequence = ds == sequence.getDatasetSequence();
+ ds.setSequenceFeatures(sequence.getSequenceFeatures());
+ if (!sameDatasetSequence && command.al.getDataset() != null)
+ {
+ // delete 'undone' sequence from alignment dataset
+ command.al.getDataset()
+ .deleteSequence(sequence.getDatasetSequence());
+ }
+ sequence.setDatasetSequence(ds);
}
- adjustFeatures(command, i, start, end, true);
+ undoCutFeatures(command, command.seqs[i], start, length,
+ sameDatasetSequence);
}
}
adjustAnnotations(command, true, seqWasDeleted, views);
static void replace(Edit command)
{
- StringBuffer tmp;
+ StringBuilder tmp;
String oldstring;
int start = command.position;
int end = command.number;
{
boolean newDSWasNeeded = command.oldds != null
&& command.oldds[i] != null;
+ boolean newStartEndWasNeeded = command.oldStartEnd!=null && command.oldStartEnd[i]!=null;
/**
* cut addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT,
* EditCommand.PASTE, sequences, 0, alignment.getWidth(), alignment) );
*
*/
+
+ Range beforeEditedPositions = command.seqs[i].findPositions(1, start);
+ Range afterEditedPositions = command.seqs[i]
+ .findPositions(end + 1, command.seqs[i].getLength());
+
oldstring = command.seqs[i].getSequenceAsString();
- tmp = new StringBuffer(oldstring.substring(0, start));
+ tmp = new StringBuilder(oldstring.substring(0, start));
tmp.append(command.string[i]);
- String nogaprep = jalview.analysis.AlignSeq.extractGaps(
- jalview.util.Comparison.GapChars,
+ String nogaprep = AlignSeq.extractGaps(Comparison.GapChars,
new String(command.string[i]));
- int ipos = command.seqs[i].findPosition(start)
- - command.seqs[i].getStart();
- tmp.append(oldstring.substring(end));
+ if (end < oldstring.length())
+ {
+ tmp.append(oldstring.substring(end));
+ }
+ // stash end prior to updating the sequence object so we can save it if
+ // need be.
+ Range oldstartend = new Range(command.seqs[i].getStart(),
+ command.seqs[i].getEnd());
command.seqs[i].setSequence(tmp.toString());
- command.string[i] = oldstring.substring(start, end).toCharArray();
- String nogapold = jalview.analysis.AlignSeq.extractGaps(
- jalview.util.Comparison.GapChars,
+ command.string[i] = oldstring
+ .substring(start, Math.min(end, oldstring.length()))
+ .toCharArray();
+ String nogapold = AlignSeq.extractGaps(Comparison.GapChars,
new String(command.string[i]));
+
if (!nogaprep.toLowerCase().equals(nogapold.toLowerCase()))
{
- if (newDSWasNeeded)
+ // we may already have dataset and limits stashed...
+ if (newDSWasNeeded || newStartEndWasNeeded)
{
+ if (newDSWasNeeded)
+ {
+ // then just switch the dataset sequence
SequenceI oldds = command.seqs[i].getDatasetSequence();
command.seqs[i].setDatasetSequence(command.oldds[i]);
command.oldds[i] = oldds;
+ }
+ if (newStartEndWasNeeded)
+ {
+ Range newStart = command.oldStartEnd[i];
+ command.oldStartEnd[i] = oldstartend;
+ command.seqs[i].setStart(newStart.getBegin());
+ command.seqs[i].setEnd(newStart.getEnd());
+ }
}
- else
+ else
{
- if (command.oldds == null)
+ // decide if we need a new dataset sequence or modify start/end
+ // first edit the original dataset sequence string
+ SequenceI oldds = command.seqs[i].getDatasetSequence();
+ String osp = oldds.getSequenceAsString();
+ int beforeStartOfEdit = -oldds.getStart() + 1
+ + (beforeEditedPositions == null
+ ? ((afterEditedPositions != null)
+ ? afterEditedPositions.getBegin() - 1
+ : oldstartend.getBegin()
+ + nogapold.length())
+ : beforeEditedPositions.getEnd()
+ );
+ int afterEndOfEdit = -oldds.getStart() + 1
+ + ((afterEditedPositions == null)
+ ? oldstartend.getEnd()
+ : afterEditedPositions.getBegin() - 1);
+ String fullseq = osp.substring(0,
+ beforeStartOfEdit)
+ + nogaprep
+ + osp.substring(afterEndOfEdit);
+
+ // and check if new sequence data is different..
+ if (!fullseq.equalsIgnoreCase(osp))
{
- command.oldds = new SequenceI[command.seqs.length];
- }
- command.oldds[i] = command.seqs[i].getDatasetSequence();
- SequenceI newds = new Sequence(
- command.seqs[i].getDatasetSequence());
- String fullseq, osp = newds.getSequenceAsString();
- fullseq = osp.substring(0, ipos) + nogaprep
- + osp.substring(ipos + nogaprep.length());
- newds.setSequence(fullseq.toUpperCase());
- // TODO: JAL-1131 ensure newly created dataset sequence is added to
- // the set of
- // dataset sequences associated with the alignment.
- // TODO: JAL-1131 fix up any annotation associated with new dataset
- // sequence to ensure that original sequence/annotation relationships
- // are preserved.
- command.seqs[i].setDatasetSequence(newds);
+ // old ds and edited ds are different, so
+ // create the new dataset sequence
+ SequenceI newds = new Sequence(oldds);
+ newds.setSequence(fullseq);
+
+ if (command.oldds == null)
+ {
+ command.oldds = new SequenceI[command.seqs.length];
+ }
+ command.oldds[i] = command.seqs[i].getDatasetSequence();
+
+ // And preserve start/end for good-measure
+ if (command.oldStartEnd == null)
+ {
+ command.oldStartEnd = new Range[command.seqs.length];
+ }
+ command.oldStartEnd[i] = oldstartend;
+ // TODO: JAL-1131 ensure newly created dataset sequence is added to
+ // the set of
+ // dataset sequences associated with the alignment.
+ // TODO: JAL-1131 fix up any annotation associated with new dataset
+ // sequence to ensure that original sequence/annotation
+ // relationships
+ // are preserved.
+ command.seqs[i].setDatasetSequence(newds);
+ }
+ else
+ {
+ if (command.oldStartEnd == null)
+ {
+ command.oldStartEnd = new Range[command.seqs.length];
+ }
+ command.oldStartEnd[i] = new Range(command.seqs[i].getStart(),
+ command.seqs[i].getEnd());
+ if (beforeEditedPositions != null
+ && afterEditedPositions == null)
+ {
+ // modification at end
+ command.seqs[i].setEnd(
+ beforeEditedPositions.getEnd() + nogaprep.length()
+ - nogapold.length());
+ }
+ else if (afterEditedPositions != null
+ && beforeEditedPositions == null)
+ {
+ // modification at start
+ command.seqs[i].setStart(
+ afterEditedPositions.getBegin() - nogaprep.length());
+ }
+ else
+ {
+ // edit covered both start and end. Here we can only guess the
+ // new
+ // start/end
+ String nogapalseq = AlignSeq.extractGaps(Comparison.GapChars,
+ command.seqs[i].getSequenceAsString().toUpperCase());
+ int newStart = command.seqs[i].getDatasetSequence()
+ .getSequenceAsString().indexOf(nogapalseq);
+ if (newStart == -1)
+ {
+ throw new Error(
+ "Implementation Error: could not locate start/end "
+ + "in dataset sequence after an edit of the sequence string");
+ }
+ int newEnd = newStart + nogapalseq.length() - 1;
+ command.seqs[i].setStart(newStart);
+ command.seqs[i].setEnd(newEnd);
+ }
+ }
}
}
tmp = null;
if (modifyVisibility && !insert)
{
// only occurs if a sequence was added or deleted.
- command.deletedAnnotationRows = new Hashtable<SequenceI, AlignmentAnnotation[]>();
+ command.deletedAnnotationRows = new Hashtable<>();
}
if (command.fullAlignmentHeight)
{
}
// and then duplicate added annotation on every other alignment
// view
- for (int vnum = 0; views != null
- && vnum < views.length; vnum++)
+ for (int vnum = 0; views != null && vnum < views.length; vnum++)
{
if (views[vnum] != command.al)
{
if (!insert)
{
- command.deletedAnnotations = new Hashtable<String, Annotation[]>();
+ command.deletedAnnotations = new Hashtable<>();
}
int aSize;
}
}
- final static void adjustFeatures(Edit command, int index, final int i,
- final int j, boolean insert)
+ /**
+ * Restores features to the state before a Cut.
+ * <ul>
+ * <li>re-add any features deleted by the cut</li>
+ * <li>remove any truncated features created by the cut</li>
+ * <li>shift right any features to the right of the cut</li>
+ * </ul>
+ *
+ * @param command
+ * the Cut command
+ * @param seq
+ * the sequence the Cut applied to
+ * @param start
+ * the start residue position of the cut
+ * @param length
+ * the number of residues cut
+ * @param sameDatasetSequence
+ * true if dataset sequence and frame of reference were left
+ * unchanged by the Cut
+ */
+ final static void undoCutFeatures(Edit command, SequenceI seq,
+ final int start, final int length, boolean sameDatasetSequence)
{
- SequenceI seq = command.seqs[index];
SequenceI sequence = seq.getDatasetSequence();
if (sequence == null)
{
sequence = seq;
}
- if (insert)
+ /*
+ * shift right features that lie to the right of the restored cut (but not
+ * if dataset sequence unchanged - so coordinates were changed by Cut)
+ */
+ if (!sameDatasetSequence)
{
- if (command.editedFeatures != null
- && command.editedFeatures.containsKey(seq))
+ /*
+ * shift right all features right of and not
+ * contiguous with the cut position
+ */
+ seq.getFeatures().shiftFeatures(start + 1, length);
+
+ /*
+ * shift right any features that start at the cut position,
+ * unless they were truncated
+ */
+ List<SequenceFeature> sfs = seq.getFeatures().findFeatures(start,
+ start);
+ for (SequenceFeature sf : sfs)
{
- sequence.setSequenceFeatures(command.editedFeatures.get(seq));
+ if (sf.getBegin() == start)
+ {
+ if (!command.truncatedFeatures.containsKey(seq)
+ || !command.truncatedFeatures.get(seq).contains(sf))
+ {
+ /*
+ * feature was shifted left to cut position (not truncated),
+ * so shift it back right
+ */
+ SequenceFeature shifted = new SequenceFeature(sf, sf.getBegin()
+ + length, sf.getEnd() + length, sf.getFeatureGroup(),
+ sf.getScore());
+ seq.addSequenceFeature(shifted);
+ seq.deleteFeature(sf);
+ }
+ }
}
-
- return;
}
- List<SequenceFeature> sf = sequence.getFeatures()
- .getPositionalFeatures();
-
- if (sf.isEmpty())
- {
- return;
- }
-
- List<SequenceFeature> oldsf = new ArrayList<SequenceFeature>();
-
- int cSize = j - i;
-
- for (SequenceFeature feature : sf)
+ /*
+ * restore any features that were deleted or truncated
+ */
+ if (command.deletedFeatures != null
+ && command.deletedFeatures.containsKey(seq))
{
- SequenceFeature copy = new SequenceFeature(feature);
-
- oldsf.add(copy);
-
- if (feature.getEnd() < i)
- {
- continue;
- }
-
- if (feature.getBegin() > j)
- {
- int newBegin = copy.getBegin() - cSize;
- int newEnd = copy.getEnd() - cSize;
- SequenceFeature newSf = new SequenceFeature(feature, newBegin,
- newEnd, feature.getFeatureGroup(), feature.getScore());
- sequence.deleteFeature(feature);
- sequence.addSequenceFeature(newSf);
- // feature.setBegin(newBegin);
- // feature.setEnd(newEnd);
- continue;
- }
-
- int newBegin = feature.getBegin();
- int newEnd = feature.getEnd();
- if (newBegin >= i)
- {
- newBegin = i;
- // feature.setBegin(i);
- }
-
- if (newEnd < j)
+ for (SequenceFeature deleted : command.deletedFeatures.get(seq))
{
- newEnd = j - 1;
- // feature.setEnd(j - 1);
+ sequence.addSequenceFeature(deleted);
}
- newEnd = newEnd - cSize;
- // feature.setEnd(feature.getEnd() - (cSize));
-
- sequence.deleteFeature(feature);
- if (newEnd >= newBegin)
- {
- sequence.addSequenceFeature(new SequenceFeature(feature, newBegin,
- newEnd, feature.getFeatureGroup(), feature.getScore()));
- }
- // if (feature.getBegin() > feature.getEnd())
- // {
- // sequence.deleteFeature(feature);
- // }
}
- if (command.editedFeatures == null)
+ /*
+ * delete any truncated features
+ */
+ if (command.truncatedFeatures != null
+ && command.truncatedFeatures.containsKey(seq))
{
- command.editedFeatures = new Hashtable<SequenceI, List<SequenceFeature>>();
+ for (SequenceFeature amended : command.truncatedFeatures.get(seq))
+ {
+ sequence.deleteFeature(amended);
+ }
}
-
- command.editedFeatures.put(seq, oldsf);
-
}
/**
*/
public Map<SequenceI, SequenceI> priorState(boolean forUndo)
{
- Map<SequenceI, SequenceI> result = new HashMap<SequenceI, SequenceI>();
+ Map<SequenceI, SequenceI> result = new HashMap<>();
if (getEdits() == null)
{
return result;
* Work backwards through the edit list, deriving the sequences before each
* was applied. The final result is the sequence set before any edits.
*/
- Iterator<Edit> editList = new ReverseListIterator<Edit>(getEdits());
+ Iterator<Edit> editList = new ReverseListIterator<>(getEdits());
while (editList.hasNext())
{
Edit oldEdit = editList.next();
public class Edit
{
- public SequenceI[] oldds;
+ private SequenceI[] oldds;
+
+ /**
+ * start and end of sequence prior to edit
+ */
+ private Range[] oldStartEnd;
+
+ private boolean fullAlignmentHeight = false;
- boolean fullAlignmentHeight = false;
+ private Map<SequenceI, AlignmentAnnotation[]> deletedAnnotationRows;
- Hashtable<SequenceI, AlignmentAnnotation[]> deletedAnnotationRows;
+ private Map<String, Annotation[]> deletedAnnotations;
- Hashtable<String, Annotation[]> deletedAnnotations;
+ /*
+ * features deleted by the cut (re-add on Undo)
+ * (including the original of any shortened features)
+ */
+ private Map<SequenceI, List<SequenceFeature>> deletedFeatures;
- Hashtable<SequenceI, List<SequenceFeature>> editedFeatures;
+ /*
+ * shortened features added by the cut (delete on Undo)
+ */
+ private Map<SequenceI, List<SequenceFeature>> truncatedFeatures;
- AlignmentI al;
+ private AlignmentI al;
- Action command;
+ final private Action command;
char[][] string;
SequenceI[] seqs;
- int[] alIndex;
+ private int[] alIndex;
- int position, number;
+ private int position;
- char gapChar;
+ private int number;
+
+ private char gapChar;
public Edit(Action cmd, SequenceI[] sqs, int pos, int count,
char gap)
Edit(Action cmd, SequenceI[] sqs, int pos, int count,
AlignmentI align)
{
- this.gapChar = align.getGapCharacter();
- this.command = cmd;
- this.seqs = sqs;
- this.position = pos;
- this.number = count;
+ this(cmd, sqs, pos, count, align.getGapCharacter());
+
this.al = align;
alIndex = new int[sqs.length];
fullAlignmentHeight = (align.getHeight() == sqs.length);
}
+ /**
+ * Constructor given a REPLACE command and the replacement string
+ *
+ * @param cmd
+ * @param sqs
+ * @param pos
+ * @param count
+ * @param align
+ * @param replace
+ */
Edit(Action cmd, SequenceI[] sqs, int pos, int count,
AlignmentI align, String replace)
{
- this.command = cmd;
- this.seqs = sqs;
- this.position = pos;
- this.number = count;
- this.al = align;
- this.gapChar = align.getGapCharacter();
+ this(cmd, sqs, pos, count, align);
+
string = new char[sqs.length][];
for (int i = 0; i < sqs.length; i++)
{
string[i] = replace.toCharArray();
}
-
- fullAlignmentHeight = (align.getHeight() == sqs.length);
}
public SequenceI[] getSequences()
}
else
{
- return new ReverseListIterator<Edit>(getEdits());
+ return new ReverseListIterator<>(getEdits());
+ }
+ }
+
+ /**
+ * Adjusts features for Cut, and saves details of changes made to allow Undo
+ * <ul>
+ * <li>features left of the cut are unchanged</li>
+ * <li>features right of the cut are shifted left</li>
+ * <li>features internal to the cut region are deleted</li>
+ * <li>features that overlap or span the cut are shortened</li>
+ * <li>the originals of any deleted or shortened features are saved, to re-add
+ * on Undo</li>
+ * <li>any added (shortened) features are saved, to delete on Undo</li>
+ * </ul>
+ *
+ * @param command
+ * @param seq
+ * @param fromPosition
+ * @param toPosition
+ * @param cutIsInternal
+ */
+ protected static void cutFeatures(Edit command, SequenceI seq,
+ int fromPosition, int toPosition, boolean cutIsInternal)
+ {
+ /*
+ * if the cut is at start or end of sequence
+ * then we don't modify the sequence feature store
+ */
+ if (!cutIsInternal)
+ {
+ return;
+ }
+ List<SequenceFeature> added = new ArrayList<>();
+ List<SequenceFeature> removed = new ArrayList<>();
+
+ SequenceFeaturesI featureStore = seq.getFeatures();
+ if (toPosition < fromPosition || featureStore == null)
+ {
+ return;
+ }
+
+ int cutStartPos = fromPosition;
+ int cutEndPos = toPosition;
+ int cutWidth = cutEndPos - cutStartPos + 1;
+
+ synchronized (featureStore)
+ {
+ /*
+ * get features that overlap the cut region
+ */
+ List<SequenceFeature> toAmend = featureStore.findFeatures(
+ cutStartPos, cutEndPos);
+
+ /*
+ * add any contact features that span the cut region
+ * (not returned by findFeatures)
+ */
+ for (SequenceFeature contact : featureStore.getContactFeatures())
+ {
+ if (contact.getBegin() < cutStartPos
+ && contact.getEnd() > cutEndPos)
+ {
+ toAmend.add(contact);
+ }
+ }
+
+ /*
+ * adjust start-end of overlapping features;
+ * delete features enclosed by the cut;
+ * delete partially overlapping contact features
+ */
+ for (SequenceFeature sf : toAmend)
+ {
+ int sfBegin = sf.getBegin();
+ int sfEnd = sf.getEnd();
+ int newBegin = sfBegin;
+ int newEnd = sfEnd;
+ boolean toDelete = false;
+ boolean follows = false;
+
+ if (sfBegin >= cutStartPos && sfEnd <= cutEndPos)
+ {
+ /*
+ * feature lies within cut region - delete it
+ */
+ toDelete = true;
+ }
+ else if (sfBegin < cutStartPos && sfEnd > cutEndPos)
+ {
+ /*
+ * feature spans cut region - left-shift the end
+ */
+ newEnd -= cutWidth;
+ }
+ else if (sfEnd <= cutEndPos)
+ {
+ /*
+ * feature overlaps left of cut region - truncate right
+ */
+ newEnd = cutStartPos - 1;
+ if (sf.isContactFeature())
+ {
+ toDelete = true;
+ }
+ }
+ else if (sfBegin >= cutStartPos)
+ {
+ /*
+ * remaining case - feature overlaps right
+ * truncate left, adjust end of feature
+ */
+ newBegin = cutIsInternal ? cutStartPos : cutEndPos + 1;
+ newEnd = newBegin + sfEnd - cutEndPos - 1;
+ if (sf.isContactFeature())
+ {
+ toDelete = true;
+ }
+ }
+
+ seq.deleteFeature(sf);
+ if (!follows)
+ {
+ removed.add(sf);
+ }
+ if (!toDelete)
+ {
+ SequenceFeature copy = new SequenceFeature(sf, newBegin, newEnd,
+ sf.getFeatureGroup(), sf.getScore());
+ seq.addSequenceFeature(copy);
+ if (!follows)
+ {
+ added.add(copy);
+ }
+ }
+ }
+
+ /*
+ * and left shift any features lying to the right of the cut region
+ */
+
+ featureStore.shiftFeatures(cutEndPos + 1, -cutWidth);
+ }
+
+ /*
+ * save deleted and amended features, so that Undo can
+ * re-add or delete them respectively
+ */
+ if (command.deletedFeatures == null)
+ {
+ command.deletedFeatures = new HashMap<>();
+ }
+ if (command.truncatedFeatures == null)
+ {
+ command.truncatedFeatures = new HashMap<>();
}
+ command.deletedFeatures.put(seq, removed);
+ command.truncatedFeatures.put(seq, added);
}
}
private AlignViewControllerGuiI avcg;
public AlignViewController(AlignViewControllerGuiI alignFrame,
- AlignViewportI viewport, AlignmentViewPanel alignPanel)
+ AlignViewportI vp, AlignmentViewPanel ap)
{
this.avcg = alignFrame;
- this.viewport = viewport;
- this.alignPanel = alignPanel;
+ this.viewport = vp;
+ this.alignPanel = ap;
}
@Override
- public void setViewportAndAlignmentPanel(AlignViewportI viewport,
- AlignmentViewPanel alignPanel)
+ public void setViewportAndAlignmentPanel(AlignViewportI vp,
+ AlignmentViewPanel ap)
{
- this.alignPanel = alignPanel;
- this.viewport = viewport;
-
+ this.alignPanel = ap;
+ this.viewport = vp;
}
@Override
/**
* Sets a bit in the BitSet for each column (base 0) in the sequence
- * collection which includes the specified feature type. Returns the number of
- * sequences which have the feature in the selected range.
+ * collection which includes a visible feature of the specified feature type.
+ * Returns the number of sequences which have the feature visible in the
+ * selected range.
*
* @param featureType
* @param sqcol
* @param bs
* @return
*/
- static int findColumnsWithFeature(String featureType,
+ int findColumnsWithFeature(String featureType,
SequenceCollectionI sqcol, BitSet bs)
{
+ FeatureRenderer fr = alignPanel == null ? null : alignPanel
+ .getFeatureRenderer();
+
final int startColumn = sqcol.getStartRes() + 1; // converted to base 1
final int endColumn = sqcol.getEndRes() + 1;
List<SequenceI> seqs = sqcol.getSequences();
List<SequenceFeature> sfs = sq.findFeatures(startColumn,
endColumn, featureType);
- if (!sfs.isEmpty())
- {
- nseq++;
- }
-
+ boolean found = false;
for (SequenceFeature sf : sfs)
{
+ if (fr.getColour(sf) == null)
+ {
+ continue;
+ }
+ if (!found)
+ {
+ nseq++;
+ }
+ found = true;
+
int sfStartCol = sq.findIndex(sf.getBegin());
int sfEndCol = sq.findIndex(sf.getEnd());
public boolean parseFeaturesFile(String file, DataSourceType protocol,
boolean relaxedIdMatching)
{
- boolean featuresFile = false;
+ boolean featuresAdded = false;
+ FeatureRenderer fr = alignPanel.getFeatureRenderer();
try
{
- featuresFile = new FeaturesFile(false, file, protocol).parse(
- viewport.getAlignment().getDataset(),
- alignPanel.getFeatureRenderer().getFeatureColours(), false,
- relaxedIdMatching);
+ featuresAdded = new FeaturesFile(false, file, protocol).parse(
+ viewport.getAlignment().getDataset(), fr.getFeatureColours(),
+ fr.getFeatureFilters(), false, relaxedIdMatching);
} catch (Exception ex)
{
ex.printStackTrace();
}
- if (featuresFile)
+ if (featuresAdded)
{
avcg.refreshFeatureUI(true);
- if (alignPanel.getFeatureRenderer() != null)
+ if (fr != null)
{
// update the min/max ranges where necessary
- alignPanel.getFeatureRenderer().findAllFeatures(true);
+ fr.findAllFeatures(true);
}
if (avcg.getFeatureSettingsUI() != null)
{
alignPanel.paintAlignment(true, true);
}
- return featuresFile;
+ return featuresAdded;
}
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
{
private Alignment dataset;
- protected List<SequenceI> sequences;
+ private List<SequenceI> sequences;
protected List<SequenceGroup> groups;
return sequences.get(i);
}
}
+
return null;
}
public int getWidth()
{
int maxLength = -1;
-
+
for (int i = 0; i < sequences.size(); i++)
{
if (getSequenceAt(i).getLength() > maxLength)
maxLength = getSequenceAt(i).getLength();
}
}
-
+
return maxLength;
}
+ /*
+ @Override
+ public int getWidth()
+ {
+ final Wrapper temp = new Wrapper();
+
+ forEachSequence(new Consumer<SequenceI>()
+ {
+ @Override
+ public void accept(SequenceI s)
+ {
+ if (s.getLength() > temp.inner)
+ {
+ temp.inner = s.getLength();
+ }
+ }
+ }, 0, sequences.size() - 1);
+
+ return temp.inner;
+ }
+
+ public static class Wrapper
+ {
+ public int inner;
+ }*/
/**
* DOCUMENT ME!
AlignmentAnnotation annot = new AlignmentAnnotation(name, name,
new Annotation[1], 0f, 0f, AlignmentAnnotation.BAR_GRAPH);
annot.hasText = false;
- annot.setCalcId(new String(calcId));
+ if (calcId != null)
+ {
+ annot.setCalcId(new String(calcId));
+ }
annot.autoCalculated = autoCalc;
if (seqRef != null)
{
{
hiddenCols = cols;
}
+
+ @Override
+ public void setupJPredAlignment()
+ {
+ SequenceI repseq = getSequenceAt(0);
+ setSeqrep(repseq);
+ HiddenColumns cs = new HiddenColumns();
+ cs.hideList(repseq.getInsertions());
+ setHiddenColumns(cs);
+ }
+
+ @Override
+ public HiddenColumns propagateInsertions(SequenceI profileseq,
+ AlignmentView input)
+ {
+ int profsqpos = 0;
+
+ char gc = getGapCharacter();
+ Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc);
+ HiddenColumns nview = (HiddenColumns) alandhidden[1];
+ SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos];
+ return propagateInsertions(profileseq, origseq, nview);
+ }
+
+ /**
+ *
+ * @param profileseq
+ * sequence in al which corresponds to origseq
+ * @param al
+ * alignment which is to have gaps inserted into it
+ * @param origseq
+ * sequence corresponding to profileseq which defines gap map for
+ * modifying al
+ */
+ private HiddenColumns propagateInsertions(SequenceI profileseq,
+ SequenceI origseq, HiddenColumns hc)
+ {
+ // take the set of hidden columns, and the set of gaps in origseq,
+ // and remove all the hidden gaps from hiddenColumns
+
+ // first get the gaps as a Bitset
+ // then calculate hidden ^ not(gap)
+ BitSet gaps = origseq.gapBitset();
+ hc.andNot(gaps);
+
+ // for each sequence in the alignment, except the profile sequence,
+ // insert gaps corresponding to each hidden region but where each hidden
+ // column region is shifted backwards by the number of preceding visible
+ // gaps update hidden columns at the same time
+ HiddenColumns newhidden = new HiddenColumns();
+
+ int numGapsBefore = 0;
+ int gapPosition = 0;
+ Iterator<int[]> it = hc.iterator();
+ while (it.hasNext())
+ {
+ int[] region = it.next();
+
+ // get region coordinates accounting for gaps
+ // we can rely on gaps not being *in* hidden regions because we already
+ // removed those
+ while (gapPosition < region[0])
+ {
+ gapPosition++;
+ if (gaps.get(gapPosition))
+ {
+ numGapsBefore++;
+ }
+ }
+
+ int left = region[0] - numGapsBefore;
+ int right = region[1] - numGapsBefore;
+
+ newhidden.hideColumns(left, right);
+ padGaps(left, right, profileseq);
+ }
+ return newhidden;
+ }
+
+ /**
+ * Pad gaps in all sequences in alignment except profileseq
+ *
+ * @param left
+ * position of first gap to insert
+ * @param right
+ * position of last gap to insert
+ * @param profileseq
+ * sequence not to pad
+ */
+ private void padGaps(int left, int right, SequenceI profileseq)
+ {
+ char gc = getGapCharacter();
+
+ // make a string with number of gaps = length of hidden region
+ StringBuilder sb = new StringBuilder();
+ for (int g = 0; g < right - left + 1; g++)
+ {
+ sb.append(gc);
+ }
+
+ // loop over the sequences and pad with gaps where required
+ for (int s = 0, ns = getHeight(); s < ns; s++)
+ {
+ SequenceI sqobj = getSequenceAt(s);
+ if ((sqobj != profileseq) && (sqobj.getLength() >= left))
+ {
+ String sq = sqobj.getSequenceAsString();
+ sqobj.setSequence(
+ sq.substring(0, left) + sb.toString() + sq.substring(left));
+ }
+ }
+ }
+
}
import jalview.analysis.WUSSParseException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
}
/**
+ * Get the RNA Secondary Structure SequenceFeature Array if present
+ */
+ public SequenceFeature[] getRnaSecondaryStructure()
+ {
+ return this._rnasecstr;
+ }
+
+ /**
+ * Check the RNA Secondary Structure is equivalent to one in given
+ * AlignmentAnnotation param
+ */
+ public boolean rnaSecondaryStructureEquivalent(AlignmentAnnotation that)
+ {
+ return rnaSecondaryStructureEquivalent(that, true);
+ }
+
+ public boolean rnaSecondaryStructureEquivalent(AlignmentAnnotation that, boolean compareType)
+ {
+ SequenceFeature[] thisSfArray = this.getRnaSecondaryStructure();
+ SequenceFeature[] thatSfArray = that.getRnaSecondaryStructure();
+ if (thisSfArray == null || thatSfArray == null)
+ {
+ return thisSfArray == null && thatSfArray == null;
+ }
+ if (thisSfArray.length != thatSfArray.length)
+ {
+ return false;
+ }
+ Arrays.sort(thisSfArray, new SFSortByEnd()); // probably already sorted
+ // like this
+ Arrays.sort(thatSfArray, new SFSortByEnd()); // probably already sorted
+ // like this
+ for (int i=0; i < thisSfArray.length; i++) {
+ SequenceFeature thisSf = thisSfArray[i];
+ SequenceFeature thatSf = thatSfArray[i];
+ if (compareType) {
+ if (thisSf.getType() == null || thatSf.getType() == null) {
+ if (thisSf.getType() == null && thatSf.getType() == null) {
+ continue;
+ } else {
+ return false;
+ }
+ }
+ if (! thisSf.getType().equals(thatSf.getType())) {
+ return false;
+ }
+ }
+ if (!(thisSf.getBegin() == thatSf.getBegin()
+ && thisSf.getEnd() == thatSf.getEnd()))
+ {
+ return false;
+ }
+ }
+ return true;
+
+ }
+
+ /**
* map of positions in the associated annotation
*/
private Map<Integer, Annotation> sequenceMapping;
char firstChar = 0;
for (int i = 0; i < annotations.length; i++)
{
+ // DEBUG System.out.println(i + ": " + annotations[i]);
if (annotations[i] == null)
{
continue;
if (annotations[i].secondaryStructure == 'H'
|| annotations[i].secondaryStructure == 'E')
{
+ // DEBUG System.out.println( "/H|E/ '" +
+ // annotations[i].secondaryStructure + "'");
hasIcons |= true;
}
else
// Check for RNA secondary structure
{
- // System.out.println(annotations[i].secondaryStructure);
+ // DEBUG System.out.println( "/else/ '" +
+ // annotations[i].secondaryStructure + "'");
// TODO: 2.8.2 should this ss symbol validation check be a function in
// RNA/ResidueProperties ?
if (annotations[i].secondaryStructure == '('
|| annotations[i].secondaryStructure == 'B'
|| annotations[i].secondaryStructure == 'C'
|| annotations[i].secondaryStructure == 'D'
- || annotations[i].secondaryStructure == 'E'
+ // || annotations[i].secondaryStructure == 'E' // ambiguous on
+ // its own -- already checked above
|| annotations[i].secondaryStructure == 'F'
|| annotations[i].secondaryStructure == 'G'
- || annotations[i].secondaryStructure == 'H'
+ // || annotations[i].secondaryStructure == 'H' // ambiguous on
+ // its own -- already checked above
|| annotations[i].secondaryStructure == 'I'
|| annotations[i].secondaryStructure == 'J'
|| annotations[i].secondaryStructure == 'K'
// &&
// annotations[i].displayCharacter.charAt(0)==annotations[i].secondaryStructure
firstChar != ' ' && firstChar != '$' && firstChar != 0xCE
- && firstChar != '(' && firstChar != '[' && firstChar != '>'
+ && firstChar != '(' && firstChar != '[' && firstChar != '<'
&& firstChar != '{' && firstChar != 'A' && firstChar != 'B'
&& firstChar != 'C' && firstChar != 'D' && firstChar != 'E'
&& firstChar != 'F' && firstChar != 'G' && firstChar != 'H'
this.calcId = annotation.calcId;
if (annotation.properties != null)
{
- properties = new HashMap<String, String>();
+ properties = new HashMap<>();
for (Map.Entry<String, String> val : annotation.properties.entrySet())
{
properties.put(val.getKey(), val.getValue());
if (annotation.sequenceMapping != null)
{
Integer p = null;
- sequenceMapping = new HashMap<Integer, Annotation>();
+ sequenceMapping = new HashMap<>();
Iterator<Integer> pos = annotation.sequenceMapping.keySet()
.iterator();
while (pos.hasNext())
int epos = sequenceRef.findPosition(endRes);
if (sequenceMapping != null)
{
- Map<Integer, Annotation> newmapping = new HashMap<Integer, Annotation>();
+ Map<Integer, Annotation> newmapping = new HashMap<>();
Iterator<Integer> e = sequenceMapping.keySet().iterator();
while (e.hasNext())
{
{
return;
}
- sequenceMapping = new HashMap<Integer, Annotation>();
+ sequenceMapping = new HashMap<>();
int seqPos;
{
return;
}
- hidden.makeVisibleAnnotation(this);
+ makeVisibleAnnotation(hidden);
}
public void setPadGaps(boolean padgaps, char gapchar)
/**
* properties associated with the calcId
*/
- protected Map<String, String> properties = new HashMap<String, String>();
+ protected Map<String, String> properties = new HashMap<>();
/**
* base colour for line graphs. If null, will be set automatically by
: false;
// TODO build a better annotation element map and get rid of annotations[]
- Map<Integer, Annotation> mapForsq = new HashMap<Integer, Annotation>();
+ Map<Integer, Annotation> mapForsq = new HashMap<>();
if (sequenceMapping != null)
{
if (sp2sq != null)
if (mapping != null)
{
Map<Integer, Annotation> old = sequenceMapping;
- Map<Integer, Annotation> remap = new HashMap<Integer, Annotation>();
+ Map<Integer, Annotation> remap = new HashMap<>();
int index = -1;
for (int mp[] : mapping.values())
{
{
if (properties == null)
{
- properties = new HashMap<String, String>();
+ properties = new HashMap<>();
}
properties.put(property, value);
}
return graphMin < graphMax;
}
+ /**
+ * delete any columns in alignmentAnnotation that are hidden (including
+ * sequence associated annotation).
+ *
+ * @param hiddenColumns
+ * the set of hidden columns
+ */
+ public void makeVisibleAnnotation(HiddenColumns hiddenColumns)
+ {
+ if (annotations != null)
+ {
+ makeVisibleAnnotation(0, annotations.length, hiddenColumns);
+ }
+ }
+
+ /**
+ * delete any columns in alignmentAnnotation that are hidden (including
+ * sequence associated annotation).
+ *
+ * @param start
+ * remove any annotation to the right of this column
+ * @param end
+ * remove any annotation to the left of this column
+ * @param hiddenColumns
+ * the set of hidden columns
+ */
+ public void makeVisibleAnnotation(int start, int end,
+ HiddenColumns hiddenColumns)
+ {
+ if (annotations != null)
+ {
+ if (hiddenColumns.hasHiddenColumns())
+ {
+ removeHiddenAnnotation(start, end, hiddenColumns);
+ }
+ else
+ {
+ restrict(start, end);
+ }
+ }
+ }
+
+ /**
+ * The actual implementation of deleting hidden annotation columns
+ *
+ * @param start
+ * remove any annotation to the right of this column
+ * @param end
+ * remove any annotation to the left of this column
+ * @param hiddenColumns
+ * the set of hidden columns
+ */
+ private void removeHiddenAnnotation(int start, int end,
+ HiddenColumns hiddenColumns)
+ {
+ // mangle the alignmentAnnotation annotation array
+ ArrayList<Annotation[]> annels = new ArrayList<>();
+ Annotation[] els = null;
+
+ int w = 0;
+
+ Iterator<int[]> blocks = hiddenColumns.getVisContigsIterator(start,
+ end + 1, false);
+
+ int copylength;
+ int annotationLength;
+ while (blocks.hasNext())
+ {
+ int[] block = blocks.next();
+ annotationLength = block[1] - block[0] + 1;
+
+ if (blocks.hasNext())
+ {
+ // copy just the visible segment of the annotation row
+ copylength = annotationLength;
+ }
+ else
+ {
+ if (annotationLength + block[0] <= annotations.length)
+ {
+ // copy just the visible segment of the annotation row
+ copylength = annotationLength;
+ }
+ else
+ {
+ // copy to the end of the annotation row
+ copylength = annotations.length - block[0];
+ }
+ }
+
+ els = new Annotation[annotationLength];
+ annels.add(els);
+ System.arraycopy(annotations, block[0], els, 0, copylength);
+ w += annotationLength;
+ }
+
+ if (w != 0)
+ {
+ annotations = new Annotation[w];
+
+ w = 0;
+ for (Annotation[] chnk : annels)
+ {
+ System.arraycopy(chnk, 0, annotations, w, chnk.length);
+ w += chnk.length;
+ }
+ }
+ }
+
public static Iterable<AlignmentAnnotation> findAnnotations(
Iterable<AlignmentAnnotation> list, SequenceI seq, String calcId,
String label)
}
return aa;
}
+
}
*/
AlignedCodonFrame getMapping(SequenceI mapFrom, SequenceI mapTo);
+ /**
+ * Set the hidden columns collection on the alignment
+ *
+ * @param cols
+ */
public void setHiddenColumns(HiddenColumns cols);
+ /**
+ * Set the first sequence as representative and hide its insertions. Typically
+ * used when loading JPred files.
+ */
+ public void setupJPredAlignment();
+
+ /**
+ * Add gaps into the sequences aligned to profileseq under the given
+ * AlignmentView
+ *
+ * @param profileseq
+ * sequence in al which sequences are aligned to
+ * @param input
+ * alignment view where sequence corresponding to profileseq is first
+ * entry
+ * @return new HiddenColumns for new alignment view, with insertions into
+ * profileseq marked as hidden.
+ */
+ public HiddenColumns propagateInsertions(SequenceI profileseq,
+ AlignmentView input);
+
}
return ((value == 0f)
&& ((description == null) || (description.trim().length() == 0))
&& ((displayCharacter == null)
- || (displayCharacter.trim().length() == 0))
+ || (displayCharacter.trim().length() == 0)
+ || (displayCharacter.equals(" ."))) // RNA Stockholm blank
+ // displayCharacter can
+ // end up like this
&& (secondaryStructure == '\0' || (secondaryStructure == ' '))
&& colour == null);
}
*/
package jalview.datamodel;
-import java.util.List;
+import java.util.Iterator;
public class CigarArray extends CigarBase
{
SequenceGroup selectionGroup)
{
this(constructSeqCigarArray(alignment, selectionGroup));
- constructFromAlignment(alignment,
- hidden != null ? hidden.getHiddenColumnsCopy() : null,
- selectionGroup);
+ constructFromAlignment(alignment, hidden, selectionGroup);
}
private static int[] _calcStartEndBounds(AlignmentI alignment,
* @param selectionGroup
*/
private void constructFromAlignment(AlignmentI alignment,
- List<int[]> list, SequenceGroup selectionGroup)
+ HiddenColumns hidden, SequenceGroup selectionGroup)
{
int[] _startend = _calcStartEndBounds(alignment, selectionGroup);
- int start = _startend[1], end = _startend[2];
+ int start = _startend[1];
+ int end = _startend[2];
// now construct the CigarArray operations
- if (list != null)
+ if (hidden != null)
{
int[] region;
- int hideStart, hideEnd;
+ int hideStart;
+ int hideEnd;
int last = start;
- for (int j = 0; last < end & j < list.size(); j++)
+
+ Iterator<int[]> regions = hidden.getBoundedIterator(start, end);
+ while (regions.hasNext())
{
- region = list.get(j);
+ region = regions.next();
hideStart = region[0];
hideEnd = region[1];
- // edit hidden regions to selection range
-
- // just move on if hideEnd is before last
- if (hideEnd < last)
- {
- continue;
- }
- // exit if next region is after end
- if (hideStart > end)
- {
- break;
- }
// truncate region at start if last falls in region
if ((hideStart < last) && (hideEnd >= last))
addOperation(CigarArray.D, 1 + hideEnd - hideStart);
last = hideEnd + 1;
}
+
// Final match if necessary.
if (last <= end)
{
+/*
+ * 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;
public interface ContiguousI
public class DBRefEntry implements DBRefEntryI
{
- String source = "", version = "", accessionId = "";
+ /*
+ * the mapping to chromosome (genome) is held as an instance with
+ * source = speciesId
+ * version = assemblyId
+ * accessionId = "chromosome:" + chromosomeId
+ * map = mapping from sequence to reference assembly
+ */
+ public static final String CHROMOSOME = "chromosome";
+
+ String source = "";
+
+ String version = "";
+
+ String accessionId = "";
/**
* maps from associated sequence to the database sequence's coordinate system
}
return true;
}
+
+ /**
+ * Mappings to chromosome are held with accessionId as "chromosome:id"
+ *
+ * @return
+ */
+ public boolean isChromosome()
+ {
+ return accessionId != null && accessionId.startsWith(CHROMOSOME + ":");
+ }
}
* List of databases whose sequences might have coding regions annotated
*/
public static final String[] DNACODINGDBS = { EMBL, EMBLCDS, GENEDB,
- ENSEMBL };
+ ENSEMBL, ENSEMBLGENOMES };
public static final String[] CODINGDBS = { EMBLCDS, GENEDB, ENSEMBL };
public static String[] allSources()
{
- List<String> src = new ArrayList<String>();
+ List<String> src = new ArrayList<>();
for (Field f : DBRefSource.class.getFields())
{
if (String.class.equals(f.getType()))
--- /dev/null
+package jalview.datamodel;
+
+import jalview.util.MapList;
+
+/**
+ * An interface to model one or more contiguous regions on one chromosome
+ */
+public interface GeneLociI
+{
+ /**
+ * Answers the species identifier
+ *
+ * @return
+ */
+ String getSpeciesId();
+
+ /**
+ * Answers the reference assembly identifier
+ *
+ * @return
+ */
+ String getAssemblyId();
+
+ /**
+ * Answers the chromosome identifier e.g. "2", "Y", "II"
+ *
+ * @return
+ */
+ String getChromosomeId();
+
+ /**
+ * Answers the mapping from sequence to chromosome loci. For a reverse strand
+ * mapping, the chromosomal ranges will have start > end.
+ *
+ * @return
+ */
+ MapList getMap();
+}
*/
package jalview.datamodel;
-import jalview.util.Comparison;
-import jalview.util.ShiftList;
-
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.BitSet;
-import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
-import java.util.Vector;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+/**
+ * This class manages the collection of hidden columns associated with an
+ * alignment. To iterate over the collection, or over visible columns/regions,
+ * use an iterator obtained from one of:
+ *
+ * - getBoundedIterator: iterates over the hidden regions, within some bounds,
+ * returning *absolute* positions
+ *
+ * - getBoundedStartIterator: iterates over the start positions of hidden
+ * regions, within some bounds, returning *visible* positions
+ *
+ * - getVisContigsIterator: iterates over visible regions in a range, returning
+ * *absolute* positions
+ *
+ * - getVisibleColsIterator: iterates over the visible *columns*
+ *
+ * For performance reasons, provide bounds where possible. Note that column
+ * numbering begins at 0 throughout this class.
+ *
+ * @author kmourao
+ */
+
+/* Implementation notes:
+ *
+ * Methods which change the hiddenColumns collection should use a writeLock to
+ * prevent other threads accessing the hiddenColumns collection while changes
+ * are being made. They should also reset the hidden columns cursor, and either
+ * update the hidden columns count, or set it to 0 (so that it will later be
+ * updated when needed).
+ *
+ *
+ * Methods which only need read access to the hidden columns collection should
+ * use a readLock to prevent other threads changing the hidden columns
+ * collection while it is in use.
+ */
public class HiddenColumns
{
+ private static final int HASH_MULTIPLIER = 31;
+
private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();
/*
+ * Cursor which tracks the last used hidden columns region, and the number
+ * of hidden columns up to (but not including) that region.
+ */
+ private HiddenColumnsCursor cursor = new HiddenColumnsCursor();
+
+ /*
+ * cache of the number of hidden columns: must be kept up to date by methods
+ * which add or remove hidden columns
+ */
+ private int numColumns = 0;
+
+ /*
* list of hidden column [start, end] ranges; the list is maintained in
* ascending start column order
*/
- private ArrayList<int[]> hiddenColumns;
+ private List<int[]> hiddenColumns = new ArrayList<>();
/**
* Constructor
* Copy constructor
*
* @param copy
+ * the HiddenColumns object to copy from
*/
public HiddenColumns(HiddenColumns copy)
{
+ this(copy, Integer.MIN_VALUE, Integer.MAX_VALUE, 0);
+ }
+
+ /**
+ * Copy constructor within bounds and with offset. Copies hidden column
+ * regions fully contained between start and end, and offsets positions by
+ * subtracting offset.
+ *
+ * @param copy
+ * HiddenColumns instance to copy from
+ * @param start
+ * lower bound to copy from
+ * @param end
+ * upper bound to copy to
+ * @param offset
+ * offset to subtract from each region boundary position
+ *
+ */
+ public HiddenColumns(HiddenColumns copy, int start, int end, int offset)
+ {
try
{
LOCK.writeLock().lock();
if (copy != null)
{
- if (copy.hiddenColumns != null)
+ numColumns = 0;
+ Iterator<int[]> it = copy.getBoundedIterator(start, end);
+ while (it.hasNext())
+ {
+ int[] region = it.next();
+ // still need to check boundaries because iterator returns
+ // all overlapping regions and we need contained regions
+ if (region[0] >= start && region[1] <= end)
+ {
+ hiddenColumns.add(
+ new int[]
+ { region[0] - offset, region[1] - offset });
+ numColumns += region[1] - region[0] + 1;
+ }
+ }
+ cursor = new HiddenColumnsCursor(hiddenColumns);
+ }
+ } finally
+ {
+ LOCK.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Adds the specified column range to the hidden columns collection
+ *
+ * @param start
+ * start of range to add (absolute position in alignment)
+ * @param end
+ * end of range to add (absolute position in alignment)
+ */
+ public void hideColumns(int start, int end)
+ {
+ try
+ {
+ LOCK.writeLock().lock();
+
+ int previndex = 0;
+ int prevHiddenCount = 0;
+ int regionindex = 0;
+ if (!hiddenColumns.isEmpty())
+ {
+ // set up cursor reset values
+ HiddenCursorPosition cursorPos = cursor.findRegionForColumn(start, false);
+ regionindex = cursorPos.getRegionIndex();
+
+ if (regionindex > 0)
+ {
+ // get previous index and hidden count for updating the cursor later
+ previndex = regionindex - 1;
+ int[] prevRegion = hiddenColumns.get(previndex);
+ prevHiddenCount = cursorPos.getHiddenSoFar()
+ - (prevRegion[1] - prevRegion[0] + 1);
+ }
+ }
+
+ // new range follows everything else; check first to avoid looping over
+ // whole hiddenColumns collection
+ if (hiddenColumns.isEmpty()
+ || start > hiddenColumns.get(hiddenColumns.size() - 1)[1])
+ {
+ hiddenColumns.add(new int[] { start, end });
+ numColumns += end - start + 1;
+ }
+ else
+ {
+ /*
+ * traverse existing hidden ranges and insert / amend / append as
+ * appropriate
+ */
+ boolean added = false;
+ if (regionindex > 0)
+ {
+ added = insertRangeAtRegion(regionindex - 1, start, end);
+ }
+ if (!added && regionindex < hiddenColumns.size())
+ {
+ insertRangeAtRegion(regionindex, start, end);
+ }
+ }
+
+ // reset the cursor to just before our insertion point: this saves
+ // a lot of reprocessing in large alignments
+ cursor = new HiddenColumnsCursor(hiddenColumns, previndex,
+ prevHiddenCount);
+ } finally
+ {
+ LOCK.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Insert [start, range] at the region at index i in hiddenColumns, if
+ * feasible
+ *
+ * @param i
+ * index to insert at
+ * @param start
+ * start of range to insert
+ * @param end
+ * end of range to insert
+ * @return true if range was successfully inserted
+ */
+ private boolean insertRangeAtRegion(int i, int start, int end)
+ {
+ boolean added = false;
+
+ int[] region = hiddenColumns.get(i);
+ if (end < region[0] - 1)
+ {
+ /*
+ * insert discontiguous preceding range
+ */
+ hiddenColumns.add(i, new int[] { start, end });
+ numColumns += end - start + 1;
+ added = true;
+ }
+ else if (end <= region[1])
+ {
+ /*
+ * new range overlaps existing, or is contiguous preceding it - adjust
+ * start column
+ */
+ int oldstart = region[0];
+ region[0] = Math.min(region[0], start);
+ numColumns += oldstart - region[0]; // new columns are between old and
+ // adjusted starts
+ added = true;
+ }
+ else if (start <= region[1] + 1)
+ {
+ /*
+ * new range overlaps existing, or is contiguous following it - adjust
+ * start and end columns
+ */
+ insertRangeAtOverlap(i, start, end, region);
+ added = true;
+ }
+ return added;
+ }
+
+ /**
+ * Insert a range whose start position overlaps an existing region and/or is
+ * contiguous to the right of the region
+ *
+ * @param i
+ * index to insert at
+ * @param start
+ * start of range to insert
+ * @param end
+ * end of range to insert
+ * @param region
+ * the overlapped/continued region
+ */
+ private void insertRangeAtOverlap(int i, int start, int end, int[] region)
+ {
+ int oldstart = region[0];
+ int oldend = region[1];
+ region[0] = Math.min(region[0], start);
+ region[1] = Math.max(region[1], end);
+
+ numColumns += oldstart - region[0];
+
+ /*
+ * also update or remove any subsequent ranges
+ * that are overlapped
+ */
+ int endi = i;
+ while (endi < hiddenColumns.size() - 1)
+ {
+ int[] nextRegion = hiddenColumns.get(endi + 1);
+ if (nextRegion[0] > end + 1)
+ {
+ /*
+ * gap to next hidden range - no more to update
+ */
+ break;
+ }
+ numColumns -= nextRegion[1] - nextRegion[0] + 1;
+ region[1] = Math.max(nextRegion[1], end);
+ endi++;
+ }
+ numColumns += region[1] - oldend;
+ hiddenColumns.subList(i + 1, endi + 1).clear();
+ }
+
+ /**
+ * hide a list of ranges
+ *
+ * @param ranges
+ */
+ public void hideList(List<int[]> ranges)
+ {
+ try
+ {
+ LOCK.writeLock().lock();
+ for (int[] r : ranges)
+ {
+ hideColumns(r[0], r[1]);
+ }
+ cursor = new HiddenColumnsCursor(hiddenColumns);
+
+ } finally
+ {
+ LOCK.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Unhides, and adds to the selection list, all hidden columns
+ */
+ public void revealAllHiddenColumns(ColumnSelection sel)
+ {
+ try
+ {
+ LOCK.writeLock().lock();
+
+ for (int[] region : hiddenColumns)
+ {
+ for (int j = region[0]; j < region[1] + 1; j++)
{
- hiddenColumns = copy.copyHiddenRegionsToArrayList();
+ sel.addElement(j);
}
}
+ hiddenColumns.clear();
+ cursor = new HiddenColumnsCursor(hiddenColumns);
+ numColumns = 0;
+
} finally
{
LOCK.writeLock().unlock();
}
/**
- * This method is used to return all the HiddenColumn regions and is intended
- * to remain private. External callers which need a copy of the regions can
- * call getHiddenColumnsCopyAsList.
+ * Reveals, and marks as selected, the hidden column range with the given
+ * start column
*
- * @return empty list or List of hidden column intervals
+ * @param start
+ * the start column to look for
+ * @param sel
+ * the column selection to add the hidden column range to
*/
- private List<int[]> getHiddenRegions()
+ public void revealHiddenColumns(int start, ColumnSelection sel)
{
- return hiddenColumns == null ? Collections.<int[]> emptyList()
- : hiddenColumns;
+ try
+ {
+ LOCK.writeLock().lock();
+
+ if (!hiddenColumns.isEmpty())
+ {
+ int regionIndex = cursor.findRegionForColumn(start, false)
+ .getRegionIndex();
+
+ if (regionIndex != -1 && regionIndex != hiddenColumns.size())
+ {
+ // regionIndex is the region which either contains start
+ // or lies to the right of start
+ int[] region = hiddenColumns.get(regionIndex);
+ if (start == region[0])
+ {
+ for (int j = region[0]; j < region[1] + 1; j++)
+ {
+ sel.addElement(j);
+ }
+ int colsToRemove = region[1] - region[0] + 1;
+ hiddenColumns.remove(regionIndex);
+ numColumns -= colsToRemove;
+ }
+ }
+ }
+ } finally
+ {
+ LOCK.writeLock().unlock();
+ }
}
/**
{
LOCK.readLock().lock();
StringBuilder regionBuilder = new StringBuilder();
- if (hiddenColumns != null)
+
+ boolean first = true;
+ for (int[] range : hiddenColumns)
{
- for (int[] range : hiddenColumns)
+ if (!first)
+ {
+ regionBuilder.append(delimiter);
+ }
+ else
{
- regionBuilder.append(delimiter).append(range[0]).append(between)
- .append(range[1]);
+ first = false;
}
+ regionBuilder.append(range[0]).append(between).append(range[1]);
- regionBuilder.deleteCharAt(0);
}
+
return regionBuilder.toString();
} finally
{
*/
public int getSize()
{
+ return numColumns;
+ }
+
+ /**
+ * Get the number of distinct hidden regions
+ *
+ * @return number of regions
+ */
+ public int getNumberOfRegions()
+ {
try
{
LOCK.readLock().lock();
- int size = 0;
- if (hasHiddenColumns())
- {
- for (int[] range : hiddenColumns)
- {
- size += range[1] - range[0] + 1;
- }
- }
- return size;
+ return hiddenColumns.size();
} finally
{
LOCK.readLock().unlock();
/*
* check hidden columns are either both null, or match
*/
- if (this.hiddenColumns == null)
- {
- return (that.hiddenColumns == null);
- }
- if (that.hiddenColumns == null
- || that.hiddenColumns.size() != this.hiddenColumns.size())
+
+ if (that.hiddenColumns.size() != this.hiddenColumns.size())
{
return false;
}
- int i = 0;
- for (int[] thisRange : hiddenColumns)
+
+ Iterator<int[]> it = this.iterator();
+ Iterator<int[]> thatit = that.iterator();
+ while (it.hasNext())
{
- int[] thatRange = that.hiddenColumns.get(i++);
- if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
+ if (!(Arrays.equals(it.next(), thatit.next())))
{
return false;
}
}
return true;
+
} finally
{
LOCK.readLock().unlock();
* int column index in alignment view (count from zero)
* @return alignment column index for column
*/
- public int adjustForHiddenColumns(int column)
+ public int visibleToAbsoluteColumn(int column)
{
try
{
LOCK.readLock().lock();
int result = column;
- if (hiddenColumns != null)
+
+ if (!hiddenColumns.isEmpty())
{
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.get(i);
- if (result >= region[0])
- {
- result += region[1] - region[0] + 1;
- }
- }
+ result += cursor.findRegionForColumn(column, true)
+ .getHiddenSoFar();
}
+
return result;
} finally
{
/**
* Use this method to find out where a column will appear in the visible
* alignment when hidden columns exist. If the column is not visible, then the
- * left-most visible column will always be returned.
+ * index of the next visible column on the left will be returned (or 0 if
+ * there is no visible column on the left)
*
* @param hiddenColumn
* the column index in the full alignment including hidden columns
* @return the position of the column in the visible alignment
*/
- public int findColumnPosition(int hiddenColumn)
+ public int absoluteToVisibleColumn(int hiddenColumn)
{
try
{
LOCK.readLock().lock();
int result = hiddenColumn;
- if (hiddenColumns != null)
- {
- int index = 0;
- int[] region;
- do
- {
- region = hiddenColumns.get(index++);
- if (hiddenColumn > region[1])
- {
- result -= region[1] + 1 - region[0];
- }
- } while ((hiddenColumn > region[1])
- && (index < hiddenColumns.size()));
- if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
+ if (!hiddenColumns.isEmpty())
+ {
+ HiddenCursorPosition cursorPos = cursor
+ .findRegionForColumn(hiddenColumn, false);
+ int index = cursorPos.getRegionIndex();
+ int hiddenBeforeCol = cursorPos.getHiddenSoFar();
+
+ // just subtract hidden cols count - this works fine if column is
+ // visible
+ result = hiddenColumn - hiddenBeforeCol;
+
+ // now check in case column is hidden - it will be in the returned
+ // hidden region
+ if (index < hiddenColumns.size())
{
- // Here the hidden column is within a region, so
- // we want to return the position of region[0]-1, adjusted for any
- // earlier hidden columns.
- // Calculate the difference between the actual hidden col position
- // and region[0]-1, and then subtract from result to convert result
- // from
- // the adjusted hiddenColumn value to the adjusted region[0]-1 value
-
- // However, if the region begins at 0 we cannot return region[0]-1
- // just return 0
- if (region[0] == 0)
- {
- return 0;
- }
- else
+ int[] region = hiddenColumns.get(index);
+ if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
{
- return result - (hiddenColumn - region[0] + 1);
+ // actually col is hidden, return region[0]-1
+ // unless region[0]==0 in which case return 0
+ if (region[0] == 0)
+ {
+ result = 0;
+ }
+ else
+ {
+ result = region[0] - 1 - hiddenBeforeCol;
+ }
}
}
}
+
return result; // return the shifted position after removing hidden
// columns.
} finally
/**
* Find the visible column which is a given visible number of columns to the
- * left of another visible column. i.e. for a startColumn x, the column which
- * is distance 1 away will be column x-1.
+ * left (negative visibleDistance) or right (positive visibleDistance) of
+ * startColumn. If startColumn is not visible, we use the visible column at
+ * the left boundary of the hidden region containing startColumn.
*
* @param visibleDistance
- * the number of visible columns to offset by
+ * the number of visible columns to offset by (left offset = negative
+ * value; right offset = positive value)
* @param startColumn
- * the column to start from
- * @return the position of the column in the visible alignment
+ * the position of the column to start from (absolute position)
+ * @return the position of the column which is <visibleDistance> away
+ * (absolute position)
*/
- public int subtractVisibleColumns(int visibleDistance, int startColumn)
+ public int offsetByVisibleColumns(int visibleDistance, int startColumn)
{
try
{
-
LOCK.readLock().lock();
- int distance = visibleDistance;
-
- // in case startColumn is in a hidden region, move it to the left
- int start = adjustForHiddenColumns(findColumnPosition(startColumn));
-
- // get index of hidden region to left of start
- int index = getHiddenIndexLeft(start);
- if (index == -1)
- {
- // no hidden regions to left of startColumn
- return start - distance;
- }
-
- // walk backwards through the alignment subtracting the counts of visible
- // columns from distance
- int[] region;
- int gap = 0;
- int nextstart = start;
-
- while ((index > -1) && (distance - gap > 0))
- {
- // subtract the gap to right of region from distance
- distance -= gap;
- start = nextstart;
-
- // calculate the next gap
- region = hiddenColumns.get(index);
- gap = start - region[1];
-
- // set start to just to left of current region
- nextstart = region[0] - 1;
- index--;
- }
+ int start = absoluteToVisibleColumn(startColumn);
+ return visibleToAbsoluteColumn(start + visibleDistance);
- if (distance - gap > 0)
- {
- // fell out of loop because there are no more hidden regions
- distance -= gap;
- return nextstart - distance;
- }
- return start - distance;
} finally
{
LOCK.readLock().unlock();
}
-
}
/**
- * Use this method to determine the set of hiddenRegion start positions
+ * This method returns the rightmost limit of a region of an alignment with
+ * hidden columns. In otherwords, the next hidden column.
*
- * @return list of column number in visible view where hidden regions start
+ * @param alPos
+ * the absolute (visible) alignmentPosition to find the next hidden
+ * column for
+ * @return the index of the next hidden column, or alPos if there is no next
+ * hidden column
*/
- public List<Integer> findHiddenRegionPositions()
+ public int getNextHiddenBoundary(boolean left, int alPos)
{
try
{
LOCK.readLock().lock();
- List<Integer> positions = null;
-
- if (hiddenColumns != null)
+ if (!hiddenColumns.isEmpty())
{
- positions = new ArrayList<>(hiddenColumns.size());
+ int index = cursor.findRegionForColumn(alPos, false)
+ .getRegionIndex();
- positions.add(hiddenColumns.get(0)[0]);
- for (int i = 1; i < hiddenColumns.size(); ++i)
+ if (left && index > 0)
{
-
- int result = 0;
- if (hiddenColumns != null)
+ int[] region = hiddenColumns.get(index - 1);
+ return region[1];
+ }
+ else if (!left && index < hiddenColumns.size())
+ {
+ int[] region = hiddenColumns.get(index);
+ if (alPos < region[0])
{
- int index = 0;
- int gaps = 0;
- do
- {
- int[] region = hiddenColumns.get(index);
- gaps += region[1] + 1 - region[0];
- result = region[1] + 1;
- index++;
- } while (index <= i);
-
- result -= gaps;
+ return region[0];
+ }
+ else if ((alPos <= region[1])
+ && (index + 1 < hiddenColumns.size()))
+ {
+ // alPos is within a hidden region, return the next one
+ // if there is one
+ region = hiddenColumns.get(index + 1);
+ return region[0];
}
- positions.add(result);
}
}
- else
- {
- positions = new ArrayList<>();
- }
-
- return positions;
+ return alPos;
} finally
{
LOCK.readLock().unlock();
}
/**
- * This method returns the rightmost limit of a region of an alignment with
- * hidden columns. In otherwords, the next hidden column.
+ * Answers if a column in the alignment is visible
*
- * @param index
- * int
+ * @param column
+ * absolute position of column in the alignment
+ * @return true if column is visible
*/
- public int getHiddenBoundaryRight(int alPos)
+ public boolean isVisible(int column)
{
try
{
LOCK.readLock().lock();
- if (hiddenColumns != null)
+
+ if (!hiddenColumns.isEmpty())
{
- int index = 0;
- do
+ int regionindex = cursor.findRegionForColumn(column, false)
+ .getRegionIndex();
+ if (regionindex > -1 && regionindex < hiddenColumns.size())
{
- int[] region = hiddenColumns.get(index);
- if (alPos < region[0])
+ int[] region = hiddenColumns.get(regionindex);
+ // already know that column <= region[1] as cursor returns containing
+ // region or region to right
+ if (column >= region[0])
{
- return region[0];
+ return false;
}
-
- index++;
- } while (index < hiddenColumns.size());
+ }
}
+ return true;
- return alPos;
} finally
{
LOCK.readLock().unlock();
}
-
}
/**
- * This method returns the leftmost limit of a region of an alignment with
- * hidden columns. In otherwords, the previous hidden column.
*
- * @param index
- * int
+ * @return true if there are columns hidden
*/
- public int getHiddenBoundaryLeft(int alPos)
+ public boolean hasHiddenColumns()
{
try
{
LOCK.readLock().lock();
- if (hiddenColumns != null)
- {
- int index = hiddenColumns.size() - 1;
- do
- {
- int[] region = hiddenColumns.get(index);
- if (alPos > region[1])
- {
- return region[1];
- }
-
- index--;
- } while (index > -1);
- }
-
- return alPos;
+ // we don't use getSize()>0 here because it has to iterate over
+ // the full hiddenColumns collection and so will be much slower
+ return (!hiddenColumns.isEmpty());
} finally
{
LOCK.readLock().unlock();
}
/**
- * This method returns the index of the hidden region to the left of a column
- * position. If the column is in a hidden region it returns the index of the
- * region to the left. If there is no hidden region to the left it returns -1.
*
- * @param pos
- * int
+ * @return true if there is more than one hidden column region
*/
- private int getHiddenIndexLeft(int pos)
+ public boolean hasMultiHiddenColumnRegions()
{
try
{
-
LOCK.readLock().lock();
- if (hiddenColumns != null)
- {
- int index = hiddenColumns.size() - 1;
- do
- {
- int[] region = hiddenColumns.get(index);
- if (pos > region[1])
- {
- return index;
- }
-
- index--;
- } while (index > -1);
- }
-
- return -1;
+ return !hiddenColumns.isEmpty() && hiddenColumns.size() > 1;
} finally
{
LOCK.readLock().unlock();
}
-
}
+
/**
- * Adds the specified column range to the hidden columns
- *
- * @param start
- * @param end
+ * Returns a hashCode built from hidden column ranges
*/
- public void hideColumns(int start, int end)
+ @Override
+ public int hashCode()
{
- boolean wasAlreadyLocked = false;
try
{
- // check if the write lock was already locked by this thread,
- // as this method can be called internally in loops within HiddenColumns
- if (!LOCK.isWriteLockedByCurrentThread())
- {
- LOCK.writeLock().lock();
- }
- else
- {
- wasAlreadyLocked = true;
- }
-
- if (hiddenColumns == null)
- {
- hiddenColumns = new ArrayList<>();
- }
+ LOCK.readLock().lock();
+ int hashCode = 1;
- /*
- * traverse existing hidden ranges and insert / amend / append as
- * appropriate
- */
- for (int i = 0; i < hiddenColumns.size(); i++)
+ for (int[] hidden : hiddenColumns)
{
- int[] region = hiddenColumns.get(i);
-
- if (end < region[0] - 1)
- {
- /*
- * insert discontiguous preceding range
- */
- hiddenColumns.add(i, new int[] { start, end });
- return;
- }
-
- if (end <= region[1])
- {
- /*
- * new range overlaps existing, or is contiguous preceding it - adjust
- * start column
- */
- region[0] = Math.min(region[0], start);
- return;
- }
-
- if (start <= region[1] + 1)
- {
- /*
- * new range overlaps existing, or is contiguous following it - adjust
- * start and end columns
- */
- region[0] = Math.min(region[0], start);
- region[1] = Math.max(region[1], end);
-
- /*
- * also update or remove any subsequent ranges
- * that are overlapped
- */
- while (i < hiddenColumns.size() - 1)
- {
- int[] nextRegion = hiddenColumns.get(i + 1);
- if (nextRegion[0] > end + 1)
- {
- /*
- * gap to next hidden range - no more to update
- */
- break;
- }
- region[1] = Math.max(nextRegion[1], end);
- hiddenColumns.remove(i + 1);
- }
- return;
- }
+ hashCode = HASH_MULTIPLIER * hashCode + hidden[0];
+ hashCode = HASH_MULTIPLIER * hashCode + hidden[1];
}
-
- /*
- * remaining case is that the new range follows everything else
- */
- hiddenColumns.add(new int[] { start, end });
+ return hashCode;
} finally
{
- if (!wasAlreadyLocked)
- {
- LOCK.writeLock().unlock();
- }
+ LOCK.readLock().unlock();
}
}
- public boolean isVisible(int column)
+ /**
+ * Hide columns corresponding to the marked bits
+ *
+ * @param inserts
+ * - columns mapped to bits starting from zero
+ */
+ public void hideColumns(BitSet inserts)
+ {
+ hideColumns(inserts, 0, inserts.length() - 1);
+ }
+
+ /**
+ * Hide columns corresponding to the marked bits, within the range
+ * [start,end]. Entries in tohide which are outside [start,end] are ignored.
+ *
+ * @param tohide
+ * columns mapped to bits starting from zero
+ * @param start
+ * start of range to hide columns within
+ * @param end
+ * end of range to hide columns within
+ */
+ private void hideColumns(BitSet tohide, int start, int end)
{
try
{
- LOCK.readLock().lock();
-
- if (hiddenColumns != null)
+ LOCK.writeLock().lock();
+ for (int firstSet = tohide
+ .nextSetBit(start), lastSet = start; firstSet >= start
+ && lastSet <= end; firstSet = tohide
+ .nextSetBit(lastSet))
{
- for (int[] region : hiddenColumns)
+ lastSet = tohide.nextClearBit(firstSet);
+ if (lastSet <= end)
{
- if (column >= region[0] && column <= region[1])
- {
- return false;
- }
+ hideColumns(firstSet, lastSet - 1);
+ }
+ else if (firstSet <= end)
+ {
+ hideColumns(firstSet, end);
}
}
-
- return true;
+ cursor = new HiddenColumnsCursor(hiddenColumns);
} finally
{
- LOCK.readLock().unlock();
- }
- }
-
- private ArrayList<int[]> copyHiddenRegionsToArrayList()
- {
- int size = 0;
- if (hiddenColumns != null)
- {
- size = hiddenColumns.size();
- }
- ArrayList<int[]> copy = new ArrayList<>(size);
-
- for (int i = 0, j = size; i < j; i++)
- {
- int[] rh;
- int[] cp;
- rh = hiddenColumns.get(i);
- if (rh != null)
- {
- cp = new int[rh.length];
- System.arraycopy(rh, 0, cp, 0, rh.length);
- copy.add(cp);
- }
+ LOCK.writeLock().unlock();
}
-
- return copy;
}
/**
- * Returns a copy of the vector of hidden regions, as an ArrayList. Before
- * using this method please consider if you really need access to the hidden
- * regions - a new (or existing!) method on HiddenColumns might be more
- * appropriate.
+ * Hide columns corresponding to the marked bits, within the range
+ * [start,end]. Entries in tohide which are outside [start,end] are ignored.
+ * NB Existing entries in [start,end] are cleared.
*
- * @return hidden regions as an ArrayList of [start,end] pairs
+ * @param tohide
+ * columns mapped to bits starting from zero
+ * @param start
+ * start of range to hide columns within
+ * @param end
+ * end of range to hide columns within
*/
- public ArrayList<int[]> getHiddenColumnsCopy()
+ public void clearAndHideColumns(BitSet tohide, int start, int end)
{
- try
- {
- LOCK.readLock().lock();
- return copyHiddenRegionsToArrayList();
- } finally
- {
- LOCK.readLock().unlock();
- }
+ clearHiddenColumnsInRange(start, end);
+ hideColumns(tohide, start, end);
}
/**
- * propagate shift in alignment columns to column selection
+ * Make all columns in the range [start,end] visible
*
* @param start
- * beginning of edit
- * @param left
- * shift in edit (+ve for removal, or -ve for inserts)
+ * start of range to show columns
+ * @param end
+ * end of range to show columns
*/
- public List<int[]> compensateForEdit(int start, int change,
- ColumnSelection sel)
+ private void clearHiddenColumnsInRange(int start, int end)
{
try
{
LOCK.writeLock().lock();
- List<int[]> deletedHiddenColumns = null;
-
- if (hiddenColumns != null)
+
+ if (!hiddenColumns.isEmpty())
{
- deletedHiddenColumns = new ArrayList<>();
- int hSize = hiddenColumns.size();
- for (int i = 0; i < hSize; i++)
+ HiddenCursorPosition pos = cursor.findRegionForColumn(start, false);
+ int index = pos.getRegionIndex();
+
+ if (index != -1 && index != hiddenColumns.size())
{
- int[] region = hiddenColumns.get(i);
- if (region[0] > start && start + change > region[1])
+ // regionIndex is the region which either contains start
+ // or lies to the right of start
+ int[] region = hiddenColumns.get(index);
+ if (region[0] < start && region[1] >= start)
{
- deletedHiddenColumns.add(region);
-
- hiddenColumns.remove(i);
- i--;
- hSize--;
- continue;
+ // region contains start, truncate so that it ends just before start
+ numColumns -= region[1] - start + 1;
+ region[1] = start - 1;
+ index++;
}
- if (region[0] > start)
+ int endi = index;
+ while (endi < hiddenColumns.size())
{
- region[0] -= change;
- region[1] -= change;
- }
+ region = hiddenColumns.get(endi);
- if (region[0] < 0)
- {
- region[0] = 0;
+ if (region[1] > end)
+ {
+ if (region[0] <= end)
+ {
+ // region contains end, truncate so it starts just after end
+ numColumns -= end - region[0] + 1;
+ region[0] = end + 1;
+ }
+ break;
+ }
+
+ numColumns -= region[1] - region[0] + 1;
+ endi++;
}
+ hiddenColumns.subList(index, endi).clear();
}
- this.revealHiddenColumns(0, sel);
+ cursor = new HiddenColumnsCursor(hiddenColumns);
}
-
- return deletedHiddenColumns;
} finally
{
LOCK.writeLock().unlock();
}
/**
- * propagate shift in alignment columns to column selection special version of
- * compensateForEdit - allowing for edits within hidden regions
*
- * @param start
- * beginning of edit
- * @param left
- * shift in edit (+ve for removal, or -ve for inserts)
+ * @param updates
+ * BitSet where hidden columns will be marked
*/
- public void compensateForDelEdits(int start, int change)
+ protected void andNot(BitSet updates)
{
try
{
LOCK.writeLock().lock();
- if (hiddenColumns != null)
- {
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.get(i);
- if (region[0] >= start)
- {
- region[0] -= change;
- }
- if (region[1] >= start)
- {
- region[1] -= change;
- }
- if (region[1] < region[0])
- {
- hiddenColumns.remove(i--);
- }
- if (region[0] < 0)
- {
- region[0] = 0;
- }
- if (region[1] < 0)
- {
- region[1] = 0;
- }
- }
+ BitSet hiddenBitSet = new BitSet();
+ for (int[] range : hiddenColumns)
+ {
+ hiddenBitSet.set(range[0], range[1] + 1);
}
+ hiddenBitSet.andNot(updates);
+ hiddenColumns.clear();
+ hideColumns(hiddenBitSet);
} finally
{
LOCK.writeLock().unlock();
}
/**
- * return all visible segments between the given start and end boundaries
+ * Calculate the visible start and end index of an alignment.
*
- * @param start
- * (first column inclusive from 0)
- * @param end
- * (last column - not inclusive)
- * @return int[] {i_start, i_end, ..} where intervals lie in
- * start<=i_start<=i_end<end
+ * @param width
+ * full alignment width
+ * @return integer array where: int[0] = startIndex, and int[1] = endIndex
*/
- public int[] getVisibleContigs(int start, int end)
+ public int[] getVisibleStartAndEndIndex(int width)
{
try
{
LOCK.readLock().lock();
- if (hiddenColumns != null && hiddenColumns.size() > 0)
- {
- List<int[]> visiblecontigs = new ArrayList<>();
- List<int[]> regions = getHiddenRegions();
- int vstart = start;
- int[] region;
- int hideStart;
- int hideEnd;
+ int firstVisible = 0;
+ int lastVisible = width - 1;
- for (int j = 0; vstart < end && j < regions.size(); j++)
- {
- region = regions.get(j);
- hideStart = region[0];
- hideEnd = region[1];
-
- if (hideEnd < vstart)
- {
- continue;
- }
- if (hideStart > vstart)
- {
- visiblecontigs.add(new int[] { vstart, hideStart - 1 });
- }
- vstart = hideEnd + 1;
- }
+ if (!hiddenColumns.isEmpty())
+ {
+ // first visible col with index 0, convert to absolute index
+ firstVisible = visibleToAbsoluteColumn(0);
- if (vstart < end)
+ // last visible column is either immediately to left of
+ // last hidden region, or is just the last column in the alignment
+ int[] lastregion = hiddenColumns.get(hiddenColumns.size() - 1);
+ if (lastregion[1] == width - 1)
{
- visiblecontigs.add(new int[] { vstart, end - 1 });
+ // last region is at very end of alignment
+ // last visible column immediately precedes it
+ lastVisible = lastregion[0] - 1;
}
- int[] vcontigs = new int[visiblecontigs.size() * 2];
- for (int i = 0, j = visiblecontigs.size(); i < j; i++)
- {
- int[] vc = visiblecontigs.get(i);
- visiblecontigs.set(i, null);
- vcontigs[i * 2] = vc[0];
- vcontigs[i * 2 + 1] = vc[1];
- }
- visiblecontigs.clear();
- return vcontigs;
- }
- else
- {
- return new int[] { start, end - 1 };
}
+ return new int[] { firstVisible, lastVisible };
+
} finally
{
LOCK.readLock().unlock();
}
}
- public String[] getVisibleSequenceStrings(int start, int end,
- SequenceI[] seqs)
+ /**
+ * Finds the hidden region (if any) which starts or ends at res
+ *
+ * @param res
+ * visible residue position, unadjusted for hidden columns
+ * @return region as [start,end] or null if no matching region is found. If
+ * res is adjacent to two regions, returns the left region.
+ */
+ public int[] getRegionWithEdgeAtRes(int res)
{
try
{
LOCK.readLock().lock();
- int iSize = seqs.length;
- String[] selections = new String[iSize];
- if (hiddenColumns != null && hiddenColumns.size() > 0)
- {
- for (int i = 0; i < iSize; i++)
- {
- StringBuffer visibleSeq = new StringBuffer();
- List<int[]> regions = getHiddenRegions();
-
- int blockStart = start;
- int blockEnd = end;
- int[] region;
- int hideStart;
- int hideEnd;
+ int adjres = visibleToAbsoluteColumn(res);
- for (int j = 0; j < regions.size(); j++)
- {
- region = regions.get(j);
- hideStart = region[0];
- hideEnd = region[1];
-
- if (hideStart < start)
- {
- continue;
- }
-
- blockStart = Math.min(blockStart, hideEnd + 1);
- blockEnd = Math.min(blockEnd, hideStart);
-
- if (blockStart > blockEnd)
- {
- break;
- }
-
- visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
-
- blockStart = hideEnd + 1;
- blockEnd = end;
- }
-
- if (end > blockStart)
- {
- visibleSeq.append(seqs[i].getSequence(blockStart, end));
- }
+ int[] reveal = null;
- selections[i] = visibleSeq.toString();
- }
- }
- else
+ if (!hiddenColumns.isEmpty())
{
- for (int i = 0; i < iSize; i++)
+ // look for a region ending just before adjres
+ int regionindex = cursor.findRegionForColumn(adjres - 1, false)
+ .getRegionIndex();
+ if (regionindex < hiddenColumns.size()
+ && hiddenColumns.get(regionindex)[1] == adjres - 1)
+ {
+ reveal = hiddenColumns.get(regionindex);
+ }
+ // check if the region ends just after adjres
+ else if (regionindex < hiddenColumns.size()
+ && hiddenColumns.get(regionindex)[0] == adjres + 1)
{
- selections[i] = seqs[i].getSequenceAsString(start, end);
+ reveal = hiddenColumns.get(regionindex);
}
}
+ return reveal;
- return selections;
} finally
{
LOCK.readLock().unlock();
}
/**
- * Locate the first and last position visible for this sequence. if seq isn't
- * visible then return the position of the left and right of the hidden
- * boundary region, and the corresponding alignment column indices for the
- * extent of the sequence
- *
- * @param seq
- * @return int[] { visible start, visible end, first seqpos, last seqpos,
- * alignment index for seq start, alignment index for seq end }
+ * Return an iterator over the hidden regions
*/
- public int[] locateVisibleBoundsOfSequence(SequenceI seq)
+ public Iterator<int[]> iterator()
{
try
{
LOCK.readLock().lock();
- int fpos = seq.getStart();
- int lpos = seq.getEnd();
- int start = 0;
-
- if (hiddenColumns == null || hiddenColumns.size() == 0)
- {
- int ifpos = seq.findIndex(fpos) - 1;
- int ilpos = seq.findIndex(lpos) - 1;
- return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
- }
-
- // Simply walk along the sequence whilst watching for hidden column
- // boundaries
- List<int[]> regions = getHiddenRegions();
- int spos = fpos;
- int lastvispos = -1;
- int rcount = 0;
- int hideStart = seq.getLength();
- int hideEnd = -1;
- int visPrev = 0;
- int visNext = 0;
- int firstP = -1;
- int lastP = -1;
- boolean foundStart = false;
- for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
- && p < pLen; p++)
- {
- if (!Comparison.isGap(seq.getCharAt(p)))
- {
- // keep track of first/last column
- // containing sequence data regardless of visibility
- if (firstP == -1)
- {
- firstP = p;
- }
- lastP = p;
- // update hidden region start/end
- while (hideEnd < p && rcount < regions.size())
- {
- int[] region = regions.get(rcount++);
- visPrev = visNext;
- visNext += region[0] - visPrev;
- hideStart = region[0];
- hideEnd = region[1];
- }
- if (hideEnd < p)
- {
- hideStart = seq.getLength();
- }
- // update visible boundary for sequence
- if (p < hideStart)
- {
- if (!foundStart)
- {
- fpos = spos;
- start = p;
- foundStart = true;
- }
- lastvispos = p;
- lpos = spos;
- }
- // look for next sequence position
- spos++;
- }
- }
- if (foundStart)
- {
- return new int[] { findColumnPosition(start),
- findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
- }
- // otherwise, sequence was completely hidden
- return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
+ return new RangeIterator(hiddenColumns);
} finally
{
LOCK.readLock().unlock();
}
/**
- * delete any columns in alignmentAnnotation that are hidden (including
- * sequence associated annotation).
+ * Return a bounded iterator over the hidden regions
*
- * @param alignmentAnnotation
+ * @param start
+ * position to start from (inclusive, absolute column position)
+ * @param end
+ * position to end at (inclusive, absolute column position)
+ * @return
*/
- public void makeVisibleAnnotation(AlignmentAnnotation alignmentAnnotation)
+ public Iterator<int[]> getBoundedIterator(int start, int end)
{
- makeVisibleAnnotation(-1, -1, alignmentAnnotation);
+ try
+ {
+ LOCK.readLock().lock();
+ return new RangeIterator(start, end, hiddenColumns);
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
}
/**
- * delete any columns in alignmentAnnotation that are hidden (including
- * sequence associated annotation).
+ * Return a bounded iterator over the *visible* start positions of hidden
+ * regions
*
* @param start
- * remove any annotation to the right of this column
+ * position to start from (inclusive, visible column position)
* @param end
- * remove any annotation to the left of this column
- * @param alignmentAnnotation
- * the annotation to operate on
+ * position to end at (inclusive, visible column position)
*/
- public void makeVisibleAnnotation(int start, int end,
- AlignmentAnnotation alignmentAnnotation)
+ public Iterator<Integer> getStartRegionIterator(int start, int end)
{
try
{
LOCK.readLock().lock();
- if (alignmentAnnotation.annotations == null)
- {
- return;
- }
- if (start == end && end == -1)
- {
- start = 0;
- end = alignmentAnnotation.annotations.length;
- }
- if (hiddenColumns != null && hiddenColumns.size() > 0)
- {
- // then mangle the alignmentAnnotation annotation array
- Vector<Annotation[]> annels = new Vector<>();
- Annotation[] els = null;
- List<int[]> regions = getHiddenRegions();
- int blockStart = start;
- int blockEnd = end;
- int[] region;
- int hideStart;
- int hideEnd;
- int w = 0;
-
- for (int j = 0; j < regions.size(); j++)
- {
- region = regions.get(j);
- hideStart = region[0];
- hideEnd = region[1];
-
- if (hideStart < start)
- {
- continue;
- }
-
- blockStart = Math.min(blockStart, hideEnd + 1);
- blockEnd = Math.min(blockEnd, hideStart);
-
- if (blockStart > blockEnd)
- {
- break;
- }
-
- annels.addElement(els = new Annotation[blockEnd - blockStart]);
- System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
- 0, els.length);
- w += els.length;
- blockStart = hideEnd + 1;
- blockEnd = end;
- }
- if (end > blockStart)
- {
- annels.addElement(els = new Annotation[end - blockStart + 1]);
- if ((els.length
- + blockStart) <= alignmentAnnotation.annotations.length)
- {
- // copy just the visible segment of the annotation row
- System.arraycopy(alignmentAnnotation.annotations, blockStart,
- els, 0, els.length);
- }
- else
- {
- // copy to the end of the annotation row
- System.arraycopy(alignmentAnnotation.annotations, blockStart,
- els, 0,
- (alignmentAnnotation.annotations.length - blockStart));
- }
- w += els.length;
- }
- if (w == 0)
- {
- return;
- }
+ // get absolute position of column in alignment
+ int absoluteStart = visibleToAbsoluteColumn(start);
- alignmentAnnotation.annotations = new Annotation[w];
- w = 0;
+ // Get cursor position and supply it to the iterator:
+ // Since we want visible region start, we look for a cursor for the
+ // (absoluteStart-1), then if absoluteStart is the start of a visible
+ // region we'll get the cursor pointing to the region before, which is
+ // what we want
+ HiddenCursorPosition pos = cursor
+ .findRegionForColumn(absoluteStart - 1, false);
- for (Annotation[] chnk : annels)
- {
- System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
- chnk.length);
- w += chnk.length;
- }
- }
- else
- {
- alignmentAnnotation.restrict(start, end);
- }
+ return new StartRegionIterator(pos, start, end,
+ hiddenColumns);
} finally
{
LOCK.readLock().unlock();
}
/**
+ * Return an iterator over visible *columns* (not regions) between the given
+ * start and end boundaries
*
- * @return true if there are columns hidden
+ * @param start
+ * first column (inclusive)
+ * @param end
+ * last column (inclusive)
*/
- public boolean hasHiddenColumns()
+ public Iterator<Integer> getVisibleColsIterator(int start, int end)
{
try
{
LOCK.readLock().lock();
- return hiddenColumns != null && hiddenColumns.size() > 0;
+ return new RangeElementsIterator(
+ new VisibleContigsIterator(start, end + 1, hiddenColumns));
} finally
{
LOCK.readLock().unlock();
}
/**
+ * return an iterator over visible segments between the given start and end
+ * boundaries
*
- * @return true if there are more than one set of columns hidden
+ * @param start
+ * first column, inclusive from 0
+ * @param end
+ * last column - not inclusive
+ * @param useVisibleCoords
+ * if true, start and end are visible column positions, not absolute
+ * positions*
*/
- public boolean hasManyHiddenColumns()
+ public VisibleContigsIterator getVisContigsIterator(int start,
+ int end,
+ boolean useVisibleCoords)
{
+ int adjstart = start;
+ int adjend = end;
+ if (useVisibleCoords)
+ {
+ adjstart = visibleToAbsoluteColumn(start);
+ adjend = visibleToAbsoluteColumn(end);
+ }
+
try
{
LOCK.readLock().lock();
- return hiddenColumns != null && hiddenColumns.size() > 1;
+ return new VisibleContigsIterator(adjstart, adjend, hiddenColumns);
} finally
{
LOCK.readLock().unlock();
}
}
-
- /**
- * mark the columns corresponding to gap characters as hidden in the column
- * selection
- *
- * @param sr
- */
- public void hideInsertionsFor(SequenceI sr)
- {
- try
- {
- LOCK.writeLock().lock();
- List<int[]> inserts = sr.getInsertions();
- for (int[] r : inserts)
- {
- hideColumns(r[0], r[1]);
- }
- } finally
- {
- LOCK.writeLock().unlock();
- }
- }
-
- /**
- * Unhides, and adds to the selection list, all hidden columns
- */
- public void revealAllHiddenColumns(ColumnSelection sel)
- {
- try
- {
- LOCK.writeLock().lock();
- if (hiddenColumns != null)
- {
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.get(i);
- for (int j = region[0]; j < region[1] + 1; j++)
- {
- sel.addElement(j);
- }
- }
- }
-
- hiddenColumns = null;
- } finally
- {
- LOCK.writeLock().unlock();
- }
- }
-
- /**
- * Reveals, and marks as selected, the hidden column range with the given
- * start column
- *
- * @param start
- */
- public void revealHiddenColumns(int start, ColumnSelection sel)
- {
- try
- {
- LOCK.writeLock().lock();
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.get(i);
- if (start == region[0])
- {
- for (int j = region[0]; j < region[1] + 1; j++)
- {
- sel.addElement(j);
- }
-
- hiddenColumns.remove(region);
- break;
- }
- }
- if (hiddenColumns.size() == 0)
- {
- hiddenColumns = null;
- }
- } finally
- {
- LOCK.writeLock().unlock();
- }
- }
-
- /**
- * removes intersection of position,length ranges in deletions from the
- * start,end regions marked in intervals.
- *
- * @param shifts
- * @param intervals
- * @return
- */
- private boolean pruneIntervalList(final List<int[]> shifts,
- ArrayList<int[]> intervals)
- {
- boolean pruned = false;
- int i = 0;
- int j = intervals.size() - 1;
- int s = 0;
- int t = shifts.size() - 1;
- int[] hr = intervals.get(i);
- int[] sr = shifts.get(s);
- while (i <= j && s <= t)
- {
- boolean trailinghn = hr[1] >= sr[0];
- if (!trailinghn)
- {
- if (i < j)
- {
- hr = intervals.get(++i);
- }
- else
- {
- i++;
- }
- continue;
- }
- int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert
- if (endshift < hr[0] || endshift < sr[0])
- { // leadinghc disjoint or not a deletion
- if (s < t)
- {
- sr = shifts.get(++s);
- }
- else
- {
- s++;
- }
- continue;
- }
- boolean leadinghn = hr[0] >= sr[0];
- boolean leadinghc = hr[0] < endshift;
- boolean trailinghc = hr[1] < endshift;
- if (leadinghn)
- {
- if (trailinghc)
- { // deleted hidden region.
- intervals.remove(i);
- pruned = true;
- j--;
- if (i <= j)
- {
- hr = intervals.get(i);
- }
- continue;
- }
- if (leadinghc)
- {
- hr[0] = endshift; // clip c terminal region
- leadinghn = !leadinghn;
- pruned = true;
- }
- }
- if (!leadinghn)
- {
- if (trailinghc)
- {
- if (trailinghn)
- {
- hr[1] = sr[0] - 1;
- pruned = true;
- }
- }
- else
- {
- // sr contained in hr
- if (s < t)
- {
- sr = shifts.get(++s);
- }
- else
- {
- s++;
- }
- continue;
- }
- }
- }
- return pruned; // true if any interval was removed or modified by
- // operations.
- }
-
- /**
- * remove any hiddenColumns or selected columns and shift remaining based on a
- * series of position, range deletions.
- *
- * @param deletions
- */
- public void pruneDeletions(List<int[]> shifts)
- {
- try
- {
- LOCK.writeLock().lock();
- // delete any intervals intersecting.
- if (hiddenColumns != null)
- {
- pruneIntervalList(shifts, hiddenColumns);
- if (hiddenColumns != null && hiddenColumns.size() == 0)
- {
- hiddenColumns = null;
- }
- }
- } finally
- {
- LOCK.writeLock().unlock();
- }
- }
-
- /**
- * Add gaps into the sequences aligned to profileseq under the given
- * AlignmentView
- *
- * @param profileseq
- * @param al
- * - alignment to have gaps inserted into it
- * @param input
- * - alignment view where sequence corresponding to profileseq is
- * first entry
- * @return new HiddenColumns for new alignment view, with insertions into
- * profileseq marked as hidden.
- */
- public static HiddenColumns propagateInsertions(SequenceI profileseq,
- AlignmentI al, AlignmentView input)
- {
- int profsqpos = 0;
-
- char gc = al.getGapCharacter();
- Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc);
- HiddenColumns nview = (HiddenColumns) alandhidden[1];
- SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos];
- nview.propagateInsertions(profileseq, al, origseq);
- return nview;
- }
-
- /**
- *
- * @param profileseq
- * - sequence in al which corresponds to origseq
- * @param al
- * - alignment which is to have gaps inserted into it
- * @param origseq
- * - sequence corresponding to profileseq which defines gap map for
- * modifying al
- */
- private void propagateInsertions(SequenceI profileseq, AlignmentI al,
- SequenceI origseq)
- {
- char gc = al.getGapCharacter();
- // recover mapping between sequence's non-gap positions and positions
- // mapping to view.
- pruneDeletions(ShiftList.parseMap(origseq.gapMap()));
- int[] viscontigs = getVisibleContigs(0, profileseq.getLength());
- int spos = 0;
- int offset = 0;
-
- // add profile to visible contigs
- for (int v = 0; v < viscontigs.length; v += 2)
- {
- if (viscontigs[v] > spos)
- {
- StringBuffer sb = new StringBuffer();
- for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++)
- {
- sb.append(gc);
- }
- for (int s = 0, ns = al.getHeight(); s < ns; s++)
- {
- SequenceI sqobj = al.getSequenceAt(s);
- if (sqobj != profileseq)
- {
- String sq = al.getSequenceAt(s).getSequenceAsString();
- if (sq.length() <= spos + offset)
- {
- // pad sequence
- int diff = spos + offset - sq.length() - 1;
- if (diff > 0)
- {
- // pad gaps
- sq = sq + sb;
- while ((diff = spos + offset - sq.length() - 1) > 0)
- {
- // sq = sq
- // + ((diff >= sb.length()) ? sb.toString() : sb
- // .substring(0, diff));
- if (diff >= sb.length())
- {
- sq += sb.toString();
- }
- else
- {
- char[] buf = new char[diff];
- sb.getChars(0, diff, buf, 0);
- sq += buf.toString();
- }
- }
- }
- sq += sb.toString();
- }
- else
- {
- al.getSequenceAt(s).setSequence(sq.substring(0, spos + offset)
- + sb.toString() + sq.substring(spos + offset));
- }
- }
- }
- // offset+=sb.length();
- }
- spos = viscontigs[v + 1] + 1;
- }
- if ((offset + spos) < profileseq.getLength())
- {
- // pad the final region with gaps.
- StringBuffer sb = new StringBuffer();
- for (int s = 0, ns = profileseq.getLength() - spos
- - offset; s < ns; s++)
- {
- sb.append(gc);
- }
- for (int s = 0, ns = al.getHeight(); s < ns; s++)
- {
- SequenceI sqobj = al.getSequenceAt(s);
- if (sqobj == profileseq)
- {
- continue;
- }
- String sq = sqobj.getSequenceAsString();
- // pad sequence
- int diff = origseq.getLength() - sq.length();
- while (diff > 0)
- {
- // sq = sq
- // + ((diff >= sb.length()) ? sb.toString() : sb
- // .substring(0, diff));
- if (diff >= sb.length())
- {
- sq += sb.toString();
- }
- else
- {
- char[] buf = new char[diff];
- sb.getChars(0, diff, buf, 0);
- sq += buf.toString();
- }
- diff = origseq.getLength() - sq.length();
- }
- }
- }
- }
-
- /**
- * remove any hiddenColumns or selected columns and shift remaining based on a
- * series of position, range deletions.
- *
- * @param deletions
- */
- private void pruneDeletions(ShiftList deletions)
- {
- if (deletions != null)
- {
- final List<int[]> shifts = deletions.getShifts();
- if (shifts != null && shifts.size() > 0)
- {
- pruneDeletions(shifts);
-
- // and shift the rest.
- this.compensateForEdits(deletions);
- }
- }
- }
-
- /**
- * Adjust hidden column boundaries based on a series of column additions or
- * deletions in visible regions.
- *
- * @param shiftrecord
- * @return
- */
- private ShiftList compensateForEdits(ShiftList shiftrecord)
- {
- if (shiftrecord != null)
- {
- final List<int[]> shifts = shiftrecord.getShifts();
- if (shifts != null && shifts.size() > 0)
- {
- int shifted = 0;
- for (int i = 0, j = shifts.size(); i < j; i++)
- {
- int[] sh = shifts.get(i);
- compensateForDelEdits(shifted + sh[0], sh[1]);
- shifted -= sh[1];
- }
- }
- return shiftrecord.getInverse();
- }
- return null;
- }
-
- /**
- * Returns a hashCode built from hidden column ranges
- */
- @Override
- public int hashCode()
- {
- try
- {
- LOCK.readLock().lock();
- int hashCode = 1;
- if (hiddenColumns != null)
- {
- for (int[] hidden : hiddenColumns)
- {
- hashCode = 31 * hashCode + hidden[0];
- hashCode = 31 * hashCode + hidden[1];
- }
- }
- return hashCode;
- } finally
- {
- LOCK.readLock().unlock();
- }
- }
-
- /**
- * Hide columns corresponding to the marked bits
- *
- * @param inserts
- * - columns map to bits starting from zero
- */
- public void hideMarkedBits(BitSet inserts)
- {
- try
- {
- LOCK.writeLock().lock();
- for (int firstSet = inserts
- .nextSetBit(0), lastSet = 0; firstSet >= 0; firstSet = inserts
- .nextSetBit(lastSet))
- {
- lastSet = inserts.nextClearBit(firstSet);
- hideColumns(firstSet, lastSet - 1);
- }
- } finally
- {
- LOCK.writeLock().unlock();
- }
- }
-
- /**
- *
- * @param inserts
- * BitSet where hidden columns will be marked
- */
- public void markHiddenRegions(BitSet inserts)
- {
- try
- {
- LOCK.readLock().lock();
- if (hiddenColumns == null)
- {
- return;
- }
- for (int[] range : hiddenColumns)
- {
- inserts.set(range[0], range[1] + 1);
- }
- } finally
- {
- LOCK.readLock().unlock();
- }
- }
-
- /**
- * Calculate the visible start and end index of an alignment.
- *
- * @param width
- * full alignment width
- * @return integer array where: int[0] = startIndex, and int[1] = endIndex
- */
- public int[] getVisibleStartAndEndIndex(int width)
- {
- try
- {
- LOCK.readLock().lock();
- int[] alignmentStartEnd = new int[] { 0, width - 1 };
- int startPos = alignmentStartEnd[0];
- int endPos = alignmentStartEnd[1];
-
- int[] lowestRange = new int[] { -1, -1 };
- int[] higestRange = new int[] { -1, -1 };
-
- if (hiddenColumns == null)
- {
- return new int[] { startPos, endPos };
- }
-
- for (int[] hiddenCol : hiddenColumns)
- {
- lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange;
- higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange;
- }
-
- if (lowestRange[0] == -1 && lowestRange[1] == -1)
- {
- startPos = alignmentStartEnd[0];
- }
- else
- {
- startPos = lowestRange[1] + 1;
- }
-
- if (higestRange[0] == -1 && higestRange[1] == -1)
- {
- endPos = alignmentStartEnd[1];
- }
- else
- {
- endPos = higestRange[0] - 1;
- }
- return new int[] { startPos, endPos };
- } finally
- {
- LOCK.readLock().unlock();
- }
-
- }
-
- /**
- * Finds the hidden region (if any) which starts or ends at res
- *
- * @param res
- * visible residue position, unadjusted for hidden columns
- * @return region as [start,end] or null if no matching region is found
- */
- public int[] getRegionWithEdgeAtRes(int res)
- {
- try
- {
- LOCK.readLock().lock();
- int adjres = adjustForHiddenColumns(res);
-
- int[] reveal = null;
- if (hiddenColumns != null)
- {
- for (int[] region : hiddenColumns)
- {
- if (adjres + 1 == region[0] || adjres - 1 == region[1])
- {
- reveal = region;
- break;
- }
- }
- }
- return reveal;
- } finally
- {
- LOCK.readLock().unlock();
- }
- }
-
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class HiddenColumnsCursor
+{
+ // absolute position of first hidden column
+ private int firstColumn;
+
+ private List<int[]> hiddenColumns = new ArrayList<>();
+
+ private HiddenCursorPosition cursorPos = new HiddenCursorPosition(0, 0);
+
+ protected HiddenColumnsCursor()
+ {
+
+ }
+
+ protected HiddenColumnsCursor(List<int[]> hiddenCols)
+ {
+ resetCursor(hiddenCols, 0, 0);
+ }
+
+ protected HiddenColumnsCursor(List<int[]> hiddenCols, int index,
+ int hiddencount)
+ {
+ resetCursor(hiddenCols, index, hiddencount);
+ }
+
+ /**
+ * Reset the cursor with a new hidden columns collection, where we know in
+ * advance the index and hidden columns count of a particular location.
+ *
+ * @param hiddenCols
+ * new hidden columns collection
+ * @param index
+ * cursor index to reset to
+ * @param hiddencount
+ * hidden columns count to reset to
+ */
+ private void resetCursor(List<int[]> hiddenCols, int index,
+ int hiddencount)
+ {
+ hiddenColumns = hiddenCols;
+ if (!hiddenCols.isEmpty())
+ {
+ firstColumn = hiddenColumns.get(0)[0];
+ cursorPos = new HiddenCursorPosition(index,
+ hiddencount);
+ }
+ }
+
+ /**
+ * Get the cursor pointing to the hidden region that column is within (if
+ * column is hidden) or which is to the right of column (if column is
+ * visible). If no hidden columns are to the right, returns a cursor pointing
+ * to an imaginary hidden region beyond the end of the hidden columns
+ * collection (this ensures the count of previous hidden columns is correct).
+ * If hidden columns is empty returns null.
+ *
+ * @param column
+ * index of column in visible or absolute coordinates
+ * @param useVisible
+ * true if column is in visible coordinates, false if absolute
+ * @return cursor pointing to hidden region containing the column (if hidden)
+ * or to the right of the column (if visible)
+ */
+ protected HiddenCursorPosition findRegionForColumn(int column,
+ boolean useVisible)
+ {
+ if (hiddenColumns.isEmpty())
+ {
+ return null;
+ }
+
+ // used to add in hiddenColumns offset when working with visible columns
+ int offset = (useVisible ? 1 : 0);
+
+ HiddenCursorPosition pos = cursorPos;
+ int index = pos.getRegionIndex();
+ int hiddenCount = pos.getHiddenSoFar();
+
+ if (column < firstColumn)
+ {
+ pos = new HiddenCursorPosition(0, 0);
+ }
+
+ // column is after current region
+ else if ((index < hiddenColumns.size())
+ && (hiddenColumns.get(index)[0] <= column
+ + offset * hiddenCount))
+ {
+ // iterate from where we are now, if we're lucky we'll be close by
+ // (but still better than iterating from 0)
+ // stop when we find the region *before* column
+ // i.e. the next region starts after column or if not, ends after column
+ pos = searchForward(pos, column, useVisible);
+ }
+
+ // column is before current region
+ else
+ {
+ pos = searchBackward(pos, column, useVisible);
+ }
+ cursorPos = pos;
+ return pos;
+ }
+
+ /**
+ * Search forwards through the hidden columns collection to find the hidden
+ * region immediately before a column
+ *
+ * @param pos
+ * current position
+ * @param column
+ * column to locate
+ * @param useVisible
+ * whether using visible or absolute coordinates
+ * @return position of region before column
+ */
+ private HiddenCursorPosition searchForward(HiddenCursorPosition pos,
+ int column, boolean useVisible)
+ {
+ HiddenCursorPosition p = pos;
+ if (useVisible)
+ {
+ while ((p.getRegionIndex() < hiddenColumns.size())
+ && hiddenColumns.get(p.getRegionIndex())[0] <= column
+ + p.getHiddenSoFar())
+ {
+ p = stepForward(p);
+ }
+ }
+ else
+ {
+ while ((p.getRegionIndex() < hiddenColumns.size())
+ && hiddenColumns.get(p.getRegionIndex())[1] < column)
+ {
+ p = stepForward(p);
+ }
+ }
+ return p;
+ }
+
+ /**
+ * Move to the next (rightwards) hidden region after a given cursor position
+ *
+ * @param p
+ * current position of cursor
+ * @return new position of cursor at next region
+ */
+ private HiddenCursorPosition stepForward(HiddenCursorPosition p)
+ {
+ int[] region = hiddenColumns.get(p.getRegionIndex());
+
+ // increment the index, and add this region's hidden columns to the hidden
+ // column count
+ return new HiddenCursorPosition(p.getRegionIndex() + 1,
+ p.getHiddenSoFar() + region[1] - region[0] + 1);
+ }
+
+ /**
+ * Search backwards through the hidden columns collection to find the hidden
+ * region immediately before (left of) a given column
+ *
+ * @param pos
+ * current position
+ * @param column
+ * column to locate
+ * @param useVisible
+ * whether using visible or absolute coordinates
+ * @return position of region immediately to left of column
+ */
+ private HiddenCursorPosition searchBackward(HiddenCursorPosition p,
+ int column, boolean useVisible)
+ {
+ int i = p.getRegionIndex();
+ int h = p.getHiddenSoFar();
+
+ // used to add in hiddenColumns offset when working with visible columns
+ int offset = (useVisible ? 1 : 0);
+
+ while ((i > 0) && (hiddenColumns.get(i - 1)[1] >= column + offset * h))
+ {
+ i--;
+ int[] region = hiddenColumns.get(i);
+ h -= region[1] - region[0] + 1;
+ }
+ return new HiddenCursorPosition(i, h);
+ }
+
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+public final class HiddenCursorPosition
+{
+ // index of last visited region
+ private final int regionIndex;
+
+ // number of hidden columns before last visited region
+ private final int hiddenSoFar;
+
+ public HiddenCursorPosition(int index, int hiddencount)
+ {
+ regionIndex = index;
+ hiddenSoFar = hiddencount;
+ }
+
+ public int getRegionIndex()
+ {
+ return regionIndex;
+ }
+
+ public int getHiddenSoFar()
+ {
+ return hiddenSoFar;
+ }
+}
+/*
+ * 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;
/**
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Iterator over each element in a set of ranges i.e. if ranges is {[3,6],
+ * [12,15]} it will iterate over {3,4,5,6,12,13,14,15}. Uses a local copy of the
+ * set of ranges.
+ *
+ * @author kmourao
+ *
+ */
+public class RangeElementsIterator implements Iterator<Integer>
+{
+ private int last;
+
+ private int current;
+
+ private int next;
+
+ private Iterator<int[]> rangeIterator;
+
+ private int[] nextRange = null;
+
+ RangeElementsIterator(Iterator<int[]> it)
+ {
+ rangeIterator = it;
+ if (rangeIterator.hasNext())
+ {
+ nextRange = rangeIterator.next();
+ next = nextRange[0];
+ last = nextRange[1];
+ }
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return rangeIterator.hasNext() || next <= last;
+ }
+
+ @Override
+ public Integer next()
+ {
+ if (!hasNext())
+ {
+ throw new NoSuchElementException();
+ }
+
+ current = next;
+
+ // recalculate next
+ next++;
+
+ // if there are more ranges need to check if next is in a range
+ checkNextRange();
+ return current;
+ }
+
+ /**
+ * Check how next position relates to next range, and update next position if
+ * necessary
+ */
+ private void checkNextRange()
+ {
+ if (nextRange != null && next > nextRange[1])
+ {
+ if (rangeIterator.hasNext())
+ {
+ nextRange = rangeIterator.next();
+ next = nextRange[0];
+ last = nextRange[1];
+ }
+ else
+ {
+ nextRange = null;
+ }
+
+ }
+ }
+
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An iterator which iterates over a list of ranges. Works with a copy of the
+ * collection of ranges.
+ */
+public class RangeIterator implements Iterator<int[]>
+{
+ // current index in rangeList
+ private int currentPosition = 0;
+
+ // current range in rangeList
+ private int[] currentRange;
+
+ // local copy or reference to rangeList
+ private List<int[]> localRanges;
+
+ /**
+ * Unbounded constructor
+ *
+ * @param rangeList
+ * list of ranges to iterate over
+ */
+ RangeIterator(List<int[]> rangeList)
+ {
+ if (!rangeList.isEmpty())
+ {
+ int last = rangeList.get(rangeList.size() - 1)[1];
+ init(0, last, rangeList);
+ }
+ else
+ {
+ init(0, 0, rangeList);
+ }
+ }
+
+ /**
+ * Construct an iterator over rangeList bounded at [lowerBound,upperBound]
+ *
+ * @param lowerBound
+ * lower bound to iterate from
+ * @param upperBound
+ * upper bound to iterate to
+ * @param rangeList
+ * list of ranges to iterate over
+ */
+ RangeIterator(int lowerBound, int upperBound,
+ List<int[]> rangeList)
+ {
+ init(lowerBound, upperBound, rangeList);
+ }
+
+ /**
+ * Construct an iterator over rangeList bounded at [lowerBound,upperBound]
+ *
+ * @param lowerBound
+ * lower bound to iterate from
+ * @param upperBound
+ * upper bound to iterate to
+ */
+ private void init(int lowerBound, int upperBound,
+ List<int[]> rangeList)
+ {
+ int start = lowerBound;
+ int end = upperBound;
+
+ if (rangeList != null)
+ {
+ localRanges = new ArrayList<>();
+
+ // iterate until a range overlaps with [start,end]
+ int i = 0;
+ while ((i < rangeList.size()) && (rangeList.get(i)[1] < start))
+ {
+ i++;
+ }
+
+ // iterate from start to end, adding each range. Positions are
+ // absolute, and all ranges which *overlap* [start,end] are added.
+ while (i < rangeList.size() && (rangeList.get(i)[0] <= end))
+ {
+ int[] rh = rangeList.get(i);
+ int[] cp = new int[2];
+ System.arraycopy(rh, 0, cp, 0, rh.length);
+ localRanges.add(cp);
+ i++;
+ }
+ }
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return (localRanges != null) && (currentPosition < localRanges.size());
+ }
+
+ @Override
+ public int[] next()
+ {
+ currentRange = localRanges.get(currentPosition);
+ currentPosition++;
+ return currentRange;
+ }
+
+ @Override
+ public void remove()
+ {
+ localRanges.remove(--currentPosition);
+ }
+}
{
int count = 0;
BitSet mask = new BitSet();
+ int startRes = sqcol.getStartRes();
+ int endRes = sqcol.getEndRes();
+
for (SequenceI s : sqcol.getSequences())
{
- int[] cols = getResults(s, sqcol.getStartRes(), sqcol.getEndRes());
+ int[] cols = getResults(s, startRes, endRes);
if (cols != null)
{
for (int pair = 0; pair < cols.length; pair += 2)
import java.util.BitSet;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;
/**
*
- * Implements the SequenceI interface for a char[] based sequence object.
- *
- * @author $author$
- * @version $Revision$
+ * Implements the SequenceI interface for a char[] based sequence object
*/
public class Sequence extends ASequence implements SequenceI
{
{
if (pdbIds == null)
{
- pdbIds = new Vector<PDBEntry>();
+ pdbIds = new Vector<>();
pdbIds.add(entry);
return true;
}
@Override
public Vector<PDBEntry> getAllPDBEntries()
{
- return pdbIds == null ? new Vector<PDBEntry>() : pdbIds;
+ return pdbIds == null ? new Vector<>() : pdbIds;
}
/**
}
/**
- * DOCUMENT ME!
+ * Sets the sequence description, and also parses out any special formats of
+ * interest
*
* @param desc
- * DOCUMENT ME!
*/
@Override
public void setDescription(String desc)
this.description = desc;
}
+ @Override
+ public void setGeneLoci(String speciesId, String assemblyId,
+ String chromosomeId, MapList map)
+ {
+ addDBRef(new DBRefEntry(speciesId, assemblyId, DBRefEntry.CHROMOSOME
+ + ":" + chromosomeId, new Mapping(map)));
+ }
+
/**
- * DOCUMENT ME!
+ * Returns the gene loci mapping for the sequence (may be null)
*
- * @return DOCUMENT ME!
+ * @return
+ */
+ @Override
+ public GeneLociI getGeneLoci()
+ {
+ DBRefEntry[] refs = getDBRefs();
+ if (refs != null)
+ {
+ for (final DBRefEntry ref : refs)
+ {
+ if (ref.isChromosome())
+ {
+ return new GeneLociI()
+ {
+ @Override
+ public String getSpeciesId()
+ {
+ return ref.getSource();
+ }
+
+ @Override
+ public String getAssemblyId()
+ {
+ return ref.getVersion();
+ }
+
+ @Override
+ public String getChromosomeId()
+ {
+ // strip off "chromosome:" prefix to chrId
+ return ref.getAccessionId().substring(
+ DBRefEntry.CHROMOSOME.length() + 1);
+ }
+
+ @Override
+ public MapList getMap()
+ {
+ return ref.getMap().getMap();
+ }
+ };
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Answers the description
+ *
+ * @return
*/
@Override
public String getDescription()
* preserve end residue column provided cursor was valid
*/
int endColumn = isValidCursor(cursor) ? cursor.lastColumnPosition : 0;
+
if (residuePos == this.end)
{
endColumn = column;
* @param curs
* @return
*/
- protected int findIndex(int pos, SequenceCursor curs)
+ protected int findIndex(final int pos, SequenceCursor curs)
{
if (!isValidCursor(curs))
{
/*
* move left or right to find pos from hint.position
*/
- int col = curs.columnPosition - 1; // convert from base 1 to 0-based array
- // index
+ int col = curs.columnPosition - 1; // convert from base 1 to base 0
int newPos = curs.residuePosition;
int delta = newPos > pos ? -1 : 1;
while (newPos != pos)
{
col += delta; // shift one column left or right
- if (col < 0 || col == sequence.length)
+ if (col < 0)
{
break;
}
+ if (col == sequence.length)
+ {
+ col--; // return last column if we failed to reach pos
+ break;
+ }
if (!Comparison.isGap(sequence[col]))
{
newPos += delta;
}
col++; // convert back to base 1
- updateCursor(pos, col, curs.firstColumnPosition);
+
+ /*
+ * only update cursor if we found the target position
+ */
+ if (newPos == pos)
+ {
+ updateCursor(pos, col, curs.firstColumnPosition);
+ }
return col;
}
return map;
}
+ /**
+ * Build a bitset corresponding to sequence gaps
+ *
+ * @return a BitSet where set values correspond to gaps in the sequence
+ */
+ @Override
+ public BitSet gapBitset()
+ {
+ BitSet gaps = new BitSet(sequence.length);
+ int j = 0;
+ while (j < sequence.length)
+ {
+ if (jalview.util.Comparison.isGap(sequence[j]))
+ {
+ gaps.set(j);
+ }
+ j++;
+ }
+ return gaps;
+ }
+
@Override
public int[] findPositionMap()
{
@Override
public List<int[]> getInsertions()
{
- ArrayList<int[]> map = new ArrayList<int[]>();
+ ArrayList<int[]> map = new ArrayList<>();
int lastj = -1, j = 0;
int pos = start;
int seqlen = sequence.length;
boolean createNewDs = false;
// TODO: take a (second look) at the dataset creation validation method for
// the very large sequence case
+
int startIndex = findIndex(start) - 1;
int endIndex = findIndex(end) - 1;
int startDeleteColumn = -1; // for dataset sequence deletions
int deleteCount = 0;
- for (int s = i; s < j; s++)
+ for (int s = i; s < j && s < sequence.length; s++)
{
if (Comparison.isGap(sequence[s]))
{
{
if (this.annotation == null)
{
- this.annotation = new Vector<AlignmentAnnotation>();
+ this.annotation = new Vector<>();
}
if (!this.annotation.contains(annotation))
{
return null;
}
- Vector<AlignmentAnnotation> subset = new Vector<AlignmentAnnotation>();
+ Vector<AlignmentAnnotation> subset = new Vector<>();
Enumeration<AlignmentAnnotation> e = annotation.elements();
while (e.hasMoreElements())
{
public List<AlignmentAnnotation> getAlignmentAnnotations(String calcId,
String label)
{
- List<AlignmentAnnotation> result = new ArrayList<AlignmentAnnotation>();
+ List<AlignmentAnnotation> result = new ArrayList<>();
if (this.annotation != null)
{
for (AlignmentAnnotation ann : annotation)
}
synchronized (dbrefs)
{
- List<DBRefEntry> primaries = new ArrayList<DBRefEntry>();
+ List<DBRefEntry> primaries = new ArrayList<>();
DBRefEntry[] tmp = new DBRefEntry[1];
for (DBRefEntry ref : dbrefs)
{
List<SequenceFeature> result = getFeatures().findFeatures(startPos,
endPos, types);
+ if (datasetSequence != null)
+ {
+ result = datasetSequence.getFeatures().findFeatures(startPos, endPos,
+ types);
+ }
+ else
+ {
+ result = sequenceFeatureStore.findFeatures(startPos, endPos, types);
+ }
/*
* if end column is gapped, endPos may be to the right,
return count;
}
+
+ @Override
+ public String getSequenceStringFromIterator(Iterator<int[]> it)
+ {
+ StringBuilder newSequence = new StringBuilder();
+ while (it.hasNext())
+ {
+ int[] block = it.next();
+ if (it.hasNext())
+ {
+ newSequence.append(getSequence(block[0], block[1] + 1));
+ }
+ else
+ {
+ newSequence.append(getSequence(block[0], block[1]));
+ }
+ }
+
+ return newSequence.toString();
+ }
+
+ @Override
+ public int firstResidueOutsideIterator(Iterator<int[]> regions)
+ {
+ int start = 0;
+
+ if (!regions.hasNext())
+ {
+ return findIndex(getStart()) - 1;
+ }
+
+ // Simply walk along the sequence whilst watching for region
+ // boundaries
+ int hideStart = getLength();
+ int hideEnd = -1;
+ boolean foundStart = false;
+
+ // step through the non-gapped positions of the sequence
+ for (int i = getStart(); i <= getEnd() && (!foundStart); i++)
+ {
+ // get alignment position of this residue in the sequence
+ int p = findIndex(i) - 1;
+
+ // update region start/end
+ while (hideEnd < p && regions.hasNext())
+ {
+ int[] region = regions.next();
+ hideStart = region[0];
+ hideEnd = region[1];
+ }
+ if (hideEnd < p)
+ {
+ hideStart = getLength();
+ }
+ // update boundary for sequence
+ if (p < hideStart)
+ {
+ start = p;
+ foundStart = true;
+ }
+ }
+
+ if (foundStart)
+ {
+ return start;
+ }
+ // otherwise, sequence was completely hidden
+ return 0;
+ }
}
+/*
+ * 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;
/**
*/
package jalview.datamodel;
+import jalview.datamodel.features.FeatureAttributeType;
+import jalview.datamodel.features.FeatureAttributes;
import jalview.datamodel.features.FeatureLocationI;
+import jalview.datamodel.features.FeatureSourceI;
+import jalview.datamodel.features.FeatureSources;
+import jalview.util.StringUtils;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
import java.util.Vector;
/**
- * DOCUMENT ME!
- *
- * @author $author$
- * @version $Revision$
+ * A class that models a single contiguous feature on a sequence. If flag
+ * 'contactFeature' is true, the start and end positions are interpreted instead
+ * as two contact points.
*/
public class SequenceFeature implements FeatureLocationI
{
// private key for ENA location designed not to conflict with real GFF data
private static final String LOCATION = "!Location";
+ private static final String ROW_DATA = "<tr><td>%s</td><td>%s</td><td>%s</td></tr>";
+
/*
* ATTRIBUTES is reserved for the GFF 'column 9' data, formatted as
* name1=value1;name2=value2,value3;...etc
public Vector<String> links;
+ /*
+ * the identifier (if known) for the FeatureSource held in FeatureSources,
+ * as a provider of metadata about feature attributes
+ */
+ private String source;
+
/**
* Constructs a duplicate feature. Note: Uses makes a shallow copy of the
* otherDetails map, so the new and original SequenceFeature may reference the
this(newType, sf.getDescription(), newBegin, newEnd, newScore,
newGroup);
+ this.source = sf.source;
+
if (sf.otherDetails != null)
{
- otherDetails = new HashMap<String, Object>();
+ otherDetails = new HashMap<>();
for (Entry<String, Object> entry : sf.otherDetails.entrySet())
{
otherDetails.put(entry.getKey(), entry.getValue());
}
if (sf.links != null && sf.links.size() > 0)
{
- links = new Vector<String>();
+ links = new Vector<>();
for (int i = 0, iSize = sf.links.size(); i < iSize; i++)
{
links.addElement(sf.links.elementAt(i));
{
if (links == null)
{
- links = new Vector<String>();
+ links = new Vector<>();
}
if (!links.contains(labelLink))
}
/**
+ * Answers the value of the specified attribute as string, or null if no such
+ * value. If more than one attribute name is provided, tries to resolve as keys
+ * to nested maps. For example, if attribute "CSQ" holds a map of key-value
+ * pairs, then getValueAsString("CSQ", "Allele") returns the value of "Allele"
+ * in that map.
+ *
+ * @param key
+ * @return
+ */
+ public String getValueAsString(String... key)
+ {
+ if (otherDetails == null)
+ {
+ return null;
+ }
+ Object value = otherDetails.get(key[0]);
+ if (key.length > 1 && value instanceof Map<?, ?>)
+ {
+ value = ((Map) value).get(key[1]);
+ }
+ return value == null ? null : value.toString();
+ }
+
+ /**
* Returns a property value for the given key if known, else the specified
* default value
*
{
if (otherDetails == null)
{
- otherDetails = new HashMap<String, Object>();
+ otherDetails = new HashMap<>();
}
otherDetails.put(key, value);
+ recordAttribute(key, value);
+ }
+ }
+
+ /**
+ * Notifies the addition of a feature attribute. This lets us keep track of
+ * which attributes are present on each feature type, and also the range of
+ * numerical-valued attributes.
+ *
+ * @param key
+ * @param value
+ */
+ protected void recordAttribute(String key, Object value)
+ {
+ String attDesc = null;
+ if (source != null)
+ {
+ attDesc = FeatureSources.getInstance().getSource(source)
+ .getAttributeName(key);
}
+
+ FeatureAttributes.getInstance().addAttribute(this.type, attDesc, value,
+ key);
}
/*
{
return begin == 0 && end == 0;
}
+
+ /**
+ * Answers an html-formatted report of feature details
+ *
+ * @return
+ */
+ public String getDetailsReport()
+ {
+ FeatureSourceI metadata = FeatureSources.getInstance()
+ .getSource(source);
+
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("<br>");
+ sb.append("<table>");
+ sb.append(String.format(ROW_DATA, "Type", type, ""));
+ sb.append(String.format(ROW_DATA, "Start/end", begin == end ? begin
+ : begin + (isContactFeature() ? ":" : "-") + end, ""));
+ String desc = StringUtils.stripHtmlTags(description);
+ sb.append(String.format(ROW_DATA, "Description", desc, ""));
+ if (!Float.isNaN(score) && score != 0f)
+ {
+ sb.append(String.format(ROW_DATA, "Score", score, ""));
+ }
+ if (featureGroup != null)
+ {
+ sb.append(String.format(ROW_DATA, "Group", featureGroup, ""));
+ }
+
+ if (otherDetails != null)
+ {
+ TreeMap<String, Object> ordered = new TreeMap<>(
+ String.CASE_INSENSITIVE_ORDER);
+ ordered.putAll(otherDetails);
+
+ for (Entry<String, Object> entry : ordered.entrySet())
+ {
+ String key = entry.getKey();
+ if (ATTRIBUTES.equals(key))
+ {
+ continue; // to avoid double reporting
+ }
+
+ Object value = entry.getValue();
+ if (value instanceof Map<?, ?>)
+ {
+ /*
+ * expand values in a Map attribute across separate lines
+ * copy to a TreeMap for alphabetical ordering
+ */
+ Map<String, Object> values = (Map<String, Object>) value;
+ SortedMap<String, Object> sm = new TreeMap<>(
+ String.CASE_INSENSITIVE_ORDER);
+ sm.putAll(values);
+ for (Entry<?, ?> e : sm.entrySet())
+ {
+ sb.append(String.format(ROW_DATA, key, e.getKey().toString(), e
+ .getValue().toString()));
+ }
+ }
+ else
+ {
+ // tried <td title="key"> but it failed to provide a tooltip :-(
+ String attDesc = null;
+ if (metadata != null)
+ {
+ attDesc = metadata.getAttributeName(key);
+ }
+ String s = entry.getValue().toString();
+ if (isValueInteresting(key, s, metadata))
+ {
+ sb.append(String.format(ROW_DATA, key, attDesc == null ? ""
+ : attDesc, s));
+ }
+ }
+ }
+ }
+ sb.append("</table>");
+
+ String text = sb.toString();
+ return text;
+ }
+
+ /**
+ * Answers true if we judge the value is worth displaying, by some heuristic
+ * rules, else false
+ *
+ * @param key
+ * @param value
+ * @param metadata
+ * @return
+ */
+ boolean isValueInteresting(String key, String value,
+ FeatureSourceI metadata)
+ {
+ /*
+ * currently suppressing zero values as well as null or empty
+ */
+ if (value == null || "".equals(value) || ".".equals(value)
+ || "0".equals(value))
+ {
+ return false;
+ }
+
+ if (metadata == null)
+ {
+ return true;
+ }
+
+ FeatureAttributeType attType = metadata.getAttributeType(key);
+ if (attType != null
+ && (attType == FeatureAttributeType.Float || attType
+ .equals(FeatureAttributeType.Integer)))
+ {
+ try
+ {
+ float fval = Float.valueOf(value);
+ if (fval == 0f)
+ {
+ return false;
+ }
+ } catch (NumberFormatException e)
+ {
+ // ignore
+ }
+ }
+
+ return true; // default to interesting
+ }
+
+ /**
+ * Sets the feature source identifier
+ *
+ * @param theSource
+ */
+ public void setSource(String theSource)
+ {
+ source = theSource;
+ }
+}
+
+class SFSortByEnd implements Comparator<SequenceFeature>
+{
+ @Override
+ public int compare(SequenceFeature a, SequenceFeature b)
+ {
+ return a.getEnd() - b.getEnd();
+ }
+}
+
+class SFSortByBegin implements Comparator<SequenceFeature>
+{
+ @Override
+ public int compare(SequenceFeature a, SequenceFeature b)
+ {
+ return a.getBegin() - b.getBegin();
+ }
}
*/
public ResidueShaderI cs;
- // start column (base 0)
- int startRes = 0;
+ /**
+ * start column (base 0)
+ */
+ private int startRes = 0;
- // end column (base 0)
- int endRes = 0;
+ /**
+ * end column (base 0)
+ */
+ private int endRes = 0;
public Color outlineColour = Color.black;
displayBoxes = seqsel.displayBoxes;
displayText = seqsel.displayText;
colourText = seqsel.colourText;
+
startRes = seqsel.startRes;
endRes = seqsel.endRes;
cs = new ResidueShader((ResidueShader) seqsel.cs);
/**
* Set the first column selected by this group. Runs from 0<=i<N_cols
*
- * @param i
+ * @param newStart
*/
- public void setStartRes(int i)
+ public void setStartRes(int newStart)
{
int before = startRes;
- startRes = i;
- changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes);
+ startRes= Math.max(0,newStart); // sanity check for negative start column positions
+ changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes);
+
+
+
}
/**
{
if (consensus.annotations[i] != null)
{
- if (consensus.annotations[i].description.charAt(0) == '[')
+ String desc = consensus.annotations[i].description;
+ if (desc.length() > 1 && desc.charAt(0) == '[')
{
- seqs.append(consensus.annotations[i].description.charAt(1));
+ seqs.append(desc.charAt(1));
}
else
{
package jalview.datamodel;
import jalview.datamodel.features.SequenceFeaturesI;
+import jalview.util.MapList;
import java.util.BitSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Vector;
public int findPosition(int i);
/**
- * Returns the from-to sequence positions (start..) for the given column
- * positions (1..), or null if no residues are included in the range
+ * Returns the sequence positions for first and last residues lying within the
+ * given column positions [fromColum,toColumn] (where columns are numbered
+ * from 1), or null if no residues are included in the range
*
* @param fromColum
+ * - first column base 1
* @param toColumn
+ * - last column, base 1
* @return
*/
public Range findPositions(int fromColum, int toColumn);
public int[] gapMap();
/**
+ * Build a bitset corresponding to sequence gaps
+ *
+ * @return a BitSet where set values correspond to gaps in the sequence
+ */
+ public BitSet gapBitset();
+
+ /**
* Returns an int array where indices correspond to each position in sequence
* char array and the element value gives the result of findPosition for that
* index in the sequence.
* @param c2
*/
public int replace(char c1, char c2);
+
+ /**
+ * Answers the GeneLociI, or null if not known
+ *
+ * @return
+ */
+ GeneLociI getGeneLoci();
+
+ /**
+ * Sets the mapping to gene loci for the sequence
+ *
+ * @param speciesId
+ * @param assemblyId
+ * @param chromosomeId
+ * @param map
+ */
+ void setGeneLoci(String speciesId, String assemblyId,
+ String chromosomeId, MapList map);
+
+
+ /**
+ * Returns the sequence string constructed from the substrings of a sequence
+ * defined by the int[] ranges provided by an iterator. E.g. the iterator
+ * could iterate over all visible regions of the alignment
+ *
+ * @param it
+ * the iterator to use
+ * @return a String corresponding to the sequence
+ */
+ public String getSequenceStringFromIterator(Iterator<int[]> it);
+
+ /**
+ * Locate the first position in this sequence which is not contained in an
+ * iterator region. If no such position exists, return 0
+ *
+ * @param it
+ * iterator over regions
+ * @return first residue not contained in regions
+ */
+ public int firstResidueOutsideIterator(Iterator<int[]> it);
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An iterator which iterates over visible start positions of hidden column
+ * regions in a range.
+ */
+public class StartRegionIterator implements Iterator<Integer>
+{
+ // start position to iterate from
+ private int start;
+
+ // end position to iterate to
+ private int end;
+
+ // current index in hiddenColumns
+ private int currentPosition = 0;
+
+ // local copy or reference to hiddenColumns
+ private List<Integer> positions = null;
+
+ /**
+ * Construct an iterator over hiddenColums bounded at [lowerBound,upperBound]
+ *
+ * @param lowerBound
+ * lower bound to iterate from
+ * @param upperBound
+ * upper bound to iterate to
+ * @param useCopyCols
+ * whether to make a local copy of hiddenColumns for iteration (set
+ * to true if calling from outwith the HiddenColumns class)
+ */
+ StartRegionIterator(int lowerBound, int upperBound,
+ List<int[]> hiddenColumns)
+ {
+ this(null, lowerBound, upperBound, hiddenColumns);
+ }
+
+ /**
+ * Construct an iterator over hiddenColums bounded at [lowerBound,upperBound]
+ *
+ * @param pos
+ * a hidden cursor position to start from - may be null
+ * @param lowerBound
+ * lower bound to iterate from - will be ignored if pos != null
+ * @param upperBound
+ * upper bound to iterate to
+ * @param hiddenColumns
+ * the hidden columns collection to use
+ */
+ StartRegionIterator(HiddenCursorPosition pos, int lowerBound,
+ int upperBound, List<int[]> hiddenColumns)
+ {
+ start = lowerBound;
+ end = upperBound;
+
+ if (hiddenColumns != null)
+ {
+ positions = new ArrayList<>(hiddenColumns.size());
+
+ // navigate to start, keeping count of hidden columns
+ int i = 0;
+ int hiddenSoFar = 0;
+
+ if (pos != null)
+ {
+ // use the cursor position provided
+ i = pos.getRegionIndex();
+ hiddenSoFar = pos.getHiddenSoFar();
+ }
+ else
+ {
+ // navigate to start
+ while ((i < hiddenColumns.size())
+ && (hiddenColumns.get(i)[0] < start + hiddenSoFar))
+ {
+ int[] region = hiddenColumns.get(i);
+ hiddenSoFar += region[1] - region[0] + 1;
+ i++;
+ }
+ }
+
+ // iterate from start to end, adding start positions of each
+ // hidden region. Positions are visible columns count, not absolute
+ while (i < hiddenColumns.size()
+ && (hiddenColumns.get(i)[0] <= end + hiddenSoFar))
+ {
+ int[] region = hiddenColumns.get(i);
+ positions.add(region[0] - hiddenSoFar);
+ hiddenSoFar += region[1] - region[0] + 1;
+ i++;
+ }
+ }
+ else
+ {
+ positions = new ArrayList<>();
+ }
+
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return (currentPosition < positions.size());
+ }
+
+ /**
+ * Get next hidden region start position
+ *
+ * @return the start position in *visible* coordinates
+ */
+ @Override
+ public Integer next()
+ {
+ int result = positions.get(currentPosition);
+ currentPosition++;
+ return result;
+ }
+}
+
HiddenColumns hidden;
- public VisibleColsCollection(int s, int e, AlignmentI al)
+ public VisibleColsCollection(int s, int e, HiddenColumns h)
{
start = s;
end = e;
- hidden = al.getHiddenColumns();
+ hidden = h;
}
@Override
public Iterator<Integer> iterator()
{
- return new VisibleColsIterator(start, end, hidden);
+ return hidden.getVisibleColsIterator(start, end);
}
@Override
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.datamodel;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-/**
- * An iterator which iterates over all visible columns in an alignment
- *
- * @author kmourao
- *
- */
-public class VisibleColsIterator implements Iterator<Integer>
-{
- private int last;
-
- private int current;
-
- private int next;
-
- private List<int[]> hidden;
-
- private int lasthiddenregion;
-
- public VisibleColsIterator(int firstcol, int lastcol,
- HiddenColumns hiddenCols)
- {
- last = lastcol;
- current = firstcol;
- next = firstcol;
- hidden = hiddenCols.getHiddenColumnsCopy();
- lasthiddenregion = -1;
-
- if (hidden != null)
- {
- int i = 0;
- for (i = 0; i < hidden.size(); ++i)
- {
- if (current >= hidden.get(i)[0] && current <= hidden.get(i)[1])
- {
- // current is hidden, move to right
- current = hidden.get(i)[1] + 1;
- next = current;
- }
- if (current < hidden.get(i)[0])
- {
- break;
- }
- }
- lasthiddenregion = i - 1;
-
- for (i = hidden.size() - 1; i >= 0; --i)
- {
- if (last >= hidden.get(i)[0] && last <= hidden.get(i)[1])
- {
- // last is hidden, move to left
- last = hidden.get(i)[0] - 1;
- }
- if (last > hidden.get(i)[1])
- {
- break;
- }
- }
- }
- }
-
- @Override
- public boolean hasNext()
- {
- return next <= last;
- }
-
- @Override
- public Integer next()
- {
- if (next > last)
- {
- throw new NoSuchElementException();
- }
- current = next;
- if ((hidden != null) && (lasthiddenregion + 1 < hidden.size()))
- {
- // still some more hidden regions
- if (next + 1 < hidden.get(lasthiddenregion + 1)[0])
- {
- // next+1 is still before the next hidden region
- next++;
- }
- else if ((next + 1 >= hidden.get(lasthiddenregion + 1)[0])
- && (next + 1 <= hidden.get(lasthiddenregion + 1)[1]))
- {
- // next + 1 is in the next hidden region
- next = hidden.get(lasthiddenregion + 1)[1] + 1;
- lasthiddenregion++;
- }
- }
- else
- {
- // finished with hidden regions, just increment normally
- next++;
- }
- return current;
- }
-
- @Override
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
-}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An iterator which iterates over visible regions in a range. Provides a
+ * special "endsAtHidden" indicator to allow callers to determine if the final
+ * visible column is adjacent to a hidden region.
+ */
+public class VisibleContigsIterator implements Iterator<int[]>
+{
+ private List<int[]> vcontigs = new ArrayList<>();
+
+ private int currentPosition = 0;
+
+ private boolean endsAtHidden = false;
+
+ VisibleContigsIterator(int start, int end,
+ List<int[]> hiddenColumns)
+ {
+ if (hiddenColumns != null && hiddenColumns.size() > 0)
+ {
+ int vstart = start;
+ int hideStart;
+ int hideEnd;
+
+ for (int[] region : hiddenColumns)
+ {
+ endsAtHidden = false;
+ hideStart = region[0];
+ hideEnd = region[1];
+
+ // navigate to start
+ if (hideEnd < vstart)
+ {
+ continue;
+ }
+ if (hideStart > vstart)
+ {
+ if (end - 1 > hideStart - 1)
+ {
+ int[] contig = new int[] { vstart, hideStart - 1 };
+ vcontigs.add(contig);
+ endsAtHidden = true;
+ }
+ else
+ {
+ int[] contig = new int[] { vstart, end - 1 };
+ vcontigs.add(contig);
+ }
+ }
+ vstart = hideEnd + 1;
+
+ // exit if we're past the end
+ if (vstart >= end)
+ {
+ break;
+ }
+ }
+
+ if (vstart < end)
+ {
+ int[] contig = new int[] { vstart, end - 1 };
+ vcontigs.add(contig);
+ endsAtHidden = false;
+ }
+ }
+ else
+ {
+ int[] contig = new int[] { start, end - 1 };
+ vcontigs.add(contig);
+ }
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return (currentPosition < vcontigs.size());
+ }
+
+ @Override
+ public int[] next()
+ {
+ int[] result = vcontigs.get(currentPosition);
+ currentPosition++;
+ return result;
+ }
+
+ public boolean endsAtHidden()
+ {
+ return endsAtHidden;
+ }
+}
+
--- /dev/null
+package jalview.datamodel.features;
+
+/**
+ * A class to model the datatype of feature attributes.
+ *
+ * @author gmcarstairs
+ *
+ */
+public enum FeatureAttributeType
+{
+ String, Integer, Float, Character, Flag;
+}
--- /dev/null
+package jalview.datamodel.features;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/**
+ * A singleton class to hold the set of attributes known for each feature type
+ */
+public class FeatureAttributes
+{
+ public enum Datatype
+ {
+ Character, Number, Mixed
+ }
+
+ private static FeatureAttributes instance = new FeatureAttributes();
+
+ /*
+ * map, by feature type, of a map, by attribute name, of
+ * attribute description and min-max range (if known)
+ */
+ private Map<String, Map<String[], AttributeData>> attributes;
+
+ /*
+ * a case-insensitive comparator so that attributes are ordered e.g.
+ * AC
+ * af
+ * CSQ:AFR_MAF
+ * CSQ:Allele
+ */
+ private Comparator<String[]> comparator = new Comparator<String[]>()
+ {
+ @Override
+ public int compare(String[] o1, String[] o2)
+ {
+ int i = 0;
+ while (i < o1.length || i < o2.length)
+ {
+ if (o2.length <= i)
+ {
+ return o1.length <= i ? 0 : 1;
+ }
+ if (o1.length <= i)
+ {
+ return -1;
+ }
+ int comp = String.CASE_INSENSITIVE_ORDER.compare(o1[i], o2[i]);
+ if (comp != 0)
+ {
+ return comp;
+ }
+ i++;
+ }
+ return 0; // same length and all matched
+ }
+ };
+
+ private class AttributeData
+ {
+ /*
+ * description(s) for this attribute, if known
+ * (different feature source might have differing descriptions)
+ */
+ List<String> description;
+
+ /*
+ * minimum value (of any numeric values recorded)
+ */
+ float min = 0f;
+
+ /*
+ * maximum value (of any numeric values recorded)
+ */
+ float max = 0f;
+
+ /*
+ * flag is set true if any numeric value is detected for this attribute
+ */
+ boolean hasValue = false;
+
+ Datatype type;
+
+ /**
+ * Note one instance of this attribute, recording unique, non-null
+ * descriptions, and the min/max of any numerical values
+ *
+ * @param desc
+ * @param value
+ */
+ void addInstance(String desc, String value)
+ {
+ addDescription(desc);
+
+ if (value != null)
+ {
+ value = value.trim();
+
+ /*
+ * Parse numeric value unless we have previously
+ * seen text data for this attribute type
+ */
+ if (type == null || type == Datatype.Number)
+ {
+ try
+ {
+ float f = Float.valueOf(value);
+ min = hasValue ? Float.min(min, f) : f;
+ max = hasValue ? Float.max(max, f) : f;
+ hasValue = true;
+ type = (type == null || type == Datatype.Number)
+ ? Datatype.Number
+ : Datatype.Mixed;
+ } catch (NumberFormatException e)
+ {
+ /*
+ * non-numeric data: treat attribute as Character (or Mixed)
+ */
+ type = (type == null || type == Datatype.Character)
+ ? Datatype.Character
+ : Datatype.Mixed;
+ min = 0f;
+ max = 0f;
+ hasValue = false;
+ }
+ }
+ }
+ }
+
+ /**
+ * Answers the description of the attribute, if recorded and unique, or null if either no, or more than description is recorded
+ * @return
+ */
+ public String getDescription()
+ {
+ if (description != null && description.size() == 1)
+ {
+ return description.get(0);
+ }
+ return null;
+ }
+
+ public Datatype getType()
+ {
+ return type;
+ }
+
+ /**
+ * Adds the given description to the list of known descriptions (without
+ * duplication)
+ *
+ * @param desc
+ */
+ public void addDescription(String desc)
+ {
+ if (desc != null)
+ {
+ if (description == null)
+ {
+ description = new ArrayList<>();
+ }
+ if (!description.contains(desc))
+ {
+ description.add(desc);
+ }
+ }
+ }
+ }
+
+ /**
+ * Answers the singleton instance of this class
+ *
+ * @return
+ */
+ public static FeatureAttributes getInstance()
+ {
+ return instance;
+ }
+
+ private FeatureAttributes()
+ {
+ attributes = new HashMap<>();
+ }
+
+ /**
+ * Answers the attribute names known for the given feature type, in
+ * alphabetical order (not case sensitive), or an empty set if no attributes
+ * are known. An attribute name is typically 'simple' e.g. "AC", but may be
+ * 'compound' e.g. {"CSQ", "Allele"} where a feature has map-valued attributes
+ *
+ * @param featureType
+ * @return
+ */
+ public List<String[]> getAttributes(String featureType)
+ {
+ if (!attributes.containsKey(featureType))
+ {
+ return Collections.<String[]> emptyList();
+ }
+
+ return new ArrayList<>(attributes.get(featureType).keySet());
+ }
+
+ /**
+ * Answers true if at least one attribute is known for the given feature type,
+ * else false
+ *
+ * @param featureType
+ * @return
+ */
+ public boolean hasAttributes(String featureType)
+ {
+ if (attributes.containsKey(featureType))
+ {
+ if (!attributes.get(featureType).isEmpty())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Records the given attribute name and description for the given feature
+ * type, and updates the min-max for any numeric value
+ *
+ * @param featureType
+ * @param description
+ * @param value
+ * @param attName
+ */
+ public void addAttribute(String featureType, String description,
+ Object value, String... attName)
+ {
+ if (featureType == null || attName == null)
+ {
+ return;
+ }
+
+ /*
+ * if attribute value is a map, drill down one more level to
+ * record its sub-fields
+ */
+ if (value instanceof Map<?, ?>)
+ {
+ for (Entry<?, ?> entry : ((Map<?, ?>) value).entrySet())
+ {
+ String[] attNames = new String[attName.length + 1];
+ System.arraycopy(attName, 0, attNames, 0, attName.length);
+ attNames[attName.length] = entry.getKey().toString();
+ addAttribute(featureType, description, entry.getValue(), attNames);
+ }
+ return;
+ }
+
+ String valueAsString = value.toString();
+ Map<String[], AttributeData> atts = attributes.get(featureType);
+ if (atts == null)
+ {
+ atts = new TreeMap<>(comparator);
+ attributes.put(featureType, atts);
+ }
+ AttributeData attData = atts.get(attName);
+ if (attData == null)
+ {
+ attData = new AttributeData();
+ atts.put(attName, attData);
+ }
+ attData.addInstance(description, valueAsString);
+ }
+
+ /**
+ * Answers the description of the given attribute for the given feature type,
+ * if known and unique, else null
+ *
+ * @param featureType
+ * @param attName
+ * @return
+ */
+ public String getDescription(String featureType, String... attName)
+ {
+ String desc = null;
+ Map<String[], AttributeData> atts = attributes.get(featureType);
+ if (atts != null)
+ {
+ AttributeData attData = atts.get(attName);
+ if (attData != null)
+ {
+ desc = attData.getDescription();
+ }
+ }
+ return desc;
+ }
+
+ /**
+ * Answers the [min, max] value range of the given attribute for the given
+ * feature type, if known, else null. Attributes with a mixture of text and
+ * numeric values are considered text (do not return a min-max range).
+ *
+ * @param featureType
+ * @param attName
+ * @return
+ */
+ public float[] getMinMax(String featureType, String... attName)
+ {
+ Map<String[], AttributeData> atts = attributes.get(featureType);
+ if (atts != null)
+ {
+ AttributeData attData = atts.get(attName);
+ if (attData != null && attData.hasValue)
+ {
+ return new float[] { attData.min, attData.max };
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Records the given attribute description for the given feature type
+ *
+ * @param featureType
+ * @param attName
+ * @param description
+ */
+ public void addDescription(String featureType, String description,
+ String... attName)
+ {
+ if (featureType == null || attName == null)
+ {
+ return;
+ }
+
+ Map<String[], AttributeData> atts = attributes.get(featureType);
+ if (atts == null)
+ {
+ atts = new TreeMap<>(comparator);
+ attributes.put(featureType, atts);
+ }
+ AttributeData attData = atts.get(attName);
+ if (attData == null)
+ {
+ attData = new AttributeData();
+ atts.put(attName, attData);
+ }
+ attData.addDescription(description);
+ }
+
+ /**
+ * Answers the datatype of the feature, which is one of Character, Number or
+ * Mixed (or null if not known), as discovered from values recorded.
+ *
+ * @param featureType
+ * @param attName
+ * @return
+ */
+ public Datatype getDatatype(String featureType, String... attName)
+ {
+ Map<String[], AttributeData> atts = attributes.get(featureType);
+ if (atts != null)
+ {
+ AttributeData attData = atts.get(attName);
+ if (attData != null)
+ {
+ return attData.getType();
+ }
+ }
+ return null;
+ }
+}
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
package jalview.datamodel.features;
import jalview.datamodel.ContiguousI;
--- /dev/null
+package jalview.datamodel.features;
+
+import jalview.datamodel.SequenceFeature;
+import jalview.util.MessageManager;
+import jalview.util.matcher.Condition;
+import jalview.util.matcher.Matcher;
+import jalview.util.matcher.MatcherI;
+
+/**
+ * An immutable class that models one or more match conditions, each of which is
+ * applied to the value obtained by lookup given the match key.
+ * <p>
+ * For example, the value provider could be a SequenceFeature's attributes map,
+ * and the conditions might be
+ * <ul>
+ * <li>CSQ contains "pathological"</li>
+ * <li>AND</li>
+ * <li>AF <= 1.0e-5</li>
+ * </ul>
+ *
+ * @author gmcarstairs
+ *
+ */
+public class FeatureMatcher implements FeatureMatcherI
+{
+ private static final String SCORE = "Score";
+
+ private static final String LABEL = "Label";
+
+ private static final String SPACE = " ";
+
+ private static final String QUOTE = "'";
+
+ /*
+ * a dummy matcher that comes in useful for the 'add a filter' gui row
+ */
+ public static final FeatureMatcherI NULL_MATCHER = FeatureMatcher
+ .byLabel(Condition.values()[0], "");
+
+ private static final String COLON = ":";
+
+ /*
+ * if true, match is against feature description
+ */
+ final private boolean byLabel;
+
+ /*
+ * if true, match is against feature score
+ */
+ final private boolean byScore;
+
+ /*
+ * if not null, match is against feature attribute [sub-attribute]
+ */
+ final private String[] key;
+
+ final private MatcherI matcher;
+
+ /**
+ * A helper method that converts a 'compound' attribute name from its display
+ * form, e.g. CSQ:PolyPhen to array form, e.g. { "CSQ", "PolyPhen" }
+ *
+ * @param attribute
+ * @return
+ */
+ public static String[] fromAttributeDisplayName(String attribute)
+ {
+ return attribute == null ? null : attribute.split(COLON);
+ }
+
+ /**
+ * A helper method that converts a 'compound' attribute name to its display
+ * form, e.g. CSQ:PolyPhen from its array form, e.g. { "CSQ", "PolyPhen" }
+ *
+ * @param attName
+ * @return
+ */
+ public static String toAttributeDisplayName(String[] attName)
+ {
+ return attName == null ? "" : String.join(COLON, attName);
+ }
+
+ /**
+ * A factory constructor that converts a stringified object (as output by
+ * toStableString) to an object instance. Returns null if parsing fails.
+ * <p>
+ * Leniency in parsing (for manually created feature files):
+ * <ul>
+ * <li>keywords Score and Label, and the condition, are not
+ * case-sensitive</li>
+ * <li>quotes around value and pattern are optional if string does not include
+ * a space</li>
+ * </ul>
+ *
+ * @param descriptor
+ * @return
+ */
+ public static FeatureMatcher fromString(final String descriptor)
+ {
+ String invalidFormat = "Invalid matcher format: " + descriptor;
+
+ /*
+ * expect
+ * value condition pattern
+ * where value is Label or Space or attributeName or attName1:attName2
+ * and pattern is a float value as string, or a text string
+ * attribute names or patterns may be quoted (must be if include space)
+ */
+ String attName = null;
+ boolean byScore = false;
+ boolean byLabel = false;
+ Condition cond = null;
+ String pattern = null;
+
+ /*
+ * parse first field (Label / Score / attribute)
+ * optionally in quotes (required if attName includes space)
+ */
+ String leftToParse = descriptor;
+ String firstField = null;
+
+ if (descriptor.startsWith(QUOTE))
+ {
+ // 'Label' / 'Score' / 'attName'
+ int nextQuotePos = descriptor.indexOf(QUOTE, 1);
+ if (nextQuotePos == -1)
+ {
+ System.err.println(invalidFormat);
+ return null;
+ }
+ firstField = descriptor.substring(1, nextQuotePos);
+ leftToParse = descriptor.substring(nextQuotePos + 1).trim();
+ }
+ else
+ {
+ // Label / Score / attName (unquoted)
+ int nextSpacePos = descriptor.indexOf(SPACE);
+ if (nextSpacePos == -1)
+ {
+ System.err.println(invalidFormat);
+ return null;
+ }
+ firstField = descriptor.substring(0, nextSpacePos);
+ leftToParse = descriptor.substring(nextSpacePos + 1).trim();
+ }
+ String lower = firstField.toLowerCase();
+ if (lower.startsWith(LABEL.toLowerCase()))
+ {
+ byLabel = true;
+ }
+ else if (lower.startsWith(SCORE.toLowerCase()))
+ {
+ byScore = true;
+ }
+ else
+ {
+ attName = firstField;
+ }
+
+ /*
+ * next field is the comparison condition
+ * most conditions require a following pattern (optionally quoted)
+ * although some conditions e.g. Present do not
+ */
+ int nextSpacePos = leftToParse.indexOf(SPACE);
+ if (nextSpacePos == -1)
+ {
+ /*
+ * no value following condition - only valid for some conditions
+ */
+ cond = Condition.fromString(leftToParse);
+ if (cond == null || cond.needsAPattern())
+ {
+ System.err.println(invalidFormat);
+ return null;
+ }
+ }
+ else
+ {
+ /*
+ * condition and pattern
+ */
+ cond = Condition.fromString(leftToParse.substring(0, nextSpacePos));
+ leftToParse = leftToParse.substring(nextSpacePos + 1).trim();
+ if (leftToParse.startsWith(QUOTE))
+ {
+ // pattern in quotes
+ if (leftToParse.endsWith(QUOTE))
+ {
+ pattern = leftToParse.substring(1, leftToParse.length() - 1);
+ }
+ else
+ {
+ // unbalanced quote
+ System.err.println(invalidFormat);
+ return null;
+ }
+ }
+ else
+ {
+ // unquoted pattern
+ pattern = leftToParse;
+ }
+ }
+
+ /*
+ * we have parsed out value, condition and pattern
+ * so can now make the FeatureMatcher
+ */
+ try
+ {
+ if (byLabel)
+ {
+ return FeatureMatcher.byLabel(cond, pattern);
+ }
+ else if (byScore)
+ {
+ return FeatureMatcher.byScore(cond, pattern);
+ }
+ else
+ {
+ String[] attNames = FeatureMatcher
+ .fromAttributeDisplayName(attName);
+ return FeatureMatcher.byAttribute(cond, pattern, attNames);
+ }
+ } catch (NumberFormatException e)
+ {
+ // numeric condition with non-numeric pattern
+ return null;
+ }
+ }
+
+ /**
+ * A factory constructor method for a matcher that applies its match condition
+ * to the feature label (description)
+ *
+ * @param cond
+ * @param pattern
+ * @return
+ * @throws NumberFormatException
+ * if an invalid numeric pattern is supplied
+ */
+ public static FeatureMatcher byLabel(Condition cond, String pattern)
+ {
+ return new FeatureMatcher(new Matcher(cond, pattern), true, false,
+ null);
+ }
+
+ /**
+ * A factory constructor method for a matcher that applies its match condition
+ * to the feature score
+ *
+ * @param cond
+ * @param pattern
+ * @return
+ * @throws NumberFormatException
+ * if an invalid numeric pattern is supplied
+ */
+ public static FeatureMatcher byScore(Condition cond, String pattern)
+ {
+ return new FeatureMatcher(new Matcher(cond, pattern), false, true,
+ null);
+ }
+
+ /**
+ * A factory constructor method for a matcher that applies its match condition
+ * to the named feature attribute [and optional sub-attribute]
+ *
+ * @param cond
+ * @param pattern
+ * @param attName
+ * @return
+ * @throws NumberFormatException
+ * if an invalid numeric pattern is supplied
+ */
+ public static FeatureMatcher byAttribute(Condition cond, String pattern,
+ String... attName)
+ {
+ return new FeatureMatcher(new Matcher(cond, pattern), false, false,
+ attName);
+ }
+
+ private FeatureMatcher(Matcher m, boolean forLabel, boolean forScore,
+ String[] theKey)
+ {
+ key = theKey;
+ matcher = m;
+ byLabel = forLabel;
+ byScore = forScore;
+ }
+ @Override
+ public boolean matches(SequenceFeature feature)
+ {
+ String value = byLabel ? feature.getDescription()
+ : (byScore ? String.valueOf(feature.getScore())
+ : feature.getValueAsString(key));
+ return matcher.matches(value);
+ }
+
+ @Override
+ public String[] getAttribute()
+ {
+ return key;
+ }
+
+ @Override
+ public MatcherI getMatcher()
+ {
+ return matcher;
+ }
+
+ /**
+ * Answers a string description of this matcher, suitable for display, debugging
+ * or logging. The format may change in future.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ if (byLabel)
+ {
+ sb.append(MessageManager.getString("label.label"));
+ }
+ else if (byScore)
+ {
+ sb.append(MessageManager.getString("label.score"));
+ }
+ else
+ {
+ sb.append(String.join(COLON, key));
+ }
+
+ Condition condition = matcher.getCondition();
+ sb.append(SPACE).append(condition.toString().toLowerCase());
+ if (condition.isNumeric())
+ {
+ sb.append(SPACE).append(matcher.getPattern());
+ }
+ else if (condition.needsAPattern())
+ {
+ sb.append(" '").append(matcher.getPattern()).append(QUOTE);
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public boolean isByLabel()
+ {
+ return byLabel;
+ }
+
+ @Override
+ public boolean isByScore()
+ {
+ return byScore;
+ }
+
+ @Override
+ public boolean isByAttribute()
+ {
+ return getAttribute() != null;
+ }
+
+ /**
+ * {@inheritDoc} The output of this method should be parseable by method
+ * <code>fromString<code> to restore the original object.
+ */
+ @Override
+ public String toStableString()
+ {
+ StringBuilder sb = new StringBuilder();
+ if (byLabel)
+ {
+ sb.append(LABEL); // no i18n here unlike toString() !
+ }
+ else if (byScore)
+ {
+ sb.append(SCORE);
+ }
+ else
+ {
+ /*
+ * enclose attribute name in quotes if it includes space
+ */
+ String displayName = toAttributeDisplayName(key);
+ if (displayName.contains(SPACE))
+ {
+ sb.append(QUOTE).append(displayName).append(QUOTE);
+ }
+ else
+ {
+ sb.append(displayName);
+ }
+ }
+
+ Condition condition = matcher.getCondition();
+ sb.append(SPACE).append(condition.getStableName());
+ String pattern = matcher.getPattern();
+ if (condition.needsAPattern())
+ {
+ /*
+ * enclose pattern in quotes if it includes space
+ */
+ if (pattern.contains(SPACE))
+ {
+ sb.append(SPACE).append(QUOTE).append(pattern).append(QUOTE);
+ }
+ else
+ {
+ sb.append(SPACE).append(pattern);
+ }
+ }
+
+ return sb.toString();
+ }
+}
--- /dev/null
+package jalview.datamodel.features;
+
+import jalview.datamodel.SequenceFeature;
+import jalview.util.matcher.MatcherI;
+
+/**
+ * An interface for an object that can apply a match condition to a
+ * SequenceFeature object
+ *
+ * @author gmcarstairs
+ */
+public interface FeatureMatcherI
+{
+ /**
+ * Answers true if the value provided for this matcher's key passes this
+ * matcher's match condition
+ *
+ * @param feature
+ * @return
+ */
+ boolean matches(SequenceFeature feature);
+
+ /**
+ * Answers the attribute key this matcher operates on (or null if match is by
+ * Label or Score)
+ *
+ * @return
+ */
+ String[] getAttribute();
+
+ /**
+ * Answers true if match is against feature label (description), else false
+ *
+ * @return
+ */
+ boolean isByLabel();
+
+ /**
+ * Answers true if match is against feature score, else false
+ *
+ * @return
+ */
+ boolean isByScore();
+
+ /**
+ * Answers true if match is against a feature attribute (text or range)
+ *
+ * @return
+ */
+ boolean isByAttribute();
+
+ /**
+ * Answers the match condition that is applied
+ *
+ * @return
+ */
+ MatcherI getMatcher();
+
+ /**
+ * Answers a string representation of this object suitable for use when
+ * persisting data, in a format that can be reliably read back. Any changes to
+ * the format should be backwards compatible.
+ */
+ String toStableString();
+}
--- /dev/null
+package jalview.datamodel.features;
+
+import jalview.datamodel.SequenceFeature;
+import jalview.util.MessageManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class that models one or more match conditions, which may be combined with
+ * AND or OR (but not a mixture)
+ *
+ * @author gmcarstairs
+ */
+public class FeatureMatcherSet implements FeatureMatcherSetI
+{
+ private static final String OR = "OR";
+
+ private static final String AND = "AND";
+
+ private static final String SPACE = " ";
+
+ private static final String CLOSE_BRACKET = ")";
+
+ private static final String OPEN_BRACKET = "(";
+
+ private static final String OR_I18N = MessageManager
+ .getString("label.or");
+
+ private static final String AND_18N = MessageManager
+ .getString("label.and");
+
+ List<FeatureMatcherI> matchConditions;
+
+ boolean andConditions;
+
+ /**
+ * A factory constructor that converts a stringified object (as output by
+ * toStableString) to an object instance.
+ *
+ * Format:
+ * <ul>
+ * <li>(condition1) AND (condition2) AND (condition3)</li>
+ * <li>or</li>
+ * <li>(condition1) OR (condition2) OR (condition3)</li>
+ * </ul>
+ * where OR and AND are not case-sensitive, and may not be mixed. Brackets are
+ * optional if there is only one condition.
+ *
+ * @param descriptor
+ * @return
+ * @see FeatureMatcher#fromString(String)
+ */
+ public static FeatureMatcherSet fromString(final String descriptor)
+ {
+ String invalid = "Invalid descriptor: " + descriptor;
+ boolean firstCondition = true;
+ FeatureMatcherSet result = new FeatureMatcherSet();
+
+ String leftToParse = descriptor.trim();
+
+ while (leftToParse.length() > 0)
+ {
+ /*
+ * inspect AND or OR condition, check not mixed
+ */
+ boolean and = true;
+ if (!firstCondition)
+ {
+ int spacePos = leftToParse.indexOf(SPACE);
+ if (spacePos == -1)
+ {
+ // trailing junk after a match condition
+ System.err.println(invalid);
+ return null;
+ }
+ String conjunction = leftToParse.substring(0, spacePos);
+ leftToParse = leftToParse.substring(spacePos + 1).trim();
+ if (conjunction.equalsIgnoreCase(AND))
+ {
+ and = true;
+ }
+ else if (conjunction.equalsIgnoreCase(OR))
+ {
+ and = false;
+ }
+ else
+ {
+ // not an AND or an OR - invalid
+ System.err.println(invalid);
+ return null;
+ }
+ }
+
+ /*
+ * now extract the next condition and AND or OR it
+ */
+ String nextCondition = leftToParse;
+ if (leftToParse.startsWith(OPEN_BRACKET))
+ {
+ int closePos = leftToParse.indexOf(CLOSE_BRACKET);
+ if (closePos == -1)
+ {
+ System.err.println(invalid);
+ return null;
+ }
+ nextCondition = leftToParse.substring(1, closePos);
+ leftToParse = leftToParse.substring(closePos + 1).trim();
+ }
+ else
+ {
+ leftToParse = "";
+ }
+
+ FeatureMatcher fm = FeatureMatcher.fromString(nextCondition);
+ if (fm == null)
+ {
+ System.err.println(invalid);
+ return null;
+ }
+ try
+ {
+ if (and)
+ {
+ result.and(fm);
+ }
+ else
+ {
+ result.or(fm);
+ }
+ firstCondition = false;
+ } catch (IllegalStateException e)
+ {
+ // thrown if OR and AND are mixed
+ System.err.println(invalid);
+ return null;
+ }
+
+ }
+ return result;
+ }
+
+ /**
+ * Constructor
+ */
+ public FeatureMatcherSet()
+ {
+ matchConditions = new ArrayList<>();
+ }
+
+ @Override
+ public boolean matches(SequenceFeature feature)
+ {
+ /*
+ * no conditions matches anything
+ */
+ if (matchConditions.isEmpty())
+ {
+ return true;
+ }
+
+ /*
+ * AND until failure
+ */
+ if (andConditions)
+ {
+ for (FeatureMatcherI m : matchConditions)
+ {
+ if (!m.matches(feature))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * OR until match
+ */
+ for (FeatureMatcherI m : matchConditions)
+ {
+ if (m.matches(feature))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void and(FeatureMatcherI m)
+ {
+ if (!andConditions && matchConditions.size() > 1)
+ {
+ throw new IllegalStateException("Can't add an AND to OR conditions");
+ }
+ matchConditions.add(m);
+ andConditions = true;
+ }
+
+ @Override
+ public void or(FeatureMatcherI m)
+ {
+ if (andConditions && matchConditions.size() > 1)
+ {
+ throw new IllegalStateException("Can't add an OR to AND conditions");
+ }
+ matchConditions.add(m);
+ andConditions = false;
+ }
+
+ @Override
+ public boolean isAnded()
+ {
+ return andConditions;
+ }
+
+ @Override
+ public Iterable<FeatureMatcherI> getMatchers()
+ {
+ return matchConditions;
+ }
+
+ /**
+ * Answers a string representation of this object suitable for display, and
+ * possibly internationalized. The format is not guaranteed stable and may
+ * change in future.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ boolean multiple = matchConditions.size() > 1;
+ for (FeatureMatcherI matcher : matchConditions)
+ {
+ if (!first)
+ {
+ String joiner = andConditions ? AND_18N : OR_I18N;
+ sb.append(SPACE).append(joiner.toLowerCase()).append(SPACE);
+ }
+ first = false;
+ if (multiple)
+ {
+ sb.append(OPEN_BRACKET).append(matcher.toString())
+ .append(CLOSE_BRACKET);
+ }
+ else
+ {
+ sb.append(matcher.toString());
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return matchConditions == null || matchConditions.isEmpty();
+ }
+
+ /**
+ * {@inheritDoc} The output of this method should be parseable by method
+ * <code>fromString<code> to restore the original object.
+ */
+ @Override
+ public String toStableString()
+ {
+ StringBuilder sb = new StringBuilder();
+ boolean moreThanOne = matchConditions.size() > 1;
+ boolean first = true;
+
+ for (FeatureMatcherI matcher : matchConditions)
+ {
+ if (!first)
+ {
+ String joiner = andConditions ? AND : OR;
+ sb.append(SPACE).append(joiner).append(SPACE);
+ }
+ first = false;
+ if (moreThanOne)
+ {
+ sb.append(OPEN_BRACKET).append(matcher.toStableString())
+ .append(CLOSE_BRACKET);
+ }
+ else
+ {
+ sb.append(matcher.toStableString());
+ }
+ }
+ return sb.toString();
+ }
+
+}
--- /dev/null
+package jalview.datamodel.features;
+
+import jalview.datamodel.SequenceFeature;
+
+/**
+ * An interface to describe a set of one or more feature matchers, where all
+ * matchers are combined with either AND or OR
+ *
+ * @author gmcarstairs
+ *
+ */
+public interface FeatureMatcherSetI
+{
+ /**
+ * Answers true if the feature provided passes this matcher's match condition
+ *
+ * @param feature
+ * @return
+ */
+ boolean matches(SequenceFeature feature);
+
+ /**
+ * Adds (ANDs) match condition m to this object's matcher set
+ *
+ * @param m
+ * @throws IllegalStateException
+ * if an attempt is made to AND to existing OR-ed conditions
+ */
+ void and(FeatureMatcherI m);
+
+ /**
+ * Answers true if any second condition is AND-ed with this one, false if it
+ * is OR-ed
+ *
+ * @return
+ */
+ boolean isAnded();
+
+ /**
+ * Adds (ORs) the given condition to this object's match conditions
+ *
+ * @param m
+ * @throws IllegalStateException
+ * if an attempt is made to OR to existing AND-ed conditions
+ */
+ void or(FeatureMatcherI m);
+
+ /**
+ * Answers an iterator over the combined match conditions
+ *
+ * @return
+ */
+ Iterable<FeatureMatcherI> getMatchers();
+
+ /**
+ * Answers true if this object contains no conditions
+ *
+ * @return
+ */
+ boolean isEmpty();
+
+ /**
+ * Answers a string representation of this object suitable for use when
+ * persisting data, in a format that can be reliably read back. Any changes to
+ * the format should be backwards compatible.
+ */
+ String toStableString();
+}
--- /dev/null
+package jalview.datamodel.features;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A class to model one source of feature data, including metadata about
+ * attributes of features
+ *
+ * @author gmcarstairs
+ *
+ */
+public class FeatureSource implements FeatureSourceI
+{
+ private String name;
+
+ private Map<String, String> attributeNames;
+
+ private Map<String, FeatureAttributeType> attributeTypes;
+
+ /**
+ * Constructor
+ *
+ * @param theName
+ */
+ public FeatureSource(String theName)
+ {
+ this.name = theName;
+ attributeNames = new HashMap<>();
+ attributeTypes = new HashMap<>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getAttributeName(String attributeId)
+ {
+ return attributeNames.get(attributeId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public FeatureAttributeType getAttributeType(String attributeId)
+ {
+ return attributeTypes.get(attributeId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setAttributeName(String id, String attName)
+ {
+ attributeNames.put(id, attName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setAttributeType(String id, FeatureAttributeType type)
+ {
+ attributeTypes.put(id, type);
+ }
+
+}
--- /dev/null
+package jalview.datamodel.features;
+
+public interface FeatureSourceI
+{
+ /**
+ * Answers a name for the feature source (not necessarily unique)
+ *
+ * @return
+ */
+ String getName();
+
+ /**
+ * Answers the 'long name' of an attribute given its id (short name or
+ * abbreviation), or null if not known
+ *
+ * @param attributeId
+ * @return
+ */
+ String getAttributeName(String attributeId);
+
+ /**
+ * Sets the 'long name' of an attribute given its id (short name or
+ * abbreviation).
+ *
+ * @param id
+ * @param name
+ */
+ void setAttributeName(String id, String name);
+
+ /**
+ * Answers the datatype of the attribute with given id, or null if not known
+ *
+ * @param attributeId
+ * @return
+ */
+ FeatureAttributeType getAttributeType(String attributeId);
+
+ /**
+ * Sets the datatype of the attribute with given id
+ *
+ * @param id
+ * @param type
+ */
+ void setAttributeType(String id, FeatureAttributeType type);
+}
--- /dev/null
+package jalview.datamodel.features;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A singleton to hold metadata about feature attributes, keyed by a unique
+ * feature source identifier
+ *
+ * @author gmcarstairs
+ *
+ */
+public class FeatureSources
+{
+ private static FeatureSources instance = new FeatureSources();
+
+ private Map<String, FeatureSourceI> sources;
+
+ /**
+ * Answers the singleton instance of this class
+ *
+ * @return
+ */
+ public static FeatureSources getInstance()
+ {
+ return instance;
+ }
+
+ private FeatureSources()
+ {
+ sources = new HashMap<>();
+ }
+
+ /**
+ * Answers the FeatureSource with the given unique identifier, or null if not
+ * known
+ *
+ * @param sourceId
+ * @return
+ */
+ public FeatureSourceI getSource(String sourceId)
+ {
+ return sources.get(sourceId);
+ }
+
+ /**
+ * Adds the given source under the given key. This will replace any existing
+ * source with the same id, it is the caller's responsibility to ensure keys
+ * are unique if necessary.
+ *
+ * @param sourceId
+ * @param source
+ */
+ public void addSource(String sourceId, FeatureSource source)
+ {
+ sources.put(sourceId, source);
+ }
+}
+/*
+ * 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.features;
import jalview.datamodel.ContiguousI;
}
/**
- * Adds the shift value to the start and end of all positional features.
- * Returns true if at least one feature was updated, else false.
+ * Adds the shift amount to the start and end of all positional features whose
+ * start position is at or after fromPosition. Returns true if at least one
+ * feature was shifted, else false.
*
- * @param shift
+ * @param fromPosition
+ * @param shiftBy
* @return
*/
- public synchronized boolean shiftFeatures(int shift)
+ public synchronized boolean shiftFeatures(int fromPosition, int shiftBy)
{
/*
* Because begin and end are final fields (to ensure the data store's
boolean modified = false;
for (SequenceFeature sf : getPositionalFeatures())
{
- modified = true;
- int newBegin = sf.getBegin() + shift;
- int newEnd = sf.getEnd() + shift;
-
- /*
- * sanity check: don't shift left of the first residue
- */
- if (newEnd > 0)
+ if (sf.getBegin() >= fromPosition)
{
- newBegin = Math.max(1, newBegin);
- SequenceFeature sf2 = new SequenceFeature(sf, newBegin, newEnd,
- sf.getFeatureGroup(), sf.getScore());
- addFeature(sf2);
+ modified = true;
+ int newBegin = sf.getBegin() + shiftBy;
+ int newEnd = sf.getEnd() + shiftBy;
+
+ /*
+ * sanity check: don't shift left of the first residue
+ */
+ if (newEnd > 0)
+ {
+ newBegin = Math.max(1, newBegin);
+ SequenceFeature sf2 = new SequenceFeature(sf, newBegin, newEnd,
+ sf.getFeatureGroup(), sf.getScore());
+ addFeature(sf2);
+ }
+ delete(sf);
}
- delete(sf);
}
return modified;
}
+/*
+ * 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.features;
import jalview.datamodel.ContiguousI;
+/*
+ * 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.features;
import jalview.datamodel.ContiguousI;
+/*
+ * 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.features;
import jalview.datamodel.ContiguousI;
+/*
+ * 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.features;
import jalview.datamodel.ContiguousI;
*/
// featureStore = Collections
// .synchronizedSortedMap(new TreeMap<String, FeatureStore>());
- featureStore = new TreeMap<String, FeatureStore>();
+ featureStore = new TreeMap<>();
}
/**
}
/**
- * Answers true if the given type is one of the specified sequence ontology
- * terms (or a sub-type of one), or if no terms are supplied. Answers false if
- * filter terms are specified and the given term does not match any of them.
+ * Answers true if the given type matches one of the specified terms (or is a
+ * sub-type of one in the Sequence Ontology), or if no terms are supplied.
+ * Answers false if filter terms are specified and the given term does not
+ * match any of them.
*
* @param type
* @param soTerm
SequenceOntologyI so = SequenceOntologyFactory.getInstance();
for (String term : soTerm)
{
- if (so.isA(type, term))
+ if (type.equals(term) || so.isA(type, term))
{
return true;
}
* {@inheritDoc}
*/
@Override
- public boolean shiftFeatures(int shift)
+ public boolean shiftFeatures(int fromPosition, int shiftBy)
{
boolean modified = false;
for (FeatureStore fs : featureStore.values())
{
- modified |= fs.shiftFeatures(shift);
+ modified |= fs.shiftFeatures(fromPosition, shiftBy);
}
return modified;
}
-}
\ No newline at end of file
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void deleteAll()
+ {
+ featureStore.clear();
+ }
+}
+/*
+ * 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.features;
import jalview.datamodel.SequenceFeature;
String group, String... type);
/**
- * Answers a list of all features stored, whose type either matches one of the
- * given ontology terms, or is a specialisation of a term in the Sequence
- * Ontology. Results are returned in no particular guaranteed order.
+ * Answers a list of all features stored, whose type either matches, or is a
+ * specialisation (in the Sequence Ontology) of, one of the given terms.
+ * Results are returned in no particular order.
*
* @param ontologyTerm
* @return
float getMaximumScore(String type, boolean positional);
/**
- * Adds the shift amount to the start and end of all positional features,
- * returning true if at least one feature was shifted, else false
+ * Adds the shift amount to the start and end of all positional features whose
+ * start position is at or after fromPosition. Returns true if at least one
+ * feature was shifted, else false.
*
- * @param shift
+ * @param fromPosition
+ * @param shiftBy
*/
- abstract boolean shiftFeatures(int shift);
-}
\ No newline at end of file
+ boolean shiftFeatures(int fromPosition, int shiftBy);
+
+ /**
+ * Deletes all positional and non-positional features
+ */
+ void deleteAll();
+}
+/*
+ * 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.xdb.uniprot;
+import java.util.Vector;
+
/**
* A data model class for binding from Uniprot XML via uniprot_mapping.xml
*/
{
private String type;
- private String description;
+ private String description = null;
+
+ private String original = null;
+
+ private Vector<String> variation = null;
private String status;
this.begin = p;
this.end = p;
}
+
+ public String getOriginal()
+ {
+ return original;
+ }
+
+ public void setOriginal(String original)
+ {
+ this.original = original;
+ }
+
+ public Vector<String> getVariation()
+ {
+ return variation;
+ }
+
+ public void setVariation(Vector<String> variant)
+ {
+ this.variation = variant;
+ }
}
package jalview.ext.ensembl;
import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
import jalview.io.gff.SequenceOntologyFactory;
import jalview.io.gff.SequenceOntologyI;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
import com.stevesoft.pat.Regex;
private static final Regex ACCESSION_REGEX = new Regex(
"(ENS([A-Z]{3}|)[TG][0-9]{11}$)" + "|" + "(CCDS[0-9.]{3,}$)");
- private static Map<String, String> params = new HashMap<String, String>();
-
- static
- {
- params.put("object_type", "transcript");
- }
-
/*
* fetch exon features on genomic sequence (to identify the cdna regions)
* and cds and variation features (to retain)
}
/**
- * Answers true if the sequence feature type is 'exon' (or a subtype of exon
- * in the Sequence Ontology), and the Parent of the feature is the transcript
- * we are retrieving
+ * Answers a list of sequence features (if any) whose type is 'exon' (or a
+ * subtype of exon in the Sequence Ontology), and whose Parent is the
+ * transcript we are retrieving
*/
@Override
- protected boolean identifiesSequence(SequenceFeature sf, String accId)
+ protected List<SequenceFeature> getIdentifyingFeatures(SequenceI seq,
+ String accId)
{
- if (SequenceOntologyFactory.getInstance().isA(sf.getType(),
- SequenceOntologyI.EXON))
+ List<SequenceFeature> result = new ArrayList<>();
+ List<SequenceFeature> sfs = seq.getFeatures()
+ .getFeaturesByOntology(SequenceOntologyI.EXON);
+ for (SequenceFeature sf : sfs)
{
String parentFeature = (String) sf.getValue(PARENT);
if (("transcript:" + accId).equals(parentFeature))
{
- return true;
+ result.add(sf);
}
}
- return false;
+
+ return result;
}
/**
- * Parameter object_type=cdna added to ensure cdna and not peptide is returned
- * (JAL-2529)
+ * Parameter object_type=Transcaript added to ensure cdna and not peptide is
+ * returned (JAL-2529)
*/
@Override
- protected Map<String, String> getAdditionalParameters()
+ protected String getObjectType()
{
- return params;
+ return OBJECT_TYPE_TRANSCRIPT;
}
}
}
/**
- * Answers true if the sequence feature type is 'CDS' (or a subtype of CDS in
- * the Sequence Ontology), and the Parent of the feature is the transcript we
- * are retrieving
+ * Answers a list of sequence features (if any) whose type is 'CDS' (or a
+ * subtype of CDS in the Sequence Ontology), and whose Parent is the
+ * transcript we are retrieving
*/
@Override
- protected boolean identifiesSequence(SequenceFeature sf, String accId)
+ protected List<SequenceFeature> getIdentifyingFeatures(SequenceI seq,
+ String accId)
{
- if (SequenceOntologyFactory.getInstance().isA(sf.getType(),
- SequenceOntologyI.CDS))
+ List<SequenceFeature> result = new ArrayList<>();
+ List<SequenceFeature> sfs = seq.getFeatures()
+ .getFeaturesByOntology(SequenceOntologyI.CDS);
+ for (SequenceFeature sf : sfs)
{
String parentFeature = (String) sf.getValue(PARENT);
if (("transcript:" + accId).equals(parentFeature))
{
- return true;
+ result.add(sf);
}
}
- return false;
+ return result;
}
/**
protected List<int[]> getCdsRanges(SequenceI dnaSeq)
{
int len = dnaSeq.getLength();
- List<int[]> ranges = new ArrayList<int[]>();
+ List<int[]> ranges = new ArrayList<>();
ranges.add(new int[] { 1, len });
return ranges;
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ext.ensembl;
+
+/**
+ * A data class to model the data and rest version of one Ensembl domain,
+ * currently for rest.ensembl.org and rest.ensemblgenomes.org
+ *
+ * @author gmcarstairs
+ */
+class EnsemblData
+{
+ /*
+ * The http domain this object is holding data values for
+ */
+ String domain;
+
+ /*
+ * The latest version Jalview has tested for, e.g. "4.5"; a minor version change should be
+ * ok, a major version change may break stuff
+ */
+ String expectedRestVersion;
+
+ /*
+ * Major / minor / point version e.g. "4.5.1"
+ * @see http://rest.ensembl.org/info/rest/?content-type=application/json
+ */
+ String restVersion;
+
+ /*
+ * data version
+ * @see http://rest.ensembl.org/info/data/?content-type=application/json
+ */
+ String dataVersion;
+
+ /*
+ * true when http://rest.ensembl.org/info/ping/?content-type=application/json
+ * returns response code 200 and not {"error":"Database is unavailable"}
+ */
+ boolean restAvailable;
+
+ /*
+ * absolute time when availability was last checked
+ */
+ long lastAvailableCheckTime;
+
+ /*
+ * absolute time when version numbers were last checked
+ */
+ long lastVersionCheckTime;
+
+ // 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
+ *
+ * @param restExpected
+ */
+ EnsemblData(String theDomain, String restExpected)
+ {
+ domain = theDomain;
+ expectedRestVersion = restExpected;
+ lastAvailableCheckTime = -1;
+ lastVersionCheckTime = -1;
+ }
+
+}
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
+import jalview.io.DataSourceType;
import jalview.io.FeaturesFile;
import jalview.io.FileParse;
+import java.io.BufferedReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
public AlignmentI getSequenceRecords(String query) throws IOException
{
// TODO: use a vararg String... for getSequenceRecords instead?
- List<String> queries = new ArrayList<String>();
+ List<String> queries = new ArrayList<>();
queries.add(query);
- FileParse fp = getSequenceReader(queries);
- if (fp == null || !fp.isValid())
+ BufferedReader fp = getSequenceReader(queries);
+ if (fp == null)
{
return null;
}
- FeaturesFile fr = new FeaturesFile(fp);
+ FeaturesFile fr = new FeaturesFile(
+ new FileParse(fp, null, DataSourceType.URL));
return new Alignment(fr.getSeqsAsArray());
}
urlstring.append("?content-type=text/x-gff3");
/*
+ * specify object_type=gene in case is shared by transcript and/or protein;
+ * currently only fetching features for gene sequences;
+ * refactor in future if needed to fetch for transcripts
+ */
+ urlstring.append("&").append(OBJECT_TYPE).append("=")
+ .append(OBJECT_TYPE_GENE);
+
+ /*
* specify features to retrieve
* @see http://rest.ensembl.org/documentation/info/overlap_id
- * could make the list a configurable entry in jalview.properties
+ * could make the list a configurable entry in .jalview_properties
*/
for (EnsemblFeatureType feature : featuresWanted)
{
* describes the required encoding of the response.
*/
@Override
- protected String getRequestMimeType(boolean multipleIds)
+ protected String getRequestMimeType()
{
return "text/x-gff3";
}
/**
- * Returns the MIME type for GFF3.
+ * Returns the MIME type for GFF3
*/
@Override
protected String getResponseMimeType()
import jalview.api.FeatureColourI;
import jalview.api.FeatureSettingsModelI;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.GeneLociI;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
return EnsemblSeqType.GENOMIC;
}
+ @Override
+ protected String getObjectType()
+ {
+ return OBJECT_TYPE_GENE;
+ }
+
/**
* Returns an alignment containing the gene(s) for the given gene or
* transcript identifier, or external identifier (e.g. Uniprot id). If given a
{
continue;
}
+
if (geneAlignment.getHeight() == 1)
{
+ // ensure id has 'correct' case for the Ensembl identifier
+ geneId = geneAlignment.getSequenceAt(0).getName();
+
+ findGeneLoci(geneAlignment.getSequenceAt(0), geneId);
+
getTranscripts(geneAlignment, geneId);
}
if (al == null)
}
/**
+ * Calls the /lookup/id REST service, parses the response for gene
+ * coordinates, and if successful, adds these to the sequence. If this fails,
+ * fall back on trying to parse the sequence description in case it is in
+ * Ensembl-gene format e.g. chromosome:GRCh38:17:45051610:45109016:1.
+ *
+ * @param seq
+ * @param geneId
+ */
+ void findGeneLoci(SequenceI seq, String geneId)
+ {
+ GeneLociI geneLoci = new EnsemblLookup(getDomain()).getGeneLoci(geneId);
+ if (geneLoci != null)
+ {
+ seq.setGeneLoci(geneLoci.getSpeciesId(), geneLoci.getAssemblyId(),
+ geneLoci.getChromosomeId(), geneLoci.getMap());
+ }
+ else
+ {
+ parseChromosomeLocations(seq);
+ }
+ }
+
+ /**
+ * Parses and saves fields of an Ensembl-style description e.g.
+ * chromosome:GRCh38:17:45051610:45109016:1
+ *
+ * @param seq
+ */
+ boolean parseChromosomeLocations(SequenceI seq)
+ {
+ String description = seq.getDescription();
+ if (description == null)
+ {
+ return false;
+ }
+ String[] tokens = description.split(":");
+ if (tokens.length == 6 && tokens[0].startsWith(DBRefEntry.CHROMOSOME))
+ {
+ String ref = tokens[1];
+ String chrom = tokens[2];
+ try
+ {
+ int chStart = Integer.parseInt(tokens[3]);
+ int chEnd = Integer.parseInt(tokens[4]);
+ boolean forwardStrand = "1".equals(tokens[5]);
+ String species = ""; // not known here
+ int[] from = new int[] { seq.getStart(), seq.getEnd() };
+ int[] to = new int[] { forwardStrand ? chStart : chEnd,
+ forwardStrand ? chEnd : chStart };
+ MapList map = new MapList(from, to, 1, 1);
+ seq.setGeneLoci(species, ref, chrom, map);
+ return true;
+ } catch (NumberFormatException e)
+ {
+ System.err.println("Bad integers in description " + description);
+ }
+ }
+ return false;
+ }
+
+ /**
* Converts a query, which may contain one or more gene, transcript, or
* external (to Ensembl) identifiers, into a non-redundant list of gene
* identifiers.
*/
List<String> getGeneIds(String accessions)
{
- List<String> geneIds = new ArrayList<String>();
+ List<String> geneIds = new ArrayList<>();
for (String acc : accessions.split(getAccessionSeparator()))
{
int transcriptLength = 0;
final char[] geneChars = gene.getSequence();
int offset = gene.getStart(); // to convert to 0-based positions
- List<int[]> mappedFrom = new ArrayList<int[]>();
+ List<int[]> mappedFrom = new ArrayList<>();
for (SequenceFeature sf : splices)
{
* transfer features to the new sequence; we use EnsemblCdna to do this,
* to filter out unwanted features types (see method retainFeature)
*/
- List<int[]> mapTo = new ArrayList<int[]>();
+ List<int[]> mapTo = new ArrayList<>();
mapTo.add(new int[] { 1, transcriptLength });
MapList mapping = new MapList(mappedFrom, mapTo, 1, 1);
EnsemblCdna cdna = new EnsemblCdna(getDomain());
cdna.transferFeatures(gene.getFeatures().getPositionalFeatures(),
transcript.getDatasetSequence(), mapping, parentId);
+ mapTranscriptToChromosome(transcript, gene, mapping);
+
/*
* fetch and save cross-references
*/
}
/**
+ * If the gene has a mapping to chromosome coordinates, derive the transcript
+ * chromosome regions and save on the transcript sequence
+ *
+ * @param transcript
+ * @param gene
+ * @param mapping
+ * the mapping from gene to transcript positions
+ */
+ protected void mapTranscriptToChromosome(SequenceI transcript,
+ SequenceI gene, MapList mapping)
+ {
+ GeneLociI loci = gene.getGeneLoci();
+ if (loci == null)
+ {
+ return;
+ }
+
+ MapList geneMapping = loci.getMap();
+
+ List<int[]> exons = mapping.getFromRanges();
+ List<int[]> transcriptLoci = new ArrayList<>();
+
+ for (int[] exon : exons)
+ {
+ transcriptLoci.add(geneMapping.locateInTo(exon[0], exon[1]));
+ }
+
+ List<int[]> transcriptRange = Arrays.asList(new int[] {
+ transcript.getStart(), transcript.getEnd() });
+ MapList mapList = new MapList(transcriptRange, transcriptLoci, 1, 1);
+
+ transcript.setGeneLoci(loci.getSpeciesId(), loci.getAssemblyId(),
+ loci.getChromosomeId(), mapList);
+ }
+
+ /**
* Returns the 'transcript_id' property of the sequence feature (or null)
*
* @param feature
protected List<SequenceFeature> getTranscriptFeatures(String accId,
SequenceI geneSequence)
{
- List<SequenceFeature> transcriptFeatures = new ArrayList<SequenceFeature>();
+ List<SequenceFeature> transcriptFeatures = new ArrayList<>();
String parentIdentifier = GENE_PREFIX + accId;
for (SequenceFeature sf : sfs)
{
String parent = (String) sf.getValue(PARENT);
- if (parentIdentifier.equals(parent))
+ if (parentIdentifier.equalsIgnoreCase(parent))
{
transcriptFeatures.add(sf);
}
}
/**
- * Answers true for a feature of type 'gene' (or a sub-type of gene in the
- * Sequence Ontology), whose ID is the accession we are retrieving
+ * Answers a list of sequence features (if any) whose type is 'gene' (or a
+ * subtype of gene in the Sequence Ontology), and whose ID is the accession we
+ * are retrieving
*/
@Override
- protected boolean identifiesSequence(SequenceFeature sf, String accId)
+ protected List<SequenceFeature> getIdentifyingFeatures(SequenceI seq,
+ String accId)
{
- if (SequenceOntologyFactory.getInstance().isA(sf.getType(),
- SequenceOntologyI.GENE))
+ List<SequenceFeature> result = new ArrayList<>();
+ List<SequenceFeature> sfs = seq.getFeatures()
+ .getFeaturesByOntology(SequenceOntologyI.GENE);
+ for (SequenceFeature sf : sfs)
{
- String id = (String) sf.getValue(ID);
- if ((GENE_PREFIX + accId).equals(id))
+ // NB features as gff use 'ID'; rest services return as 'id'
+ String id = (String) sf.getValue("ID");
+ if ((GENE_PREFIX + accId).equalsIgnoreCase(id))
{
- return true;
+ result.add(sf);
}
}
- return false;
+ return result;
}
/**
if (isTranscript(type))
{
String parent = (String) sf.getValue(PARENT);
- if (!(GENE_PREFIX + accessionId).equals(parent))
+ if (!(GENE_PREFIX + accessionId).equalsIgnoreCase(parent))
{
return false;
}
}
/**
- * Answers false. This allows an optimisation - a single 'gene' feature is all
- * that is needed to identify the positions of the gene on the genomic
- * sequence.
- */
- @Override
- protected boolean isSpliceable()
- {
- return false;
- }
-
- /**
* Override to do nothing as Ensembl doesn't return a protein sequence for a
* gene identifier
*/
package jalview.ext.ensembl;
import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.io.gff.SequenceOntologyI;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* A client to fetch genomic sequence from Ensembl
}
/**
- * Answers true if the sequence feature type is 'transcript' (or a subtype of
- * transcript in the Sequence Ontology), and the ID of the feature is the
- * transcript we are retrieving
+ * Answers a list of sequence features (if any) whose type is 'transcript' (or
+ * a subtype of transcript in the Sequence Ontology), and whose ID is the
+ * accession we are retrieving.
+ * <p>
+ * Note we also include features of type "NMD_transcript_variant", although
+ * not strictly 'transcript' in the SO, as they used in Ensembl as if they
+ * were.
*/
@Override
- protected boolean identifiesSequence(SequenceFeature sf, String accId)
+ protected List<SequenceFeature> getIdentifyingFeatures(SequenceI seq,
+ String accId)
{
- if (isTranscript(sf.getType()))
+ List<SequenceFeature> result = new ArrayList<>();
+ List<SequenceFeature> sfs = seq.getFeatures().getFeaturesByOntology(
+ SequenceOntologyI.TRANSCRIPT,
+ SequenceOntologyI.NMD_TRANSCRIPT_VARIANT);
+ for (SequenceFeature sf : sfs)
{
- String id = (String) sf.getValue(ID);
+ // NB features as gff use 'ID'; rest services return as 'id'
+ String id = (String) sf.getValue("ID");
if (("transcript:" + accId).equals(id))
{
- return true;
+ result.add(sf);
}
}
- return false;
+ return result;
}
}
*/
package jalview.ext.ensembl;
+import jalview.bin.Cache;
+import jalview.datamodel.DBRefSource;
+
/**
* A class to behave much like EnsemblGene but referencing the ensemblgenomes
* domain and data
*/
public EnsemblGenomes()
{
- super(ENSEMBL_GENOMES_REST);
+ super();
+ setDomain(Cache.getDefault(ENSEMBL_GENOMES_BASEURL,
+ DEFAULT_ENSEMBL_GENOMES_BASEURL));
}
@Override
public String getDbName()
{
- return "EnsemblGenomes";
+ return DBRefSource.ENSEMBLGENOMES;
}
@Override
@Override
public String getDbSource()
{
- return "EnsemblGenomes";
+ return DBRefSource.ENSEMBLGENOMES;
}
}
-/*
- * 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.ext.ensembl;
-/**
- * A data class to model the data and rest version of one Ensembl domain,
- * currently for rest.ensembl.org and rest.ensemblgenomes.org
- *
- * @author gmcarstairs
- */
-class EnsemblInfo
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefSource;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.json.simple.JSONArray;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+public class EnsemblInfo extends EnsemblRestClient
{
- /*
- * The http domain this object is holding data values for
- */
- String domain;
/*
- * The latest version Jalview has tested for, e.g. "4.5"; a minor version change should be
- * ok, a major version change may break stuff
+ * cached results of REST /info/divisions service, currently
+ * <pre>
+ * {
+ * { "ENSEMBLFUNGI", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBLBACTERIA", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBLPROTISTS", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBLMETAZOA", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBLPLANTS", "http://rest.ensemblgenomes.org"},
+ * "ENSEMBL", "http://rest.ensembl.org" }
+ * }
+ * </pre>
+ * The values for EnsemblGenomes are retrieved by a REST call, that for
+ * Ensembl is added programmatically for convenience of lookup
*/
- String expectedRestVersion;
+ private static Map<String, String> divisions;
- /*
- * Major / minor / point version e.g. "4.5.1"
- * @see http://rest.ensembl.org/info/rest/?content-type=application/json
- */
- String restVersion;
+ @Override
+ public String getDbName()
+ {
+ return "ENSEMBL";
+ }
- /*
- * data version
- * @see http://rest.ensembl.org/info/data/?content-type=application/json
- */
- String dataVersion;
+ @Override
+ public AlignmentI getSequenceRecords(String queries) throws Exception
+ {
+ return null;
+ }
- /*
- * true when http://rest.ensembl.org/info/ping/?content-type=application/json
- * returns response code 200 and not {"error":"Database is unavailable"}
+ @Override
+ protected URL getUrl(List<String> ids) throws MalformedURLException
+ {
+ return null;
+ }
+
+ @Override
+ protected boolean useGetRequest()
+ {
+ return true;
+ }
+
+ /**
+ * Answers the domain (http://rest.ensembl.org or
+ * http://rest.ensemblgenomes.org) for the given division, or null if not
+ * recognised by Ensembl.
+ *
+ * @param division
+ * @return
*/
- boolean restAvailable;
+ public String getDomain(String division)
+ {
+ if (divisions == null)
+ {
+ fetchDivisions();
+ }
+ return divisions.get(division.toUpperCase());
+ }
- /*
- * absolute time when availability was last checked
+ /**
+ * On first request only, populate the lookup map by fetching the list of
+ * divisions known to EnsemblGenomes.
*/
- long lastAvailableCheckTime;
+ void fetchDivisions()
+ {
+ divisions = new HashMap<>();
- /*
- * absolute time when version numbers were last checked
+ /*
+ * for convenience, pre-fill ensembl.org as the domain for "ENSEMBL"
+ */
+ divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ensemblDomain);
+
+ BufferedReader br = null;
+ try
+ {
+ URL url = getDivisionsUrl(ensemblGenomesDomain);
+ if (url != null)
+ {
+ br = getHttpResponse(url, null);
+ }
+ parseResponse(br, ensemblGenomesDomain);
+ } catch (IOException e)
+ {
+ // ignore
+ } finally
+ {
+ if (br != null)
+ {
+ try
+ {
+ br.close();
+ } catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Parses the JSON response to /info/divisions, and add each to the lookup map
+ *
+ * @param br
+ * @param domain
*/
- long lastVersionCheckTime;
+ void parseResponse(BufferedReader br, String domain)
+ {
+ JSONParser jp = new JSONParser();
- // flag set to true if REST major version is not the one expected
- boolean restMajorVersionMismatch;
+ try
+ {
+ JSONArray parsed = (JSONArray) jp.parse(br);
+
+ Iterator rvals = parsed.iterator();
+ while (rvals.hasNext())
+ {
+ String division = rvals.next().toString();
+ divisions.put(division.toUpperCase(), domain);
+ }
+ } catch (IOException | ParseException | NumberFormatException e)
+ {
+ // ignore
+ }
+ }
/**
- * Constructor given expected REST version number e.g 4.5 or 3.4.3
+ * Constructs the URL for the EnsemblGenomes /info/divisions REST service
+ * @param domain TODO
*
- * @param restExpected
+ * @return
+ * @throws MalformedURLException
*/
- EnsemblInfo(String theDomain, String restExpected)
+ URL getDivisionsUrl(String domain) throws MalformedURLException
{
- domain = theDomain;
- expectedRestVersion = restExpected;
- lastAvailableCheckTime = -1;
- lastVersionCheckTime = -1;
+ return new URL(domain
+ + "/info/divisions?content-type=application/json");
}
+ /**
+ * Returns the set of 'divisions' recognised by Ensembl or EnsemblGenomes
+ *
+ * @return
+ */
+ public Set<String> getDivisions() {
+ if (divisions == null)
+ {
+ fetchDivisions();
+ }
+
+ return divisions.keySet();
+ }
}
*/
package jalview.ext.ensembl;
+import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.GeneLociI;
+import jalview.util.MapList;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
/**
- * A client for the Ensembl lookup REST endpoint; used to find the Parent gene
- * identifier given a transcript identifier.
+ * A client for the Ensembl /lookup REST endpoint, used to find the gene
+ * identifier given a gene, transcript or protein identifier, or to extract the
+ * species or chromosomal coordinates from the same service response
*
* @author gmcarstairs
- *
*/
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";
+ private static final String SPECIES = "species";
/**
* Default constructor (to use rest.ensembl.org)
protected URL getUrl(List<String> ids) throws MalformedURLException
{
String identifier = ids.get(0);
- return getUrl(identifier);
+ return getUrl(identifier, null);
}
/**
+ * Gets the url for lookup of the given identifier, optionally with objectType
+ * also specified in the request
+ *
* @param identifier
+ * @param objectType
* @return
*/
- protected URL getUrl(String identifier)
+ protected URL getUrl(String identifier, String objectType)
{
String url = getDomain() + "/lookup/id/" + identifier
+ CONTENT_TYPE_JSON;
+ if (objectType != null)
+ {
+ url += "&" + OBJECT_TYPE + "=" + objectType;
+ }
+
try
{
return new URL(url);
return true;
}
- @Override
- protected String getRequestMimeType(boolean multipleIds)
+ /**
+ * Returns the gene id related to the given identifier (which may be for a
+ * gene, transcript or protein), or null if none is found
+ *
+ * @param identifier
+ * @return
+ */
+ public String getGeneId(String identifier)
{
- return "application/json";
+ return getGeneId(identifier, null);
}
- @Override
- protected String getResponseMimeType()
+ /**
+ * Returns the gene id related to the given identifier (which may be for a
+ * gene, transcript or protein), or null if none is found
+ *
+ * @param identifier
+ * @param objectType
+ * @return
+ */
+ public String getGeneId(String identifier, String objectType)
{
- return "application/json";
+ return parseGeneId(getResult(identifier, objectType));
}
/**
- * Calls the Ensembl lookup REST endpoint and retrieves the 'Parent' for the
+ * 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
+ */
+ protected String parseGeneId(JSONObject val)
+ {
+ if (val == null)
+ {
+ return null;
+ }
+ String geneId = null;
+ String type = val.get(OBJECT_TYPE).toString();
+ if (OBJECT_TYPE_GENE.equalsIgnoreCase(type))
+ {
+ // got the gene - just returns its id
+ geneId = val.get(JSON_ID).toString();
+ }
+ else if (OBJECT_TYPE_TRANSCRIPT.equalsIgnoreCase(type))
+ {
+ // got the transcript - return its (Gene) Parent
+ geneId = val.get(PARENT).toString();
+ }
+ else if (OBJECT_TYPE_TRANSLATION.equalsIgnoreCase(type))
+ {
+ // got the protein - get its Parent, restricted to type Transcript
+ String transcriptId = val.get(PARENT).toString();
+ geneId = getGeneId(transcriptId, OBJECT_TYPE_TRANSCRIPT);
+ }
+
+ return geneId;
+ }
+
+ /**
+ * Calls the Ensembl lookup REST endpoint and retrieves the 'species' for the
* given identifier, or null if not found
*
* @param identifier
* @return
*/
- public String getGeneId(String identifier)
+ public String getSpecies(String identifier)
+ {
+ String species = null;
+ JSONObject json = getResult(identifier, null);
+ if (json != null)
+ {
+ Object o = json.get(SPECIES);
+ if (o != null)
+ {
+ species = o.toString();
+ }
+ }
+ return species;
+ }
+
+ /**
+ * Calls the /lookup/id rest service and returns the response as a JSONObject,
+ * or null if any error
+ *
+ * @param identifier
+ * @param objectType
+ * (optional)
+ * @return
+ */
+ protected JSONObject getResult(String identifier, String objectType)
{
List<String> ids = Arrays.asList(new String[] { identifier });
BufferedReader br = null;
try
{
- URL url = getUrl(identifier);
+ URL url = getUrl(identifier, objectType);
+
if (url != null)
{
br = getHttpResponse(url, ids);
}
- return br == null ? null : parseResponse(br);
- } catch (IOException e)
+ return br == null ? null : (JSONObject) (new JSONParser().parse(br));
+ } catch (IOException | ParseException e)
{
- // ignore
+ System.err.println("Error parsing " + identifier + " lookup response "
+ + e.getMessage());
return null;
} finally
{
}
/**
- * 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.
+ * Calls the /lookup/id rest service for the given id, and if successful,
+ * parses and returns the gene's chromosomal coordinates
*
- * @param br
+ * @param geneId
* @return
- * @throws IOException
*/
- protected String parseResponse(BufferedReader br) throws IOException
+ public GeneLociI getGeneLoci(String geneId)
{
- String geneId = null;
- JSONParser jp = new JSONParser();
+ return parseGeneLoci(getResult(geneId, OBJECT_TYPE_GENE));
+ }
+
+ /**
+ * Parses the /lookup/id response for species, asssembly_name,
+ * seq_region_name, start, end and returns an object that wraps them, or null
+ * if unsuccessful
+ *
+ * @param json
+ * @return
+ */
+ GeneLociI parseGeneLoci(JSONObject json)
+ {
+ if (json == null)
+ {
+ return null;
+ }
+
try
{
- JSONObject val = (JSONObject) jp.parse(br);
- String type = val.get(OBJECT_TYPE).toString();
- if (OBJECT_TYPE_GENE.equalsIgnoreCase(type))
+ final String species = json.get("species").toString();
+ final String assembly = json.get("assembly_name").toString();
+ final String chromosome = json.get("seq_region_name").toString();
+ String strand = json.get("strand").toString();
+ int start = Integer.parseInt(json.get("start").toString());
+ int end = Integer.parseInt(json.get("end").toString());
+ int fromEnd = end - start + 1;
+ boolean reverseStrand = "-1".equals(strand);
+ int toStart = reverseStrand ? end : start;
+ int toEnd = reverseStrand ? start : end;
+ List<int[]> fromRange = Collections.singletonList(new int[] { 1,
+ fromEnd });
+ List<int[]> toRange = Collections.singletonList(new int[] { toStart,
+ toEnd });
+ final MapList map = new MapList(fromRange, toRange, 1, 1);
+ return new GeneLociI()
{
- 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
+
+ @Override
+ public String getSpeciesId()
{
- geneId = getGeneId(transcriptId);
- } catch (StackOverflowError e)
+ return species == null ? "" : species;
+ }
+
+ @Override
+ public String getAssemblyId()
{
- /*
- * unlikely data condition error!
- */
- System.err
- .println("** Ensembl lookup "
- + getUrl(transcriptId).toString()
- + " looping on Parent!");
+ return assembly;
}
- }
- } catch (ParseException e)
+
+ @Override
+ public String getChromosomeId()
+ {
+ return chromosome;
+ }
+
+ @Override
+ public MapList getMap()
+ {
+ return map;
+ }
+ };
+ } catch (NullPointerException | NumberFormatException e)
{
- // ignore
+ Cache.log.error("Error looking up gene loci: " + e.getMessage());
+ e.printStackTrace();
}
- return geneId;
+ return null;
}
}
--- /dev/null
+package jalview.ext.ensembl;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.GeneLociI;
+import jalview.util.MapList;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+public class EnsemblMap extends EnsemblRestClient
+{
+ private static final String MAPPED = "mapped";
+
+ private static final String MAPPINGS = "mappings";
+
+ private static final String CDS = "cds";
+
+ private static final String CDNA = "cdna";
+
+ /**
+ * Default constructor (to use rest.ensembl.org)
+ */
+ public EnsemblMap()
+ {
+ super();
+ }
+
+ /**
+ * Constructor given the target domain to fetch data from
+ *
+ * @param
+ */
+ public EnsemblMap(String domain)
+ {
+ super(domain);
+ }
+
+ @Override
+ public String getDbName()
+ {
+ return DBRefSource.ENSEMBL;
+ }
+
+ @Override
+ public AlignmentI getSequenceRecords(String queries) throws Exception
+ {
+ return null; // not used
+ }
+
+ /**
+ * Constructs a URL of the format <code>
+ * http://rest.ensembl.org/map/human/GRCh38/17:45051610..45109016:1/GRCh37?content-type=application/json
+ * </code>
+ *
+ * @param species
+ * @param chromosome
+ * @param fromRef
+ * @param toRef
+ * @param startPos
+ * @param endPos
+ * @return
+ * @throws MalformedURLException
+ */
+ protected URL getAssemblyMapUrl(String species, String chromosome, String fromRef,
+ String toRef, int startPos, int endPos)
+ throws MalformedURLException
+ {
+ /*
+ * start-end might be reverse strand - present forwards to the service
+ */
+ boolean forward = startPos <= endPos;
+ int start = forward ? startPos : endPos;
+ int end = forward ? endPos : startPos;
+ String strand = forward ? "1" : "-1";
+ String url = String.format(
+ "%s/map/%s/%s/%s:%d..%d:%s/%s?content-type=application/json",
+ getDomain(), species, fromRef, chromosome, start, end, strand,
+ toRef);
+ return new URL(url);
+ }
+
+ @Override
+ protected boolean useGetRequest()
+ {
+ return true;
+ }
+
+ @Override
+ protected URL getUrl(List<String> ids) throws MalformedURLException
+ {
+ return null; // not used
+ }
+
+ /**
+ * Calls the REST /map service to get the chromosomal coordinates (start/end)
+ * in 'toRef' that corresponding to the (start/end) queryRange in 'fromRef'
+ *
+ * @param species
+ * @param chromosome
+ * @param fromRef
+ * @param toRef
+ * @param queryRange
+ * @return
+ * @see http://rest.ensemblgenomes.org/documentation/info/assembly_map
+ */
+ public int[] getAssemblyMapping(String species, String chromosome,
+ String fromRef, String toRef, int[] queryRange)
+ {
+ URL url = null;
+ BufferedReader br = null;
+
+ try
+ {
+ url = getAssemblyMapUrl(species, chromosome, fromRef, toRef, queryRange[0],
+ queryRange[1]);
+ br = getHttpResponse(url, null);
+ return (parseAssemblyMappingResponse(br));
+ } catch (Throwable t)
+ {
+ System.out.println("Error calling " + url + ": " + t.getMessage());
+ return null;
+ } finally
+ {
+ if (br != null)
+ {
+ try
+ {
+ br.close();
+ } catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Parses the JSON response from the /map/<species>/ REST service. The
+ * format is (with some fields omitted)
+ *
+ * <pre>
+ * {"mappings":
+ * [{
+ * "original": {"end":45109016,"start":45051610},
+ * "mapped" : {"end":43186384,"start":43128978}
+ * }] }
+ * </pre>
+ *
+ * @param br
+ * @return
+ */
+ protected int[] parseAssemblyMappingResponse(BufferedReader br)
+ {
+ int[] result = null;
+ JSONParser jp = new JSONParser();
+
+ try
+ {
+ JSONObject parsed = (JSONObject) jp.parse(br);
+ JSONArray mappings = (JSONArray) parsed.get(MAPPINGS);
+
+ Iterator rvals = mappings.iterator();
+ while (rvals.hasNext())
+ {
+ // todo check for "mapped"
+ JSONObject val = (JSONObject) rvals.next();
+ JSONObject mapped = (JSONObject) val.get(MAPPED);
+ int start = Integer.parseInt(mapped.get("start").toString());
+ int end = Integer.parseInt(mapped.get("end").toString());
+ String strand = mapped.get("strand").toString();
+ if ("1".equals(strand))
+ {
+ result = new int[] { start, end };
+ }
+ else
+ {
+ result = new int[] { end, start };
+ }
+ }
+ } catch (IOException | ParseException | NumberFormatException e)
+ {
+ // ignore
+ }
+ return result;
+ }
+
+ /**
+ * Calls the REST /map/cds/id service, and returns a DBRefEntry holding the
+ * returned chromosomal coordinates, or returns null if the call fails
+ *
+ * @param division
+ * e.g. Ensembl, EnsemblMetazoa
+ * @param accession
+ * e.g. ENST00000592782, Y55B1AR.1.1
+ * @param start
+ * @param end
+ * @return
+ */
+ public GeneLociI getCdsMapping(String division, String accession,
+ int start, int end)
+ {
+ return getIdMapping(division, accession, start, end, CDS);
+ }
+
+ /**
+ * Calls the REST /map/cdna/id service, and returns a DBRefEntry holding the
+ * returned chromosomal coordinates, or returns null if the call fails
+ *
+ * @param division
+ * e.g. Ensembl, EnsemblMetazoa
+ * @param accession
+ * e.g. ENST00000592782, Y55B1AR.1.1
+ * @param start
+ * @param end
+ * @return
+ */
+ public GeneLociI getCdnaMapping(String division, String accession,
+ int start, int end)
+ {
+ return getIdMapping(division, accession, start, end, CDNA);
+ }
+
+ GeneLociI getIdMapping(String division, String accession, int start,
+ int end, String cdsOrCdna)
+ {
+ URL url = null;
+ BufferedReader br = null;
+
+ try
+ {
+ String domain = new EnsemblInfo().getDomain(division);
+ if (domain != null)
+ {
+ url = getIdMapUrl(domain, accession, start, end, cdsOrCdna);
+ br = getHttpResponse(url, null);
+ if (br != null)
+ {
+ return (parseIdMappingResponse(br, accession, domain));
+ }
+ }
+ return null;
+ } catch (Throwable t)
+ {
+ System.out.println("Error calling " + url + ": " + t.getMessage());
+ return null;
+ } finally
+ {
+ if (br != null)
+ {
+ try
+ {
+ br.close();
+ } catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Constructs a URL to the /map/cds/<id> or /map/cdna/<id> REST service. The
+ * REST call is to either ensembl or ensemblgenomes, as determined from the
+ * division, e.g. Ensembl or EnsemblProtists.
+ *
+ * @param domain
+ * @param accession
+ * @param start
+ * @param end
+ * @param cdsOrCdna
+ * @return
+ * @throws MalformedURLException
+ */
+ URL getIdMapUrl(String domain, String accession, int start, int end,
+ String cdsOrCdna) throws MalformedURLException
+ {
+ String url = String
+ .format("%s/map/%s/%s/%d..%d?include_original_region=1&content-type=application/json",
+ domain, cdsOrCdna, accession, start, end);
+ return new URL(url);
+ }
+
+ /**
+ * Parses the JSON response from the /map/cds/ or /map/cdna REST service. The
+ * format is
+ *
+ * <pre>
+ * {"mappings":
+ * [
+ * {"assembly_name":"TAIR10","end":2501311,"seq_region_name":"1","gap":0,
+ * "strand":-1,"coord_system":"chromosome","rank":0,"start":2501114},
+ * {"assembly_name":"TAIR10","end":2500815,"seq_region_name":"1","gap":0,
+ * "strand":-1,"coord_system":"chromosome","rank":0,"start":2500714}
+ * ]
+ * }
+ * </pre>
+ *
+ * @param br
+ * @param accession
+ * @param domain
+ * @return
+ */
+ GeneLociI parseIdMappingResponse(BufferedReader br, String accession,
+ String domain)
+ {
+ JSONParser jp = new JSONParser();
+
+ try
+ {
+ JSONObject parsed = (JSONObject) jp.parse(br);
+ JSONArray mappings = (JSONArray) parsed.get(MAPPINGS);
+
+ Iterator rvals = mappings.iterator();
+ String assembly = null;
+ String chromosome = null;
+ int fromEnd = 0;
+ List<int[]> regions = new ArrayList<>();
+
+ while (rvals.hasNext())
+ {
+ JSONObject val = (JSONObject) rvals.next();
+ JSONObject original = (JSONObject) val.get("original");
+ fromEnd = Integer.parseInt(original.get("end").toString());
+
+ JSONObject mapped = (JSONObject) val.get(MAPPED);
+ int start = Integer.parseInt(mapped.get("start").toString());
+ int end = Integer.parseInt(mapped.get("end").toString());
+ String ass = mapped.get("assembly_name").toString();
+ if (assembly != null && !assembly.equals(ass))
+ {
+ System.err
+ .println("EnsemblMap found multiple assemblies - can't resolve");
+ return null;
+ }
+ assembly = ass;
+ String chr = mapped.get("seq_region_name").toString();
+ if (chromosome != null && !chromosome.equals(chr))
+ {
+ System.err
+ .println("EnsemblMap found multiple chromosomes - can't resolve");
+ return null;
+ }
+ chromosome = chr;
+ String strand = mapped.get("strand").toString();
+ if ("-1".equals(strand))
+ {
+ regions.add(new int[] { end, start });
+ }
+ else
+ {
+ regions.add(new int[] { start, end });
+ }
+ }
+
+ /*
+ * processed all mapped regions on chromosome, assemble the result,
+ * having first fetched the species id for the accession
+ */
+ final String species = new EnsemblLookup(domain)
+ .getSpecies(accession);
+ final String as = assembly;
+ final String chr = chromosome;
+ List<int[]> fromRange = Collections.singletonList(new int[] { 1,
+ fromEnd });
+ final MapList map = new MapList(fromRange, regions, 1, 1);
+ return new GeneLociI()
+ {
+
+ @Override
+ public String getSpeciesId()
+ {
+ return species == null ? "" : species;
+ }
+
+ @Override
+ public String getAssemblyId()
+ {
+ return as;
+ }
+
+ @Override
+ public String getChromosomeId()
+ {
+ return chr;
+ }
+
+ @Override
+ public MapList getMap()
+ {
+ return map;
+ }
+ };
+ } catch (IOException | ParseException | NumberFormatException e)
+ {
+ // ignore
+ }
+
+ return null;
+ }
+
+}
import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+
+import java.util.ArrayList;
+import java.util.List;
import com.stevesoft.pat.Regex;
}
@Override
- protected boolean identifiesSequence(SequenceFeature sf, String accId)
+ protected List<SequenceFeature> getIdentifyingFeatures(SequenceI seq,
+ String accId)
{
- // not applicable - protein sequence is not a 'subset' of genomic sequence
- return false;
+ return new ArrayList<>();
}
@Override
*/
package jalview.ext.ensembl;
-import jalview.io.DataSourceType;
-import jalview.io.FileParse;
import jalview.util.StringUtils;
import java.io.BufferedReader;
* @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 = "6.0";
+ private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "7.0";
- private static final String LATEST_ENSEMBL_REST_VERSION = "6.1";
+ private static final String LATEST_ENSEMBL_REST_VERSION = "7.0";
private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
- private static Map<String, EnsemblInfo> domainData;
-
- // @see https://github.com/Ensembl/ensembl-rest/wiki/Output-formats
- private static final String PING_URL = "http://rest.ensembl.org/info/ping.json";
+ private static Map<String, EnsemblData> domainData;
private final static long AVAILABILITY_RETEST_INTERVAL = 10000L; // 10 seconds
static
{
domainData = new HashMap<>();
- domainData.put(ENSEMBL_REST,
- new EnsemblInfo(ENSEMBL_REST, LATEST_ENSEMBL_REST_VERSION));
- domainData.put(ENSEMBL_GENOMES_REST, new EnsemblInfo(
- ENSEMBL_GENOMES_REST, LATEST_ENSEMBLGENOMES_REST_VERSION));
+ domainData.put(DEFAULT_ENSEMBL_BASEURL,
+ new EnsemblData(DEFAULT_ENSEMBL_BASEURL, LATEST_ENSEMBL_REST_VERSION));
+ domainData.put(DEFAULT_ENSEMBL_GENOMES_BASEURL, new EnsemblData(
+ DEFAULT_ENSEMBL_GENOMES_BASEURL, LATEST_ENSEMBLGENOMES_REST_VERSION));
}
protected volatile boolean inProgress = false;
*/
public EnsemblRestClient()
{
- this(ENSEMBL_REST);
+ super();
+
+ /*
+ * initialise domain info lazily
+ */
+ if (!domainData.containsKey(ensemblDomain))
+ {
+ domainData.put(ensemblDomain,
+ new EnsemblData(ensemblDomain, LATEST_ENSEMBL_REST_VERSION));
+ }
+ if (!domainData.containsKey(ensemblGenomesDomain))
+ {
+ domainData.put(ensemblGenomesDomain, new EnsemblData(
+ ensemblGenomesDomain, LATEST_ENSEMBLGENOMES_REST_VERSION));
+ }
}
/**
protected abstract boolean useGetRequest();
/**
- * Return the desired value for the Content-Type request header
- *
- * @param multipleIds
+ * Returns the desired value for the Content-Type request header. Default is
+ * application/json, override if required to vary this.
*
* @return
* @see https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers
*/
- protected abstract String getRequestMimeType(boolean multipleIds);
+ protected String getRequestMimeType()
+ {
+ return "application/json";
+ }
/**
- * Return the desired value for the Accept request header
+ * Return the desired value for the Accept request header. Default is
+ * application/json, override if required to vary this.
*
* @return
* @see https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers
*/
- protected abstract String getResponseMimeType();
+ protected String getResponseMimeType()
+ {
+ return "application/json";
+ }
/**
* Checks Ensembl's REST 'ping' endpoint, and returns true if response
boolean checkEnsembl()
{
BufferedReader br = null;
+ String pingUrl = getDomain() + "/info/ping" + CONTENT_TYPE_JSON;
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_JSON);
+ URL ping = new URL(pingUrl);
/*
* expect {"ping":1} if ok
} catch (Throwable t)
{
System.err.println(
- "Error connecting to " + PING_URL + ": " + t.getMessage());
+ "Error connecting to " + pingUrl + ": " + t.getMessage());
} finally
{
if (br != null)
}
/**
- * returns a reader to a Fasta response from the Ensembl sequence endpoint
+ * Returns a reader to a (Json) response from the Ensembl sequence endpoint.
+ * If the request failed the return value may be null.
*
* @param ids
* @return
* @throws IOException
*/
- protected FileParse getSequenceReader(List<String> ids) throws IOException
+ protected BufferedReader getSequenceReader(List<String> ids)
+ throws IOException
{
URL url = getUrl(ids);
BufferedReader reader = getHttpResponse(url, ids);
- if (reader == null)
- {
- // request failed
- return null;
- }
- FileParse fp = new FileParse(reader, url.toString(),
- DataSourceType.URL);
- return fp;
+ return reader;
}
/**
}
/**
- * Sends the HTTP request and gets the response as a reader
+ * Sends the HTTP request and gets the response as a reader. Returns null if
+ * the HTTP response code was not 200.
*
* @param url
* @param ids
* in milliseconds
* @return
* @throws IOException
- * if response code was not 200, or other I/O error
*/
protected BufferedReader getHttpResponse(URL url, List<String> ids,
int readTimeout) throws IOException
boolean multipleIds = ids != null && ids.size() > 1;
connection.setRequestMethod(
multipleIds ? HttpMethod.POST : HttpMethod.GET);
- connection.setRequestProperty("Content-Type",
- getRequestMimeType(multipleIds));
+ connection.setRequestProperty("Content-Type", getRequestMimeType());
connection.setRequestProperty("Accept", getResponseMimeType());
connection.setUseCaches(false);
*/
protected boolean isEnsemblAvailable()
{
- EnsemblInfo info = domainData.get(getDomain());
+ EnsemblData info = domainData.get(getDomain());
long now = System.currentTimeMillis();
*/
private void checkEnsemblRestVersion()
{
- EnsemblInfo info = domainData.get(getDomain());
+ EnsemblData info = domainData.get(getDomain());
JSONParser jp = new JSONParser();
URL url = null;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
import jalview.datamodel.Mapping;
+import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.datamodel.features.SequenceFeatures;
import jalview.exceptions.JalviewException;
-import jalview.io.FastaFile;
-import jalview.io.FileParse;
+import jalview.io.gff.Gff3Helper;
import jalview.io.gff.SequenceOntologyFactory;
import jalview.io.gff.SequenceOntologyI;
import jalview.util.Comparison;
import jalview.util.IntRangeComparator;
import jalview.util.MapList;
+import java.io.BufferedReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
+
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
/**
* Base class for Ensembl sequence fetchers
*/
public abstract class EnsemblSeqProxy extends EnsemblRestClient
{
- private static final String ALLELES = "alleles";
-
- protected static final String PARENT = "Parent";
-
- protected static final String ID = "ID";
-
protected static final String NAME = "Name";
protected static final String DESCRIPTION = "description";
try
{
/*
- * get 'dummy' genomic sequence with exon, cds and variation features
+ * get 'dummy' genomic sequence with gene, transcript,
+ * exon, cds and variation features
*/
SequenceI genomicSequence = null;
EnsemblFeatures gffFetcher = new EnsemblFeatures(getDomain());
/*
* transfer features to the query sequence
*/
- SequenceI querySeq = alignment.findName(accId);
+ SequenceI querySeq = alignment.findName(accId, true);
if (transferFeatures(accId, genomicSequence, querySeq))
{
inProgress = false;
throw new JalviewException("ENSEMBL Rest API not available.");
}
- FileParse fp = getSequenceReader(ids);
- if (fp == null)
+ BufferedReader br = getSequenceReader(ids);
+ if (br == null)
{
return alignment;
}
- FastaFile fr = new FastaFile(fp);
- if (fr.hasWarningMessage())
+ List<SequenceI> seqs = parseSequenceJson(br);
+
+ if (seqs.isEmpty())
{
- System.out.println(
- String.format("Warning when retrieving %d ids %s\n%s",
- ids.size(), ids.toString(), fr.getWarningMessage()));
+ throw new IOException("No data returned for " + ids);
}
- else if (fr.getSeqs().size() != ids.size())
+
+ if (seqs.size() != ids.size())
{
System.out.println(String.format(
"Only retrieved %d sequences for %d query strings",
- fr.getSeqs().size(), ids.size()));
- }
-
- if (fr.getSeqs().size() == 1 && fr.getSeqs().get(0).getLength() == 0)
- {
- /*
- * POST request has returned an empty FASTA file e.g. for invalid id
- */
- throw new IOException("No data returned for " + ids);
+ seqs.size(), ids.size()));
}
- if (fr.getSeqs().size() > 0)
+ if (!seqs.isEmpty())
{
- AlignmentI seqal = new Alignment(fr.getSeqsAsArray());
- for (SequenceI sq : seqal.getSequences())
+ AlignmentI seqal = new Alignment(
+ seqs.toArray(new SequenceI[seqs.size()]));
+ for (SequenceI seq : seqs)
{
- if (sq.getDescription() == null)
+ if (seq.getDescription() == null)
{
- sq.setDescription(getDbName());
+ seq.setDescription(getDbName());
}
- String name = sq.getName();
+ String name = seq.getName();
if (ids.contains(name)
|| ids.contains(name.replace("ENSP", "ENST")))
{
- DBRefEntry dbref = DBRefUtils.parseToDbRef(sq, getDbSource(),
+ // TODO JAL-3077 use true accession version in dbref
+ DBRefEntry dbref = DBRefUtils.parseToDbRef(seq, getDbSource(),
getEnsemblDataVersion(), name);
- sq.addDBRef(dbref);
+ seq.addDBRef(dbref);
}
}
if (alignment == null)
}
/**
+ * Parses a JSON response for a single sequence ID query
+ *
+ * @param br
+ * @return a single jalview.datamodel.Sequence
+ * @see http://rest.ensembl.org/documentation/info/sequence_id
+ */
+ protected List<SequenceI> parseSequenceJson(BufferedReader br)
+ {
+ JSONParser jp = new JSONParser();
+ List<SequenceI> result = new ArrayList<>();
+ try
+ {
+ /*
+ * for now, assumes only one sequence returned; refactor if needed
+ * in future to handle a JSONArray with more than one
+ */
+ final JSONObject val = (JSONObject) jp.parse(br);
+ Object s = val.get("desc");
+ String desc = s == null ? null : s.toString();
+ s = val.get("id");
+ String id = s == null ? null : s.toString();
+ s = val.get("seq");
+ String seq = s == null ? null : s.toString();
+ Sequence sequence = new Sequence(id, seq);
+ if (desc != null)
+ {
+ sequence.setDescription(desc);
+ }
+ // todo JAL-3077 make a DBRefEntry with true accession version
+ // s = val.get("version");
+ // String version = s == null ? "0" : s.toString();
+ // DBRefEntry dbref = new DBRefEntry(getDbSource(), version, id);
+ // sequence.addDBRef(dbref);
+ result.add(sequence);
+ } catch (ParseException | IOException e)
+ {
+ System.err.println("Error processing JSON response: " + e.toString());
+ // ignore
+ }
+ return result;
+ }
+
+ /**
* Returns the URL for the REST call
*
* @return
}
// @see https://github.com/Ensembl/ensembl-rest/wiki/Output-formats
urlstring.append("?type=").append(getSourceEnsemblType().getType());
- urlstring.append(("&Accept=text/x-fasta"));
+ urlstring.append(("&Accept=application/json"));
+ urlstring.append(("&Content-Type=application/json"));
- Map<String, String> params = getAdditionalParameters();
- if (params != null)
+ String objectType = getObjectType();
+ if (objectType != null)
{
- for (Entry<String, String> entry : params.entrySet())
- {
- urlstring.append("&").append(entry.getKey()).append("=")
- .append(entry.getValue());
- }
+ urlstring.append("&").append(OBJECT_TYPE).append("=")
+ .append(objectType);
}
URL url = new URL(urlstring.toString());
}
/**
- * Override this method to add any additional x=y URL parameters needed
+ * Override this method to specify object_type request parameter
*
* @return
*/
- protected Map<String, String> getAdditionalParameters()
+ protected String getObjectType()
{
return null;
}
return false;
}
- @Override
- protected String getRequestMimeType(boolean multipleIds)
- {
- return multipleIds ? "application/json" : "text/x-fasta";
- }
-
- @Override
- protected String getResponseMimeType()
- {
- return "text/x-fasta";
- }
-
/**
*
* @return the configured sequence return type for this source
protected MapList getGenomicRangesFromFeatures(SequenceI sourceSequence,
String accId, int start)
{
- // SequenceFeature[] sfs = sourceSequence.getSequenceFeatures();
- List<SequenceFeature> sfs = sourceSequence.getFeatures()
- .getPositionalFeatures();
+ List<SequenceFeature> sfs = getIdentifyingFeatures(sourceSequence,
+ accId);
if (sfs.isEmpty())
{
return null;
* generously initial size for number of cds regions
* (worst case titin Q8WZ42 has c. 313 exons)
*/
- List<int[]> regions = new ArrayList<int[]>(100);
+ List<int[]> regions = new ArrayList<>(100);
int mappedLength = 0;
int direction = 1; // forward
boolean directionSet = false;
for (SequenceFeature sf : sfs)
{
+ int strand = sf.getStrand();
+ strand = strand == 0 ? 1 : strand; // treat unknown as forward
+
+ if (directionSet && strand != direction)
+ {
+ // abort - mix of forward and backward
+ System.err
+ .println("Error: forward and backward strand for " + accId);
+ return null;
+ }
+ direction = strand;
+ directionSet = true;
+
/*
- * accept the target feature type or a specialisation of it
- * (e.g. coding_exon for exon)
+ * add to CDS ranges, semi-sorted forwards/backwards
*/
- if (identifiesSequence(sf, accId))
+ if (strand < 0)
{
- int strand = sf.getStrand();
- strand = strand == 0 ? 1 : strand; // treat unknown as forward
-
- if (directionSet && strand != direction)
- {
- // abort - mix of forward and backward
- System.err.println(
- "Error: forward and backward strand for " + accId);
- return null;
- }
- direction = strand;
- directionSet = true;
-
- /*
- * add to CDS ranges, semi-sorted forwards/backwards
- */
- if (strand < 0)
- {
- regions.add(0, new int[] { sf.getEnd(), sf.getBegin() });
- }
- else
- {
- regions.add(new int[] { sf.getBegin(), sf.getEnd() });
- }
- mappedLength += Math.abs(sf.getEnd() - sf.getBegin() + 1);
-
- if (!isSpliceable())
- {
- /*
- * 'gene' sequence is contiguous so we can stop as soon as its
- * identifying feature has been found
- */
- break;
- }
+ regions.add(0, new int[] { sf.getEnd(), sf.getBegin() });
+ }
+ else
+ {
+ regions.add(new int[] { sf.getBegin(), sf.getEnd() });
}
+ mappedLength += Math.abs(sf.getEnd() - sf.getBegin() + 1);
}
if (regions.isEmpty())
}
/**
- * Answers true if the sequence being retrieved may occupy discontiguous
- * regions on the genomic sequence.
- */
- protected boolean isSpliceable()
- {
- return true;
- }
-
- /**
- * Returns true if the sequence feature marks positions of the genomic
+ * Answers a list of sequence features that mark positions of the genomic
* sequence feature which are within the sequence being retrieved. For
* example, an 'exon' feature whose parent is the target transcript marks the
- * cdna positions of the transcript.
+ * cdna positions of the transcript. For a gene sequence, this is trivially
+ * just the 'gene' feature with matching gene id.
*
- * @param sf
+ * @param seq
* @param accId
* @return
*/
- protected abstract boolean identifiesSequence(SequenceFeature sf,
- String accId);
+ protected abstract List<SequenceFeature> getIdentifyingFeatures(
+ SequenceI seq, String accId);
/**
* Transfers the sequence feature to the target sequence, locating its start
*/
static void reverseComplementAlleles(SequenceFeature sf)
{
- final String alleles = (String) sf.getValue(ALLELES);
+ final String alleles = (String) sf.getValue(Gff3Helper.ALLELES);
if (alleles == null)
{
return;
reverseComplementAllele(complement, allele);
}
String comp = complement.toString();
- sf.setValue(ALLELES, comp);
+ sf.setValue(Gff3Helper.ALLELES, comp);
sf.setDescription(comp);
/*
String atts = sf.getAttributes();
if (atts != null)
{
- atts = atts.replace(ALLELES + "=" + alleles, ALLELES + "=" + comp);
+ atts = atts.replace(Gff3Helper.ALLELES + "=" + alleles,
+ Gff3Helper.ALLELES + "=" + comp);
sf.setAttributes(atts);
}
}
{
String parent = (String) sf.getValue(PARENT);
// using contains to allow for prefix "gene:", "transcript:" etc
- if (parent != null && !parent.contains(identifier))
+ if (parent != null
+ && !parent.toUpperCase().contains(identifier.toUpperCase()))
{
// this genomic feature belongs to a different transcript
return false;
protected List<SequenceFeature> findFeatures(SequenceI sequence,
String term, String parentId)
{
- List<SequenceFeature> result = new ArrayList<SequenceFeature>();
+ List<SequenceFeature> result = new ArrayList<>();
List<SequenceFeature> sfs = sequence.getFeatures()
.getFeaturesByOntology(term);
for (SequenceFeature sf : sfs)
{
String parent = (String) sf.getValue(PARENT);
- if (parent != null && parent.equals(parentId))
+ if (parent != null && parent.equalsIgnoreCase(parentId))
{
result.add(sf);
}
*/
package jalview.ext.ensembl;
+import jalview.bin.Cache;
import jalview.datamodel.DBRefSource;
import jalview.ws.seqfetcher.DbSourceProxyImpl;
*/
abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl
{
+ // domain properties lookup keys:
+ protected static final String ENSEMBL_BASEURL = "ENSEMBL_BASEURL";
+
+ protected static final String ENSEMBL_GENOMES_BASEURL = "ENSEMBL_GENOMES_BASEURL";
+
+ // domain properties default values:
+ protected static final String DEFAULT_ENSEMBL_BASEURL = "https://rest.ensembl.org";
+
+ protected static final String DEFAULT_ENSEMBL_GENOMES_BASEURL = "https://rest.ensemblgenomes.org";
+
/*
* accepts ENSG/T/E/P with 11 digits
* or ENSMUSP or similar for other species
"(ENS([A-Z]{3}|)[GTEP]{1}[0-9]{11}$)" + "|"
+ "(CCDS[0-9.]{3,}$)");
- protected static final String ENSEMBL_GENOMES_REST = "http://rest.ensemblgenomes.org";
+ protected final String ensemblGenomesDomain;
+
+ protected final String ensemblDomain;
+
+ protected static final String OBJECT_TYPE_TRANSLATION = "Translation";
+
+ protected static final String OBJECT_TYPE_TRANSCRIPT = "Transcript";
+
+ protected static final String OBJECT_TYPE_GENE = "Gene";
- protected static final String ENSEMBL_REST = "http://rest.ensembl.org";
+ protected static final String PARENT = "Parent";
+
+ protected static final String JSON_ID = "id";
+
+ protected static final String OBJECT_TYPE = "object_type";
/*
* possible values for the 'feature' parameter of the /overlap REST service
constrained, regulatory
}
- private String domain = ENSEMBL_REST;
+ private String domain;
+
+ /**
+ * Constructor
+ */
+ public EnsemblSequenceFetcher()
+ {
+ /*
+ * the default domain names may be overridden in .jalview_properties;
+ * this allows an easy change from http to https in future if needed
+ */
+ ensemblDomain = Cache.getDefault(ENSEMBL_BASEURL,
+ DEFAULT_ENSEMBL_BASEURL);
+ ensemblGenomesDomain = Cache.getDefault(ENSEMBL_GENOMES_BASEURL,
+ DEFAULT_ENSEMBL_GENOMES_BASEURL);
+ domain = ensemblDomain;
+ }
@Override
public String getDbSource()
{
// NB ensure Uniprot xrefs are canonicalised from "Ensembl" to "ENSEMBL"
- if (ENSEMBL_GENOMES_REST.equals(getDomain()))
+ if (ensemblGenomesDomain.equals(getDomain()))
{
return DBRefSource.ENSEMBLGENOMES;
}
{
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
*
while (rvals.hasNext())
{
JSONObject val = (JSONObject) rvals.next();
- String id = val.get(ID).toString();
+ String id = val.get(JSON_ID).toString();
String type = val.get(TYPE).toString();
if (id != null && GENE.equals(type))
{
if (br != null)
{
String geneId = parseSymbolResponse(br);
- System.out.println(url + " returned " + geneId);
if (geneId != null && !result.contains(geneId))
{
result.add(geneId);
return true;
}
- @Override
- protected String getRequestMimeType(boolean multipleIds)
- {
- return "application/json";
- }
-
- @Override
- protected String getResponseMimeType()
- {
- return "application/json";
- }
-
/**
* Calls the Ensembl xrefs REST endpoint and retrieves any cross-references
* ("primary_id") for the given identifier (Ensembl accession id) and database
*/
public List<DBRefEntry> getCrossReferences(String identifier)
{
- List<DBRefEntry> result = new ArrayList<DBRefEntry>();
- List<String> ids = new ArrayList<String>();
+ List<DBRefEntry> result = new ArrayList<>();
+ List<String> ids = new ArrayList<>();
ids.add(identifier);
BufferedReader br = null;
throws IOException
{
JSONParser jp = new JSONParser();
- List<DBRefEntry> result = new ArrayList<DBRefEntry>();
+ List<DBRefEntry> result = new ArrayList<>();
try
{
JSONArray responses = (JSONArray) jp.parse(br);
*/
package jalview.ext.htsjdk;
-import htsjdk.samtools.SAMSequenceDictionary;
-import htsjdk.samtools.SAMSequenceRecord;
-import htsjdk.samtools.reference.ReferenceSequence;
-import htsjdk.samtools.reference.ReferenceSequenceFile;
-import htsjdk.samtools.reference.ReferenceSequenceFileFactory;
-import htsjdk.samtools.util.StringUtil;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
import java.io.File;
+import java.io.IOException;
import java.math.BigInteger;
+import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import htsjdk.samtools.SAMException;
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import htsjdk.samtools.reference.FastaSequenceIndexCreator;
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequenceFileFactory;
+import htsjdk.samtools.util.StringUtil;
+
/**
* a source of sequence data accessed via the HTSJDK
*
*/
public class HtsContigDb
{
-
private String name;
private File dbLocation;
private htsjdk.samtools.reference.ReferenceSequenceFile refFile = null;
- public HtsContigDb(String name, File descriptor) throws Exception
+ public static void createFastaSequenceIndex(Path path, boolean overwrite)
+ throws IOException
+ {
+ try
+ {
+ FastaSequenceIndexCreator.create(path, overwrite);
+ } catch (SAMException e)
+ {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ public HtsContigDb(String name, File descriptor)
{
if (descriptor.isFile())
{
initSource();
}
- private void initSource() throws Exception
+ public void close()
+ {
+ if (refFile != null)
+ {
+ try
+ {
+ refFile.close();
+ } catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ }
+
+ private void initSource()
{
if (refFile != null)
{
final ReferenceSequenceFile refSeqFile = ReferenceSequenceFileFactory
.getReferenceSequenceFile(f, truncate);
ReferenceSequence refSeq;
- List<SAMSequenceRecord> ret = new ArrayList<SAMSequenceRecord>();
- Set<String> sequenceNames = new HashSet<String>();
+ List<SAMSequenceRecord> ret = new ArrayList<>();
+ Set<String> sequenceNames = new HashSet<>();
for (int numSequences = 0; (refSeq = refSeqFile
.nextSequence()) != null; ++numSequences)
{
// ///// end of hts bits.
- SequenceI getSequenceProxy(String id)
+ /**
+ * Reads the contig with the given id and returns as a Jalview SequenceI object.
+ * Note the database must be indexed for this operation to succeed.
+ *
+ * @param id
+ * @return
+ */
+ public SequenceI getSequenceProxy(String id)
{
- if (!isValid())
+ if (!isValid() || !refFile.isIndexed())
{
+ System.err.println(
+ "Cannot read contig as file is invalid or not indexed");
return null;
}
ReferenceSequence sseq = refFile.getSequence(id);
return new Sequence(sseq.getName(), new String(sseq.getBases()));
}
+
+ public boolean isIndexed()
+ {
+ return refFile != null && refFile.isIndexed();
+ }
+
}
--- /dev/null
+package jalview.ext.htsjdk;
+
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.vcf.VCFFileReader;
+import htsjdk.variant.vcf.VCFHeader;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A thin wrapper for htsjdk classes to read either plain, or compressed, or
+ * compressed and indexed VCF files
+ */
+public class VCFReader implements Closeable, Iterable<VariantContext>
+{
+ private static final String GZ = "gz";
+
+ private static final String TBI_EXTENSION = ".tbi";
+
+ private boolean indexed;
+
+ private VCFFileReader reader;
+
+ /**
+ * Constructor given a raw or compressed VCF file or a (tabix) index file
+ * <p>
+ * For now, file type is inferred from its suffix: .gz or .bgz for compressed
+ * data, .tbi for an index file, anything else is assumed to be plain text
+ * VCF.
+ *
+ * @param f
+ * @throws IOException
+ */
+ public VCFReader(String filePath) throws IOException
+ {
+ if (filePath.endsWith(GZ))
+ {
+ if (new File(filePath + TBI_EXTENSION).exists())
+ {
+ indexed = true;
+ }
+ }
+ else if (filePath.endsWith(TBI_EXTENSION))
+ {
+ indexed = true;
+ filePath = filePath.substring(0, filePath.length() - 4);
+ }
+
+ reader = new VCFFileReader(new File(filePath), indexed);
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ if (reader != null)
+ {
+ reader.close();
+ }
+ }
+
+ /**
+ * Returns an iterator over VCF variants in the file. The client should call
+ * close() on the iterator when finished with it.
+ */
+ @Override
+ public CloseableIterator<VariantContext> iterator()
+ {
+ return reader == null ? null : reader.iterator();
+ }
+
+ /**
+ * Queries for records overlapping the region specified. Note that this method
+ * is performant if the VCF file is indexed, and may be very slow if it is
+ * not.
+ * <p>
+ * Client code should call close() on the iterator when finished with it.
+ *
+ * @param chrom
+ * the chromosome to query
+ * @param start
+ * query interval start
+ * @param end
+ * query interval end
+ * @return
+ */
+ public CloseableIterator<VariantContext> query(final String chrom,
+ final int start, final int end)
+ {
+ if (reader == null) {
+ return null;
+ }
+ if (indexed)
+ {
+ return reader.query(chrom, start, end);
+ }
+ else
+ {
+ return queryUnindexed(chrom, start, end);
+ }
+ }
+
+ /**
+ * Returns an iterator over variant records read from a flat file which
+ * overlap the specified chromosomal positions. Call close() on the iterator
+ * when finished with it!
+ *
+ * @param chrom
+ * @param start
+ * @param end
+ * @return
+ */
+ protected CloseableIterator<VariantContext> queryUnindexed(
+ final String chrom, final int start, final int end)
+ {
+ final CloseableIterator<VariantContext> it = reader.iterator();
+
+ return new CloseableIterator<VariantContext>()
+ {
+ boolean atEnd = false;
+
+ // prime look-ahead buffer with next matching record
+ private VariantContext next = findNext();
+
+ private VariantContext findNext()
+ {
+ if (atEnd)
+ {
+ return null;
+ }
+ VariantContext variant = null;
+ while (it.hasNext())
+ {
+ variant = it.next();
+ int vstart = variant.getStart();
+
+ if (vstart > end)
+ {
+ atEnd = true;
+ close();
+ return null;
+ }
+
+ int vend = variant.getEnd();
+ // todo what is the undeprecated way to get
+ // the chromosome for the variant?
+ if (chrom.equals(variant.getChr()) && (vstart <= end)
+ && (vend >= start))
+ {
+ return variant;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ boolean hasNext = !atEnd && (next != null);
+ if (!hasNext)
+ {
+ close();
+ }
+ return hasNext;
+ }
+
+ @Override
+ public VariantContext next()
+ {
+ /*
+ * return the next match, and then re-prime
+ * it with the following one (if any)
+ */
+ VariantContext temp = next;
+ next = findNext();
+ return temp;
+ }
+
+ @Override
+ public void remove()
+ {
+ // not implemented
+ }
+
+ @Override
+ public void close()
+ {
+ it.close();
+ }
+ };
+ }
+
+ /**
+ * Returns an object that models the VCF file headers
+ *
+ * @return
+ */
+ public VCFHeader getFileHeader()
+ {
+ return reader == null ? null : reader.getFileHeader();
+ }
+
+ /**
+ * Answers true if we are processing a tab-indexed VCF file, false if it is a
+ * plain text (uncompressed) file.
+ *
+ * @return
+ */
+ public boolean isIndex()
+ {
+ return indexed;
+ }
+}
lastCommand = command;
}
+ Thread colourby = null;
/**
* Sends a set of colour commands to the structure viewer
*
*/
@Override
protected void colourBySequence(
- StructureMappingcommandSet[] colourBySequenceCommands)
+ final StructureMappingcommandSet[] colourBySequenceCommands)
{
- for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
+ if (colourby != null)
{
- for (String cbyseq : cpdbbyseq.commands)
+ colourby.interrupt();
+ colourby = null;
+ }
+ colourby = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
{
- executeWhenReady(cbyseq);
+ for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
+ {
+ for (String cbyseq : cpdbbyseq.commands)
+ {
+ executeWhenReady(cbyseq);
+ }
+ }
}
- }
+ });
+ colourby.start();
}
/**
try
{
// recover PDB filename for the model hovered over.
- int _mp = _modelFileNameMap.length - 1,
- mnumber = new Integer(mdlId).intValue() - 1;
- while (mnumber < _modelFileNameMap[_mp])
+ int mnumber = new Integer(mdlId).intValue() - 1;
+ if (_modelFileNameMap != null)
{
- _mp--;
+ int _mp = _modelFileNameMap.length - 1;
+
+ while (mnumber < _modelFileNameMap[_mp])
+ {
+ _mp--;
+ }
+ pdbfilename = modelFileNames[_mp];
}
- pdbfilename = modelFileNames[_mp];
- if (pdbfilename == null)
+ else
{
- pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
- .getAbsolutePath();
- }
+ if (mnumber >= 0 && mnumber < modelFileNames.length)
+ {
+ pdbfilename = modelFileNames[mnumber];
+ }
+ if (pdbfilename == null)
+ {
+ pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
+ .getAbsolutePath();
+ }
+ }
} catch (Exception e)
{
}
return chainNames;
}
- protected abstract IProgressIndicator getIProgressIndicator();
+ protected IProgressIndicator getIProgressIndicator()
+ {
+ return null;
+ }
public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
{
continue;
}
- int lastPos = -1;
for (int s = 0; s < sequence[pdbfnum].length; s++)
{
for (int sp, m = 0; m < mapping.length; m++)
if (mapping[m].getSequence() == sequence[pdbfnum][s]
&& (sp = al.findIndex(sequence[pdbfnum][s])) > -1)
{
+ int lastPos = StructureMapping.UNASSIGNED_VALUE;
SequenceI asp = al.getSequenceAt(sp);
for (int r = 0; r < asp.getLength(); r++)
{
}
int pos = mapping[m].getPDBResNum(asp.findPosition(r));
- if (pos < 1 || pos == lastPos)
+ if (pos == lastPos)
{
continue;
}
+ if (pos == StructureMapping.UNASSIGNED_VALUE)
+ {
+ // terminate current colour op
+ if (command.length() > 0
+ && command.charAt(command.length() - 1) != ';')
+ {
+ command.append(";");
+ }
+ // reset lastPos
+ lastPos = StructureMapping.UNASSIGNED_VALUE;
+ continue;
+ }
lastPos = pos;
// TODO: deal with case when buffer is too large for Jmol to parse
// - execute command and flush
- command.append(";");
+ if (command.length() > 0
+ && command.charAt(command.length() - 1) != ';')
+ {
+ command.append(";");
+ }
+
if (command.length() > 51200)
{
// add another chunk
import jalview.io.FileParse;
import jalview.io.StructureFile;
import jalview.schemes.ResidueProperties;
-import jalview.structure.StructureImportSettings;
import jalview.util.Format;
import jalview.util.MessageManager;
{
Viewer viewer = null;
+ public JmolParser(boolean immediate, String inFile,
+ DataSourceType sourceType) throws IOException
+ {
+ super(immediate, inFile, sourceType);
+ }
+
public JmolParser(String inFile, DataSourceType sourceType)
throws IOException
{
}
lastID = tmpatom.resNumIns.trim();
}
- xferSettings();
+ if (isParseImmediately())
+ {
+ // configure parsing settings from the static singleton
+ xferSettings();
+ }
makeResidueList();
makeCaBondList();
prot.add(chainseq);
}
- if (StructureImportSettings.isProcessSecondaryStructure())
+ // look at local setting for adding secondary tructure
+ if (predictSecondaryStructure)
{
createAnnotation(chainseq, chain, ms.at);
}
public boolean equals(Object otherObject)
{
FTSDataColumnI that = (FTSDataColumnI) otherObject;
- return this.getCode().equals(that.getCode())
+ return otherObject == null ? false
+ : this.getCode().equals(that.getCode())
&& this.getName().equals(that.getName())
&& this.getGroup().equals(that.getGroup());
}
protected JTabbedPane tabs = new JTabbedPane();
protected IProgressIndicator progressIndicator;
- protected JComboBox<FTSDataColumnI> cmb_searchTarget = new JComboBox<FTSDataColumnI>();
+ protected JComboBox<FTSDataColumnI> cmb_searchTarget = new JComboBox<>();
protected JButton btn_ok = new JButton();
protected int pageLimit;
- protected HashSet<String> paginatorCart = new HashSet<String>();
+ protected HashSet<String> paginatorCart = new HashSet<>();
private static final int MIN_WIDTH = 670;
private void jbInit() throws Exception
{
- txt_search = new JvCacheableInputBox<String>(getCacheKey());
+ txt_search = new JvCacheableInputBox<>(getCacheKey());
populateCmbSearchTargetOptions();
Integer width = getTempUserPrefs().get("FTSPanel.width") == null ? 800
: getTempUserPrefs().get("FTSPanel.width");
if (tabs != null)
{
tabs.setOpaque(true);
- tabs.insertTab("Free Text Search", null, this, "", 0);
+ tabs.insertTab(MessageManager.getString("label.free_text_search"),
+ null, this, "", 0);
mainFrame.setContentPane(tabs);
tabs.setVisible(true);
}
*/
public void populateCmbSearchTargetOptions()
{
- List<FTSDataColumnI> searchableTargets = new ArrayList<FTSDataColumnI>();
+ List<FTSDataColumnI> searchableTargets = new ArrayList<>();
try
{
Collection<FTSDataColumnI> foundFTSTargets = getFTSRestClient()
package jalview.fts.service.uniprot;
+import jalview.bin.Cache;
import jalview.fts.api.FTSData;
import jalview.fts.api.FTSDataColumnI;
import jalview.fts.api.FTSRestClientI;
public class UniProtFTSRestClient extends FTSRestClient
{
+ private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org";
+
private static FTSRestClientI instance = null;
- public static final String UNIPROT_SEARCH_ENDPOINT = "http://www.uniprot.org/uniprot/?";
+ public final String uniprotSearchEndpoint;
+
+ public UniProtFTSRestClient()
+ {
+ super();
+ uniprotSearchEndpoint = Cache.getDefault("UNIPROT_DOMAIN",
+ DEFAULT_UNIPROT_DOMAIN) + "/uniprot/?";
+ }
@Override
public FTSRestResponse executeRequest(FTSRestRequest uniportRestRequest)
}
WebResource webResource = null;
- webResource = client.resource(UNIPROT_SEARCH_ENDPOINT)
+ webResource = client.resource(uniprotSearchEndpoint)
.queryParam("format", "tab")
.queryParam("columns", wantedFields)
.queryParam("limit", String.valueOf(responseSize))
String[] foundDataRow = uniProtTabDelimittedResponseString.split("\n");
if (foundDataRow != null && foundDataRow.length > 0)
{
- result = new ArrayList<FTSData>();
+ result = new ArrayList<>();
boolean firstRow = true;
for (String dataRow : foundDataRow)
{
import jalview.io.NewickFile;
import jalview.io.ScoreMatrixFile;
import jalview.io.TCoffeeScoreFile;
+import jalview.io.vcf.VCFLoader;
import jalview.jbgui.GAlignFrame;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemes;
AlignmentI al = getViewport().getAlignment();
boolean nucleotide = al.isNucleotide();
+ loadVcf.setVisible(nucleotide);
showTranslation.setVisible(nucleotide);
showReverse.setVisible(nucleotide);
showReverseComplement.setVisible(nucleotide);
@Override
public void exportFeatures_actionPerformed(ActionEvent e)
{
- new AnnotationExporter().exportFeatures(alignPanel);
+ new AnnotationExporter(alignPanel).exportFeatures();
}
@Override
public void exportAnnotations_actionPerformed(ActionEvent e)
{
- new AnnotationExporter().exportAnnotations(alignPanel);
+ new AnnotationExporter(alignPanel).exportAnnotations();
}
@Override
@Override
protected void copy_actionPerformed(ActionEvent e)
{
- System.gc();
if (viewport.getSelectionGroup() == null)
{
return;
return;
}
- ArrayList<int[]> hiddenColumns = null;
+ HiddenColumns hiddenColumns = null;
if (viewport.hasHiddenColumns())
{
- hiddenColumns = new ArrayList<>();
int hiddenOffset = viewport.getSelectionGroup().getStartRes();
int hiddenCutoff = viewport.getSelectionGroup().getEndRes();
- ArrayList<int[]> hiddenRegions = viewport.getAlignment()
- .getHiddenColumns().getHiddenColumnsCopy();
- for (int[] region : hiddenRegions)
- {
- if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
- {
- hiddenColumns
- .add(new int[]
- { region[0] - hiddenOffset, region[1] - hiddenOffset });
- }
- }
+
+ // create new HiddenColumns object with copy of hidden regions
+ // between startRes and endRes, offset by startRes
+ hiddenColumns = new HiddenColumns(
+ viewport.getAlignment().getHiddenColumns(), hiddenOffset,
+ hiddenCutoff, hiddenOffset);
}
Desktop.jalviewClipboard = new Object[] { seqs,
if (Desktop.jalviewClipboard != null
&& Desktop.jalviewClipboard[2] != null)
{
- List<int[]> hc = (List<int[]>) Desktop.jalviewClipboard[2];
- for (int[] region : hc)
- {
- af.viewport.hideColumns(region[0], region[1]);
- }
+ HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2];
+ af.viewport.setHiddenColumns(hc);
}
// >>>This is a fix for the moment, until a better solution is
if (Desktop.jalviewClipboard != null
&& Desktop.jalviewClipboard[2] != null)
{
- List<int[]> hc = (List<int[]>) Desktop.jalviewClipboard[2];
- for (int region[] : hc)
- {
- af.viewport.hideColumns(region[0], region[1]);
- }
+ HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2];
+ af.viewport.setHiddenColumns(hc);
}
// >>>This is a fix for the moment, until a better solution is
alignPanel.setOverviewPanel(null);
};
});
+ if (getKeyListeners().length > 0)
+ {
+ frame.addKeyListener(getKeyListeners()[0]);
+ }
alignPanel.setOverviewPanel(overview);
}
protected void showProductsFor(final SequenceI[] sel, final boolean _odna,
final String source)
{
- new Thread(CrossRefAction.showProductsFor(sel, _odna, source, this))
+ new Thread(CrossRefAction.getHandlerFor(sel, _odna, source, this))
.start();
}
int assocfiles = 0;
if (filesmatched.size() > 0)
{
- 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)
-
+ boolean autoAssociate = Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false);
+ if (!autoAssociate)
+ {
+ String msg = MessageManager.formatMessage(
+ "label.automatically_associate_structure_files_with_sequences_same_name",
+ new Object[]
+ { Integer.valueOf(filesmatched.size())
+ .toString() });
+ String ttl = MessageManager.getString(
+ "label.automatically_associate_structure_files_by_name");
+ int choice = JvOptionPane.showConfirmDialog(thisaf, msg,
+ ttl, JvOptionPane.YES_NO_OPTION);
+ autoAssociate = choice == JvOptionPane.YES_OPTION;
+ }
+ if (autoAssociate)
{
for (Object[] fm : filesmatched)
{
alignPanel.paintAlignment(true, false);
}
}
+ else
+ {
+ /*
+ * add declined structures as sequences
+ */
+ for (Object[] o : filesmatched)
+ {
+ filesnotmatched.add((String) o[0]);
+ }
+ }
}
if (filesnotmatched.size() > 0)
{
new JnetAnnotationMaker();
JnetAnnotationMaker.add_annotation(predictions,
viewport.getAlignment(), 0, false);
- SequenceI repseq = viewport.getAlignment().getSequenceAt(0);
- viewport.getAlignment().setSeqrep(repseq);
- HiddenColumns cs = new HiddenColumns();
- cs.hideInsertionsFor(repseq);
- viewport.getAlignment().setHiddenColumns(cs);
+ viewport.getAlignment().setupJPredAlignment();
isAnnotation = true;
}
// else if (IdentifyFile.FeaturesFile.equals(format))
MessageManager.getString("option.trim_retrieved_seqs"));
trimrs.setToolTipText(
MessageManager.getString("label.trim_retrieved_sequences"));
- trimrs.setSelected(Cache.getDefault("TRIM_FETCHED_DATASET_SEQS", true));
+ trimrs.setSelected(
+ Cache.getDefault(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES, true));
trimrs.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
trimrs.setSelected(trimrs.isSelected());
- Cache.setProperty("TRIM_FETCHED_DATASET_SEQS",
+ Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES,
Boolean.valueOf(trimrs.isSelected()).toString());
};
});
{
if (avc.createGroup())
{
+ if (applyAutoAnnotationSettings.isSelected())
+ {
+ alignPanel.updateAnnotation(true, false);
+ }
alignPanel.alignmentChanged();
}
}
new CalculationChooser(AlignFrame.this);
}
}
+
+ @Override
+ protected void loadVcf_actionPerformed()
+ {
+ JalviewFileChooser chooser = new JalviewFileChooser(
+ Cache.getProperty("LAST_DIRECTORY"));
+ chooser.setFileView(new JalviewFileView());
+ chooser.setDialogTitle(MessageManager.getString("label.load_vcf_file"));
+ chooser.setToolTipText(MessageManager.getString("label.load_vcf_file"));
+
+ int value = chooser.showOpenDialog(null);
+
+ if (value == JalviewFileChooser.APPROVE_OPTION)
+ {
+ String choice = chooser.getSelectedFile().getPath();
+ Cache.setProperty("LAST_DIRECTORY", choice);
+ SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
+ new VCFLoader(choice).loadVCF(seqs, this);
+ }
+
+ }
}
class PrintThread extends Thread
import jalview.analysis.AlignmentUtils;
import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
-import jalview.analysis.TreeModel;
import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureColourI;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.HiddenColumns;
-import jalview.datamodel.PDBEntry;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceGroup;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Rectangle;
-import java.util.ArrayList;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
-import java.util.Vector;
import javax.swing.JInternalFrame;
* area
* @return
*/
- public int[] getViewAsVisibleContigs(boolean selectedRegionOnly)
+ public Iterator<int[]> getViewAsVisibleContigs(boolean selectedRegionOnly)
{
- int[] viscontigs = null;
- int start = 0, end = 0;
+ int start = 0;
+ int end = 0;
if (selectedRegionOnly && selectionGroup != null)
{
start = selectionGroup.getStartRes();
{
end = alignment.getWidth();
}
- viscontigs = alignment.getHiddenColumns().getVisibleContigs(start, end);
- return viscontigs;
+ return (alignment.getHiddenColumns().getVisContigsIterator(start, end,
+ false));
}
/**
return validCharWidth;
}
- private Hashtable<String, AutoCalcSetting> calcIdParams = new Hashtable<String, AutoCalcSetting>();
+ private Hashtable<String, AutoCalcSetting> calcIdParams = new Hashtable<>();
public AutoCalcSetting getCalcIdSettingsFor(String calcId)
{
import jalview.structure.StructureSelectionManager;
import jalview.util.Comparison;
import jalview.util.MessageManager;
-import jalview.util.Platform;
import jalview.viewmodel.ViewportListenerI;
import jalview.viewmodel.ViewportRanges;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
-import java.awt.Insets;
+import java.awt.Graphics2D;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentAdapter;
if (av.hasHiddenColumns())
{
HiddenColumns hidden = av.getAlignment().getHiddenColumns();
- start = hidden.findColumnPosition(start);
- end = hidden.findColumnPosition(end);
+ start = hidden.absoluteToVisibleColumn(start);
+ end = hidden.absoluteToVisibleColumn(end);
if (start == end)
{
if (!hidden.isVisible(r[0]))
protected void validateAnnotationDimensions(boolean adjustPanelHeight)
{
int annotationHeight = getAnnotationPanel().adjustPanelHeight();
+ annotationHeight = getAnnotationPanel()
+ .adjustForAlignFrame(adjustPanelHeight, annotationHeight);
- if (adjustPanelHeight)
- {
- int rowHeight = av.getCharHeight();
- int alignmentHeight = rowHeight * av.getAlignment().getHeight();
-
- /*
- * Estimate available height in the AlignFrame for alignment +
- * annotations. Deduct an estimate for title bar, menu bar, scale panel,
- * hscroll, status bar (as these are not laid out we can't inspect their
- * actual heights). Insets gives frame borders.
- */
- int stuff = Platform.isAMac() ? 80 : 100;
- Insets insets = alignFrame.getInsets();
- int availableHeight = alignFrame.getHeight() - stuff - insets.top
- - insets.bottom;
-
- /*
- * If not enough vertical space, maximize annotation height while keeping
- * at least two rows of alignment visible
- */
- if (annotationHeight + alignmentHeight > availableHeight)
- {
- annotationHeight = Math.min(annotationHeight,
- availableHeight - 2 * rowHeight);
- }
- }
- else
- {
- // maintain same window layout whilst updating sliders
- annotationHeight = annotationScroller.getSize().height;
- }
hscroll.addNotify();
-
annotationScroller.setPreferredSize(
new Dimension(annotationScroller.getWidth(), annotationHeight));
{
annotationScroller.setVisible(true);
annotationSpaceFillerHolder.setVisible(true);
+ validateAnnotationDimensions(false);
}
int canvasWidth = getSeqPanel().seqCanvas.getWidth();
{
// reset the width to exclude hidden columns
width = av.getAlignment().getHiddenColumns()
- .findColumnPosition(width);
+ .absoluteToVisibleColumn(width);
}
hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
@Override
public void paintComponent(Graphics g)
{
- invalidate();
+ invalidate(); // needed so that the id width adjuster works correctly
Dimension d = getIdPanel().getIdCanvas().getPreferredSize();
idPanelHolder.setPreferredSize(d);
hscrollFillerPanel.setPreferredSize(new Dimension(d.width, 12));
- validate();
+
+ validate(); // needed so that the id width adjuster works correctly
/*
- * set scroll bar positions
+ * set scroll bar positions - tried to remove but necessary for split panel to resize correctly
+ * though I still think this call should be elsewhere.
*/
ViewportRanges ranges = av.getRanges();
setScrollValues(ranges.getStartRes(), ranges.getStartSeq());
}
/**
- * DOCUMENT ME!
- *
- * @param pg
- * DOCUMENT ME!
- * @param pwidth
- * DOCUMENT ME!
- * @param pheight
- * DOCUMENT ME!
- * @param pi
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- *
- * @throws PrinterException
- * DOCUMENT ME!
- */
- /**
* Draws the alignment image, including sequence ids, sequences, and
* annotation labels and annotations if shown, on either one or two Graphics
- * context.
+ * contexts.
*
* @param pageWidth
+ * in pixels
* @param pageHeight
- * @param pi
+ * in pixels
+ * @param pageIndex
+ * (0, 1, ...)
* @param idGraphics
* the graphics context for sequence ids and annotation labels
* @param alignmentGraphics
* @return
* @throws PrinterException
*/
- public int printUnwrapped(int pageWidth, int pageHeight, int pi,
+ public int printUnwrapped(int pageWidth, int pageHeight, int pageIndex,
Graphics idGraphics, Graphics alignmentGraphics)
throws PrinterException
{
: idWidth;
FontMetrics fm = getFontMetrics(av.getFont());
- int charHeight = av.getCharHeight();
- int scaleHeight = charHeight + fm.getDescent();
+ final int charHeight = av.getCharHeight();
+ final int scaleHeight = charHeight + fm.getDescent();
idGraphics.setColor(Color.white);
idGraphics.fillRect(0, 0, pageWidth, pageHeight);
/*
* How many sequences and residues can we fit on a printable page?
*/
- int totalRes = (pageWidth - idWidth) / av.getCharWidth();
-
- int totalSeq = (pageHeight - scaleHeight) / charHeight - 1;
-
- int alignmentWidth = av.getAlignment().getWidth();
- int pagesWide = (alignmentWidth / totalRes) + 1;
+ final int totalRes = (pageWidth - idWidth) / av.getCharWidth();
- final int startRes = (pi % pagesWide) * totalRes;
- int endRes = (startRes + totalRes) - 1;
+ final int totalSeq = (pageHeight - scaleHeight) / charHeight - 1;
- if (endRes > (alignmentWidth - 1))
- {
- endRes = alignmentWidth - 1;
- }
+ final int alignmentWidth = av.getAlignment().getWidth();
+ final int pagesWide = (alignmentWidth / totalRes) + 1;
- final int startSeq = (pi / pagesWide) * totalSeq;
- int endSeq = startSeq + totalSeq;
+ final int startRes = (pageIndex % pagesWide) * totalRes;
+ final int endRes = Math.min(startRes + totalRes - 1,
+ alignmentWidth - 1);
- int alignmentHeight = av.getAlignment().getHeight();
- if (endSeq > alignmentHeight)
- {
- endSeq = alignmentHeight;
- }
+ final int startSeq = (pageIndex / pagesWide) * totalSeq;
+ final int alignmentHeight = av.getAlignment().getHeight();
+ final int endSeq = Math.min(startSeq + totalSeq, alignmentHeight);
int pagesHigh = ((alignmentHeight / totalSeq) + 1) * pageHeight;
pagesHigh /= pageHeight;
- if (pi >= (pagesWide * pagesHigh))
+ if (pageIndex >= (pagesWide * pagesHigh))
{
return Printable.NO_SUCH_PAGE;
}
* then reset to top left (0, 0)
*/
idGraphics.translate(0, scaleHeight);
- idGraphics.setFont(getIdPanel().getIdCanvas().getIdfont());
- Color currentColor = null;
- Color currentTextColor = null;
-
- SequenceI seq;
- for (int i = startSeq; i < endSeq; i++)
- {
- seq = av.getAlignment().getSequenceAt(i);
- if ((av.getSelectionGroup() != null)
- && av.getSelectionGroup().getSequences(null).contains(seq))
- {
- /*
- * gray out ids of sequences in selection group (if any)
- */
- currentColor = Color.gray;
- currentTextColor = Color.black;
- }
- else
- {
- currentColor = av.getSequenceColour(seq);
- currentTextColor = Color.black;
- }
-
- idGraphics.setColor(currentColor);
- idGraphics.fillRect(0, (i - startSeq) * charHeight, idWidth,
- charHeight);
-
- idGraphics.setColor(currentTextColor);
+ IdCanvas idCanvas = getIdPanel().getIdCanvas();
+ List<SequenceI> selection = av.getSelectionGroup() == null ? null
+ : av.getSelectionGroup().getSequences(null);
+ idCanvas.drawIds((Graphics2D) idGraphics, av, startSeq, endSeq - 1,
+ selection);
- int xPos = 0;
- String displayId = seq.getDisplayId(av.getShowJVSuffix());
- if (av.isRightAlignIds())
- {
- fm = idGraphics.getFontMetrics();
- xPos = idWidth - fm.stringWidth(displayId) - 4;
- }
-
- idGraphics.drawString(displayId, xPos,
- (((i - startSeq) * charHeight) + charHeight)
- - (charHeight / 5));
- }
idGraphics.setFont(av.getFont());
idGraphics.translate(0, -scaleHeight);
*/
alignmentGraphics.translate(alignmentGraphicsOffset, scaleHeight);
getSeqPanel().seqCanvas.drawPanelForPrinting(alignmentGraphics, startRes,
- endRes, startSeq, endSeq);
+ endRes, startSeq, endSeq - 1);
alignmentGraphics.translate(-alignmentGraphicsOffset, 0);
if (av.isShowAnnotation() && (endSeq == alignmentHeight))
}
/**
- * DOCUMENT ME!
+ * Prints one page of an alignment in wrapped mode. Returns
+ * Printable.PAGE_EXISTS (0) if a page was drawn, or Printable.NO_SUCH_PAGE if
+ * no page could be drawn (page number out of range).
*
- * @param pg
- * DOCUMENT ME!
- * @param pwidth
- * DOCUMENT ME!
- * @param pheight
- * DOCUMENT ME!
- * @param pi
- * DOCUMENT ME!
+ * @param pageWidth
+ * @param pageHeight
+ * @param pageNumber
+ * (0, 1, ...)
+ * @param g
*
- * @return DOCUMENT ME!
+ * @return
*
* @throws PrinterException
- * DOCUMENT ME!
*/
- public int printWrappedAlignment(int pwidth, int pheight, int pi,
- Graphics pg) throws PrinterException
+ public int printWrappedAlignment(int pageWidth, int pageHeight, int pageNumber,
+ Graphics g) throws PrinterException
{
int annotationHeight = 0;
- AnnotationLabels labels = null;
if (av.isShowAnnotation())
{
annotationHeight = getAnnotationPanel().adjustPanelHeight();
- labels = new AnnotationLabels(av);
}
int hgap = av.getCharHeight();
if (av.hasHiddenColumns())
{
maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth) - 1;
+ .absoluteToVisibleColumn(maxwidth) - 1;
}
int resWidth = getSeqPanel().seqCanvas
- .getWrappedCanvasWidth(pwidth - idWidth);
+ .getWrappedCanvasWidth(pageWidth - idWidth);
int totalHeight = cHeight * (maxwidth / resWidth + 1);
- pg.setColor(Color.white);
- pg.fillRect(0, 0, pwidth, pheight);
- pg.setFont(av.getFont());
-
- // //////////////
- // Draw the ids
- pg.setColor(Color.black);
+ g.setColor(Color.white);
+ g.fillRect(0, 0, pageWidth, pageHeight);
+ g.setFont(av.getFont());
+ g.setColor(Color.black);
- pg.translate(0, -pi * pheight);
-
- pg.setClip(0, pi * pheight, pwidth, pheight);
-
- int ypos = hgap;
-
- do
- {
- for (int i = 0; i < av.getAlignment().getHeight(); i++)
- {
- pg.setFont(getIdPanel().getIdCanvas().getIdfont());
- SequenceI s = av.getAlignment().getSequenceAt(i);
- String string = s.getDisplayId(av.getShowJVSuffix());
- int xPos = 0;
- if (av.isRightAlignIds())
- {
- FontMetrics fm = pg.getFontMetrics();
- xPos = idWidth - fm.stringWidth(string) - 4;
- }
- pg.drawString(string, xPos,
- ((i * av.getCharHeight()) + ypos + av.getCharHeight())
- - (av.getCharHeight() / 5));
- }
- if (labels != null)
- {
- pg.translate(-3, ypos
- + (av.getAlignment().getHeight() * av.getCharHeight()));
+ /*
+ * method: print the whole wrapped alignment, but with a clip region that
+ * is restricted to the requested page; this supports selective print of
+ * single pages or ranges, (at the cost of some repeated processing in
+ * the 'normal' case, when all pages are printed)
+ */
+ g.translate(0, -pageNumber * pageHeight);
- pg.setFont(av.getFont());
- labels.drawComponent(pg, idWidth);
- pg.translate(+3, -ypos
- - (av.getAlignment().getHeight() * av.getCharHeight()));
- }
+ g.setClip(0, pageNumber * pageHeight, pageWidth, pageHeight);
- ypos += cHeight;
- } while (ypos < totalHeight);
+ /*
+ * draw sequence ids and annotation labels (if shown)
+ */
+ IdCanvas idCanvas = getIdPanel().getIdCanvas();
+ idCanvas.drawIdsWrapped((Graphics2D) g, av, 0, totalHeight);
- pg.translate(idWidth, 0);
+ g.translate(idWidth, 0);
- getSeqPanel().seqCanvas.drawWrappedPanelForPrinting(pg, pwidth - idWidth,
+ getSeqPanel().seqCanvas.drawWrappedPanelForPrinting(g, pageWidth - idWidth,
totalHeight, 0);
- if ((pi * pheight) < totalHeight)
+ if ((pageNumber * pageHeight) < totalHeight)
{
return Printable.PAGE_EXISTS;
-
}
else
{
if (av.hasHiddenColumns())
{
maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth);
+ .absoluteToVisibleColumn(maxwidth);
}
int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight())
if (av.hasHiddenColumns())
{
maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth) - 1;
+ .absoluteToVisibleColumn(maxwidth) - 1;
}
int height = ((maxwidth / chunkWidth) + 1) * cHeight;
*/
protected void scrollToCentre(SearchResultsI sr, int verticalOffset)
{
- /*
- * To avoid jumpy vertical scrolling (if some sequences are gapped or not
- * mapped), we can make the scroll-to location a sequence above the one
- * actually mapped.
- */
- SequenceI mappedTo = sr.getResults().get(0).getSequence();
- List<SequenceI> seqs = av.getAlignment().getSequences();
-
- /*
- * This is like AlignmentI.findIndex(seq) but here we are matching the
- * dataset sequence not the aligned sequence
- */
- boolean matched = false;
- for (SequenceI seq : seqs)
- {
- if (mappedTo == seq.getDatasetSequence())
- {
- matched = true;
- break;
- }
- }
- if (!matched)
- {
- return; // failsafe, shouldn't happen
- }
-
- /*
- * Scroll to position but centring the target residue.
- */
scrollToPosition(sr, verticalOffset, true, true);
}
}
}
+ @Override
+ protected void sliderDragReleased()
+ {
+ super.sliderDragReleased();
+ ap.paintAlignment(true, true);
+ }
+
}
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
-import java.util.ArrayList;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
{
HiddenColumns oldHidden = av.getAnnotationColumnSelectionState()
.getOldHiddenColumns();
- if (oldHidden != null)
- {
- ArrayList<int[]> regions = oldHidden.getHiddenColumnsCopy();
- for (int[] positions : regions)
- {
- av.hideColumns(positions[0], positions[1]);
- }
- }
- // TODO not clear why we need to hide all the columns (above) if we are
- // going to copy the hidden columns over wholesale anyway
av.getAlignment().setHiddenColumns(oldHidden);
}
av.sendSelection();
package jalview.gui;
import jalview.api.FeatureColourI;
+import jalview.bin.Cache;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.io.AnnotationFile;
import jalview.io.FeaturesFile;
import jalview.io.JalviewFileChooser;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.io.FileWriter;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
*/
public class AnnotationExporter extends JPanel
{
- JInternalFrame frame;
+ private JInternalFrame frame;
- AlignmentPanel ap;
+ private AlignmentPanel ap;
- boolean features = true;
+ /*
+ * true if exporting features, false if exporting annotations
+ */
+ private boolean exportFeatures = true;
private AlignmentAnnotation[] annotations;
private boolean wholeView;
- public AnnotationExporter()
+ public AnnotationExporter(AlignmentPanel panel)
{
+ this.ap = panel;
try
{
jbInit();
frame.getPreferredSize().height);
}
- public void exportFeatures(AlignmentPanel ap)
+ /**
+ * Configures the diglog for options to export visible features
+ */
+ public void exportFeatures()
{
- this.ap = ap;
- features = true;
+ exportFeatures = true;
CSVFormat.setVisible(false);
frame.setTitle(MessageManager.getString("label.export_features"));
}
- public void exportAnnotations(AlignmentPanel ap)
+ /**
+ * Configures the dialog for options to export all visible annotations
+ */
+ public void exportAnnotations()
{
- this.ap = ap;
- annotations = ap.av.isShowAnnotation() ? null
- : ap.av.getAlignment().getAlignmentAnnotation();
- wholeView = true;
- startExportAnnotation();
+ boolean showAnnotation = ap.av.isShowAnnotation();
+ exportAnnotation(showAnnotation ? null
+ : ap.av.getAlignment().getAlignmentAnnotation(), true);
}
- public void exportAnnotations(AlignmentPanel alp,
- AlignmentAnnotation[] toExport)
+ /**
+ * Configures the dialog for options to export the given annotation row
+ *
+ * @param toExport
+ */
+ public void exportAnnotation(AlignmentAnnotation toExport)
{
- ap = alp;
- annotations = toExport;
- wholeView = false;
- startExportAnnotation();
+ exportAnnotation(new AlignmentAnnotation[] { toExport }, false);
}
- private void startExportAnnotation()
+ private void exportAnnotation(AlignmentAnnotation[] toExport,
+ boolean forWholeView)
{
- features = false;
+ wholeView = forWholeView;
+ annotations = toExport;
+ exportFeatures = false;
GFFFormat.setVisible(false);
CSVFormat.setVisible(true);
frame.setTitle(MessageManager.getString("label.export_annotations"));
}
- public void toFile_actionPerformed(ActionEvent e)
+ private void toFile_actionPerformed()
{
JalviewFileChooser chooser = new JalviewFileChooser(
- jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+ Cache.getProperty("LAST_DIRECTORY"));
chooser.setFileView(new JalviewFileView());
- chooser.setDialogTitle(features
+ chooser.setDialogTitle(exportFeatures
? MessageManager.getString("label.save_features_to_file")
: MessageManager.getString("label.save_annotation_to_file"));
chooser.setToolTipText(MessageManager.getString("action.save"));
if (value == JalviewFileChooser.APPROVE_OPTION)
{
- String text = getFileContents();
+ String text = getText();
try
{
- java.io.PrintWriter out = new java.io.PrintWriter(
- new java.io.FileWriter(chooser.getSelectedFile()));
-
+ PrintWriter out = new PrintWriter(
+ new FileWriter(chooser.getSelectedFile()));
out.print(text);
out.close();
} catch (Exception ex)
}
}
- close_actionPerformed(null);
+ close_actionPerformed();
+ }
+
+ /**
+ * Answers the text to output for either Features (in GFF or Jalview format) or
+ * Annotations (in CSV or Jalview format)
+ *
+ * @return
+ */
+ private String getText()
+ {
+ return exportFeatures ? getFeaturesText() : getAnnotationsText();
}
- private String getFileContents()
+ /**
+ * Returns the text contents for output of annotations in either CSV or Jalview
+ * format
+ *
+ * @return
+ */
+ private String getAnnotationsText()
{
- String text = MessageManager
- .getString("label.no_features_on_alignment");
- if (features)
+ String text;
+ if (CSVFormat.isSelected())
{
- FeaturesFile formatter = new FeaturesFile();
- SequenceI[] sequences = ap.av.getAlignment().getSequencesArray();
- Map<String, FeatureColourI> featureColours = ap.getFeatureRenderer()
- .getDisplayedFeatureCols();
- List<String> featureGroups = ap.getFeatureRenderer()
- .getDisplayedFeatureGroups();
- boolean includeNonPositional = ap.av.isShowNPFeats();
- if (GFFFormat.isSelected())
- {
- text = formatter.printGffFormat(sequences, featureColours,
- featureGroups, includeNonPositional);
- }
- else
- {
- text = formatter.printJalviewFormat(sequences, featureColours,
- featureGroups, includeNonPositional);
- }
+ text = new AnnotationFile().printCSVAnnotations(annotations);
}
else
{
- if (CSVFormat.isSelected())
+ if (wholeView)
{
- text = new AnnotationFile().printCSVAnnotations(annotations);
+ text = new AnnotationFile().printAnnotationsForView(ap.av);
}
else
{
- if (wholeView)
- {
- text = new AnnotationFile().printAnnotationsForView(ap.av);
- }
- else
- {
- text = new AnnotationFile().printAnnotations(annotations, null,
- null);
- }
+ text = new AnnotationFile().printAnnotations(annotations, null,
+ null);
}
}
return text;
}
- public void toTextbox_actionPerformed(ActionEvent e)
+ /**
+ * Returns the text contents for output of features in either GFF or Jalview
+ * format
+ *
+ * @return
+ */
+ private String getFeaturesText()
+ {
+ String text;
+ SequenceI[] sequences = ap.av.getAlignment().getSequencesArray();
+ Map<String, FeatureColourI> featureColours = ap.getFeatureRenderer()
+ .getDisplayedFeatureCols();
+ Map<String, FeatureMatcherSetI> featureFilters = ap.getFeatureRenderer()
+ .getFeatureFilters();
+ List<String> featureGroups = ap.getFeatureRenderer()
+ .getDisplayedFeatureGroups();
+ boolean includeNonPositional = ap.av.isShowNPFeats();
+
+ FeaturesFile formatter = new FeaturesFile();
+ if (GFFFormat.isSelected())
+ {
+ text = formatter.printGffFormat(sequences, featureColours,
+ featureGroups, includeNonPositional);
+ }
+ else
+ {
+ text = formatter.printJalviewFormat(sequences, featureColours,
+ featureFilters, featureGroups, includeNonPositional);
+ }
+ return text;
+ }
+
+ private void toTextbox_actionPerformed()
{
CutAndPasteTransfer cap = new CutAndPasteTransfer();
try
{
- String text = getFileContents();
+ String text = getText();
cap.setText(text);
- Desktop.addInternalFrame(cap, (features ? MessageManager
+ Desktop.addInternalFrame(cap, (exportFeatures ? MessageManager
.formatMessage("label.features_for_params", new String[]
{ ap.alignFrame.getTitle() })
: MessageManager.formatMessage("label.annotations_for_params",
600, 500);
} catch (OutOfMemoryError oom)
{
- new OOMWarning((features ? MessageManager.formatMessage(
+ new OOMWarning((exportFeatures ? MessageManager.formatMessage(
"label.generating_features_for_params", new String[]
{ ap.alignFrame.getTitle() })
: MessageManager.formatMessage(
cap.dispose();
}
- close_actionPerformed(null);
+ close_actionPerformed();
}
- public void close_actionPerformed(ActionEvent e)
+ private void close_actionPerformed()
{
try
{
@Override
public void actionPerformed(ActionEvent e)
{
- toFile_actionPerformed(e);
+ toFile_actionPerformed();
}
});
toTextbox.setText(MessageManager.getString("label.to_textbox"));
@Override
public void actionPerformed(ActionEvent e)
{
- toTextbox_actionPerformed(e);
+ toTextbox_actionPerformed();
}
});
close.setText(MessageManager.getString("action.close"));
@Override
public void actionPerformed(ActionEvent e)
{
- close_actionPerformed(e);
+ close_actionPerformed();
}
});
jalviewFormat.setOpaque(false);
*/
package jalview.gui;
+import jalview.analysis.AlignSeq;
import jalview.analysis.AlignmentUtils;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.io.FileFormat;
import jalview.io.FormatAdapter;
+import jalview.util.Comparison;
import jalview.util.MessageManager;
+import jalview.util.Platform;
import java.awt.Color;
+import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.MediaTracker;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Iterator;
import java.util.regex.Pattern;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.ToolTipManager;
/**
- * DOCUMENT ME!
- *
- * @author $author$
- * @version $Revision$
+ * The panel that holds the labels for alignment annotations, providing
+ * tooltips, context menus, drag to reorder rows, and drag to adjust panel
+ * height
*/
public class AnnotationLabels extends JPanel
implements MouseListener, MouseMotionListener, ActionListener
{
+ /**
+ * width in pixels within which height adjuster arrows are shown and active
+ */
+ private static final int HEIGHT_ADJUSTER_WIDTH = 50;
+
+ /**
+ * height in pixels for allowing height adjuster to be active
+ */
+ private static int HEIGHT_ADJUSTER_HEIGHT = 10;
+
private static final Pattern LEFT_ANGLE_BRACKET_PATTERN = Pattern
.compile("<");
- String TOGGLE_LABELSCALE = MessageManager
+ private static final Font font = new Font("Arial", Font.PLAIN, 11);
+
+ private static final String TOGGLE_LABELSCALE = MessageManager
.getString("label.scale_label_to_column");
- String ADDNEW = MessageManager.getString("label.add_new_row");
+ private static final String ADDNEW = MessageManager
+ .getString("label.add_new_row");
- String EDITNAME = MessageManager
+ private static final String EDITNAME = MessageManager
.getString("label.edit_label_description");
- String HIDE = MessageManager.getString("label.hide_row");
+ private static final String HIDE = MessageManager
+ .getString("label.hide_row");
- String DELETE = MessageManager.getString("label.delete_row");
+ private static final String DELETE = MessageManager
+ .getString("label.delete_row");
- String SHOWALL = MessageManager.getString("label.show_all_hidden_rows");
+ private static final String SHOWALL = MessageManager
+ .getString("label.show_all_hidden_rows");
- String OUTPUT_TEXT = MessageManager.getString("label.export_annotation");
+ private static final String OUTPUT_TEXT = MessageManager
+ .getString("label.export_annotation");
- String COPYCONS_SEQ = MessageManager
+ private static final String COPYCONS_SEQ = MessageManager
.getString("label.copy_consensus_sequence");
- boolean resizePanel = false;
-
- Image image;
+ private final boolean debugRedraw = false;
- AlignmentPanel ap;
+ private AlignmentPanel ap;
AlignViewport av;
- boolean resizing = false;
-
- MouseEvent dragEvent;
+ private MouseEvent dragEvent;
- int oldY;
+ private int oldY;
- int selectedRow;
+ private int selectedRow;
private int scrollOffset = 0;
- Font font = new Font("Arial", Font.PLAIN, 11);
-
private boolean hasHiddenRows;
+ private boolean resizePanel = false;
+
/**
- * Creates a new AnnotationLabels object.
+ * Creates a new AnnotationLabels object
*
* @param ap
- * DOCUMENT ME!
*/
public AnnotationLabels(AlignmentPanel ap)
{
av = ap.av;
ToolTipManager.sharedInstance().registerComponent(this);
- java.net.URL url = getClass().getResource("/images/idwidth.gif");
- Image temp = null;
-
- if (url != null)
- {
- temp = java.awt.Toolkit.getDefaultToolkit().createImage(url);
- }
-
- try
- {
- MediaTracker mt = new MediaTracker(this);
- mt.addImage(temp, 0);
- mt.waitForID(0);
- } catch (Exception ex)
- {
- }
-
- BufferedImage bi = new BufferedImage(temp.getHeight(this),
- temp.getWidth(this), BufferedImage.TYPE_INT_RGB);
- Graphics2D g = (Graphics2D) bi.getGraphics();
- g.rotate(Math.toRadians(90));
- g.drawImage(temp, 0, -bi.getWidth(this), this);
- image = bi;
-
addMouseListener(this);
addMouseMotionListener(this);
addMouseWheelListener(ap.getAnnotationPanel());
}
else if (evt.getActionCommand().equals(OUTPUT_TEXT))
{
- new AnnotationExporter().exportAnnotations(ap,
- new AlignmentAnnotation[]
- { aa[selectedRow] });
+ new AnnotationExporter(ap).exportAnnotation(aa[selectedRow]);
}
else if (evt.getActionCommand().equals(COPYCONS_SEQ))
{
}
/**
- * DOCUMENT ME!
+ * Reorders annotation rows after a drag of a label
*
* @param evt
- * DOCUMENT ME!
*/
@Override
public void mouseReleased(MouseEvent evt)
getSelectedRow(evt.getY() - getScrollOffset());
int end = selectedRow;
+ /*
+ * if dragging to resize instead, start == end
+ */
if (start != end)
{
// Swap these annotations
}
/**
- * DOCUMENT ME!
- *
- * @param evt
- * DOCUMENT ME!
- */
- @Override
- public void mouseEntered(MouseEvent evt)
- {
- if (evt.getY() < 10)
- {
- resizePanel = true;
- repaint();
- }
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param evt
- * DOCUMENT ME!
+ * Removes the height adjuster image on leaving the panel, unless currently
+ * dragging it
*/
@Override
public void mouseExited(MouseEvent evt)
{
- if (dragEvent == null)
+ if (resizePanel && dragEvent == null)
{
resizePanel = false;
repaint();
}
/**
- * DOCUMENT ME!
+ * A mouse drag may be either an adjustment of the panel height (if flag
+ * resizePanel is set on), or a reordering of the annotation rows. The former
+ * is dealt with by this method, the latter in mouseReleased.
*
* @param evt
- * DOCUMENT ME!
*/
@Override
public void mouseDragged(MouseEvent evt)
}
/**
- * DOCUMENT ME!
+ * Updates the tooltip as the mouse moves over the labels
*
* @param evt
- * DOCUMENT ME!
*/
@Override
public void mouseMoved(MouseEvent evt)
{
- resizePanel = evt.getY() < 10;
+ showOrHideAdjuster(evt);
getSelectedRow(evt.getY() - getScrollOffset());
}
}
+ /**
+ * Shows the height adjuster image if the mouse moves into the top left
+ * region, or hides it if the mouse leaves the regio
+ *
+ * @param evt
+ */
+ protected void showOrHideAdjuster(MouseEvent evt)
+ {
+ boolean was = resizePanel;
+ resizePanel = evt.getY() < HEIGHT_ADJUSTER_HEIGHT && evt.getX() < HEIGHT_ADJUSTER_WIDTH;
+
+ if (resizePanel != was)
+ {
+ setCursor(Cursor.getPredefinedCursor(
+ resizePanel ? Cursor.S_RESIZE_CURSOR
+ : Cursor.DEFAULT_CURSOR));
+ repaint();
+ }
+ }
+
@Override
public void mouseClicked(MouseEvent evt)
{
// process modifiers
SequenceGroup sg = ap.av.getSelectionGroup();
if (sg == null || sg == aa[selectedRow].groupRef
- || !(jalview.util.Platform.isControlDown(evt)
- || evt.isShiftDown()))
+ || !(Platform.isControlDown(evt) || evt.isShiftDown()))
{
- if (jalview.util.Platform.isControlDown(evt)
- || evt.isShiftDown())
+ if (Platform.isControlDown(evt) || evt.isShiftDown())
{
// clone a new selection group from the associated group
ap.av.setSelectionGroup(
// we make a copy rather than edit the current selection if no
// modifiers pressed
// see Enhancement JAL-1557
- if (!(jalview.util.Platform.isControlDown(evt)
- || evt.isShiftDown()))
+ if (!(Platform.isControlDown(evt) || evt.isShiftDown()))
{
sg = new SequenceGroup(sg);
sg.clear();
}
else
{
- if (jalview.util.Platform.isControlDown(evt))
+ if (Platform.isControlDown(evt))
{
sg.addOrRemove(aa[selectedRow].sequenceRef, true);
}
if (dseqs[0] == null)
{
dseqs[0] = new Sequence(sq);
- dseqs[0].setSequence(jalview.analysis.AlignSeq.extractGaps(
- jalview.util.Comparison.GapChars, sq.getSequenceAsString()));
+ dseqs[0].setSequence(AlignSeq.extractGaps(Comparison.GapChars,
+ sq.getSequenceAsString()));
sq.setDatasetSequence(dseqs[0]);
}
Alignment ds = new Alignment(dseqs);
if (av.hasHiddenColumns())
{
- omitHidden = av.getAlignment().getHiddenColumns()
- .getVisibleSequenceStrings(0, sq.getLength(), seqs);
+ Iterator<int[]> it = av.getAlignment().getHiddenColumns()
+ .getVisContigsIterator(0, sq.getLength(), false);
+ omitHidden = new String[] { sq.getSequenceStringFromIterator(it) };
}
int[] alignmentStartEnd = new int[] { 0, ds.getWidth() - 1 };
Toolkit.getDefaultToolkit().getSystemClipboard()
.setContents(new StringSelection(output), Desktop.instance);
- ArrayList<int[]> hiddenColumns = null;
+ HiddenColumns hiddenColumns = null;
if (av.hasHiddenColumns())
{
- hiddenColumns = av.getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy();
+ hiddenColumns = new HiddenColumns(
+ av.getAlignment().getHiddenColumns());
}
Desktop.jalviewClipboard = new Object[] { seqs, ds, // what is the dataset
drawComponent(g, false, width);
}
- private final boolean debugRedraw = false;
-
/**
* Draw the full set of annotation Labels for the alignment at the given
* cursor
}
}
- if (resizePanel)
- {
- g.drawImage(image, 2, 0 - getScrollOffset(), this);
- }
- else if (dragEvent != null && aa != null)
+ if (!resizePanel && dragEvent != null && aa != null)
{
g.setColor(Color.lightGray);
g.drawString(aa[selectedRow].label, dragEvent.getX(),
{
return scrollOffset;
}
+
+ @Override
+ public void mouseEntered(MouseEvent e)
+ {
+ }
}
import jalview.schemes.ResidueProperties;
import jalview.util.Comparison;
import jalview.util.MessageManager;
+import jalview.util.Platform;
import jalview.viewmodel.ViewportListenerI;
import jalview.viewmodel.ViewportRanges;
if (e.isShiftDown())
{
e.consume();
- if (e.getWheelRotation() > 0)
+ double wheelRotation = e.getPreciseWheelRotation();
+ if (wheelRotation > 0)
{
av.getRanges().scrollRight(true);
}
- else
+ else if (wheelRotation < 0)
{
av.getRanges().scrollRight(false);
}
@Override
public Dimension getPreferredScrollableViewportSize()
{
- return getPreferredSize();
+ Dimension ps = getPreferredSize();
+ return new Dimension(ps.width, adjustForAlignFrame(false, ps.height));
}
@Override
if (av.hasHiddenColumns())
{
column = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(column);
+ .visibleToAbsoluteColumn(column);
}
AlignmentAnnotation ann = aa[row];
{
this.setToolTipText(JvSwingUtils.wrapTooltip(true, description));
}
+ else
+ {
+ this.setToolTipText(null); // no tooltip if null or empty description
+ }
}
else
{
@Override
public void paintComponent(Graphics g)
{
+ super.paintComponent(g);
+
g.setColor(Color.white);
g.fillRect(0, 0, getWidth(), getHeight());
gg.fillRect(0, 0, imgWidth, image.getHeight());
imageFresh = true;
}
-
+
drawComponent(gg, av.getRanges().getStartRes(),
av.getRanges().getEndRes() + 1);
imageFresh = false;
int er = av.getRanges().getEndRes() + 1;
int transX = 0;
- long stime = System.currentTimeMillis();
gg.copyArea(0, 0, imgWidth, getHeight(),
-horizontal * av.getCharWidth(), 0);
- long mtime = System.currentTimeMillis();
if (horizontal > 0) // scrollbar pulled right, image to the left
{
drawComponent(gg, sr, er);
gg.translate(-transX, 0);
- long dtime = System.currentTimeMillis();
+
fastPaint = true;
- repaint();
- long rtime = System.currentTimeMillis();
- if (debugRedraw)
- {
- System.err.println("Scroll:\t" + horizontal + "\tCopyArea:\t"
- + (mtime - stime) + "\tDraw component:\t" + (dtime - mtime)
- + "\tRepaint call:\t" + (rtime - dtime));
- }
+ // Call repaint on alignment panel so that repaints from other alignment
+ // panel components can be aggregated. Otherwise performance of the overview
+ // window and others may be adversely affected.
+ av.getAlignPanel().repaint();
}
private volatile boolean lastImageGood = false;
repaint();
}
}
+
+ /**
+ * computes the visible height of the annotation panel
+ *
+ * @param adjustPanelHeight
+ * - when false, just adjust existing height according to other
+ * windows
+ * @param annotationHeight
+ * @return height to use for the ScrollerPreferredVisibleSize
+ */
+ public int adjustForAlignFrame(boolean adjustPanelHeight,
+ int annotationHeight)
+ {
+ /*
+ * Estimate available height in the AlignFrame for alignment +
+ * annotations. Deduct an estimate for title bar, menu bar, scale panel,
+ * hscroll, status bar, insets.
+ */
+ int stuff = (ap.getViewName() != null ? 30 : 0)
+ + (Platform.isAMac() ? 120 : 140);
+ int availableHeight = ap.alignFrame.getHeight() - stuff;
+ int rowHeight = av.getCharHeight();
+
+ if (adjustPanelHeight)
+ {
+ int alignmentHeight = rowHeight * av.getAlignment().getHeight();
+
+ /*
+ * If not enough vertical space, maximize annotation height while keeping
+ * at least two rows of alignment visible
+ */
+ if (annotationHeight + alignmentHeight > availableHeight)
+ {
+ annotationHeight = Math.min(annotationHeight,
+ availableHeight - 2 * rowHeight);
+ }
+ }
+ else
+ {
+ // maintain same window layout whilst updating sliders
+ annotationHeight = Math.min(ap.annotationScroller.getSize().height,
+ availableHeight - 2 * rowHeight);
+ }
+ return annotationHeight;
+ }
}
@Override
public void mouseReleased(MouseEvent evt)
{
- if (sliderDragging)
- {
- sliderDragging = false;
- valueChanged(true);
- }
+ sliderDragReleased();
}
});
}
{
this.annotations = anns;
}
+
+ protected void sliderDragReleased()
+ {
+ if (sliderDragging)
+ {
+ sliderDragging = false;
+ valueChanged(true);
+ }
+ }
}
import java.util.Vector;
import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
private static final String SPACE = " ";
- private static final String BACKSLASH = "\"";
+ private static final String QUOTE = "\"";
AppJmolBinding jmb;
{
return progressBar;
}
+
/**
- * add a single PDB structure to a new or existing Jmol view
+ * display a single PDB structure in a new Jmol view
*
* @param pdbentry
* @param seq
final AlignmentPanel ap)
{
progressBar = ap.alignFrame;
- String pdbId = pdbentry.getId();
- /*
- * If the PDB file is already loaded, the user may just choose to add to an
- * existing viewer (or cancel)
- */
- if (addAlreadyLoadedFile(seq, chains, ap, pdbId))
- {
- return;
- }
-
- /*
- * Check if there are other Jmol views involving this alignment and prompt
- * user about adding this molecule to one of them
- */
- if (addToExistingViewer(pdbentry, seq, chains, ap, pdbId))
- {
- return;
- }
-
- /*
- * If the options above are declined or do not apply, open a new viewer
- */
- openNewJmol(ap, new PDBEntry[] { pdbentry }, new SequenceI[][] { seq });
+ openNewJmol(ap, alignAddedStructures, new PDBEntry[] { pdbentry },
+ new SequenceI[][]
+ { seq });
}
- private void openNewJmol(AlignmentPanel ap, PDBEntry[] pdbentrys,
+ private void openNewJmol(AlignmentPanel ap, boolean alignAdded,
+ PDBEntry[] pdbentrys,
SequenceI[][] seqs)
{
progressBar = ap.alignFrame;
addAlignmentPanel(ap);
useAlignmentPanelForColourbyseq(ap);
- if (pdbentrys.length > 1)
- {
- alignAddedStructures = true;
- useAlignmentPanelForSuperposition(ap);
- }
+ alignAddedStructures = alignAdded;
+ useAlignmentPanelForSuperposition(ap);
+
jmb.setColourBySequence(true);
setSize(400, 400); // probably should be a configurable/dynamic default here
initMenus();
}
/**
- * create a new Jmol containing several structures superimposed using the
- * given alignPanel.
+ * create a new Jmol containing several structures optionally superimposed
+ * using the given alignPanel.
*
* @param ap
+ * @param alignAdded
+ * - true to superimpose
* @param pe
* @param seqs
*/
- public AppJmol(AlignmentPanel ap, PDBEntry[] pe, SequenceI[][] seqs)
+ public AppJmol(AlignmentPanel ap, boolean alignAdded, PDBEntry[] pe,
+ SequenceI[][] seqs)
{
- openNewJmol(ap, pe, seqs);
+ openNewJmol(ap, alignAdded, pe, seqs);
}
- /**
- * Returns a list of any Jmol viewers. The list is restricted to those linked
- * to the given alignment panel if it is not null.
- */
- @Override
- protected List<StructureViewerBase> getViewersFor(AlignmentPanel apanel)
- {
- List<StructureViewerBase> result = new ArrayList<>();
- JInternalFrame[] frames = Desktop.instance.getAllFrames();
-
- for (JInternalFrame frame : frames)
- {
- if (frame instanceof AppJmol)
- {
- if (apanel == null
- || ((StructureViewerBase) frame).isLinkedWith(apanel))
- {
- result.add((StructureViewerBase) frame);
- }
- }
- }
- return result;
- }
void initJmol(String command)
{
jmb.setFinishedInit(true);
}
- boolean allChainsSelected = false;
-
@Override
void showSelectedChains()
{
StringBuilder fileList = new StringBuilder();
for (String s : files)
{
- fileList.append(SPACE).append(BACKSLASH)
- .append(Platform.escapeString(s)).append(BACKSLASH);
+ fileList.append(SPACE).append(QUOTE)
+ .append(Platform.escapeString(s)).append(QUOTE);
}
String filesString = fileList.toString();
jmb.updateColours(ap);
}
// do superposition if asked to
- if (Cache.getDefault("AUTOSUPERIMPOSE", true) && alignAddedStructures)
+ if (alignAddedStructures)
{
alignAddedStructures();
}
}
}
});
- alignAddedStructures = false;
+
}
/**
String file = jmb.getPdbEntry(pi).getFile();
if (file == null)
{
+ // todo: extract block as method and pull up (also ChimeraViewFrame)
// retrieve the pdb and store it locally
AlignmentI pdbseq = null;
pdbid = jmb.getPdbEntry(pi).getId();
}
}
+ /**
+ * highlight a region from start to end (inclusive) on rna
+ *
+ * @param rna
+ * @param start
+ * - first base pair index (from 0)
+ * @param end
+ * - last base pair index (from 0)
+ */
public void highlightRegion(RNA rna, int start, int end)
{
clearLastSelection();
RnaModel rnaModel = models.get(rna);
if (rnaModel.seq == sequence)
{
- int highlightPos = rnaModel.gapped ? index : position - 1;
+ int highlightPos = rnaModel.gapped ? index
+ : position - sequence.getStart();
mouseOverHighlighter.highlightRegion(rna, highlightPos, highlightPos);
vab.updateSelectedRNA(rna);
}
{
return;
}
- if (seqsel != null && seqsel.getSize() > 0)
+
+ RnaModel rnaModel = models.get(rna);
+
+ if (seqsel != null && seqsel.getSize() > 0
+ && seqsel.contains(rnaModel.seq))
{
int start = seqsel.getStartRes(), end = seqsel.getEndRes();
- ShiftList shift = offsets.get(rna);
- if (shift != null)
+ if (rnaModel.gapped)
{
- start = shift.shift(start);
- end = shift.shift(end);
+ ShiftList shift = offsets.get(rna);
+ if (shift != null)
+ {
+ start = shift.shift(start);
+ end = shift.shift(end);
+ }
}
+ else
+ {
+ start = rnaModel.seq.findPosition(start) - rnaModel.seq.getStart();
+ end = rnaModel.seq.findPosition(end) - rnaModel.seq.getStart();
+ }
+
selectionHighlighter.highlightRegion(rna, start, end);
selectionHighlighter.getLastHighlight()
.setOutlineColor(seqsel.getOutlineColour());
* around to the bottom of the window stack (as the original implementation
* does)
*
- * @see com.sun.java.swing.plaf.windows.WindowsDesktopManager
+ * see com.sun.java.swing.plaf.windows.WindowsDesktopManager
*/
public class AquaInternalFrameManager extends DefaultDesktopManager
{
super.activateFrame(f);
}
- // If this is the first activation, add to child list.
- if (fChildFrames.indexOf(f) == -1)
+ // add or relocate to top of stack
+ if (fChildFrames.indexOf(f) != -1)
{
- fChildFrames.addElement(f);
+ fChildFrames.remove(f);
}
+ fChildFrames.addElement(f);
if (fCurrentFrame != null && f != fCurrentFrame)
{
{
switchFrame(false);
}
-}
\ No newline at end of file
+}
JPanel treePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
treePanel.setOpaque(false);
- treePanel.setBorder(BorderFactory
- .createTitledBorder(MessageManager.getString("label.tree")));
+ JvSwingUtils.createTitledBorder(treePanel,
+ MessageManager.getString("label.tree"), true);
// then copy the inset dimensions for the border-less PCA panel
JPanel pcaBorderless = new JPanel(new FlowLayout(FlowLayout.LEFT));
savemenu.setVisible(false); // not yet implemented
viewMenu.add(fitToWindow);
- /*
- * exchange of Jalview features and Chimera attributes is for now
- * an optionally enabled experimental feature
- */
- if (Desktop.instance.showExperimental())
+ JMenuItem writeFeatures = new JMenuItem(
+ MessageManager.getString("label.create_chimera_attributes"));
+ writeFeatures.setToolTipText(MessageManager
+ .getString("label.create_chimera_attributes_tip"));
+ writeFeatures.addActionListener(new ActionListener()
{
- JMenuItem writeFeatures = new JMenuItem(
- MessageManager.getString("label.create_chimera_attributes"));
- writeFeatures.setToolTipText(MessageManager
- .getString("label.create_chimera_attributes_tip"));
- writeFeatures.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- sendFeaturesToChimera();
- }
- });
- viewerActionMenu.add(writeFeatures);
-
- final JMenu fetchAttributes = new JMenu(
- MessageManager.getString("label.fetch_chimera_attributes"));
- fetchAttributes.setToolTipText(MessageManager
- .getString("label.fetch_chimera_attributes_tip"));
- fetchAttributes.addMouseListener(new MouseAdapter()
+ @Override
+ public void actionPerformed(ActionEvent e)
{
+ sendFeaturesToChimera();
+ }
+ });
+ viewerActionMenu.add(writeFeatures);
- @Override
- public void mouseEntered(MouseEvent e)
- {
- buildAttributesMenu(fetchAttributes);
- }
- });
- viewerActionMenu.add(fetchAttributes);
- }
+ final JMenu fetchAttributes = new JMenu(
+ MessageManager.getString("label.fetch_chimera_attributes"));
+ fetchAttributes.setToolTipText(
+ MessageManager.getString("label.fetch_chimera_attributes_tip"));
+ fetchAttributes.addMouseListener(new MouseAdapter()
+ {
+
+ @Override
+ public void mouseEntered(MouseEvent e)
+ {
+ buildAttributesMenu(fetchAttributes);
+ }
+ });
+ viewerActionMenu.add(fetchAttributes);
}
/**
}
/**
- * add a single PDB structure to a new or existing Chimera view
+ * open a single PDB structure in a new Chimera view
*
* @param pdbentry
* @param seq
String[] chains, final AlignmentPanel ap)
{
this();
- String pdbId = pdbentry.getId();
-
- /*
- * If the PDB file is already loaded, the user may just choose to add to an
- * existing viewer (or cancel)
- */
- if (addAlreadyLoadedFile(seq, chains, ap, pdbId))
- {
- return;
- }
- /*
- * Check if there are other Chimera views involving this alignment and give
- * user the option to add and align this molecule to one of them (or cancel)
- */
- if (addToExistingViewer(pdbentry, seq, chains, ap, pdbId))
- {
- return;
- }
-
- /*
- * If the options above are declined or do not apply, show the structure in
- * a new viewer
- */
openNewChimera(ap, new PDBEntry[] { pdbentry },
new SequenceI[][]
{ seq });
if (pdbentrys.length > 1)
{
- alignAddedStructures = true;
useAlignmentPanelForSuperposition(ap);
}
jmb.setColourBySequence(true);
}
/**
- * create a new viewer containing several structures superimposed using the
- * given alignPanel.
+ * create a new viewer containing several structures, optionally superimposed
+ * using the given alignPanel.
*
* @param pe
* @param seqs
* @param ap
*/
- public ChimeraViewFrame(PDBEntry[] pe, SequenceI[][] seqs,
+ public ChimeraViewFrame(PDBEntry[] pe, boolean alignAdded,
+ SequenceI[][] seqs,
AlignmentPanel ap)
{
this();
+ setAlignAddedStructures(alignAdded);
openNewChimera(ap, pe, seqs);
}
}
/**
- * Returns a list of any Chimera viewers in the desktop. The list is
- * restricted to those linked to the given alignment panel if it is not null.
- */
- @Override
- protected List<StructureViewerBase> getViewersFor(AlignmentPanel ap)
- {
- List<StructureViewerBase> result = new ArrayList<>();
- JInternalFrame[] frames = Desktop.instance.getAllFrames();
-
- for (JInternalFrame frame : frames)
- {
- if (frame instanceof ChimeraViewFrame)
- {
- if (ap == null || ((StructureViewerBase) frame).isLinkedWith(ap))
- {
- result.add((StructureViewerBase) frame);
- }
- }
- }
- return result;
- }
-
- /**
* Launch Chimera. If we have a chimera session file name, send Chimera the
* command to open its saved session file.
*/
jmb.updateColours(ap);
}
// do superposition if asked to
- if (Cache.getDefault("AUTOSUPERIMPOSE", true) && alignAddedStructures)
+ if (alignAddedStructures)
{
new Thread(new Runnable()
{
alignStructs_withAllAlignPanels();
}
}).start();
- alignAddedStructures = false;
}
addingStructures = false;
}
private String fetchPdbFile(PDBEntry processingEntry) throws Exception
{
- // FIXME: this is duplicated code with Jmol frame ?
String filePath = null;
Pdb pdbclient = new Pdb();
AlignmentI pdbseq = null;
import jalview.bin.Cache;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
+import jalview.datamodel.GeneLociI;
import jalview.datamodel.SequenceI;
+import jalview.ext.ensembl.EnsemblInfo;
+import jalview.ext.ensembl.EnsemblMap;
import jalview.io.gff.SequenceOntologyI;
import jalview.structure.StructureSelectionManager;
+import jalview.util.DBRefUtils;
+import jalview.util.MapList;
+import jalview.util.MappingUtils;
import jalview.util.MessageManager;
import jalview.ws.SequenceFetcher;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
-
-import javax.swing.JOptionPane;
+import java.util.Map;
+import java.util.Set;
/**
* Factory constructor and runnable for discovering and displaying
private SequenceI[] sel;
- private boolean _odna;
+ private final boolean _odna;
private String source;
- List<AlignmentViewPanel> xrefViews = new ArrayList<AlignmentViewPanel>();
+ List<AlignmentViewPanel> xrefViews = new ArrayList<>();
- public List<jalview.api.AlignmentViewPanel> getXrefViews()
+ List<AlignmentViewPanel> getXrefViews()
{
return xrefViews;
}
{
return;
}
+
+ /*
+ * try to look up chromosomal coordinates for nucleotide
+ * sequences (if not already retrieved)
+ */
+ findGeneLoci(xrefs.getSequences());
+
/*
* get display scheme (if any) to apply to features
*/
if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
{
- boolean copyAlignmentIsAligned = false;
- if (dna)
- {
- copyAlignment = AlignmentUtils.makeCdsAlignment(sel, dataset,
- xrefsAlignment.getSequencesArray());
- if (copyAlignment.getHeight() == 0)
- {
- JvOptionPane.showMessageDialog(alignFrame,
- MessageManager.getString("label.cant_map_cds"),
- MessageManager.getString("label.operation_failed"),
- JvOptionPane.OK_OPTION);
- System.err.println("Failed to make CDS alignment");
- }
-
- /*
- * pending getting Embl transcripts to 'align',
- * we are only doing this for Ensembl
- */
- // TODO proper criteria for 'can align as cdna'
- if (DBRefSource.ENSEMBL.equalsIgnoreCase(source)
- || AlignmentUtils.looksLikeEnsembl(alignment))
- {
- copyAlignment.alignAs(alignment);
- copyAlignmentIsAligned = true;
- }
- }
- else
+ copyAlignment = copyAlignmentForSplitFrame(alignment, dataset, dna,
+ xrefs, xrefsAlignment);
+ if (copyAlignment == null)
{
- copyAlignment = AlignmentUtils.makeCopyAlignment(sel,
- xrefs.getSequencesArray(), dataset);
- }
- copyAlignment
- .setGapCharacter(alignFrame.viewport.getGapCharacter());
-
- StructureSelectionManager ssm = StructureSelectionManager
- .getStructureSelectionManager(Desktop.instance);
-
- /*
- * register any new mappings for sequence mouseover etc
- * (will not duplicate any previously registered mappings)
- */
- ssm.registerMappings(dataset.getCodonFrames());
-
- if (copyAlignment.getHeight() <= 0)
- {
- System.err.println(
- "No Sequences generated for xRef type " + source);
- return;
- }
- /*
- * align protein to dna
- */
- if (dna && copyAlignmentIsAligned)
- {
- xrefsAlignment.alignAs(copyAlignment);
- }
- else
- {
- /*
- * align cdna to protein - currently only if
- * fetching and aligning Ensembl transcripts!
- */
- // TODO: generalise for other sources of locus/transcript/cds data
- if (dna && DBRefSource.ENSEMBL.equalsIgnoreCase(source))
- {
- copyAlignment.alignAs(xrefsAlignment);
- }
+ return; // failed
}
}
+
/*
* build AlignFrame(s) according to available alignment data
*/
xrefViews.add(newFrame.alignPanel);
return; // via finally clause
}
+
AlignFrame copyThis = new AlignFrame(copyAlignment,
AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
copyThis.setTitle(alignFrame.getTitle());
/*
* copy feature rendering settings to split frame
*/
- newFrame.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
- .transferSettings(myFeatureStyling);
- copyThis.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
- .transferSettings(myFeatureStyling);
+ FeatureRenderer fr1 = newFrame.alignPanel.getSeqPanel().seqCanvas
+ .getFeatureRenderer();
+ fr1.transferSettings(myFeatureStyling);
+ fr1.findAllFeatures(true);
+ FeatureRenderer fr2 = copyThis.alignPanel.getSeqPanel().seqCanvas
+ .getFeatureRenderer();
+ fr2.transferSettings(myFeatureStyling);
+ fr2.findAllFeatures(true);
/*
* apply 'database source' feature configuration
}
/**
+ * Tries to add chromosomal coordinates to any nucleotide sequence which does
+ * not already have them. Coordinates are retrieved from Ensembl given an
+ * Ensembl identifier, either on the sequence itself or on a peptide sequence
+ * it has a reference to.
+ *
+ * <pre>
+ * Example (human):
+ * - fetch EMBLCDS cross-references for Uniprot entry P30419
+ * - the EMBL sequences do not have xrefs to Ensembl
+ * - the Uniprot entry has xrefs to
+ * ENSP00000258960, ENSP00000468424, ENST00000258960, ENST00000592782
+ * - either of the transcript ids can be used to retrieve gene loci e.g.
+ * http://rest.ensembl.org/map/cds/ENST00000592782/1..100000
+ * Example (invertebrate):
+ * - fetch EMBLCDS cross-references for Uniprot entry Q43517 (FER1_SOLLC)
+ * - the Uniprot entry has an xref to ENSEMBLPLANTS Solyc10g044520.1.1
+ * - can retrieve gene loci with
+ * http://rest.ensemblgenomes.org/map/cds/Solyc10g044520.1.1/1..100000
+ * </pre>
+ *
+ * @param sequences
+ */
+ public static void findGeneLoci(List<SequenceI> sequences)
+ {
+ Map<DBRefEntry, GeneLociI> retrievedLoci = new HashMap<>();
+ for (SequenceI seq : sequences)
+ {
+ findGeneLoci(seq, retrievedLoci);
+ }
+ }
+
+ /**
+ * Tres to find chromosomal coordinates for the sequence, by searching its
+ * direct and indirect cross-references for Ensembl. If the loci have already
+ * been retrieved, just reads them out of the map of retrievedLoci; this is
+ * the case of an alternative transcript for the same protein. Otherwise calls
+ * a REST service to retrieve the loci, and if successful, adds them to the
+ * sequence and to the retrievedLoci.
+ *
+ * @param seq
+ * @param retrievedLoci
+ */
+ static void findGeneLoci(SequenceI seq,
+ Map<DBRefEntry, GeneLociI> retrievedLoci)
+ {
+ /*
+ * don't replace any existing chromosomal coordinates
+ */
+ if (seq == null || seq.isProtein() || seq.getGeneLoci() != null
+ || seq.getDBRefs() == null)
+ {
+ return;
+ }
+
+ Set<String> ensemblDivisions = new EnsemblInfo().getDivisions();
+
+ /*
+ * first look for direct dbrefs from sequence to Ensembl
+ */
+ String[] divisionsArray = ensemblDivisions
+ .toArray(new String[ensemblDivisions.size()]);
+ DBRefEntry[] seqRefs = seq.getDBRefs();
+ DBRefEntry[] directEnsemblRefs = DBRefUtils.selectRefs(seqRefs,
+ divisionsArray);
+ if (directEnsemblRefs != null)
+ {
+ for (DBRefEntry ensemblRef : directEnsemblRefs)
+ {
+ if (fetchGeneLoci(seq, ensemblRef, retrievedLoci))
+ {
+ return;
+ }
+ }
+ }
+
+ /*
+ * else look for indirect dbrefs from sequence to Ensembl
+ */
+ for (DBRefEntry dbref : seq.getDBRefs())
+ {
+ if (dbref.getMap() != null && dbref.getMap().getTo() != null)
+ {
+ DBRefEntry[] dbrefs = dbref.getMap().getTo().getDBRefs();
+ DBRefEntry[] indirectEnsemblRefs = DBRefUtils.selectRefs(dbrefs,
+ divisionsArray);
+ if (indirectEnsemblRefs != null)
+ {
+ for (DBRefEntry ensemblRef : indirectEnsemblRefs)
+ {
+ if (fetchGeneLoci(seq, ensemblRef, retrievedLoci))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Retrieves chromosomal coordinates for the Ensembl (or EnsemblGenomes)
+ * identifier in dbref. If successful, and the sequence length matches gene
+ * loci length, then add it to the sequence, and to the retrievedLoci map.
+ * Answers true if successful, else false.
+ *
+ * @param seq
+ * @param dbref
+ * @param retrievedLoci
+ * @return
+ */
+ static boolean fetchGeneLoci(SequenceI seq, DBRefEntry dbref,
+ Map<DBRefEntry, GeneLociI> retrievedLoci)
+ {
+ String accession = dbref.getAccessionId();
+ String division = dbref.getSource();
+
+ /*
+ * hack: ignore cross-references to Ensembl protein ids
+ * (or use map/translation perhaps?)
+ * todo: is there an equivalent in EnsemblGenomes?
+ */
+ if (accession.startsWith("ENSP"))
+ {
+ return false;
+ }
+ EnsemblMap mapper = new EnsemblMap();
+
+ /*
+ * try CDS mapping first
+ */
+ GeneLociI geneLoci = mapper.getCdsMapping(division, accession, 1,
+ seq.getLength());
+ if (geneLoci != null)
+ {
+ MapList map = geneLoci.getMap();
+ int mappedFromLength = MappingUtils.getLength(map.getFromRanges());
+ if (mappedFromLength == seq.getLength())
+ {
+ seq.setGeneLoci(geneLoci.getSpeciesId(), geneLoci.getAssemblyId(),
+ geneLoci.getChromosomeId(), geneLoci.getMap());
+ retrievedLoci.put(dbref, geneLoci);
+ return true;
+ }
+ }
+
+ /*
+ * else try CDNA mapping
+ */
+ geneLoci = mapper.getCdnaMapping(division, accession, 1,
+ seq.getLength());
+ if (geneLoci != null)
+ {
+ MapList map = geneLoci.getMap();
+ int mappedFromLength = MappingUtils.getLength(map.getFromRanges());
+ if (mappedFromLength == seq.getLength())
+ {
+ seq.setGeneLoci(geneLoci.getSpeciesId(), geneLoci.getAssemblyId(),
+ geneLoci.getChromosomeId(), geneLoci.getMap());
+ retrievedLoci.put(dbref, geneLoci);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param alignment
+ * @param dataset
+ * @param dna
+ * @param xrefs
+ * @param xrefsAlignment
+ * @return
+ */
+ protected AlignmentI copyAlignmentForSplitFrame(AlignmentI alignment,
+ AlignmentI dataset, boolean dna, AlignmentI xrefs,
+ AlignmentI xrefsAlignment)
+ {
+ AlignmentI copyAlignment;
+ boolean copyAlignmentIsAligned = false;
+ if (dna)
+ {
+ copyAlignment = AlignmentUtils.makeCdsAlignment(sel, dataset,
+ xrefsAlignment.getSequencesArray());
+ if (copyAlignment.getHeight() == 0)
+ {
+ JvOptionPane.showMessageDialog(alignFrame,
+ MessageManager.getString("label.cant_map_cds"),
+ MessageManager.getString("label.operation_failed"),
+ JvOptionPane.OK_OPTION);
+ System.err.println("Failed to make CDS alignment");
+ return null;
+ }
+
+ /*
+ * pending getting Embl transcripts to 'align',
+ * we are only doing this for Ensembl
+ */
+ // TODO proper criteria for 'can align as cdna'
+ if (DBRefSource.ENSEMBL.equalsIgnoreCase(source)
+ || AlignmentUtils.looksLikeEnsembl(alignment))
+ {
+ copyAlignment.alignAs(alignment);
+ copyAlignmentIsAligned = true;
+ }
+ }
+ else
+ {
+ copyAlignment = AlignmentUtils.makeCopyAlignment(sel,
+ xrefs.getSequencesArray(), dataset);
+ }
+ copyAlignment
+ .setGapCharacter(alignFrame.viewport.getGapCharacter());
+
+ StructureSelectionManager ssm = StructureSelectionManager
+ .getStructureSelectionManager(Desktop.instance);
+
+ /*
+ * register any new mappings for sequence mouseover etc
+ * (will not duplicate any previously registered mappings)
+ */
+ ssm.registerMappings(dataset.getCodonFrames());
+
+ if (copyAlignment.getHeight() <= 0)
+ {
+ System.err.println(
+ "No Sequences generated for xRef type " + source);
+ return null;
+ }
+
+ /*
+ * align protein to dna
+ */
+ if (dna && copyAlignmentIsAligned)
+ {
+ xrefsAlignment.alignAs(copyAlignment);
+ }
+ else
+ {
+ /*
+ * align cdna to protein - currently only if
+ * fetching and aligning Ensembl transcripts!
+ */
+ // TODO: generalise for other sources of locus/transcript/cds data
+ if (dna && DBRefSource.ENSEMBL.equalsIgnoreCase(source))
+ {
+ copyAlignment.alignAs(xrefsAlignment);
+ }
+ }
+
+ return copyAlignment;
+ }
+
+ /**
* Makes an alignment containing the given sequences, and adds them to the
* given dataset, which is also set as the dataset for the new alignment
*
return al;
}
- public CrossRefAction(AlignFrame alignFrame, SequenceI[] sel,
- boolean _odna, String source)
+ /**
+ * Constructor
+ *
+ * @param af
+ * @param seqs
+ * @param fromDna
+ * @param dbSource
+ */
+ CrossRefAction(AlignFrame af, SequenceI[] seqs, boolean fromDna,
+ String dbSource)
{
- this.alignFrame = alignFrame;
- this.sel = sel;
- this._odna = _odna;
- this.source = source;
+ this.alignFrame = af;
+ this.sel = seqs;
+ this._odna = fromDna;
+ this.source = dbSource;
}
- public static CrossRefAction showProductsFor(final SequenceI[] sel,
- final boolean _odna, final String source,
+ public static CrossRefAction getHandlerFor(final SequenceI[] sel,
+ final boolean fromDna, final String source,
final AlignFrame alignFrame)
{
- return new CrossRefAction(alignFrame, sel, _odna, source);
+ return new CrossRefAction(alignFrame, sel, fromDna, source);
}
}
*/
public void setText(String text)
{
+ textarea.setDocument(textarea.getEditorKit().createDefaultDocument());
textarea.setText(text);
}
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.gui;
-
-import jalview.jbgui.GDasSourceBrowser;
-import jalview.util.MessageManager;
-import jalview.util.TableSorter;
-import jalview.ws.dbsources.das.api.DasSourceRegistryI;
-import jalview.ws.dbsources.das.api.jalviewSourceI;
-
-import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.table.AbstractTableModel;
-
-import org.biodas.jdas.schema.sources.CAPABILITY;
-import org.biodas.jdas.schema.sources.COORDINATES;
-import org.biodas.jdas.schema.sources.PROP;
-import org.biodas.jdas.schema.sources.VERSION;
-
-public class DasSourceBrowser extends GDasSourceBrowser
- implements Runnable, ListSelectionListener
-{
- DasSourceRegistryI sourceRegistry = null;
-
- Vector<String> selectedSources;
-
- public DasSourceBrowser(FeatureSettings featureSettings)
- {
- fs = featureSettings;
- // TODO DasSourceRegistryProvider API
- sourceRegistry = jalview.bin.Cache.getDasSourceRegistry();
- String registry = sourceRegistry.getDasRegistryURL();
-
- registryURL.setText(registry);
-
- setSelectedFromProperties();
-
- displayFullDetails(null);
- table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
- filter1.addListSelectionListener(this);
- filter2.addListSelectionListener(this);
- filter3.addListSelectionListener(this);
-
- // Ask to be notified of selection changes.
- ListSelectionModel rowSM = table.getSelectionModel();
- rowSM.addListSelectionListener(new ListSelectionListener()
- {
- @Override
- public void valueChanged(ListSelectionEvent e)
- {
- ListSelectionModel lsm = (ListSelectionModel) e.getSource();
- if (!lsm.isSelectionEmpty())
- {
- int selectedRow = lsm.getMinSelectionIndex();
- displayFullDetails(table.getValueAt(selectedRow, 0).toString());
- }
- }
- });
-
- table.addMouseListener(new MouseAdapter()
- {
- @Override
- public void mouseClicked(MouseEvent evt)
- {
- if (evt.getClickCount() == 2 || evt.isPopupTrigger())
- {
- editRemoveLocalSource(evt);
- }
- }
- });
-
- if (sourceRegistry.getSources() != null)
- {
- init();
- }
- }
-
- FeatureSettings fs = null;
-
- private boolean loadingDasSources;
-
- public DasSourceBrowser()
- {
- this(null);
- }
-
- @Override
- public void paintComponent(java.awt.Graphics g)
- {
- if (sourceRegistry == null)
- {
- Thread worker = new Thread(this);
- worker.start();
- }
- }
-
- void init()
- {
- List<jalviewSourceI> sources = sourceRegistry.getSources();
- int dSize = sources.size();
- Object[][] data = new Object[dSize][2];
- for (int i = 0; i < dSize; i++)
- {
- data[i][0] = sources.get(i).getTitle(); // what's equivalent of nickname
- data[i][1] = new Boolean(
- selectedSources.contains(sources.get(i).getTitle()));
- }
-
- refreshTableData(data);
- setCapabilities(sourceRegistry);
-
- javax.swing.SwingUtilities.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- TableSorter sorter = (TableSorter) table.getModel();
- sorter.setSortingStatus(1, TableSorter.DESCENDING);
- sorter.setSortingStatus(1, TableSorter.NOT_SORTED);
- }
- });
-
- progressBar.setIndeterminate(false);
- progressBar.setVisible(false);
- addLocal.setVisible(true);
- refresh.setVisible(true);
- }
-
- public void refreshTableData(Object[][] data)
- {
- TableSorter sorter = new TableSorter(new DASTableModel(data));
- sorter.setTableHeader(table.getTableHeader());
- table.setModel(sorter);
- }
-
- void displayFullDetails(String nickName)
- {
-
- StringBuffer text = new StringBuffer(
- "<HTML><font size=\"2\" face=\"Verdana, Arial, Helvetica, sans-serif\">");
-
- if (nickName == null)
- {
- fullDetails.setText(text + MessageManager
- .getString("label.select_das_service_from_table"));
- return;
- }
-
- int dSize = sourceRegistry.getSources().size();
- for (jalviewSourceI ds : sourceRegistry.getSources())
- {
- if (!ds.getTitle().equals(nickName))
- {
- continue;
- }
-
- VERSION latest = ds.getVersion();
- text.append(
- "<font color=\"#0000FF\">Id:</font> " + ds.getUri() + "<br>");
- text.append("<font color=\"#0000FF\">Nickname:</font> "
- + ds.getTitle() + "<br>");
-
- text.append("<font color=\"#0000FF\">URL:</font> <a href=\""
- + ds.getSourceURL() + "\">" + ds.getSourceURL() + "</a>"
- + "<br>");
- if (!ds.isLocal())
- {
- if (ds.getDocHref() != null && ds.getDocHref().length() > 0)
- {
- text.append("<font color=\"#0000FF\">Site:</font> <a href=\""
- + ds.getDocHref() + "\">" + ds.getDocHref() + "</a>"
- + "<br>");
- }
-
- text.append("<font color=\"#0000FF\">Description:</font> "
- + ds.getDescription() + "<br>");
-
- text.append(
- "<font color=\"#0000FF\">Admin Email:</font> <a href=\"mailto:"
- + ds.getEmail() + "\">" + ds.getEmail() + "</a>"
- + "<br>");
-
- text.append("<font color=\"#0000FF\">Registered at:</font> "
- + latest.getCreated() + "<br>");
-
- // TODO: Identify last successful test date
- // text.append("<font color=\"#0000FF\">Last successful test:</font> "
- // + latest.dasSources[i].getLeaseDate() + "<br>");
- }
- else
- {
- text.append("Source was added manually.<br/>");
- }
- text.append("<font color=\"#0000FF\">Labels:</font> ");
- boolean b = false;
- for (PROP labl : latest.getPROP())
- {
- if (labl.getName().equalsIgnoreCase("LABEL"))
- {
- if (b)
- {
- text.append(",");
- }
- text.append(" ");
-
- text.append(labl.getValue());
- b = true;
- }
- ;
- }
- text.append("<br>");
-
- text.append("<font color=\"#0000FF\">Capabilities:</font> ");
- CAPABILITY[] scap = latest.getCAPABILITY().toArray(new CAPABILITY[0]);
- for (int j = 0; j < scap.length; j++)
- {
- text.append(scap[j].getType());
- if (j < scap.length - 1)
- {
- text.append(", ");
- }
- }
- text.append("<br>");
-
- text.append("<font color=\"#0000FF\">Coordinates:</font>");
- int i = 1;
- for (COORDINATES dcs : latest.getCOORDINATES())
- {
- text.append("<br/>" + i++ + ". ");
- text.append(dcs.getAuthority() + " : " + dcs.getSource());
- if (dcs.getTaxid() != null && dcs.getTaxid().trim().length() > 0)
- {
- text.append(" [TaxId:" + dcs.getTaxid() + "]");
- }
- if (dcs.getVersion() != null
- && dcs.getVersion().trim().length() > 0)
- {
- {
- text.append(" {v. " + dcs.getVersion() + "}");
- }
- }
- text.append(" (<a href=\"" + dcs.getUri() + "\">" + dcs.getUri()
- + "</a>)");
- }
- text.append("</font></html>");
-
- break;
- }
-
- fullDetails.setText(text.toString());
- javax.swing.SwingUtilities.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- fullDetailsScrollpane.getVerticalScrollBar().setValue(0);
- }
- });
- }
-
- @Override
- public void run()
- {
- loadingDasSources = true;
-
- addLocal.setVisible(false);
- refresh.setVisible(false);
- progressBar.setVisible(true);
- progressBar.setIndeterminate(true);
- setParentGuiEnabled(false);
- // Refresh the source list.
- sourceRegistry.refreshSources();
-
- init();
-
- setParentGuiEnabled(true);
- loadingDasSources = false;
-
- }
-
- private void setParentGuiEnabled(boolean b)
- {
- if (fs != null)
- {
- fs.fetchDAS.setEnabled(b);
- fs.saveDAS.setEnabled(b);
- }
- }
-
- public Vector<jalviewSourceI> getSelectedSources()
- {
- // wait around if we're still loading.
- while (sourceRegistry == null)
- {
- if (!loadingDasSources)
- {
- new Thread(this).start();
- try
- {
- Thread.sleep(5);
- } catch (Exception e)
- {
- }
- ;
- while (loadingDasSources)
- {
- try
- {
- Thread.sleep(5);
- } catch (Exception e)
- {
- }
- ;
- }
- ;
- }
- }
-
- Vector<jalviewSourceI> selected = new Vector<jalviewSourceI>();
- for (String source : selectedSources)
- {
- jalviewSourceI srce = sourceRegistry.getSource(source);
- if (srce != null)
- {
- selected.addElement(srce);
- }
- }
- return selected;
- }
-
- @Override
- public void refresh_actionPerformed(ActionEvent e)
- {
- saveProperties(jalview.bin.Cache.applicationProperties);
-
- Thread worker = new Thread(this);
- worker.start();
- }
-
- private void setCapabilities(DasSourceRegistryI sourceRegistry2)
- {
- Vector<String> authority = new Vector<String>();
- Vector<String> type = new Vector<String>();
- Vector<String> label = new Vector<String>();
- Vector<String> taxIds = new Vector<String>();
- authority.add("Any");
- type.add("Any");
- label.add("Any");
-
- for (jalviewSourceI ds : sourceRegistry2.getSources())
- {
- VERSION latest = ds.getVersion();
-
- for (COORDINATES cs : latest.getCOORDINATES())
- {
- if (!type.contains(cs.getSource()))
- {
- type.add(cs.getSource()); // source==category
- }
-
- if (!authority.contains(cs.getAuthority()))
- {
- authority.add(cs.getAuthority());
- }
- }
-
- for (PROP slabel : latest.getPROP())
- {
- if (slabel.getName().equalsIgnoreCase("LABEL")
- && !label.contains(slabel.getValue()))
- {
- label.add(slabel.getValue());
- }
- }
-
- }
-
- filter1.setListData(authority);
- filter2.setListData(type);
- filter3.setListData(label);
- // filter4 taxIds
-
- javax.swing.SwingUtilities.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- filter1.setSelectedIndex(0);
- filter2.setSelectedIndex(0);
- filter3.setSelectedIndex(0);
- }
- });
- }
-
- @Override
- public void amendLocal(boolean newSource)
- {
- String url = "http://localhost:8080/", nickname = "";
- boolean seqsrc = false;
- if (!newSource)
- {
- int selectedRow = table.getSelectionModel().getMinSelectionIndex();
- nickname = table.getValueAt(selectedRow, 0).toString();
- jalviewSourceI source = sourceRegistry.getSource(nickname);
- url = source.getUri();
- seqsrc = source.isSequenceSource();
- }
-
- JTextField nametf = new JTextField(nickname, 40);
- JTextField urltf = new JTextField(url, 40);
- JCheckBox seqs = new JCheckBox(
- MessageManager.getString("label.sequence_source"));
- seqs.setSelected(seqsrc);
- JPanel panel = new JPanel(new BorderLayout());
- JPanel pane12 = new JPanel(new BorderLayout());
- pane12.add(new JLabel(MessageManager.getString("label.name:")),
- BorderLayout.CENTER);
- pane12.add(nametf, BorderLayout.EAST);
- panel.add(pane12, BorderLayout.NORTH);
- pane12 = new JPanel(new BorderLayout());
- pane12.add(new JLabel(MessageManager.getString("label.url:")),
- BorderLayout.NORTH);
- pane12.add(seqs, BorderLayout.SOUTH);
- pane12.add(urltf, BorderLayout.EAST);
- panel.add(pane12, BorderLayout.SOUTH);
-
- int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
- panel, MessageManager.getString("label.enter_local_das_source"),
- JvOptionPane.OK_CANCEL_OPTION);
-
- if (reply != JvOptionPane.OK_OPTION)
- {
- return;
- }
-
- if (!urltf.getText().endsWith("/"))
- {
- urltf.setText(urltf.getText() + "/");
- }
-
- jalviewSourceI local = sourceRegistry.createLocalSource(urltf.getText(),
- nametf.getText(), seqs.isSelected(), true);
- List sources = sourceRegistry.getSources();
- int osize = sources.size();
- int size = osize + (newSource ? 1 : 0);
-
- Object[][] data = new Object[size][2];
- DASTableModel dtm = (table != null)
- ? (DASTableModel) ((TableSorter) table.getModel())
- .getTableModel()
- : null;
- for (int i = 0; i < osize; i++)
- {
- String osrc = (dtm == null || i >= osize) ? null
- : (String) dtm.getValueAt(i, 0);
- if (!newSource && osrc != null
- && dtm.getValueAt(i, 0).equals(nickname))
- {
- data[i][0] = local.getTitle();
- data[i][1] = new Boolean(true);
- }
- else
- {
- data[i][0] = osrc;
- data[i][1] = new Boolean(selectedSources.contains(osrc));
- }
- }
- // Always add a new source at the end
- if (newSource)
- {
- data[osize][0] = local.getTitle();
- data[osize][1] = new Boolean(true);
- selectedSources.add(local.getTitle());
- }
-
- refreshTableData(data);
-
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- scrollPane.getVerticalScrollBar()
- .setValue(scrollPane.getVerticalScrollBar().getMaximum());
- }
- });
-
- displayFullDetails(local.getTitle());
- }
-
- public void editRemoveLocalSource(MouseEvent evt)
- {
- int selectedRow = table.getSelectionModel().getMinSelectionIndex();
- if (selectedRow == -1)
- {
- return;
- }
-
- String nickname = table.getValueAt(selectedRow, 0).toString();
-
- if (!sourceRegistry.getSource(nickname).isLocal())
- {
- JvOptionPane.showInternalMessageDialog(Desktop.desktop,
- MessageManager.getString(
- "label.you_can_only_edit_or_remove_local_das_sources"),
- MessageManager.getString("label.public_das_source"),
- JvOptionPane.WARNING_MESSAGE);
- return;
- }
-
- Object[] options = { "Edit", "Remove", "Cancel" };
- int choice = JvOptionPane.showInternalOptionDialog(Desktop.desktop,
- "Do you want to edit or remove " + nickname + "?",
- "Edit / Remove Local DAS Source",
- JvOptionPane.YES_NO_CANCEL_OPTION,
- JvOptionPane.QUESTION_MESSAGE, null, options, options[2]);
-
- switch (choice)
- {
- case 0:
- amendLocal(false);
- break;
- case 1:
- sourceRegistry.removeLocalSource(sourceRegistry.getSource(nickname));
- selectedSources.remove(nickname);
- Object[][] data = new Object[sourceRegistry.getSources().size()][2];
- int index = 0, l = table.getRowCount();
-
- for (int i = 0; i < l; i++)
- {
- String nm;
- if ((nm = (String) table.getValueAt(i, 0)).equals(nickname))
- {
- continue;
- }
- else
- {
- data[index][0] = nm;
- data[index][1] = new Boolean(selectedSources.contains(nm));
- index++;
- }
- }
- refreshTableData(data);
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- scrollPane.getVerticalScrollBar()
- .setValue(scrollPane.getVerticalScrollBar().getMaximum());
- }
- });
-
- break;
- }
- }
-
- @Override
- public void valueChanged(ListSelectionEvent evt)
- {
- // Called when the MainTable selection changes
- if (evt.getValueIsAdjusting())
- {
- return;
- }
-
- displayFullDetails(null);
-
- // Filter the displayed data sources
-
- ArrayList names = new ArrayList();
- ArrayList selected = new ArrayList();
-
- // The features filter is not visible, but we must still
- // filter the das source list here.
- // July 2006 - only 6 sources fo not serve features
- Object[] dummyFeatureList = new Object[] { "features" };
- List<jalviewSourceI> srcs = sourceRegistry.getSources();
- for (jalviewSourceI ds : srcs)
- {
-
- VERSION v = ds.getVersion();
- List<COORDINATES> coords = v.getCOORDINATES();
- if (ds.isLocal() || ((coords == null || coords.size() == 0)
- && filter1.getSelectedIndex() == 0
- && filter2.getSelectedIndex() == 0
- && filter3.getSelectedIndex() == 0))
- {
- // THIS IS A FIX FOR LOCAL SOURCES WHICH DO NOT
- // HAVE COORDINATE SYSTEMS, INFO WHICH AT PRESENT
- // IS ADDED FROM THE REGISTRY
- names.add(ds.getTitle());
- selected.add(new Boolean(selectedSources.contains(ds.getTitle())));
- continue;
- }
-
- if (!selectedInList(dummyFeatureList, ds.getCapabilityList(v))
- || !selectedInList(filter3.getSelectedValues(),
- ds.getLabelsFor(v)))
- {
- continue;
- }
-
- for (int j = 0; j < coords.size(); j++)
- {
- if (selectedInList(filter1.getSelectedValues(),
- new String[]
- { coords.get(j).getAuthority() })
- && selectedInList(filter2.getSelectedValues(), new String[]
- { coords.get(j).getSource() }))
- {
- names.add(ds.getTitle());
- selected.add(
- new Boolean(selectedSources.contains(ds.getTitle())));
- break;
- }
- }
- }
-
- int dSize = names.size();
- Object[][] data = new Object[dSize][2];
- for (int d = 0; d < dSize; d++)
- {
- data[d][0] = names.get(d);
- data[d][1] = selected.get(d);
- }
-
- refreshTableData(data);
- }
-
- private boolean selectedInList(Object[] selection, String[] items)
- {
- for (int i = 0; i < selection.length; i++)
- {
- if (selection[i].equals("Any"))
- {
- return true;
- }
- if (items == null || items.length == 0)
- {
- return false;
- }
- String sel = (items[0].startsWith("das1:") ? "das1:" : "")
- + selection[i];
- for (int j = 0; j < items.length; j++)
- {
- if (sel.equals(items[j]))
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- void setSelectedFromProperties()
- {
- String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE",
- "uniprot");
- StringTokenizer st = new StringTokenizer(active, "\t");
- selectedSources = new Vector();
- while (st.hasMoreTokens())
- {
- selectedSources.addElement(st.nextToken());
- }
- }
-
- @Override
- public void reset_actionPerformed(ActionEvent e)
- {
- registryURL.setText(sourceRegistry.getDasRegistryURL());
- }
-
- /**
- * set the DAS source settings in the given jalview properties.
- *
- * @param properties
- */
- public void saveProperties(Properties properties)
- {
- if (registryURL.getText() == null || registryURL.getText().length() < 1)
- {
- properties.remove(jalview.bin.Cache.DAS_REGISTRY_URL);
- }
- else
- {
- properties.setProperty(jalview.bin.Cache.DAS_REGISTRY_URL,
- registryURL.getText());
- }
-
- StringBuffer sb = new StringBuffer();
- for (int r = 0; r < table.getModel().getRowCount(); r++)
- {
- if (((Boolean) table.getValueAt(r, 1)).booleanValue())
- {
- sb.append(table.getValueAt(r, 0) + "\t");
- }
- }
-
- properties.setProperty(jalview.bin.Cache.DAS_ACTIVE_SOURCE,
- sb.toString());
-
- String sourceprop = sourceRegistry.getLocalSourceString();
- properties.setProperty(jalview.bin.Cache.DAS_LOCAL_SOURCE, sourceprop);
- }
-
- class DASTableModel extends AbstractTableModel
- {
-
- public DASTableModel(Object[][] data)
- {
- this.data = data;
- }
-
- private String[] columnNames = new String[] {
- MessageManager.getString("label.nickname"),
- MessageManager.getString("label.use_source") };
-
- private Object[][] data;
-
- @Override
- public int getColumnCount()
- {
- return columnNames.length;
- }
-
- @Override
- public int getRowCount()
- {
- return data.length;
- }
-
- @Override
- public String getColumnName(int col)
- {
- return columnNames[col];
- }
-
- @Override
- public Object getValueAt(int row, int col)
- {
- return data[row][col];
- }
-
- /*
- * JTable uses this method to determine the default renderer/ editor for
- * each cell. If we didn't implement this method, then the last column would
- * contain text ("true"/"false"), rather than a check box.
- */
- @Override
- public Class getColumnClass(int c)
- {
- return getValueAt(0, c).getClass();
- }
-
- /*
- * Don't need to implement this method unless your table's editable.
- */
- @Override
- public boolean isCellEditable(int row, int col)
- {
- // Note that the data/cell address is constant,
- // no matter where the cell appears onscreen.
- return col == 1;
-
- }
-
- /*
- * Don't need to implement this method unless your table's data can change.
- */
- @Override
- public void setValueAt(Object value, int row, int col)
- {
- data[row][col] = value;
- fireTableCellUpdated(row, col);
-
- String name = getValueAt(row, 0).toString();
- boolean selected = ((Boolean) value).booleanValue();
-
- if (selectedSources.contains(name) && !selected)
- {
- selectedSources.remove(name);
- }
-
- if (!selectedSources.contains(name) && selected)
- {
- selectedSources.add(name);
- }
- }
- }
-
- public void initDasSources()
- {
-
- Thread thr = new Thread(new Runnable()
- {
- @Override
- public void run()
- {
- // this actually initialises the das source list
- paintComponent(null); // yuk
- }
- });
- thr.start();
- while (loadingDasSources || sourceRegistry == null)
- {
- try
- {
- Thread.sleep(10);
- } catch (Exception e)
- {
- }
- ;
- }
- }
-
- /**
- * disable or enable the buttons on the source browser
- *
- * @param b
- */
- public void setGuiEnabled(boolean b)
- {
- refresh.setEnabled(b);
- addLocal.setEnabled(b);
- }
-}
import jalview.io.FileFormatI;
import jalview.io.FileFormats;
import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
import jalview.io.IdentifyFile;
import jalview.io.JalviewFileChooser;
import jalview.io.JalviewFileView;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.concurrent.Semaphore;
import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultDesktopManager;
import javax.swing.DesktopManager;
+import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
+import org.stackoverflowusers.file.WindowsShortcut;
+
/**
* Jalview Desktop
*
{
final Desktop me = this;
// Thread off the news reader, in case there are connection problems.
- addDialogThread(new Runnable()
+ new Thread(new Runnable()
{
@Override
public void run()
showNews.setVisible(true);
Cache.log.debug("Completed news thread.");
}
- });
+ }).start();
}
public void getIdentifiersOrgData()
{
// Thread off the identifiers fetcher
- addDialogThread(new Runnable()
+ new Thread(new Runnable()
{
@Override
public void run()
+ e.getMessage());
}
}
- });
+ }).start();
+ ;
}
@Override
frame.setResizable(resizable);
frame.setMaximizable(resizable);
frame.setIconifiable(resizable);
+ frame.setOpaque(false);
if (frame.getX() < 1 && frame.getY() < 1)
{
menuItem.removeActionListener(menuItem.getActionListeners()[0]);
}
windowMenu.remove(menuItem);
-
- System.gc();
};
});
}
});
+ setKeyBindings(frame);
+
desktop.add(frame);
windowMenu.add(menuItem);
}
}
+ /**
+ * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
+ * the window
+ *
+ * @param frame
+ */
+ private static void setKeyBindings(JInternalFrame frame)
+ {
+ @SuppressWarnings("serial")
+ final Action closeAction = new AbstractAction()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ frame.dispose();
+ }
+ };
+
+ /*
+ * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
+ */
+ KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
+ InputEvent.CTRL_DOWN_MASK);
+ KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
+
+ InputMap inputMap = frame
+ .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ String ctrlW = ctrlWKey.toString();
+ inputMap.put(ctrlWKey, ctrlW);
+ inputMap.put(cmdWKey, ctrlW);
+
+ ActionMap actionMap = frame.getActionMap();
+ actionMap.put(ctrlW, closeAction);
+ }
+
@Override
public void lostOwnership(Clipboard clipboard, Transferable contents)
{
{
ssm.resetAll();
}
- System.gc();
}
@Override
return groovyConsole;
}
+ /**
+ * handles the payload of a drag and drop event.
+ *
+ * TODO refactor to desktop utilities class
+ *
+ * @param files
+ * - Data source strings extracted from the drop event
+ * @param protocols
+ * - protocol for each data source extracted from the drop event
+ * @param evt
+ * - the drop event
+ * @param t
+ * - the payload from the drop event
+ * @throws Exception
+ */
public static void transferFromDropTarget(List<String> files,
List<DataSourceType> protocols, DropTargetDropEvent evt,
Transferable t) throws Exception
{
DataFlavor uriListFlavor = new DataFlavor(
- "text/uri-list;class=java.lang.String");
+ "text/uri-list;class=java.lang.String"), urlFlavour = null;
+ try
+ {
+ urlFlavour = new DataFlavor(
+ "application/x-java-url; class=java.net.URL");
+ } catch (ClassNotFoundException cfe)
+ {
+ Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
+ }
+
+ if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
+ {
+
+ try
+ {
+ java.net.URL url = (URL) t.getTransferData(urlFlavour);
+ // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
+ // means url may be null.
+ if (url != null)
+ {
+ protocols.add(DataSourceType.URL);
+ files.add(url.toString());
+ Cache.log.debug("Drop handled as URL dataflavor "
+ + files.get(files.size() - 1));
+ return;
+ }
+ else
+ {
+ if (Platform.isAMac())
+ {
+ System.err.println(
+ "Please ignore plist error - occurs due to problem with java 8 on OSX");
+ }
+ ;
+ }
+ } catch (Throwable ex)
+ {
+ Cache.log.debug("URL drop handler failed.", ex);
+ }
+ }
if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
{
// Works on Windows and MacOSX
// fallback to text: workaround - on OSX where there's a JVM bug
Cache.log.debug("standard URIListFlavor failed. Trying text");
// try text fallback
- data = (String) t.getTransferData(
- new DataFlavor("text/plain;class=java.lang.String"));
- if (Cache.log.isDebugEnabled())
+ DataFlavor textDf = new DataFlavor(
+ "text/plain;class=java.lang.String");
+ if (t.isDataFlavorSupported(textDf))
{
- Cache.log.debug("fallback returned " + data);
+ data = (String) t.getTransferData(textDf);
}
+
+ Cache.log.debug("Plain text drop content returned "
+ + (data == null ? "Null - failed" : data));
+
}
- while (protocols.size() < files.size())
- {
- Cache.log.debug("Adding missing FILE protocol for "
- + files.get(protocols.size()));
- protocols.add(DataSourceType.FILE);
- }
- for (java.util.StringTokenizer st = new java.util.StringTokenizer(
- data, "\r\n"); st.hasMoreTokens();)
+ if (data != null)
{
- added = true;
- String s = st.nextToken();
- if (s.startsWith("#"))
+ while (protocols.size() < files.size())
{
- // the line is a comment (as per the RFC 2483)
- continue;
+ Cache.log.debug("Adding missing FILE protocol for "
+ + files.get(protocols.size()));
+ protocols.add(DataSourceType.FILE);
}
- java.net.URI uri = new java.net.URI(s);
- if (uri.getScheme().toLowerCase().startsWith("http"))
+ for (java.util.StringTokenizer st = new java.util.StringTokenizer(
+ data, "\r\n"); st.hasMoreTokens();)
{
- protocols.add(DataSourceType.URL);
- files.add(uri.toString());
- }
- else
- {
- // otherwise preserve old behaviour: catch all for file objects
- java.io.File file = new java.io.File(uri);
- protocols.add(DataSourceType.FILE);
- files.add(file.toString());
+ added = true;
+ String s = st.nextToken();
+ if (s.startsWith("#"))
+ {
+ // the line is a comment (as per the RFC 2483)
+ continue;
+ }
+ java.net.URI uri = new java.net.URI(s);
+ if (uri.getScheme().toLowerCase().startsWith("http"))
+ {
+ protocols.add(DataSourceType.URL);
+ files.add(uri.toString());
+ }
+ else
+ {
+ // otherwise preserve old behaviour: catch all for file objects
+ java.io.File file = new java.io.File(uri);
+ protocols.add(DataSourceType.FILE);
+ files.add(file.toString());
+ }
}
}
+
if (Cache.log.isDebugEnabled())
{
if (data == null || !added)
{
- Cache.log.debug(
- "Couldn't resolve drop data. Here are the supported flavors:");
- for (DataFlavor fl : t.getTransferDataFlavors())
+
+ if (t.getTransferDataFlavors() != null
+ && t.getTransferDataFlavors().length > 0)
{
Cache.log.debug(
- "Supported transfer dataflavor: " + fl.toString());
- Object df = t.getTransferData(fl);
- if (df != null)
- {
- Cache.log.debug("Retrieves: " + df);
- }
- else
+ "Couldn't resolve drop data. Here are the supported flavors:");
+ for (DataFlavor fl : t.getTransferDataFlavors())
{
- Cache.log.debug("Retrieved nothing");
+ Cache.log.debug(
+ "Supported transfer dataflavor: " + fl.toString());
+ Object df = t.getTransferData(fl);
+ if (df != null)
+ {
+ Cache.log.debug("Retrieves: " + df);
+ }
+ else
+ {
+ Cache.log.debug("Retrieved nothing");
+ }
}
}
+ else
+ {
+ Cache.log.debug("Couldn't resolve dataflavor for drop: "
+ + t.toString());
+ }
+ }
+ }
+ }
+ if (Platform.isWindows())
+
+ {
+ Cache.log.debug("Scanning dropped content for Windows Link Files");
+
+ // resolve any .lnk files in the file drop
+ for (int f = 0; f < files.size(); f++)
+ {
+ String source = files.get(f).toLowerCase();
+ if (protocols.get(f).equals(DataSourceType.FILE)
+ && (source.endsWith(".lnk") || source.endsWith(".url")
+ || source.endsWith(".site")))
+ {
+ try {
+ File lf = new File(files.get(f));
+ // process link file to get a URL
+ Cache.log.debug("Found potential link file: " + lf);
+ WindowsShortcut wscfile = new WindowsShortcut(lf);
+ String fullname = wscfile.getRealFilename();
+ protocols.set(f, FormatAdapter.checkProtocol(fullname));
+ files.set(f, fullname);
+ Cache.log.debug("Parsed real filename " + fullname
+ + " to extract protocol: " + protocols.get(f));
+ }
+ catch (Exception ex)
+ {
+ Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
+ }
}
}
}
{
Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
}
+
+ /**
+ * Answers a (possibly empty) list of any structure viewer frames (currently
+ * for either Jmol or Chimera) which are currently open. This may optionally
+ * be restricted to viewers of a specified class, or viewers linked to a
+ * specified alignment panel.
+ *
+ * @param apanel
+ * if not null, only return viewers linked to this panel
+ * @param structureViewerClass
+ * if not null, only return viewers of this class
+ * @return
+ */
+ public List<StructureViewerBase> getStructureViewers(
+ AlignmentPanel apanel,
+ Class<? extends StructureViewerBase> structureViewerClass)
+ {
+ List<StructureViewerBase> result = new ArrayList<>();
+ JInternalFrame[] frames = Desktop.instance.getAllFrames();
+
+ for (JInternalFrame frame : frames)
+ {
+ if (frame instanceof StructureViewerBase)
+ {
+ if (structureViewerClass == null
+ || structureViewerClass.isInstance(frame))
+ {
+ if (apanel == null
+ || ((StructureViewerBase) frame).isLinkedWith(apanel))
+ {
+ result.add((StructureViewerBase) frame);
+ }
+ }
+ }
+ }
+ return result;
+ }
}
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.gui;
-
-import jalview.api.FeatureColourI;
-import jalview.datamodel.GraphLine;
-import jalview.schemes.FeatureColour;
-import jalview.util.MessageManager;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-
-import javax.swing.BorderFactory;
-import javax.swing.JCheckBox;
-import javax.swing.JColorChooser;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JSlider;
-import javax.swing.JTextField;
-import javax.swing.border.LineBorder;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-public class FeatureColourChooser extends JalviewDialog
-{
- // FeatureSettings fs;
- private FeatureRenderer fr;
-
- private FeatureColourI cs;
-
- private FeatureColourI oldcs;
-
- private AlignmentPanel ap;
-
- private boolean adjusting = false;
-
- final private float min;
-
- final private float max;
-
- final private float scaleFactor;
-
- private String type = null;
-
- private JPanel minColour = new JPanel();
-
- private JPanel maxColour = new JPanel();
-
- private JComboBox<String> threshold = new JComboBox<>();
-
- private JSlider slider = new JSlider();
-
- private JTextField thresholdValue = new JTextField(20);
-
- // TODO implement GUI for tolower flag
- // JCheckBox toLower = new JCheckBox();
-
- private JCheckBox thresholdIsMin = new JCheckBox();
-
- private JCheckBox colourByLabel = new JCheckBox();
-
- private GraphLine threshline;
-
- private Color oldmaxColour;
-
- private Color oldminColour;
-
- private ActionListener colourEditor = null;
-
- /**
- * Constructor
- *
- * @param frender
- * @param theType
- */
- public FeatureColourChooser(FeatureRenderer frender, String theType)
- {
- this(frender, false, theType);
- }
-
- /**
- * Constructor, with option to make a blocking dialog (has to complete in the
- * AWT event queue thread). Currently this option is always set to false.
- *
- * @param frender
- * @param blocking
- * @param theType
- */
- FeatureColourChooser(FeatureRenderer frender, boolean blocking,
- String theType)
- {
- this.fr = frender;
- this.type = theType;
- ap = fr.ap;
- String title = MessageManager
- .formatMessage("label.graduated_color_for_params", new String[]
- { theType });
- initDialogFrame(this, true, blocking, title, 480, 185);
-
- slider.addChangeListener(new ChangeListener()
- {
- @Override
- public void stateChanged(ChangeEvent evt)
- {
- if (!adjusting)
- {
- thresholdValue.setText((slider.getValue() / scaleFactor) + "");
- sliderValueChanged();
- }
- }
- });
- slider.addMouseListener(new MouseAdapter()
- {
- @Override
- public void mouseReleased(MouseEvent evt)
- {
- /*
- * only update Overview and/or structure colouring
- * when threshold slider drag ends (mouse up)
- */
- if (ap != null)
- {
- ap.paintAlignment(true, true);
- }
- }
- });
-
- float mm[] = fr.getMinMax().get(theType)[0];
- min = mm[0];
- max = mm[1];
-
- /*
- * ensure scale factor allows a scaled range with
- * 10 integer divisions ('ticks'); if we have got here,
- * we should expect that max != min
- */
- scaleFactor = (max == min) ? 1f : 100f / (max - min);
-
- oldcs = fr.getFeatureColours().get(theType);
- if (!oldcs.isSimpleColour())
- {
- if (oldcs.isAutoScaled())
- {
- // update the scale
- cs = new FeatureColour((FeatureColour) oldcs, min, max);
- }
- else
- {
- cs = new FeatureColour((FeatureColour) oldcs);
- }
- }
- else
- {
- // promote original color to a graduated color
- Color bl = oldcs.getColour();
- if (bl == null)
- {
- bl = Color.BLACK;
- }
- // original colour becomes the maximum colour
- cs = new FeatureColour(Color.white, bl, mm[0], mm[1]);
- cs.setColourByLabel(false);
- }
- minColour.setBackground(oldminColour = cs.getMinColour());
- maxColour.setBackground(oldmaxColour = cs.getMaxColour());
- adjusting = true;
-
- try
- {
- jbInit();
- } catch (Exception ex)
- {
- }
- // update the gui from threshold state
- thresholdIsMin.setSelected(!cs.isAutoScaled());
- colourByLabel.setSelected(cs.isColourByLabel());
- if (cs.hasThreshold())
- {
- // initialise threshold slider and selector
- threshold.setSelectedIndex(cs.isAboveThreshold() ? 1 : 2);
- slider.setEnabled(true);
- slider.setValue((int) (cs.getThreshold() * scaleFactor));
- thresholdValue.setEnabled(true);
- threshline = new GraphLine((max - min) / 2f, "Threshold",
- Color.black);
- threshline.value = cs.getThreshold();
- }
-
- adjusting = false;
-
- changeColour(false);
- waitForInput();
- }
-
- private void jbInit() throws Exception
- {
-
- minColour.setFont(JvSwingUtils.getLabelFont());
- minColour.setBorder(BorderFactory.createLineBorder(Color.black));
- minColour.setPreferredSize(new Dimension(40, 20));
- minColour.setToolTipText(MessageManager.getString("label.min_colour"));
- minColour.addMouseListener(new MouseAdapter()
- {
- @Override
- public void mousePressed(MouseEvent e)
- {
- if (minColour.isEnabled())
- {
- minColour_actionPerformed();
- }
- }
- });
- maxColour.setFont(JvSwingUtils.getLabelFont());
- maxColour.setBorder(BorderFactory.createLineBorder(Color.black));
- maxColour.setPreferredSize(new Dimension(40, 20));
- maxColour.setToolTipText(MessageManager.getString("label.max_colour"));
- maxColour.addMouseListener(new MouseAdapter()
- {
- @Override
- public void mousePressed(MouseEvent e)
- {
- if (maxColour.isEnabled())
- {
- maxColour_actionPerformed();
- }
- }
- });
- maxColour.setBorder(new LineBorder(Color.black));
- JLabel minText = new JLabel(MessageManager.getString("label.min"));
- minText.setFont(JvSwingUtils.getLabelFont());
- JLabel maxText = new JLabel(MessageManager.getString("label.max"));
- maxText.setFont(JvSwingUtils.getLabelFont());
- this.setLayout(new BorderLayout());
- JPanel jPanel1 = new JPanel();
- jPanel1.setBackground(Color.white);
- JPanel jPanel2 = new JPanel();
- jPanel2.setLayout(new FlowLayout());
- jPanel2.setBackground(Color.white);
- threshold.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- threshold_actionPerformed();
- }
- });
- threshold.setToolTipText(MessageManager
- .getString("label.threshold_feature_display_by_score"));
- threshold.addItem(MessageManager
- .getString("label.threshold_feature_no_threshold")); // index 0
- threshold.addItem(MessageManager
- .getString("label.threshold_feature_above_threshold")); // index 1
- threshold.addItem(MessageManager
- .getString("label.threshold_feature_below_threshold")); // index 2
-
- JPanel jPanel3 = new JPanel();
- jPanel3.setLayout(new FlowLayout());
- thresholdValue.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- thresholdValue_actionPerformed();
- }
- });
- thresholdValue.addFocusListener(new FocusAdapter()
- {
- @Override
- public void focusLost(FocusEvent e)
- {
- thresholdValue_actionPerformed();
- }
- });
- slider.setPaintLabels(false);
- slider.setPaintTicks(true);
- slider.setBackground(Color.white);
- slider.setEnabled(false);
- slider.setOpaque(false);
- slider.setPreferredSize(new Dimension(100, 32));
- slider.setToolTipText(
- MessageManager.getString("label.adjust_threshold"));
- thresholdValue.setEnabled(false);
- thresholdValue.setColumns(7);
- jPanel3.setBackground(Color.white);
- thresholdIsMin.setBackground(Color.white);
- thresholdIsMin
- .setText(MessageManager.getString("label.threshold_minmax"));
- thresholdIsMin.setToolTipText(MessageManager
- .getString("label.toggle_absolute_relative_display_threshold"));
- thresholdIsMin.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent actionEvent)
- {
- thresholdIsMin_actionPerformed();
- }
- });
- colourByLabel.setBackground(Color.white);
- colourByLabel
- .setText(MessageManager.getString("label.colour_by_label"));
- colourByLabel.setToolTipText(MessageManager.getString(
- "label.display_features_same_type_different_label_using_different_colour"));
- colourByLabel.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent actionEvent)
- {
- colourByLabel_actionPerformed();
- }
- });
-
- JPanel colourPanel = new JPanel();
- colourPanel.setBackground(Color.white);
- jPanel1.add(ok);
- jPanel1.add(cancel);
- jPanel2.add(colourByLabel, BorderLayout.WEST);
- jPanel2.add(colourPanel, BorderLayout.EAST);
- colourPanel.add(minText);
- colourPanel.add(minColour);
- colourPanel.add(maxText);
- colourPanel.add(maxColour);
- this.add(jPanel3, BorderLayout.CENTER);
- jPanel3.add(threshold);
- jPanel3.add(slider);
- jPanel3.add(thresholdValue);
- jPanel3.add(thresholdIsMin);
- this.add(jPanel1, BorderLayout.SOUTH);
- this.add(jPanel2, BorderLayout.NORTH);
- }
-
- /**
- * Action on clicking the 'minimum colour' - open a colour chooser dialog, and
- * set the selected colour (if the user does not cancel out of the dialog)
- */
- protected void minColour_actionPerformed()
- {
- Color col = JColorChooser.showDialog(this,
- MessageManager.getString("label.select_colour_minimum_value"),
- minColour.getBackground());
- if (col != null)
- {
- minColour.setBackground(col);
- minColour.setForeground(col);
- }
- minColour.repaint();
- changeColour(true);
- }
-
- /**
- * Action on clicking the 'maximum colour' - open a colour chooser dialog, and
- * set the selected colour (if the user does not cancel out of the dialog)
- */
- protected void maxColour_actionPerformed()
- {
- Color col = JColorChooser.showDialog(this,
- MessageManager.getString("label.select_colour_maximum_value"),
- maxColour.getBackground());
- if (col != null)
- {
- maxColour.setBackground(col);
- maxColour.setForeground(col);
- }
- maxColour.repaint();
- changeColour(true);
- }
-
- /**
- * Constructs and sets the selected colour options as the colour for the
- * feature type, and repaints the alignment, and optionally the Overview
- * and/or structure viewer if open
- *
- * @param updateStructsAndOverview
- */
- void changeColour(boolean updateStructsAndOverview)
- {
- // Check if combobox is still adjusting
- if (adjusting)
- {
- return;
- }
-
- boolean aboveThreshold = false;
- boolean belowThreshold = false;
- if (threshold.getSelectedIndex() == 1)
- {
- aboveThreshold = true;
- }
- else if (threshold.getSelectedIndex() == 2)
- {
- belowThreshold = true;
- }
- boolean hasThreshold = aboveThreshold || belowThreshold;
-
- slider.setEnabled(true);
- thresholdValue.setEnabled(true);
-
- FeatureColourI acg;
- if (cs.isColourByLabel())
- {
- acg = new FeatureColour(oldminColour, oldmaxColour, min, max);
- }
- else
- {
- acg = new FeatureColour(oldminColour = minColour.getBackground(),
- oldmaxColour = maxColour.getBackground(), min, max);
- }
-
- if (!hasThreshold)
- {
- slider.setEnabled(false);
- thresholdValue.setEnabled(false);
- thresholdValue.setText("");
- thresholdIsMin.setEnabled(false);
- }
- else if (threshline == null)
- {
- /*
- * todo not yet implemented: visual indication of feature threshold
- */
- threshline = new GraphLine((max - min) / 2f, "Threshold",
- Color.black);
- }
-
- if (hasThreshold)
- {
- adjusting = true;
- acg.setThreshold(threshline.value);
-
- float range = (max - min) * scaleFactor;
-
- slider.setMinimum((int) (min * scaleFactor));
- slider.setMaximum((int) (max * scaleFactor));
- // slider.setValue((int) (threshline.value * scaleFactor));
- slider.setValue(Math.round(threshline.value * scaleFactor));
- thresholdValue.setText(threshline.value + "");
- slider.setMajorTickSpacing((int) (range / 10f));
- slider.setEnabled(true);
- thresholdValue.setEnabled(true);
- thresholdIsMin.setEnabled(!colourByLabel.isSelected());
- adjusting = false;
- }
-
- acg.setAboveThreshold(aboveThreshold);
- acg.setBelowThreshold(belowThreshold);
- if (thresholdIsMin.isSelected() && hasThreshold)
- {
- acg.setAutoScaled(false);
- if (aboveThreshold)
- {
- acg = new FeatureColour((FeatureColour) acg, threshline.value, max);
- }
- else
- {
- acg = new FeatureColour((FeatureColour) acg, min, threshline.value);
- }
- }
- else
- {
- acg.setAutoScaled(true);
- }
- acg.setColourByLabel(colourByLabel.isSelected());
- if (acg.isColourByLabel())
- {
- maxColour.setEnabled(false);
- minColour.setEnabled(false);
- maxColour.setBackground(this.getBackground());
- maxColour.setForeground(this.getBackground());
- minColour.setBackground(this.getBackground());
- minColour.setForeground(this.getBackground());
-
- }
- else
- {
- maxColour.setEnabled(true);
- minColour.setEnabled(true);
- maxColour.setBackground(oldmaxColour);
- minColour.setBackground(oldminColour);
- maxColour.setForeground(oldmaxColour);
- minColour.setForeground(oldminColour);
- }
- fr.setColour(type, acg);
- cs = acg;
- ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview);
- }
-
- @Override
- protected void raiseClosed()
- {
- if (this.colourEditor != null)
- {
- colourEditor.actionPerformed(new ActionEvent(this, 0, "CLOSED"));
- }
- }
-
- @Override
- public void okPressed()
- {
- changeColour(false);
- }
-
- @Override
- public void cancelPressed()
- {
- reset();
- }
-
- /**
- * Action when the user cancels the dialog. All previous settings should be
- * restored and rendered on the alignment, and any linked Overview window or
- * structure.
- */
- void reset()
- {
- fr.setColour(type, oldcs);
- ap.paintAlignment(true, true);
- cs = null;
- }
-
- /**
- * Action on change of choice of No / Above / Below Threshold
- */
- protected void threshold_actionPerformed()
- {
- changeColour(true);
- }
-
- /**
- * Action on text entry of a threshold value
- */
- protected void thresholdValue_actionPerformed()
- {
- try
- {
- float f = Float.parseFloat(thresholdValue.getText());
- slider.setValue((int) (f * scaleFactor));
- threshline.value = f;
-
- /*
- * force repaint of any Overview window or structure
- */
- ap.paintAlignment(true, true);
- } catch (NumberFormatException ex)
- {
- }
- }
-
- /**
- * Action on change of threshold slider value. This may be done interactively
- * (by moving the slider), or programmatically (to update the slider after
- * manual input of a threshold value).
- */
- protected void sliderValueChanged()
- {
- /*
- * squash rounding errors by forcing min/max of slider to
- * actual min/max of feature score range
- */
- int value = slider.getValue();
- threshline.value = value == slider.getMaximum() ? max
- : (value == slider.getMinimum() ? min : value / scaleFactor);
- cs.setThreshold(threshline.value);
-
- /*
- * repaint alignment, but not Overview or structure,
- * to avoid overload while dragging the slider
- */
- changeColour(false);
- }
-
- protected void thresholdIsMin_actionPerformed()
- {
- changeColour(true);
- }
-
- protected void colourByLabel_actionPerformed()
- {
- changeColour(true);
- }
-
- void addActionListener(ActionListener graduatedColorEditor)
- {
- if (colourEditor != null)
- {
- System.err.println(
- "IMPLEMENTATION ISSUE: overwriting action listener for FeatureColourChooser");
- }
- colourEditor = graduatedColorEditor;
- }
-
- /**
- * Answers the last colour setting selected by user - either oldcs (which may
- * be a java.awt.Color) or the new GraduatedColor
- *
- * @return
- */
- FeatureColourI getLastColour()
- {
- if (cs == null)
- {
- return oldcs;
- }
- return cs;
- }
-
-}
final JSpinner end = new JSpinner();
start.setPreferredSize(new Dimension(80, 20));
end.setPreferredSize(new Dimension(80, 20));
- final FeatureRenderer me = this;
final JLabel colour = new JLabel();
colour.setOpaque(true);
// colour.setBorder(BorderFactory.createEtchedBorder());
colour.setMaximumSize(new Dimension(30, 16));
colour.addMouseListener(new MouseAdapter()
{
- FeatureColourChooser fcc = null;
-
+ /*
+ * open colour chooser on click in colour panel
+ */
@Override
public void mousePressed(MouseEvent evt)
{
}
else
{
- if (fcc == null)
+ /*
+ * variable colour dialog - on OK, refetch the updated
+ * feature colour and update this display
+ */
+ final String ft = features.get(featureIndex).getType();
+ final String type = ft == null ? lastFeatureAdded : ft;
+ FeatureTypeSettings fcc = new FeatureTypeSettings(
+ FeatureRenderer.this, type);
+ fcc.setRequestFocusEnabled(true);
+ fcc.requestFocus();
+ fcc.addActionListener(new ActionListener()
{
- final String ft = features.get(featureIndex).getType();
- final String type = ft == null ? lastFeatureAdded : ft;
- fcc = new FeatureColourChooser(me, type);
- fcc.setRequestFocusEnabled(true);
- fcc.requestFocus();
-
- fcc.addActionListener(new ActionListener()
+ @Override
+ public void actionPerformed(ActionEvent e)
{
-
- @Override
- public void actionPerformed(ActionEvent e)
- {
- fcol = fcc.getLastColour();
- fcc = null;
- setColour(type, fcol);
- updateColourButton(mainPanel, colour, fcol);
- }
- });
-
- }
+ fcol = FeatureRenderer.this.getFeatureStyle(ft);
+ setColour(type, fcol);
+ updateColourButton(mainPanel, colour, fcol);
+ }
+ });
}
}
});
import jalview.api.FeatureColourI;
import jalview.api.FeatureSettingsControllerI;
-import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherI;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.gui.Help.HelpId;
import jalview.io.JalviewFileChooser;
import jalview.io.JalviewFileView;
+import jalview.schemabinding.version2.Filter;
import jalview.schemabinding.version2.JalviewUserColours;
+import jalview.schemabinding.version2.MatcherSet;
import jalview.schemes.FeatureColour;
-import jalview.util.Format;
import jalview.util.MessageManager;
import jalview.util.Platform;
-import jalview.util.QuickSort;
-import jalview.viewmodel.AlignmentViewport;
-import jalview.ws.dbsources.das.api.jalviewSourceI;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
+import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.Vector;
import javax.help.HelpSetException;
import javax.swing.AbstractCellEditor;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
-import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
-import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
public class FeatureSettings extends JPanel
implements FeatureSettingsControllerI
{
- DasSourceBrowser dassourceBrowser;
+ private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
+ .getString("label.sequence_feature_colours");
- jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
+ /*
+ * column indices of fields in Feature Settings table
+ */
+ static final int TYPE_COLUMN = 0;
+
+ static final int COLOUR_COLUMN = 1;
+
+ static final int FILTER_COLUMN = 2;
+
+ static final int SHOW_COLUMN = 3;
- JPanel settingsPane = new JPanel();
+ private static final int COLUMN_COUNT = 4;
- JPanel dasSettingsPane = new JPanel();
+ private static final int MIN_WIDTH = 400;
+
+ private static final int MIN_HEIGHT = 400;
final FeatureRenderer fr;
public final AlignFrame af;
+ /*
+ * 'original' fields hold settings to restore on Cancel
+ */
Object[][] originalData;
private float originalTransparency;
+ private Map<String, FeatureMatcherSetI> originalFilters;
+
final JInternalFrame frame;
JScrollPane scrollPane = new JScrollPane();
JSlider transparency = new JSlider();
- JPanel transPanel = new JPanel(new GridLayout(1, 2));
-
- 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;
+ int selectedRow = -1;
+
+ JButton fetchDAS = new JButton();
+
+ JButton saveDAS = new JButton();
+
+ JButton cancelDAS = new JButton();
+
+ boolean resettingTable = false;
+
+ /*
+ * true when Feature Settings are updating from feature renderer
+ */
+ private boolean handlingUpdate = false;
+
+ /*
+ * holds {featureCount, totalExtent} for each feature type
+ */
+ Map<String, float[]> typeWidth = null;
+
/**
* Constructor
*
* @param af
*/
- public FeatureSettings(AlignFrame af)
+ public FeatureSettings(AlignFrame alignFrame)
{
- this.af = af;
+ this.af = alignFrame;
fr = af.getFeatureRenderer();
- // allow transparency to be recovered
- transparency.setMaximum(100
- - (int) ((originalTransparency = fr.getTransparency()) * 100));
+
+ // save transparency for restore on Cancel
+ originalTransparency = fr.getTransparency();
+ int originalTransparencyAsPercent = (int) (originalTransparency * 100);
+ transparency.setMaximum(100 - originalTransparencyAsPercent);
+
+ originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
try
{
@Override
public String getToolTipText(MouseEvent e)
{
- if (table.columnAtPoint(e.getPoint()) == 0)
+ String tip = null;
+ int column = table.columnAtPoint(e.getPoint());
+ switch (column)
{
- /*
- * Tooltip for feature name only
- */
- return JvSwingUtils.wrapTooltip(true, MessageManager
+ case TYPE_COLUMN:
+ tip = JvSwingUtils.wrapTooltip(true, MessageManager
.getString("label.feature_settings_click_drag"));
+ break;
+ case FILTER_COLUMN:
+ int row = table.rowAtPoint(e.getPoint());
+ FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
+ column);
+ tip = o.isEmpty()
+ ? MessageManager.getString("label.filters_tooltip")
+ : o.toString();
+ break;
+ default:
+ break;
}
- return null;
+ return tip;
}
};
table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
table.setFont(new Font("Verdana", Font.PLAIN, 12));
- table.setDefaultRenderer(Color.class, new ColorRenderer());
-
- table.setDefaultEditor(Color.class, new ColorEditor(this));
+ // table.setDefaultRenderer(Color.class, new ColorRenderer());
+ // table.setDefaultEditor(Color.class, new ColorEditor(this));
+ //
table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
+
+ table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
+ table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
+
+ TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
+ new ColorRenderer(), new ColorEditor(this));
+ table.addColumn(colourColumn);
+
+ TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
+ new FilterRenderer(), new FilterEditor(this));
+ table.addColumn(filterColumn);
+
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.addMouseListener(new MouseAdapter()
public void mousePressed(MouseEvent evt)
{
selectedRow = table.rowAtPoint(evt.getPoint());
+ String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
if (evt.isPopupTrigger())
{
- popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
- table.getValueAt(selectedRow, 1), fr.getMinMax(),
- evt.getX(), evt.getY());
+ Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
+ popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
+ evt.getY());
}
else if (evt.getClickCount() == 2)
{
boolean toggleSelection = Platform.isControlDown(evt);
boolean extendSelection = evt.isShiftDown();
fr.ap.alignFrame.avc.markColumnsContainingFeatures(
- invertSelection, extendSelection, toggleSelection,
- (String) table.getValueAt(selectedRow, 0));
+ invertSelection, extendSelection, toggleSelection, type);
}
}
selectedRow = table.rowAtPoint(evt.getPoint());
if (evt.isPopupTrigger())
{
- popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
- table.getValueAt(selectedRow, 1), fr.getMinMax(),
- evt.getX(), evt.getY());
+ String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
+ Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
+ popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
+ evt.getY());
}
}
});
// MessageManager.getString("label.feature_settings_click_drag")));
scrollPane.setViewportView(table);
- dassourceBrowser = new DasSourceBrowser(this);
- dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
-
if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
{
fr.findAllFeatures(true); // display everything!
if (!fs.resettingTable && !fs.handlingUpdate)
{
fs.handlingUpdate = true;
- fs.resetTable(null); // new groups may be added with new seuqence
- // feature types only
+ fs.resetTable(null);
+ // new groups may be added with new sequence feature types only
fs.handlingUpdate = false;
}
}
{
Desktop.addInternalFrame(frame,
MessageManager.getString("label.sequence_feature_settings"),
- 475, 480);
+ 600, 480);
}
else
{
Desktop.addInternalFrame(frame,
MessageManager.getString("label.sequence_feature_settings"),
- 400, 450);
+ 600, 450);
}
frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
javax.swing.event.InternalFrameEvent evt)
{
fr.removePropertyChangeListener(change);
- dassourceBrowser.fs = null;
};
});
frame.setLayer(JLayeredPane.PALETTE_LAYER);
inConstruction = false;
}
- protected void popupSort(final int selectedRow, final String type,
+ protected void popupSort(final int rowSelected, final String type,
final Object typeCol, final Map<String, float[][]> minmax, int x,
int y)
{
});
men.add(dens);
- if (minmax != null)
+
+ /*
+ * variable colour options include colour by label, by score,
+ * by selected attribute text, or attribute value
+ */
+ final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
+ MessageManager.getString("label.variable_colour"));
+ mxcol.setSelected(!featureColour.isSimpleColour());
+ men.add(mxcol);
+ mxcol.addActionListener(new ActionListener()
{
- final float[][] typeMinMax = minmax.get(type);
- /*
- * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
- * this is broken at the moment and isn't that useful anyway!
- * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
- * ActionListener() {
- *
- * public void actionPerformed(ActionEvent e) {
- * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
- * null); } else { minmax.put(type, typeMinMax); } }
- *
- * });
- *
- * men.add(chb);
- */
- if (typeMinMax != null && typeMinMax[0] != null)
- {
- // if (table.getValueAt(row, column));
- // graduated colourschemes for those where minmax exists for the
- // positional features
- final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
- "Graduated Colour");
- mxcol.setSelected(!featureColour.isSimpleColour());
- men.add(mxcol);
- mxcol.addActionListener(new ActionListener()
- {
- JColorChooser colorChooser;
+ JColorChooser colorChooser;
- @Override
- public void actionPerformed(ActionEvent e)
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ if (e.getSource() == mxcol)
+ {
+ if (featureColour.isSimpleColour())
{
- if (e.getSource() == mxcol)
- {
- if (featureColour.isSimpleColour())
- {
- FeatureColourChooser fc = new FeatureColourChooser(me.fr,
- type);
- fc.addActionListener(this);
- }
- else
- {
- // bring up simple color chooser
- colorChooser = new JColorChooser();
- JDialog dialog = JColorChooser.createDialog(me,
- "Select new Colour", true, // modal
- colorChooser, this, // OK button handler
- null); // no CANCEL button handler
- colorChooser.setColor(featureColour.getMaxColour());
- dialog.setVisible(true);
- }
- }
- else
- {
- if (e.getSource() instanceof FeatureColourChooser)
- {
- FeatureColourChooser fc = (FeatureColourChooser) e
- .getSource();
- table.setValueAt(fc.getLastColour(), selectedRow, 1);
- table.validate();
- }
- else
- {
- // probably the color chooser!
- table.setValueAt(new FeatureColour(colorChooser.getColor()),
- selectedRow, 1);
- table.validate();
- me.updateFeatureRenderer(
- ((FeatureTableModel) table.getModel()).getData(),
- false);
- }
- }
+ FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
+ fc.addActionListener(this);
}
-
- });
+ else
+ {
+ // bring up simple color chooser
+ colorChooser = new JColorChooser();
+ String title = MessageManager
+ .getString("label.select_colour");
+ JDialog dialog = JColorChooser.createDialog(me,
+ title, true, // modal
+ colorChooser, this, // OK button handler
+ null); // no CANCEL button handler
+ colorChooser.setColor(featureColour.getMaxColour());
+ dialog.setVisible(true);
+ }
+ }
+ else
+ {
+ if (e.getSource() instanceof FeatureTypeSettings)
+ {
+ /*
+ * update after OK in feature colour dialog; the updated
+ * colour will have already been set in the FeatureRenderer
+ */
+ FeatureColourI fci = fr.getFeatureColours().get(type);
+ table.setValueAt(fci, rowSelected, 1);
+ table.validate();
+ }
+ else
+ {
+ // probably the color chooser!
+ table.setValueAt(new FeatureColour(colorChooser.getColor()),
+ rowSelected, 1);
+ table.validate();
+ me.updateFeatureRenderer(
+ ((FeatureTableModel) table.getModel()).getData(),
+ false);
+ }
+ }
}
- }
+
+ });
+
JMenuItem selCols = new JMenuItem(
MessageManager.getString("label.select_columns_containing"));
selCols.addActionListener(new ActionListener()
men.show(table, x, y);
}
- /**
- * true when Feature Settings are updating from feature renderer
- */
- private boolean handlingUpdate = false;
-
- /**
- * holds {featureCount, totalExtent} for each feature type
- */
- Map<String, float[]> typeWidth = null;
-
@Override
synchronized public void discoverAllFeatureData()
{
return visible;
}
- boolean resettingTable = false;
-
synchronized void resetTable(String[] groupChanged)
{
if (resettingTable)
}
}
- Object[][] data = new Object[displayableTypes.size()][3];
+ Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
int dataIndex = 0;
if (fr.hasRenderOrder())
continue;
}
- data[dataIndex][0] = type;
- data[dataIndex][1] = fr.getFeatureStyle(type);
- data[dataIndex][2] = new Boolean(
+ data[dataIndex][TYPE_COLUMN] = type;
+ data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
+ FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
+ data[dataIndex][FILTER_COLUMN] = featureFilter == null
+ ? new FeatureMatcherSet()
+ : featureFilter;
+ data[dataIndex][SHOW_COLUMN] = new Boolean(
af.getViewport().getFeaturesDisplayed().isVisible(type));
dataIndex++;
displayableTypes.remove(type);
while (!displayableTypes.isEmpty())
{
String type = displayableTypes.iterator().next();
- data[dataIndex][0] = type;
+ data[dataIndex][TYPE_COLUMN] = type;
- data[dataIndex][1] = fr.getFeatureStyle(type);
- if (data[dataIndex][1] == null)
+ data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
+ if (data[dataIndex][COLOUR_COLUMN] == null)
{
// "Colour has been updated in another view!!"
fr.clearRenderOrder();
return;
}
-
- data[dataIndex][2] = new Boolean(true);
+ FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
+ data[dataIndex][FILTER_COLUMN] = featureFilter == null
+ ? new FeatureMatcherSet()
+ : featureFilter;
+ data[dataIndex][SHOW_COLUMN] = new Boolean(true);
dataIndex++;
displayableTypes.remove(type);
}
if (originalData == null)
{
- originalData = new Object[data.length][3];
+ originalData = new Object[data.length][COLUMN_COUNT];
for (int i = 0; i < data.length; i++)
{
- System.arraycopy(data[i], 0, originalData[i], 0, 3);
+ System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
}
}
else
}
/**
- * Updates 'originalData' (used for restore on Cancel) if we detect that
- * changes have been made outwith this dialog
+ * Updates 'originalData' (used for restore on Cancel) if we detect that changes
+ * have been made outwith this dialog
* <ul>
* <li>a new feature type added (and made visible)</li>
* <li>a feature colour changed (in the Amend Features dialog)</li>
.getData();
for (Object[] row : foundData)
{
- String type = (String) row[0];
+ String type = (String) row[TYPE_COLUMN];
boolean found = false;
for (Object[] current : currentData)
{
- if (type.equals(current[0]))
+ if (type.equals(current[TYPE_COLUMN]))
{
found = true;
/*
* currently dependent on object equality here;
* really need an equals method on FeatureColour
*/
- if (!row[1].equals(current[1]))
+ if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
{
/*
* feature colour has changed externally - update originalData
*/
for (Object[] original : originalData)
{
- if (type.equals(original[0]))
+ if (type.equals(original[TYPE_COLUMN]))
{
- original[1] = row[1];
+ original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
break;
}
}
/*
* new feature detected - add to original data (on top)
*/
- Object[][] newData = new Object[originalData.length + 1][3];
+ Object[][] newData = new Object[originalData.length
+ + 1][COLUMN_COUNT];
for (int i = 0; i < originalData.length; i++)
{
- System.arraycopy(originalData[i], 0, newData[i + 1], 0, 3);
+ System.arraycopy(originalData[i], 0, newData[i + 1], 0,
+ COLUMN_COUNT);
}
newData[0] = row;
originalData = newData;
/**
* Remove from the groups panel any checkboxes for groups that are not in the
- * foundGroups set. This enables removing a group from the display when the
- * last feature in that group is deleted.
+ * foundGroups set. This enables removing a group from the display when the last
+ * feature in that group is deleted.
*
* @param foundGroups
*/
}
}
+ /**
+ * Offers a file chooser dialog, and then loads the feature colours and
+ * filters from file in XML format and unmarshals to Jalview feature settings
+ */
void load()
{
JalviewFileChooser chooser = new JalviewFileChooser("fc",
- "Sequence Feature Colours");
+ SEQUENCE_FEATURE_COLOURS);
chooser.setFileView(new JalviewFileView());
chooser.setDialogTitle(
MessageManager.getString("label.load_feature_colours"));
if (value == JalviewFileChooser.APPROVE_OPTION)
{
File file = chooser.getSelectedFile();
+ load(file);
+ }
+ }
- try
- {
- InputStreamReader in = new InputStreamReader(
- new FileInputStream(file), "UTF-8");
+ /**
+ * Loads feature colours and filters from XML stored in the given file
+ *
+ * @param file
+ */
+ void load(File file)
+ {
+ try
+ {
+ InputStreamReader in = new InputStreamReader(
+ new FileInputStream(file), "UTF-8");
- JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
+ JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
- for (int i = jucs.getColourCount() - 1; i >= 0; i--)
- {
- String name;
- jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
- if (newcol.hasMax())
- {
- Color mincol = null, maxcol = null;
- try
- {
- mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
- maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
+ /*
+ * load feature colours
+ */
+ for (int i = jucs.getColourCount() - 1; i >= 0; i--)
+ {
+ jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
+ FeatureColourI colour = Jalview2XML.unmarshalColour(newcol);
+ fr.setColour(newcol.getName(), colour);
+ fr.setOrder(newcol.getName(), i / (float) jucs.getColourCount());
+ }
- } catch (Exception e)
- {
- Cache.log.warn("Couldn't parse out graduated feature color.",
- e);
- }
- FeatureColourI gcol = new FeatureColour(mincol, maxcol,
- newcol.getMin(), newcol.getMax());
- if (newcol.hasAutoScale())
- {
- gcol.setAutoScaled(newcol.getAutoScale());
- }
- if (newcol.hasColourByLabel())
- {
- gcol.setColourByLabel(newcol.getColourByLabel());
- }
- if (newcol.hasThreshold())
- {
- gcol.setThreshold(newcol.getThreshold());
- }
- if (newcol.getThreshType().length() > 0)
- {
- String ttyp = newcol.getThreshType();
- if (ttyp.equalsIgnoreCase("ABOVE"))
- {
- gcol.setAboveThreshold(true);
- }
- if (ttyp.equalsIgnoreCase("BELOW"))
- {
- gcol.setBelowThreshold(true);
- }
- }
- fr.setColour(name = newcol.getName(), gcol);
- }
- else
- {
- Color color = new Color(
- Integer.parseInt(jucs.getColour(i).getRGB(), 16));
- fr.setColour(name = jucs.getColour(i).getName(),
- new FeatureColour(color));
- }
- fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
- }
- if (table != null)
+ /*
+ * load feature filters; loaded filters will replace any that are
+ * currently defined, other defined filters are left unchanged
+ */
+ for (int i = 0; i < jucs.getFilterCount(); i++)
+ {
+ jalview.schemabinding.version2.Filter filterModel = jucs
+ .getFilter(i);
+ String featureType = filterModel.getFeatureType();
+ FeatureMatcherSetI filter = Jalview2XML.unmarshalFilter(featureType,
+ filterModel.getMatcherSet());
+ if (!filter.isEmpty())
{
- resetTable(null);
- Object[][] data = ((FeatureTableModel) table.getModel())
- .getData();
- ensureOrder(data);
- updateFeatureRenderer(data, false);
- table.repaint();
+ fr.setFeatureFilter(featureType, filter);
}
- } catch (Exception ex)
- {
- System.out.println("Error loading User Colour File\n" + ex);
}
+
+ /*
+ * update feature settings table
+ */
+ if (table != null)
+ {
+ resetTable(null);
+ Object[][] data = ((FeatureTableModel) table.getModel())
+ .getData();
+ ensureOrder(data);
+ updateFeatureRenderer(data, false);
+ table.repaint();
+ }
+ } catch (Exception ex)
+ {
+ System.out.println("Error loading User Colour File\n" + ex);
}
}
+ /**
+ * Offers a file chooser dialog, and then saves the current feature colours
+ * and any filters to the selected file in XML format
+ */
void save()
{
JalviewFileChooser chooser = new JalviewFileChooser("fc",
- "Sequence Feature Colours");
+ SEQUENCE_FEATURE_COLOURS);
chooser.setFileView(new JalviewFileView());
chooser.setDialogTitle(
MessageManager.getString("label.save_feature_colours"));
if (value == JalviewFileChooser.APPROVE_OPTION)
{
- String choice = chooser.getSelectedFile().getPath();
- jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
- ucs.setSchemeName("Sequence Features");
- try
- {
- PrintWriter out = new PrintWriter(new OutputStreamWriter(
- new FileOutputStream(choice), "UTF-8"));
+ save(chooser.getSelectedFile());
+ }
+ }
- Set<String> fr_colours = fr.getAllFeatureColours();
- Iterator<String> e = fr_colours.iterator();
- float[] sortOrder = new float[fr_colours.size()];
- String[] sortTypes = new String[fr_colours.size()];
- int i = 0;
- while (e.hasNext())
+ /**
+ * Saves feature colours and filters to the given file
+ *
+ * @param file
+ */
+ void save(File file)
+ {
+ JalviewUserColours ucs = new JalviewUserColours();
+ ucs.setSchemeName("Sequence Features");
+ try
+ {
+ PrintWriter out = new PrintWriter(new OutputStreamWriter(
+ new FileOutputStream(file), "UTF-8"));
+
+ /*
+ * sort feature types by colour order, from 0 (highest)
+ * to 1 (lowest)
+ */
+ Set<String> fr_colours = fr.getAllFeatureColours();
+ String[] sortedTypes = fr_colours
+ .toArray(new String[fr_colours.size()]);
+ Arrays.sort(sortedTypes, new Comparator<String>()
+ {
+ @Override
+ public int compare(String type1, String type2)
{
- sortTypes[i] = e.next();
- sortOrder[i] = fr.getOrder(sortTypes[i]);
- i++;
+ return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
}
- QuickSort.sort(sortOrder, sortTypes);
- sortOrder = null;
- for (i = 0; i < sortTypes.length; i++)
+ });
+
+ /*
+ * save feature colours
+ */
+ for (String featureType : sortedTypes)
+ {
+ FeatureColourI fcol = fr.getFeatureStyle(featureType);
+ jalview.schemabinding.version2.Colour col = Jalview2XML.marshalColour(
+ featureType, fcol);
+ ucs.addColour(col);
+ }
+
+ /*
+ * save any feature filters
+ */
+ for (String featureType : sortedTypes)
+ {
+ FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
+ if (filter != null && !filter.isEmpty())
{
- jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
- col.setName(sortTypes[i]);
- FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
- if (fcol.isSimpleColour())
- {
- col.setRGB(Format.getHexString(fcol.getColour()));
- }
- else
- {
- col.setRGB(Format.getHexString(fcol.getMaxColour()));
- col.setMin(fcol.getMin());
- col.setMax(fcol.getMax());
- col.setMinRGB(
- jalview.util.Format.getHexString(fcol.getMinColour()));
- col.setAutoScale(fcol.isAutoScaled());
- col.setThreshold(fcol.getThreshold());
- col.setColourByLabel(fcol.isColourByLabel());
- col.setThreshType(fcol.isAboveThreshold() ? "ABOVE"
- : (fcol.isBelowThreshold() ? "BELOW" : "NONE"));
- }
- ucs.addColour(col);
+ Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
+ FeatureMatcherI firstMatcher = iterator.next();
+ MatcherSet ms = Jalview2XML.marshalFilter(firstMatcher, iterator,
+ filter.isAnded());
+ Filter filterModel = new Filter();
+ filterModel.setFeatureType(featureType);
+ filterModel.setMatcherSet(ms);
+ ucs.addFilter(filterModel);
}
- ucs.marshal(out);
- out.close();
- } catch (Exception ex)
- {
- ex.printStackTrace();
}
+
+ ucs.marshal(out);
+ out.close();
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
}
}
public void invertSelection()
{
- for (int i = 0; i < table.getRowCount(); i++)
+ Object[][] data = ((FeatureTableModel) table.getModel()).getData();
+ for (int i = 0; i < data.length; i++)
{
- Boolean value = (Boolean) table.getValueAt(i, 2);
-
- table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
+ data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
}
+ updateFeatureRenderer(data, true);
+ table.repaint();
}
public void orderByAvWidth()
float[] width = new float[data.length];
float[] awidth;
float max = 0;
- int num = 0;
+
for (int i = 0; i < data.length; i++)
{
- awidth = typeWidth.get(data[i][0]);
+ awidth = typeWidth.get(data[i][TYPE_COLUMN]);
if (awidth[0] > 0)
{
width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
// weight - but have to make per
// sequence, too (awidth[2])
// if (width[i]==1) // hack to distinguish single width sequences.
- num++;
}
else
{
// awidth = (float[]) typeWidth.get(data[i][0]);
if (width[i] == 0)
{
- width[i] = fr.getOrder(data[i][0].toString());
+ width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
if (width[i] < 0)
{
- width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
+ width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
+ i / data.length);
}
}
else
{
width[i] /= max; // normalize
- fr.setOrder(data[i][0].toString(), width[i]); // store for later
+ fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
}
if (i > 0)
{
}
/**
- * Update the priority order of features; only repaint if this changed the
- * order of visible features
+ * Update the priority order of features; only repaint if this changed the order
+ * of visible features
*
* @param data
* @param visibleNew
*/
private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
{
- if (fr.setFeaturePriority(data, visibleNew))
+ FeatureSettingsBean[] rowData = getTableAsBeans(data);
+
+ if (fr.setFeaturePriority(rowData, visibleNew))
{
af.alignPanel.paintAlignment(true, true);
}
}
- int selectedRow = -1;
-
- JTabbedPane tabbedPane = new JTabbedPane();
-
- BorderLayout borderLayout1 = new BorderLayout();
-
- BorderLayout borderLayout2 = new BorderLayout();
-
- BorderLayout borderLayout3 = new BorderLayout();
-
- JPanel bigPanel = new JPanel();
-
- BorderLayout borderLayout4 = new BorderLayout();
-
- JButton invert = new JButton();
-
- JPanel buttonPanel = new JPanel();
-
- JButton cancel = new JButton();
-
- JButton ok = new JButton();
-
- JButton loadColours = new JButton();
-
- JButton saveColours = new JButton();
-
- JPanel dasButtonPanel = new JPanel();
-
- JButton fetchDAS = new JButton();
-
- JButton saveDAS = new JButton();
-
- JButton cancelDAS = new JButton();
-
- JButton optimizeOrder = new JButton();
-
- JButton sortByScore = new JButton();
-
- JButton sortByDens = new JButton();
-
- JButton help = new JButton();
-
- JPanel transbuttons = new JPanel(new GridLayout(5, 1));
+ /**
+ * Converts table data into an array of data beans
+ */
+ private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
+ {
+ FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
+ for (int i = 0; i < data.length; i++)
+ {
+ String type = (String) data[i][TYPE_COLUMN];
+ FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
+ FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
+ Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
+ rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
+ isShown);
+ }
+ return rowData;
+ }
private void jbInit() throws Exception
{
- this.setLayout(borderLayout1);
- settingsPane.setLayout(borderLayout2);
- dasSettingsPane.setLayout(borderLayout3);
- bigPanel.setLayout(borderLayout4);
+ this.setLayout(new BorderLayout());
+
+ JPanel settingsPane = new JPanel();
+ settingsPane.setLayout(new BorderLayout());
+
+ JPanel bigPanel = new JPanel();
+ bigPanel.setLayout(new BorderLayout());
groupPanel = new JPanel();
bigPanel.add(groupPanel, BorderLayout.NORTH);
+ JButton invert = new JButton(
+ MessageManager.getString("label.invert_selection"));
invert.setFont(JvSwingUtils.getLabelFont());
- invert.setText(MessageManager.getString("label.invert_selection"));
invert.addActionListener(new ActionListener()
{
@Override
invertSelection();
}
});
+
+ JButton optimizeOrder = new JButton(
+ MessageManager.getString("label.optimise_order"));
optimizeOrder.setFont(JvSwingUtils.getLabelFont());
- optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
optimizeOrder.addActionListener(new ActionListener()
{
@Override
orderByAvWidth();
}
});
+
+ JButton sortByScore = new JButton(
+ MessageManager.getString("label.seq_sort_by_score"));
sortByScore.setFont(JvSwingUtils.getLabelFont());
- sortByScore
- .setText(MessageManager.getString("label.seq_sort_by_score"));
sortByScore.addActionListener(new ActionListener()
{
@Override
af.avc.sortAlignmentByFeatureScore(null);
}
});
- sortByDens.setFont(JvSwingUtils.getLabelFont());
- sortByDens.setText(
+ JButton sortByDens = new JButton(
MessageManager.getString("label.sequence_sort_by_density"));
+ sortByDens.setFont(JvSwingUtils.getLabelFont());
sortByDens.addActionListener(new ActionListener()
{
@Override
af.avc.sortAlignmentByFeatureDensity(null);
}
});
+
+ JButton help = new JButton(MessageManager.getString("action.help"));
help.setFont(JvSwingUtils.getLabelFont());
- help.setText(MessageManager.getString("action.help"));
help.addActionListener(new ActionListener()
{
@Override
}
}
});
+
+ JButton cancel = new JButton(MessageManager.getString("action.cancel"));
cancel.setFont(JvSwingUtils.getLabelFont());
- cancel.setText(MessageManager.getString("action.cancel"));
cancel.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
fr.setTransparency(originalTransparency);
+ fr.setFeatureFilters(originalFilters);
updateFeatureRenderer(originalData);
close();
}
});
+
+ JButton ok = new JButton(MessageManager.getString("action.ok"));
ok.setFont(JvSwingUtils.getLabelFont());
- ok.setText(MessageManager.getString("action.ok"));
ok.addActionListener(new ActionListener()
{
@Override
close();
}
});
+
+ JButton loadColours = new JButton(
+ MessageManager.getString("label.load_colours"));
loadColours.setFont(JvSwingUtils.getLabelFont());
- loadColours.setText(MessageManager.getString("label.load_colours"));
+ loadColours.setToolTipText(
+ MessageManager.getString("label.load_colours_tooltip"));
loadColours.addActionListener(new ActionListener()
{
@Override
load();
}
});
+
+ JButton saveColours = new JButton(
+ MessageManager.getString("label.save_colours"));
saveColours.setFont(JvSwingUtils.getLabelFont());
- saveColours.setText(MessageManager.getString("label.save_colours"));
+ saveColours.setToolTipText(
+ MessageManager.getString("label.save_colours_tooltip"));
saveColours.addActionListener(new ActionListener()
{
@Override
if (!inConstruction)
{
fr.setTransparency((100 - transparency.getValue()) / 100f);
- af.alignPanel.paintAlignment(true,true);
+ af.alignPanel.paintAlignment(true, true);
}
}
});
transparency.setMaximum(70);
transparency.setToolTipText(
MessageManager.getString("label.transparency_tip"));
- fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
- fetchDAS.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- fetchDAS_actionPerformed(e);
- }
- });
- saveDAS.setText(MessageManager.getString("action.save_as_default"));
- saveDAS.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- saveDAS_actionPerformed(e);
- }
- });
- dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
- dasSettingsPane.setBorder(null);
- cancelDAS.setEnabled(false);
- cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
- cancelDAS.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- cancelDAS_actionPerformed(e);
- }
- });
- this.add(tabbedPane, java.awt.BorderLayout.CENTER);
- tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
- settingsPane);
- tabbedPane.addTab(MessageManager.getString("label.das_settings"),
- dasSettingsPane);
- bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
+
+ JPanel transPanel = new JPanel(new GridLayout(1, 2));
+ bigPanel.add(transPanel, BorderLayout.SOUTH);
+
+ JPanel transbuttons = new JPanel(new GridLayout(5, 1));
transbuttons.add(optimizeOrder);
transbuttons.add(invert);
transbuttons.add(sortByScore);
transbuttons.add(sortByDens);
transbuttons.add(help);
- JPanel sliderPanel = new JPanel();
- sliderPanel.add(transparency);
transPanel.add(transparency);
transPanel.add(transbuttons);
+
+ JPanel buttonPanel = new JPanel();
buttonPanel.add(ok);
buttonPanel.add(cancel);
buttonPanel.add(loadColours);
buttonPanel.add(saveColours);
- bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
- dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
- dasButtonPanel.add(fetchDAS);
- dasButtonPanel.add(cancelDAS);
- dasButtonPanel.add(saveDAS);
- settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
- settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
- }
-
- public void fetchDAS_actionPerformed(ActionEvent e)
- {
- fetchDAS.setEnabled(false);
- cancelDAS.setEnabled(true);
- dassourceBrowser.setGuiEnabled(false);
- Vector<jalviewSourceI> selectedSources = dassourceBrowser
- .getSelectedSources();
- doDasFeatureFetch(selectedSources, true, true);
- }
-
- /**
- * get the features from selectedSources for all or the current selection
- *
- * @param selectedSources
- * @param checkDbRefs
- * @param promptFetchDbRefs
- */
- private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
- boolean checkDbRefs, boolean promptFetchDbRefs)
- {
- SequenceI[] dataset, seqs;
- int iSize;
- AlignmentViewport vp = af.getViewport();
- if (vp.getSelectionGroup() != null
- && vp.getSelectionGroup().getSize() > 0)
- {
- iSize = vp.getSelectionGroup().getSize();
- dataset = new SequenceI[iSize];
- seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
- }
- else
- {
- iSize = vp.getAlignment().getHeight();
- seqs = vp.getAlignment().getSequencesArray();
- }
-
- dataset = new SequenceI[iSize];
- for (int i = 0; i < iSize; i++)
- {
- dataset[i] = seqs[i].getDatasetSequence();
- }
-
- cancelDAS.setEnabled(true);
- dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
- this, selectedSources, checkDbRefs, promptFetchDbRefs);
- af.getViewport().setShowSequenceFeatures(true);
- af.showSeqFeatures.setSelected(true);
- }
-
- /**
- * blocking call to initialise the das source browser
- */
- public void initDasSources()
- {
- dassourceBrowser.initDasSources();
- }
-
- /**
- * examine the current list of das sources and return any matching the given
- * nicknames in sources
- *
- * @param sources
- * Vector of Strings to resolve to DAS source nicknames.
- * @return sources that are present in source list.
- */
- public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
- {
- return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
- }
-
- /**
- * get currently selected das sources. ensure you have called initDasSources
- * before calling this.
- *
- * @return vector of selected das source nicknames
- */
- public Vector<jalviewSourceI> getSelectedSources()
- {
- return dassourceBrowser.getSelectedSources();
- }
-
- /**
- * properly initialise DAS fetcher and then initiate a new thread to fetch
- * features from the named sources (rather than any turned on by default)
- *
- * @param sources
- * @param block
- * if true then runs in same thread, otherwise passes to the Swing
- * executor
- */
- public void fetchDasFeatures(Vector<String> sources, boolean block)
- {
- initDasSources();
- List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
- .resolveSourceNicknames(sources);
- if (resolved.size() == 0)
- {
- resolved = dassourceBrowser.getSelectedSources();
- }
- if (resolved.size() > 0)
- {
- final List<jalviewSourceI> dassources = resolved;
- fetchDAS.setEnabled(false);
- // cancelDAS.setEnabled(true); doDasFetch does this.
- Runnable fetcher = new Runnable()
- {
-
- @Override
- public void run()
- {
- doDasFeatureFetch(dassources, true, false);
-
- }
- };
- if (block)
- {
- fetcher.run();
- }
- else
- {
- SwingUtilities.invokeLater(fetcher);
- }
- }
- }
-
- public void saveDAS_actionPerformed(ActionEvent e)
- {
- dassourceBrowser
- .saveProperties(jalview.bin.Cache.applicationProperties);
- }
-
- public void complete()
- {
- fetchDAS.setEnabled(true);
- cancelDAS.setEnabled(false);
- dassourceBrowser.setGuiEnabled(true);
-
- }
-
- public void cancelDAS_actionPerformed(ActionEvent e)
- {
- if (dasFeatureFetcher != null)
- {
- dasFeatureFetcher.cancel();
- }
- complete();
- }
-
- public void noDasSourceActive()
- {
- complete();
- JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
- MessageManager.getString("label.no_das_sources_selected_warn"),
- MessageManager.getString("label.no_das_sources_selected_title"),
- JvOptionPane.DEFAULT_OPTION, JvOptionPane.INFORMATION_MESSAGE);
+ bigPanel.add(scrollPane, BorderLayout.CENTER);
+ settingsPane.add(bigPanel, BorderLayout.CENTER);
+ settingsPane.add(buttonPanel, BorderLayout.SOUTH);
+ this.add(settingsPane);
}
// ///////////////////////////////////////////////////////////////////////
// ///////////////////////////////////////////////////////////////////////
class FeatureTableModel extends AbstractTableModel
{
- FeatureTableModel(Object[][] data)
- {
- this.data = data;
- }
-
private String[] columnNames = {
MessageManager.getString("label.feature_type"),
MessageManager.getString("action.colour"),
- MessageManager.getString("label.display") };
+ MessageManager.getString("label.filter"),
+ MessageManager.getString("label.show") };
private Object[][] data;
+ FeatureTableModel(Object[][] data)
+ {
+ this.data = data;
+ }
+
public Object[][] getData()
{
return data;
return data[row][col];
}
+ /**
+ * Answers the class of the object in column c of the first row of the table
+ */
@Override
- public Class getColumnClass(int c)
+ public Class<?> getColumnClass(int c)
{
- return getValueAt(0, c).getClass();
+ Object v = getValueAt(0, c);
+ return v == null ? null : v.getClass();
}
@Override
boolean isSelected, boolean hasFocus, int row, int column)
{
FeatureColourI cellColour = (FeatureColourI) color;
- // JLabel comp = new JLabel();
- // comp.
setOpaque(true);
- // comp.
- // setBounds(getBounds());
- Color newColor;
setToolTipText(baseTT);
setBackground(tbl.getBackground());
if (!cellColour.isSimpleColour())
Rectangle cr = tbl.getCellRect(row, column, false);
FeatureSettings.renderGraduatedColor(this, cellColour,
(int) cr.getWidth(), (int) cr.getHeight());
-
}
else
{
this.setText("");
this.setIcon(null);
- newColor = cellColour.getColour();
- setBackground(newColor);
+ setBackground(cellColour.getColour());
+ }
+ if (isSelected)
+ {
+ if (selectedBorder == null)
+ {
+ selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
+ tbl.getSelectionBackground());
+ }
+ setBorder(selectedBorder);
}
+ else
+ {
+ if (unselectedBorder == null)
+ {
+ unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
+ tbl.getBackground());
+ }
+ setBorder(unselectedBorder);
+ }
+
+ return this;
+ }
+ }
+
+ class FilterRenderer extends JLabel implements TableCellRenderer
+ {
+ javax.swing.border.Border unselectedBorder = null;
+
+ javax.swing.border.Border selectedBorder = null;
+
+ public FilterRenderer()
+ {
+ setOpaque(true); // MUST do this for background to show up.
+ setHorizontalTextPosition(SwingConstants.CENTER);
+ setVerticalTextPosition(SwingConstants.CENTER);
+ }
+
+ @Override
+ public Component getTableCellRendererComponent(JTable tbl,
+ Object filter, boolean isSelected, boolean hasFocus, int row,
+ int column)
+ {
+ FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
+ setOpaque(true);
+ String asText = theFilter.toString();
+ setBackground(tbl.getBackground());
+ this.setText(asText);
+ this.setIcon(null);
+
if (isSelected)
{
if (selectedBorder == null)
int w, int h)
{
boolean thr = false;
- String tt = "";
- String tx = "";
+ StringBuilder tt = new StringBuilder();
+ StringBuilder tx = new StringBuilder();
+
+ if (gcol.isColourByAttribute())
+ {
+ tx.append(String.join(":", gcol.getAttributeName()));
+ }
+ else if (!gcol.isColourByLabel())
+ {
+ tx.append(MessageManager.getString("label.score"));
+ }
+ tx.append(" ");
if (gcol.isAboveThreshold())
{
thr = true;
- tx += ">";
- tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
+ tx.append(">");
+ tt.append("Thresholded (Above ").append(gcol.getThreshold())
+ .append(") ");
}
if (gcol.isBelowThreshold())
{
thr = true;
- tx += "<";
- tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
+ tx.append("<");
+ tt.append("Thresholded (Below ").append(gcol.getThreshold())
+ .append(") ");
}
if (gcol.isColourByLabel())
{
- tt = "Coloured by label text. " + tt;
+ tt.append("Coloured by label text. ").append(tt);
if (thr)
{
- tx += " ";
+ tx.append(" ");
+ }
+ if (!gcol.isColourByAttribute())
+ {
+ tx.append("Label");
}
- tx += "Label";
comp.setIcon(null);
}
else
// + ", " + minCol.getBlue() + ")");
}
comp.setHorizontalAlignment(SwingConstants.CENTER);
- comp.setText(tx);
+ comp.setText(tx.toString());
if (tt.length() > 0)
{
if (comp.getToolTipText() == null)
{
- comp.setToolTipText(tt);
+ comp.setToolTipText(tt.toString());
}
else
{
- comp.setToolTipText(tt + " " + comp.getToolTipText());
+ comp.setToolTipText(
+ tt.append(" ").append(comp.getToolTipText()).toString());
}
}
}
+
+ class ColorEditor extends AbstractCellEditor
+ implements TableCellEditor, ActionListener
+ {
+ FeatureSettings me;
+
+ FeatureColourI currentColor;
+
+ FeatureTypeSettings chooser;
+
+ String type;
+
+ JButton button;
+
+ JColorChooser colorChooser;
+
+ JDialog dialog;
+
+ protected static final String EDIT = "edit";
+
+ int rowSelected = 0;
+
+ public ColorEditor(FeatureSettings me)
+ {
+ this.me = me;
+ // Set up the editor (from the table's point of view),
+ // which is a button.
+ // This button brings up the color chooser dialog,
+ // which is the editor from the user's point of view.
+ button = new JButton();
+ button.setActionCommand(EDIT);
+ button.addActionListener(this);
+ button.setBorderPainted(false);
+ // Set up the dialog that the button brings up.
+ colorChooser = new JColorChooser();
+ dialog = JColorChooser.createDialog(button,
+ MessageManager.getString("label.select_colour"), true, // modal
+ colorChooser, this, // OK button handler
+ null); // no CANCEL button handler
+ }
+
+ /**
+ * Handles events from the editor button and from the dialog's OK button.
+ */
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ // todo test e.getSource() instead here
+ if (EDIT.equals(e.getActionCommand()))
+ {
+ // The user has clicked the cell, so
+ // bring up the dialog.
+ if (currentColor.isSimpleColour())
+ {
+ // bring up simple color chooser
+ button.setBackground(currentColor.getColour());
+ colorChooser.setColor(currentColor.getColour());
+ dialog.setVisible(true);
+ }
+ else
+ {
+ // bring up graduated chooser.
+ chooser = new FeatureTypeSettings(me.fr, type);
+ /**
+ * @j2sNative
+ */
+ {
+ chooser.setRequestFocusEnabled(true);
+ chooser.requestFocus();
+ }
+ chooser.addActionListener(this);
+ // Make the renderer reappear.
+ fireEditingStopped();
+ }
+ }
+ else
+ {
+ if (currentColor.isSimpleColour())
+ {
+ /*
+ * read off colour picked in colour chooser after OK pressed
+ */
+ currentColor = new FeatureColour(colorChooser.getColor());
+ me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
+ }
+ else
+ {
+ /*
+ * after OK in variable colour dialog, any changes to colour
+ * (or filters!) are already set in FeatureRenderer, so just
+ * update table data without triggering updateFeatureRenderer
+ */
+ currentColor = fr.getFeatureColours().get(type);
+ FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
+ if (currentFilter == null)
+ {
+ currentFilter = new FeatureMatcherSet();
+ }
+ Object[] data = ((FeatureTableModel) table.getModel())
+ .getData()[rowSelected];
+ data[COLOUR_COLUMN] = currentColor;
+ data[FILTER_COLUMN] = currentFilter;
+ }
+ fireEditingStopped();
+ me.table.validate();
+ }
+ }
+
+ // Implement the one CellEditor method that AbstractCellEditor doesn't.
+ @Override
+ public Object getCellEditorValue()
+ {
+ return currentColor;
+ }
+
+ // Implement the one method defined by TableCellEditor.
+ @Override
+ public Component getTableCellEditorComponent(JTable theTable, Object value,
+ boolean isSelected, int row, int column)
+ {
+ currentColor = (FeatureColourI) value;
+ this.rowSelected = row;
+ type = me.table.getValueAt(row, TYPE_COLUMN).toString();
+ button.setOpaque(true);
+ button.setBackground(me.getBackground());
+ if (!currentColor.isSimpleColour())
+ {
+ JLabel btn = new JLabel();
+ btn.setSize(button.getSize());
+ FeatureSettings.renderGraduatedColor(btn, currentColor);
+ button.setBackground(btn.getBackground());
+ button.setIcon(btn.getIcon());
+ button.setText(btn.getText());
+ }
+ else
+ {
+ button.setText("");
+ button.setIcon(null);
+ button.setBackground(currentColor.getColour());
+ }
+ return button;
+ }
+ }
+
+ /**
+ * The cell editor for the Filter column. It displays the text of any filters
+ * for the feature type in that row (in full as a tooltip, possible abbreviated
+ * as display text). On click in the cell, opens the Feature Display Settings
+ * dialog at the Filters tab.
+ */
+ class FilterEditor extends AbstractCellEditor
+ implements TableCellEditor, ActionListener
+ {
+ FeatureSettings me;
+
+ FeatureMatcherSetI currentFilter;
+
+ Point lastLocation;
+
+ String type;
+
+ JButton button;
+
+ protected static final String EDIT = "edit";
+
+ int rowSelected = 0;
+
+ public FilterEditor(FeatureSettings me)
+ {
+ this.me = me;
+ button = new JButton();
+ button.setActionCommand(EDIT);
+ button.addActionListener(this);
+ button.setBorderPainted(false);
+ }
+
+ /**
+ * Handles events from the editor button
+ */
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ if (button == e.getSource())
+ {
+ FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
+ chooser.addActionListener(this);
+ chooser.setRequestFocusEnabled(true);
+ chooser.requestFocus();
+ if (lastLocation != null)
+ {
+ // todo open at its last position on screen
+ chooser.setBounds(lastLocation.x, lastLocation.y,
+ chooser.getWidth(), chooser.getHeight());
+ chooser.validate();
+ }
+ fireEditingStopped();
+ }
+ else if (e.getSource() instanceof Component)
+ {
+
+ /*
+ * after OK in variable colour dialog, any changes to filter
+ * (or colours!) are already set in FeatureRenderer, so just
+ * update table data without triggering updateFeatureRenderer
+ */
+ FeatureColourI currentColor = fr.getFeatureColours().get(type);
+ currentFilter = me.fr.getFeatureFilter(type);
+ if (currentFilter == null)
+ {
+ currentFilter = new FeatureMatcherSet();
+ }
+ Object[] data = ((FeatureTableModel) table.getModel())
+ .getData()[rowSelected];
+ data[COLOUR_COLUMN] = currentColor;
+ data[FILTER_COLUMN] = currentFilter;
+ fireEditingStopped();
+ me.table.validate();
+ }
+ }
+
+ @Override
+ public Object getCellEditorValue()
+ {
+ return currentFilter;
+ }
+
+ @Override
+ public Component getTableCellEditorComponent(JTable theTable, Object value,
+ boolean isSelected, int row, int column)
+ {
+ currentFilter = (FeatureMatcherSetI) value;
+ this.rowSelected = row;
+ type = me.table.getValueAt(row, TYPE_COLUMN).toString();
+ button.setOpaque(true);
+ button.setBackground(me.getBackground());
+ button.setText(currentFilter.toString());
+ button.setToolTipText(currentFilter.toString());
+ button.setIcon(null);
+ return button;
+ }
+ }
}
class FeatureIcon implements Icon
}
}
}
-
-class ColorEditor extends AbstractCellEditor
- implements TableCellEditor, ActionListener
-{
- FeatureSettings me;
-
- FeatureColourI currentColor;
-
- FeatureColourChooser chooser;
-
- String type;
-
- JButton button;
-
- JColorChooser colorChooser;
-
- JDialog dialog;
-
- protected static final String EDIT = "edit";
-
- int selectedRow = 0;
-
- public ColorEditor(FeatureSettings me)
- {
- this.me = me;
- // Set up the editor (from the table's point of view),
- // which is a button.
- // This button brings up the color chooser dialog,
- // which is the editor from the user's point of view.
- button = new JButton();
- button.setActionCommand(EDIT);
- button.addActionListener(this);
- button.setBorderPainted(false);
- // Set up the dialog that the button brings up.
- colorChooser = new JColorChooser();
- dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
- colorChooser, this, // OK button handler
- null); // no CANCEL button handler
- }
-
- /**
- * Handles events from the editor button and from the dialog's OK button.
- */
- @Override
- public void actionPerformed(ActionEvent e)
- {
-
- if (EDIT.equals(e.getActionCommand()))
- {
- // The user has clicked the cell, so
- // bring up the dialog.
- if (currentColor.isSimpleColour())
- {
- // bring up simple color chooser
- button.setBackground(currentColor.getColour());
- colorChooser.setColor(currentColor.getColour());
- dialog.setVisible(true);
- }
- else
- {
- // bring up graduated chooser.
- chooser = new FeatureColourChooser(me.fr, type);
- chooser.setRequestFocusEnabled(true);
- chooser.requestFocus();
- chooser.addActionListener(this);
- }
- // Make the renderer reappear.
- fireEditingStopped();
-
- }
- else
- { // User pressed dialog's "OK" button.
- if (currentColor.isSimpleColour())
- {
- currentColor = new FeatureColour(colorChooser.getColor());
- }
- else
- {
- currentColor = chooser.getLastColour();
- }
- me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
- fireEditingStopped();
- me.table.validate();
- }
- }
-
- // Implement the one CellEditor method that AbstractCellEditor doesn't.
- @Override
- public Object getCellEditorValue()
- {
- return currentColor;
- }
-
- // Implement the one method defined by TableCellEditor.
- @Override
- public Component getTableCellEditorComponent(JTable table, Object value,
- boolean isSelected, int row, int column)
- {
- currentColor = (FeatureColourI) value;
- this.selectedRow = row;
- type = me.table.getValueAt(row, 0).toString();
- button.setOpaque(true);
- button.setBackground(me.getBackground());
- if (!currentColor.isSimpleColour())
- {
- JLabel btn = new JLabel();
- btn.setSize(button.getSize());
- FeatureSettings.renderGraduatedColor(btn, currentColor);
- button.setBackground(btn.getBackground());
- button.setIcon(btn.getIcon());
- button.setText(btn.getText());
- }
- else
- {
- button.setText("");
- button.setIcon(null);
- button.setBackground(currentColor.getColour());
- }
- return button;
- }
-}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.gui;
+
+import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureColourI;
+import jalview.datamodel.GraphLine;
+import jalview.datamodel.features.FeatureAttributes;
+import jalview.datamodel.features.FeatureAttributes.Datatype;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.datamodel.features.FeatureMatcherI;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.schemes.FeatureColour;
+import jalview.util.ColorUtils;
+import jalview.util.MessageManager;
+import jalview.util.matcher.Condition;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JColorChooser;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.border.LineBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.basic.BasicArrowButton;
+
+/**
+ * A dialog where the user can configure colour scheme, and any filters, for one
+ * feature type
+ * <p>
+ * (Was FeatureColourChooser prior to Jalview 1.11, renamed with the addition of
+ * filter options)
+ */
+public class FeatureTypeSettings extends JalviewDialog
+{
+ private final static String LABEL_18N = MessageManager
+ .getString("label.label");
+
+ private final static String SCORE_18N = MessageManager
+ .getString("label.score");
+
+ private static final int RADIO_WIDTH = 130;
+
+ private static final String COLON = ":";
+
+ private static final int MAX_TOOLTIP_LENGTH = 50;
+
+ private static final int NO_COLOUR_OPTION = 0;
+
+ private static final int MIN_COLOUR_OPTION = 1;
+
+ private static final int MAX_COLOUR_OPTION = 2;
+
+ private static final int ABOVE_THRESHOLD_OPTION = 1;
+
+ private static final int BELOW_THRESHOLD_OPTION = 2;
+
+ private static final DecimalFormat DECFMT_2_2 = new DecimalFormat(
+ "##.##");
+
+ /*
+ * FeatureRenderer holds colour scheme and filters for feature types
+ */
+ private final FeatureRenderer fr; // todo refactor to allow interface type
+ // here
+
+ /*
+ * the view panel to update when settings change
+ */
+ private final AlignmentViewPanel ap;
+
+ private final String featureType;
+
+ /*
+ * the colour and filters to reset to on Cancel
+ */
+ private final FeatureColourI originalColour;
+
+ private final FeatureMatcherSetI originalFilter;
+
+ /*
+ * set flag to true when setting values programmatically,
+ * to avoid invocation of action handlers
+ */
+ private boolean adjusting = false;
+
+ /*
+ * minimum of the value range for graduated colour
+ * (may be for feature score or for a numeric attribute)
+ */
+ private float min;
+
+ /*
+ * maximum of the value range for graduated colour
+ */
+ private float max;
+
+ /*
+ * scale factor for conversion between absolute min-max and slider
+ */
+ private float scaleFactor;
+
+ /*
+ * radio button group, to select what to colour by:
+ * simple colour, by category (text), or graduated
+ */
+ private JRadioButton simpleColour = new JRadioButton();
+
+ private JRadioButton byCategory = new JRadioButton();
+
+ private JRadioButton graduatedColour = new JRadioButton();
+
+ /**
+ * colours and filters are shown in tabbed view or single content pane
+ */
+ JPanel coloursPanel, filtersPanel;
+
+ JPanel singleColour = new JPanel();
+
+ private JPanel minColour = new JPanel();
+
+ private JPanel maxColour = new JPanel();
+
+ private JComboBox<String> threshold = new JComboBox<>();
+
+ private JSlider slider = new JSlider();
+
+ private JTextField thresholdValue = new JTextField(20);
+
+ private JCheckBox thresholdIsMin = new JCheckBox();
+
+ private GraphLine threshline;
+
+ private ActionListener featureSettings = null;
+
+ private ActionListener changeColourAction;
+
+ /*
+ * choice of option for 'colour for no value'
+ */
+ private JComboBox<String> noValueCombo;
+
+ /*
+ * choice of what to colour by text (Label or attribute)
+ */
+ private JComboBox<String> colourByTextCombo;
+
+ /*
+ * choice of what to colour by range (Score or attribute)
+ */
+ private JComboBox<String> colourByRangeCombo;
+
+ private JRadioButton andFilters;
+
+ private JRadioButton orFilters;
+
+ /*
+ * filters for the currently selected feature type
+ */
+ private List<FeatureMatcherI> filters;
+
+ private JPanel chooseFiltersPanel;
+
+ /**
+ * Constructor
+ *
+ * @param frender
+ * @param theType
+ */
+ public FeatureTypeSettings(FeatureRenderer frender, String theType)
+ {
+ this.fr = frender;
+ this.featureType = theType;
+ ap = fr.ap;
+ originalFilter = fr.getFeatureFilter(theType);
+ originalColour = fr.getFeatureColours().get(theType);
+
+ adjusting = true;
+
+ try
+ {
+ initialise();
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ return;
+ }
+
+ updateColoursTab();
+
+ updateFiltersTab();
+
+ adjusting = false;
+
+ colourChanged(false);
+
+ String title = MessageManager
+ .formatMessage("label.display_settings_for", new String[]
+ { theType });
+ initDialogFrame(this, true, false, title, 500, 500);
+
+ waitForInput();
+ }
+
+ /**
+ * Configures the widgets on the Colours tab according to the current feature
+ * colour scheme
+ */
+ private void updateColoursTab()
+ {
+ FeatureColourI fc = fr.getFeatureColours().get(featureType);
+
+ /*
+ * suppress action handling while updating values programmatically
+ */
+ adjusting = true;
+ try
+ {
+ /*
+ * single colour
+ */
+ if (fc.isSimpleColour())
+ {
+ singleColour.setBackground(fc.getColour());
+ singleColour.setForeground(fc.getColour());
+ simpleColour.setSelected(true);
+ }
+
+ /*
+ * colour by text (Label or attribute text)
+ */
+ if (fc.isColourByLabel())
+ {
+ byCategory.setSelected(true);
+ colourByTextCombo.setEnabled(colourByTextCombo.getItemCount() > 1);
+ if (fc.isColourByAttribute())
+ {
+ String[] attributeName = fc.getAttributeName();
+ colourByTextCombo.setSelectedItem(
+ FeatureMatcher.toAttributeDisplayName(attributeName));
+ }
+ else
+ {
+ colourByTextCombo.setSelectedItem(LABEL_18N);
+ }
+ }
+ else
+ {
+ colourByTextCombo.setEnabled(false);
+ }
+
+ if (!fc.isGraduatedColour())
+ {
+ colourByRangeCombo.setEnabled(false);
+ minColour.setEnabled(false);
+ maxColour.setEnabled(false);
+ noValueCombo.setEnabled(false);
+ threshold.setEnabled(false);
+ slider.setEnabled(false);
+ thresholdValue.setEnabled(false);
+ thresholdIsMin.setEnabled(false);
+ return;
+ }
+
+ /*
+ * Graduated colour, by score or attribute value range
+ */
+ graduatedColour.setSelected(true);
+ updateColourMinMax(); // ensure min, max are set
+ colourByRangeCombo.setEnabled(colourByRangeCombo.getItemCount() > 1);
+ minColour.setEnabled(true);
+ maxColour.setEnabled(true);
+ noValueCombo.setEnabled(true);
+ threshold.setEnabled(true);
+ minColour.setBackground(fc.getMinColour());
+ maxColour.setBackground(fc.getMaxColour());
+
+ if (fc.isColourByAttribute())
+ {
+ String[] attributeName = fc.getAttributeName();
+ colourByRangeCombo.setSelectedItem(
+ FeatureMatcher.toAttributeDisplayName(attributeName));
+ }
+ else
+ {
+ colourByRangeCombo.setSelectedItem(SCORE_18N);
+ }
+ Color noColour = fc.getNoColour();
+ if (noColour == null)
+ {
+ noValueCombo.setSelectedIndex(NO_COLOUR_OPTION);
+ }
+ else if (noColour.equals(fc.getMinColour()))
+ {
+ noValueCombo.setSelectedIndex(MIN_COLOUR_OPTION);
+ }
+ else if (noColour.equals(fc.getMaxColour()))
+ {
+ noValueCombo.setSelectedIndex(MAX_COLOUR_OPTION);
+ }
+
+ /*
+ * update min-max scaling if there is a range to work with,
+ * else disable the widgets (this shouldn't happen if only
+ * valid options are offered in the combo box)
+ */
+ scaleFactor = (max == min) ? 1f : 100f / (max - min);
+ float range = (max - min) * scaleFactor;
+ slider.setMinimum((int) (min * scaleFactor));
+ slider.setMaximum((int) (max * scaleFactor));
+ slider.setMajorTickSpacing((int) (range / 10f));
+
+ threshline = new GraphLine((max - min) / 2f, "Threshold",
+ Color.black);
+ threshline.value = fc.getThreshold();
+
+ if (fc.hasThreshold())
+ {
+ threshold.setSelectedIndex(
+ fc.isAboveThreshold() ? ABOVE_THRESHOLD_OPTION
+ : BELOW_THRESHOLD_OPTION);
+ slider.setEnabled(true);
+ slider.setValue((int) (fc.getThreshold() * scaleFactor));
+ thresholdValue.setText(String.valueOf(getRoundedSliderValue()));
+ thresholdValue.setEnabled(true);
+ thresholdIsMin.setEnabled(true);
+ }
+ else
+ {
+ slider.setEnabled(false);
+ thresholdValue.setEnabled(false);
+ thresholdIsMin.setEnabled(false);
+ }
+ thresholdIsMin.setSelected(!fc.isAutoScaled());
+ } finally
+ {
+ adjusting = false;
+ }
+ }
+
+ /**
+ * Configures the initial layout
+ */
+ private void initialise()
+ {
+ this.setLayout(new BorderLayout());
+
+ /*
+ * an ActionListener that applies colour changes
+ */
+ changeColourAction = new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ colourChanged(true);
+ }
+ };
+
+ /*
+ * first panel/tab: colour options
+ */
+ JPanel coloursPanel = initialiseColoursPanel();
+ this.add(coloursPanel, BorderLayout.NORTH);
+
+ /*
+ * second panel/tab: filter options
+ */
+ JPanel filtersPanel = initialiseFiltersPanel();
+ this.add(filtersPanel, BorderLayout.CENTER);
+
+ JPanel okCancelPanel = initialiseOkCancelPanel();
+
+ this.add(okCancelPanel, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Updates the min-max range if Colour By selected item is Score, or an
+ * attribute, with a min-max range
+ */
+ protected void updateColourMinMax()
+ {
+ if (!graduatedColour.isSelected())
+ {
+ return;
+ }
+
+ String colourBy = (String) colourByRangeCombo.getSelectedItem();
+ float[] minMax = getMinMax(colourBy);
+
+ if (minMax != null)
+ {
+ min = minMax[0];
+ max = minMax[1];
+ }
+ }
+
+ /**
+ * Retrieves the min-max range:
+ * <ul>
+ * <li>of feature score, if colour or filter is by Score</li>
+ * <li>else of the selected attribute</li>
+ * </ul>
+ *
+ * @param attName
+ * @return
+ */
+ private float[] getMinMax(String attName)
+ {
+ float[] minMax = null;
+ if (SCORE_18N.equals(attName))
+ {
+ minMax = fr.getMinMax().get(featureType)[0];
+ }
+ else
+ {
+ // colour by attribute range
+ minMax = FeatureAttributes.getInstance().getMinMax(featureType,
+ FeatureMatcher.fromAttributeDisplayName(attName));
+ }
+ return minMax;
+ }
+
+ /**
+ * Lay out fields for graduated colour (by score or attribute value)
+ *
+ * @return
+ */
+ private JPanel initialiseGraduatedColourPanel()
+ {
+ JPanel graduatedColourPanel = new JPanel();
+ graduatedColourPanel.setLayout(
+ new BoxLayout(graduatedColourPanel, BoxLayout.Y_AXIS));
+ JvSwingUtils.createTitledBorder(graduatedColourPanel,
+ MessageManager.getString("label.graduated_colour"), true);
+ graduatedColourPanel.setBackground(Color.white);
+
+ /*
+ * first row: graduated colour radio button, score/attribute drop-down
+ */
+ JPanel graduatedChoicePanel = new JPanel(
+ new FlowLayout(FlowLayout.LEFT));
+ graduatedChoicePanel.setBackground(Color.white);
+ graduatedColour = new JRadioButton(
+ MessageManager.getString("label.by_range_of") + COLON);
+ graduatedColour.setPreferredSize(new Dimension(RADIO_WIDTH, 20));
+ graduatedColour.addItemListener(new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ if (graduatedColour.isSelected())
+ {
+ colourChanged(true);
+ }
+ }
+ });
+ graduatedChoicePanel.add(graduatedColour);
+
+ List<String[]> attNames = FeatureAttributes.getInstance()
+ .getAttributes(featureType);
+ colourByRangeCombo = populateAttributesDropdown(attNames, true, false);
+ colourByRangeCombo.addItemListener(new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ colourChanged(true);
+ }
+ });
+
+ /*
+ * disable graduated colour option if no range found
+ */
+ graduatedColour.setEnabled(colourByRangeCombo.getItemCount() > 0);
+
+ graduatedChoicePanel.add(colourByRangeCombo);
+ graduatedColourPanel.add(graduatedChoicePanel);
+
+ /*
+ * second row - min/max/no colours
+ */
+ JPanel colourRangePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ colourRangePanel.setBackground(Color.white);
+ graduatedColourPanel.add(colourRangePanel);
+
+ minColour.setFont(JvSwingUtils.getLabelFont());
+ minColour.setBorder(BorderFactory.createLineBorder(Color.black));
+ minColour.setPreferredSize(new Dimension(40, 20));
+ minColour.setToolTipText(MessageManager.getString("label.min_colour"));
+ minColour.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mousePressed(MouseEvent e)
+ {
+ if (minColour.isEnabled())
+ {
+ showColourChooser(minColour, "label.select_colour_minimum_value");
+ }
+ }
+ });
+
+ maxColour.setFont(JvSwingUtils.getLabelFont());
+ maxColour.setBorder(BorderFactory.createLineBorder(Color.black));
+ maxColour.setPreferredSize(new Dimension(40, 20));
+ maxColour.setToolTipText(MessageManager.getString("label.max_colour"));
+ maxColour.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mousePressed(MouseEvent e)
+ {
+ if (maxColour.isEnabled())
+ {
+ showColourChooser(maxColour, "label.select_colour_maximum_value");
+ }
+ }
+ });
+ maxColour.setBorder(new LineBorder(Color.black));
+
+ /*
+ * default max colour to last plain colour;
+ * make min colour a pale version of max colour
+ */
+ FeatureColourI fc = fr.getFeatureColours().get(featureType);
+ Color bg = fc.getColour() == null ? Color.BLACK : fc.getColour();
+ maxColour.setBackground(bg);
+ minColour.setBackground(ColorUtils.bleachColour(bg, 0.9f));
+
+ noValueCombo = new JComboBox<>();
+ noValueCombo.addItem(MessageManager.getString("label.no_colour"));
+ noValueCombo.addItem(MessageManager.getString("label.min_colour"));
+ noValueCombo.addItem(MessageManager.getString("label.max_colour"));
+ noValueCombo.addItemListener(new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ colourChanged(true);
+ }
+ });
+
+ JLabel minText = new JLabel(
+ MessageManager.getString("label.min_value") + COLON);
+ minText.setFont(JvSwingUtils.getLabelFont());
+ JLabel maxText = new JLabel(
+ MessageManager.getString("label.max_value") + COLON);
+ maxText.setFont(JvSwingUtils.getLabelFont());
+ JLabel noText = new JLabel(
+ MessageManager.getString("label.no_value") + COLON);
+ noText.setFont(JvSwingUtils.getLabelFont());
+
+ colourRangePanel.add(minText);
+ colourRangePanel.add(minColour);
+ colourRangePanel.add(maxText);
+ colourRangePanel.add(maxColour);
+ colourRangePanel.add(noText);
+ colourRangePanel.add(noValueCombo);
+
+ /*
+ * third row - threshold options and value
+ */
+ JPanel thresholdPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ thresholdPanel.setBackground(Color.white);
+ graduatedColourPanel.add(thresholdPanel);
+
+ threshold.addActionListener(changeColourAction);
+ threshold.setToolTipText(MessageManager
+ .getString("label.threshold_feature_display_by_score"));
+ threshold.addItem(MessageManager
+ .getString("label.threshold_feature_no_threshold")); // index 0
+ threshold.addItem(MessageManager
+ .getString("label.threshold_feature_above_threshold")); // index 1
+ threshold.addItem(MessageManager
+ .getString("label.threshold_feature_below_threshold")); // index 2
+
+ thresholdValue.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ thresholdValue_actionPerformed();
+ }
+ });
+ thresholdValue.addFocusListener(new FocusAdapter()
+ {
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ thresholdValue_actionPerformed();
+ }
+ });
+ slider.setPaintLabels(false);
+ slider.setPaintTicks(true);
+ slider.setBackground(Color.white);
+ slider.setEnabled(false);
+ slider.setOpaque(false);
+ slider.setPreferredSize(new Dimension(100, 32));
+ slider.setToolTipText(
+ MessageManager.getString("label.adjust_threshold"));
+
+ slider.addChangeListener(new ChangeListener()
+ {
+ @Override
+ public void stateChanged(ChangeEvent evt)
+ {
+ if (!adjusting)
+ {
+ thresholdValue
+ .setText(String.valueOf(slider.getValue() / scaleFactor));
+ sliderValueChanged();
+ }
+ }
+ });
+ slider.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mouseReleased(MouseEvent evt)
+ {
+ /*
+ * only update Overview and/or structure colouring
+ * when threshold slider drag ends (mouse up)
+ */
+ if (ap != null)
+ {
+ ap.paintAlignment(true, true);
+ }
+ }
+ });
+
+ thresholdValue.setEnabled(false);
+ thresholdValue.setColumns(7);
+
+ thresholdPanel.add(threshold);
+ thresholdPanel.add(slider);
+ thresholdPanel.add(thresholdValue);
+
+ thresholdIsMin.setBackground(Color.white);
+ thresholdIsMin
+ .setText(MessageManager.getString("label.threshold_minmax"));
+ thresholdIsMin.setToolTipText(MessageManager
+ .getString("label.toggle_absolute_relative_display_threshold"));
+ thresholdIsMin.addActionListener(changeColourAction);
+ thresholdPanel.add(thresholdIsMin);
+
+ return graduatedColourPanel;
+ }
+
+ /**
+ * Lay out OK and Cancel buttons
+ *
+ * @return
+ */
+ private JPanel initialiseOkCancelPanel()
+ {
+ JPanel okCancelPanel = new JPanel();
+ // okCancelPanel.setBackground(Color.white);
+ okCancelPanel.add(ok);
+ okCancelPanel.add(cancel);
+ return okCancelPanel;
+ }
+
+ /**
+ * Lay out Colour options panel, containing
+ * <ul>
+ * <li>plain colour, with colour picker</li>
+ * <li>colour by text, with choice of Label or other attribute</li>
+ * <li>colour by range, of score or other attribute, when available</li>
+ * </ul>
+ *
+ * @return
+ */
+ private JPanel initialiseColoursPanel()
+ {
+ JPanel colourByPanel = new JPanel();
+ colourByPanel.setBackground(Color.white);
+ colourByPanel.setLayout(new BoxLayout(colourByPanel, BoxLayout.Y_AXIS));
+ JvSwingUtils.createTitledBorder(colourByPanel,
+ MessageManager.getString("action.colour"), true);
+
+ /*
+ * simple colour radio button and colour picker
+ */
+ JPanel simpleColourPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ simpleColourPanel.setBackground(Color.white);
+ colourByPanel.add(simpleColourPanel);
+
+ simpleColour = new JRadioButton(
+ MessageManager.getString("label.simple_colour"));
+ simpleColour.setPreferredSize(new Dimension(RADIO_WIDTH, 20));
+ simpleColour.addItemListener(new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ if (simpleColour.isSelected() && !adjusting)
+ {
+ colourChanged(true);
+ }
+ }
+ });
+
+ singleColour.setFont(JvSwingUtils.getLabelFont());
+ singleColour.setBorder(BorderFactory.createLineBorder(Color.black));
+ singleColour.setPreferredSize(new Dimension(40, 20));
+ if (originalColour.isGraduatedColour())
+ {
+ singleColour.setBackground(originalColour.getMaxColour());
+ singleColour.setForeground(originalColour.getMaxColour());
+ }
+ else
+ {
+ singleColour.setBackground(originalColour.getColour());
+ singleColour.setForeground(originalColour.getColour());
+ }
+ singleColour.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mousePressed(MouseEvent e)
+ {
+ if (simpleColour.isSelected())
+ {
+ showColourChooser(singleColour, "label.select_colour");
+ }
+ }
+ });
+ simpleColourPanel.add(simpleColour); // radio button
+ simpleColourPanel.add(singleColour); // colour picker button
+
+ /*
+ * colour by text (category) radio button and drop-down choice list
+ */
+ JPanel byTextPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ byTextPanel.setBackground(Color.white);
+ JvSwingUtils.createTitledBorder(byTextPanel,
+ MessageManager.getString("label.colour_by_text"), true);
+ colourByPanel.add(byTextPanel);
+ byCategory = new JRadioButton(
+ MessageManager.getString("label.by_text_of") + COLON);
+ byCategory.setPreferredSize(new Dimension(RADIO_WIDTH, 20));
+ byCategory.addItemListener(new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ if (byCategory.isSelected())
+ {
+ colourChanged(true);
+ }
+ }
+ });
+ byTextPanel.add(byCategory);
+
+ List<String[]> attNames = FeatureAttributes.getInstance()
+ .getAttributes(featureType);
+ colourByTextCombo = populateAttributesDropdown(attNames, false, true);
+ colourByTextCombo.addItemListener(new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ colourChanged(true);
+ }
+ });
+ byTextPanel.add(colourByTextCombo);
+
+ /*
+ * graduated colour panel
+ */
+ JPanel graduatedColourPanel = initialiseGraduatedColourPanel();
+ colourByPanel.add(graduatedColourPanel);
+
+ /*
+ * 3 radio buttons select between simple colour,
+ * by category (text), or graduated
+ */
+ ButtonGroup bg = new ButtonGroup();
+ bg.add(simpleColour);
+ bg.add(byCategory);
+ bg.add(graduatedColour);
+
+ return colourByPanel;
+ }
+
+ private void showColourChooser(JPanel colourPanel, String key)
+ {
+ Color col = JColorChooser.showDialog(this,
+ MessageManager.getString(key), colourPanel.getBackground());
+ if (col != null)
+ {
+ colourPanel.setBackground(col);
+ colourPanel.setForeground(col);
+ }
+ colourPanel.repaint();
+ colourChanged(true);
+ }
+
+ /**
+ * Constructs and sets the selected colour options as the colour for the
+ * feature type, and repaints the alignment, and optionally the Overview
+ * and/or structure viewer if open
+ *
+ * @param updateStructsAndOverview
+ */
+ void colourChanged(boolean updateStructsAndOverview)
+ {
+ if (adjusting)
+ {
+ /*
+ * ignore action handlers while setting values programmatically
+ */
+ return;
+ }
+
+ /*
+ * ensure min-max range is for the latest choice of
+ * 'graduated colour by'
+ */
+ updateColourMinMax();
+
+ FeatureColourI acg = makeColourFromInputs();
+
+ /*
+ * save the colour, and repaint stuff
+ */
+ fr.setColour(featureType, acg);
+ ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview);
+
+ updateColoursTab();
+ }
+
+ /**
+ * Converts the input values into an instance of FeatureColour
+ *
+ * @return
+ */
+ private FeatureColourI makeColourFromInputs()
+ {
+ /*
+ * easiest case - a single colour
+ */
+ if (simpleColour.isSelected())
+ {
+ return new FeatureColour(singleColour.getBackground());
+ }
+
+ /*
+ * next easiest case - colour by Label, or attribute text
+ */
+ if (byCategory.isSelected())
+ {
+ Color c = singleColour.getBackground();
+ FeatureColourI fc = new FeatureColour(c);
+ fc.setColourByLabel(true);
+ String byWhat = (String) colourByTextCombo.getSelectedItem();
+ if (!LABEL_18N.equals(byWhat))
+ {
+ fc.setAttributeName(
+ FeatureMatcher.fromAttributeDisplayName(byWhat));
+ }
+ return fc;
+ }
+
+ /*
+ * remaining case - graduated colour by score, or attribute value
+ */
+ Color noColour = null;
+ if (noValueCombo.getSelectedIndex() == MIN_COLOUR_OPTION)
+ {
+ noColour = minColour.getBackground();
+ }
+ else if (noValueCombo.getSelectedIndex() == MAX_COLOUR_OPTION)
+ {
+ noColour = maxColour.getBackground();
+ }
+
+ float thresh = 0f;
+ try
+ {
+ thresh = Float.valueOf(thresholdValue.getText());
+ } catch (NumberFormatException e)
+ {
+ // invalid inputs are already handled on entry
+ }
+
+ /*
+ * min-max range is to (or from) threshold value if
+ * 'threshold is min/max' is selected
+ */
+ float minValue = min;
+ float maxValue = max;
+ final int thresholdOption = threshold.getSelectedIndex();
+ if (thresholdIsMin.isSelected()
+ && thresholdOption == ABOVE_THRESHOLD_OPTION)
+ {
+ minValue = thresh;
+ }
+ if (thresholdIsMin.isSelected()
+ && thresholdOption == BELOW_THRESHOLD_OPTION)
+ {
+ maxValue = thresh;
+ }
+
+ /*
+ * make the graduated colour
+ */
+ FeatureColourI fc = new FeatureColour(minColour.getBackground(),
+ maxColour.getBackground(), noColour, minValue, maxValue);
+
+ /*
+ * set attribute to colour by if selected
+ */
+ String byWhat = (String) colourByRangeCombo.getSelectedItem();
+ if (!SCORE_18N.equals(byWhat))
+ {
+ fc.setAttributeName(FeatureMatcher.fromAttributeDisplayName(byWhat));
+ }
+
+ /*
+ * set threshold options and 'autoscaled' which is
+ * false if 'threshold is min/max' is selected
+ * else true (colour range is on actual range of values)
+ */
+ fc.setThreshold(thresh);
+ fc.setAutoScaled(!thresholdIsMin.isSelected());
+ fc.setAboveThreshold(thresholdOption == ABOVE_THRESHOLD_OPTION);
+ fc.setBelowThreshold(thresholdOption == BELOW_THRESHOLD_OPTION);
+
+ if (threshline == null)
+ {
+ /*
+ * todo not yet implemented: visual indication of feature threshold
+ */
+ threshline = new GraphLine((max - min) / 2f, "Threshold",
+ Color.black);
+ }
+
+ return fc;
+ }
+
+ @Override
+ protected void raiseClosed()
+ {
+ if (this.featureSettings != null)
+ {
+ featureSettings.actionPerformed(new ActionEvent(this, 0, "CLOSED"));
+ }
+ }
+
+ /**
+ * Action on OK is just to dismiss the dialog - any changes have already been
+ * applied
+ */
+ @Override
+ public void okPressed()
+ {
+ }
+
+ /**
+ * Action on Cancel is to restore colour scheme and filters as they were when
+ * the dialog was opened
+ */
+ @Override
+ public void cancelPressed()
+ {
+ fr.setColour(featureType, originalColour);
+ fr.setFeatureFilter(featureType, originalFilter);
+ ap.paintAlignment(true, true);
+ }
+
+ /**
+ * Action on text entry of a threshold value
+ */
+ protected void thresholdValue_actionPerformed()
+ {
+ try
+ {
+ adjusting = true;
+ float f = Float.parseFloat(thresholdValue.getText());
+ slider.setValue((int) (f * scaleFactor));
+ threshline.value = f;
+ thresholdValue.setBackground(Color.white); // ok
+
+ /*
+ * force repaint of any Overview window or structure
+ */
+ ap.paintAlignment(true, true);
+ } catch (NumberFormatException ex)
+ {
+ thresholdValue.setBackground(Color.red); // not ok
+ } finally
+ {
+ adjusting = false;
+ }
+ }
+
+ /**
+ * Action on change of threshold slider value. This may be done interactively
+ * (by moving the slider), or programmatically (to update the slider after
+ * manual input of a threshold value).
+ */
+ protected void sliderValueChanged()
+ {
+ threshline.value = getRoundedSliderValue();
+
+ /*
+ * repaint alignment, but not Overview or structure,
+ * to avoid overload while dragging the slider
+ */
+ colourChanged(false);
+ }
+
+ /**
+ * Converts the slider value to its absolute value by dividing by the
+ * scaleFactor. Rounding errors are squashed by forcing min/max of slider
+ * range to the actual min/max of feature score range
+ *
+ * @return
+ */
+ private float getRoundedSliderValue()
+ {
+ int value = slider.getValue();
+ float f = value == slider.getMaximum() ? max
+ : (value == slider.getMinimum() ? min : value / scaleFactor);
+ return f;
+ }
+
+ void addActionListener(ActionListener listener)
+ {
+ if (featureSettings != null)
+ {
+ System.err.println(
+ "IMPLEMENTATION ISSUE: overwriting action listener for FeatureColourChooser");
+ }
+ featureSettings = listener;
+ }
+
+ /**
+ * A helper method to build the drop-down choice of attributes for a feature.
+ * If 'withRange' is true, then Score, and any attributes with a min-max
+ * range, are added. If 'withText' is true, Label and any known attributes are
+ * added. This allows 'categorical numerical' attributes e.g. codon position
+ * to be coloured by text.
+ * <p>
+ * Where metadata is available with a description for an attribute, that is
+ * added as a tooltip.
+ * <p>
+ * Attribute names may be 'simple' e.g. "AC" or 'compound' e.g. {"CSQ",
+ * "Allele"}. Compound names are rendered for display as (e.g.) CSQ:Allele.
+ * <p>
+ * This method does not add any ActionListener to the JComboBox.
+ *
+ * @param attNames
+ * @param withRange
+ * @param withText
+ */
+ protected JComboBox<String> populateAttributesDropdown(
+ List<String[]> attNames, boolean withRange, boolean withText)
+ {
+ List<String> displayAtts = new ArrayList<>();
+ List<String> tooltips = new ArrayList<>();
+
+ if (withText)
+ {
+ displayAtts.add(LABEL_18N);
+ tooltips.add(MessageManager.getString("label.description"));
+ }
+ if (withRange)
+ {
+ float[][] minMax = fr.getMinMax().get(featureType);
+ if (minMax != null && minMax[0][0] != minMax[0][1])
+ {
+ displayAtts.add(SCORE_18N);
+ tooltips.add(SCORE_18N);
+ }
+ }
+
+ FeatureAttributes fa = FeatureAttributes.getInstance();
+ for (String[] attName : attNames)
+ {
+ float[] minMax = fa.getMinMax(featureType, attName);
+ boolean hasRange = minMax != null && minMax[0] != minMax[1];
+ if (!withText && !hasRange)
+ {
+ continue;
+ }
+ displayAtts.add(FeatureMatcher.toAttributeDisplayName(attName));
+ String desc = fa.getDescription(featureType, attName);
+ if (desc != null && desc.length() > MAX_TOOLTIP_LENGTH)
+ {
+ desc = desc.substring(0, MAX_TOOLTIP_LENGTH) + "...";
+ }
+ tooltips.add(desc == null ? "" : desc);
+ }
+
+ JComboBox<String> attCombo = JvSwingUtils
+ .buildComboWithTooltips(displayAtts, tooltips);
+
+ return attCombo;
+ }
+
+ /**
+ * Populates initial layout of the feature attribute filters panel
+ */
+ private JPanel initialiseFiltersPanel()
+ {
+ filters = new ArrayList<>();
+
+ JPanel filtersPanel = new JPanel();
+ filtersPanel.setLayout(new BoxLayout(filtersPanel, BoxLayout.Y_AXIS));
+ filtersPanel.setBackground(Color.white);
+ JvSwingUtils.createTitledBorder(filtersPanel,
+ MessageManager.getString("label.filters"), true);
+
+ JPanel andOrPanel = initialiseAndOrPanel();
+ filtersPanel.add(andOrPanel);
+
+ /*
+ * panel with filters - populated by refreshFiltersDisplay,
+ * which also sets the layout manager
+ */
+ chooseFiltersPanel = new JPanel();
+ chooseFiltersPanel.setBackground(Color.white);
+ filtersPanel.add(chooseFiltersPanel);
+
+ return filtersPanel;
+ }
+
+ /**
+ * Lays out the panel with radio buttons to AND or OR filter conditions
+ *
+ * @return
+ */
+ private JPanel initialiseAndOrPanel()
+ {
+ JPanel andOrPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ andOrPanel.setBackground(Color.white);
+ andFilters = new JRadioButton(MessageManager.getString("label.and"));
+ orFilters = new JRadioButton(MessageManager.getString("label.or"));
+ ActionListener actionListener = new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ filtersChanged();
+ }
+ };
+ andFilters.addActionListener(actionListener);
+ orFilters.addActionListener(actionListener);
+ ButtonGroup andOr = new ButtonGroup();
+ andOr.add(andFilters);
+ andOr.add(orFilters);
+ andFilters.setSelected(true);
+ andOrPanel.add(
+ new JLabel(MessageManager.getString("label.join_conditions")));
+ andOrPanel.add(andFilters);
+ andOrPanel.add(orFilters);
+ return andOrPanel;
+ }
+
+ /**
+ * Refreshes the display to show any filters currently configured for the
+ * selected feature type (editable, with 'remove' option), plus one extra row
+ * for adding a condition. This should be called after a filter has been
+ * removed, added or amended.
+ */
+ private void updateFiltersTab()
+ {
+ /*
+ * clear the panel and list of filter conditions
+ */
+ chooseFiltersPanel.removeAll();
+ filters.clear();
+
+ /*
+ * look up attributes known for feature type
+ */
+ List<String[]> attNames = FeatureAttributes.getInstance()
+ .getAttributes(featureType);
+
+ /*
+ * if this feature type has filters set, load them first
+ */
+ FeatureMatcherSetI featureFilters = fr.getFeatureFilter(featureType);
+ if (featureFilters != null)
+ {
+ if (!featureFilters.isAnded())
+ {
+ orFilters.setSelected(true);
+ }
+ featureFilters.getMatchers().forEach(matcher -> filters.add(matcher));
+ }
+
+ /*
+ * and an empty filter for the user to populate (add)
+ */
+ filters.add(FeatureMatcher.NULL_MATCHER);
+
+ /*
+ * use GridLayout to 'justify' rows to the top of the panel, until
+ * there are too many to fit in, then fall back on BoxLayout
+ */
+ if (filters.size() <= 5)
+ {
+ chooseFiltersPanel.setLayout(new GridLayout(5, 1));
+ }
+ else
+ {
+ chooseFiltersPanel.setLayout(
+ new BoxLayout(chooseFiltersPanel, BoxLayout.Y_AXIS));
+ }
+
+ /*
+ * render the conditions in rows, each in its own JPanel
+ */
+ int filterIndex = 0;
+ for (FeatureMatcherI filter : filters)
+ {
+ JPanel row = addFilter(filter, attNames, filterIndex);
+ chooseFiltersPanel.add(row);
+ filterIndex++;
+ }
+
+ this.validate();
+ this.repaint();
+ }
+
+ /**
+ * A helper method that constructs a row (panel) with one filter condition:
+ * <ul>
+ * <li>a drop-down list of Label, Score and attribute names to choose
+ * from</li>
+ * <li>a drop-down list of conditions to choose from</li>
+ * <li>a text field for input of a match pattern</li>
+ * <li>optionally, a 'remove' button</li>
+ * </ul>
+ * The filter values are set as defaults for the input fields. The 'remove'
+ * button is added unless the pattern is empty (incomplete filter condition).
+ * <p>
+ * Action handlers on these fields provide for
+ * <ul>
+ * <li>validate pattern field - should be numeric if condition is numeric</li>
+ * <li>save filters and refresh display on any (valid) change</li>
+ * <li>remove filter and refresh on 'Remove'</li>
+ * <li>update conditions list on change of Label/Score/Attribute</li>
+ * <li>refresh value field tooltip with min-max range on change of
+ * attribute</li>
+ * </ul>
+ *
+ * @param filter
+ * @param attNames
+ * @param filterIndex
+ * @return
+ */
+ protected JPanel addFilter(FeatureMatcherI filter,
+ List<String[]> attNames, int filterIndex)
+ {
+ String[] attName = filter.getAttribute();
+ Condition cond = filter.getMatcher().getCondition();
+ String pattern = filter.getMatcher().getPattern();
+
+ JPanel filterRow = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ filterRow.setBackground(Color.white);
+
+ /*
+ * drop-down choice of attribute, with description as a tooltip
+ * if we can obtain it
+ */
+ final JComboBox<String> attCombo = populateAttributesDropdown(attNames,
+ true, true);
+ String filterBy = setSelectedAttribute(attCombo, filter);
+
+ JComboBox<Condition> condCombo = new JComboBox<>();
+
+ JTextField patternField = new JTextField(8);
+ patternField.setText(pattern);
+
+ /*
+ * action handlers that validate and (if valid) apply changes
+ */
+ ActionListener actionListener = new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ if (validateFilter(patternField, condCombo))
+ {
+ if (updateFilter(attCombo, condCombo, patternField, filterIndex))
+ {
+ filtersChanged();
+ }
+ }
+ }
+ };
+ ItemListener itemListener = new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ actionListener.actionPerformed(null);
+ }
+ };
+
+ if (filter == FeatureMatcher.NULL_MATCHER) // the 'add a condition' row
+ {
+ attCombo.setSelectedIndex(0);
+ }
+ else
+ {
+ attCombo.setSelectedItem(
+ FeatureMatcher.toAttributeDisplayName(attName));
+ }
+ attCombo.addItemListener(new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ /*
+ * on change of attribute, refresh the conditions list to
+ * ensure it is appropriate for the attribute datatype
+ */
+ populateConditions((String) attCombo.getSelectedItem(),
+ (Condition) condCombo.getSelectedItem(), condCombo,
+ patternField);
+ actionListener.actionPerformed(null);
+ }
+ });
+
+ filterRow.add(attCombo);
+
+ /*
+ * drop-down choice of test condition
+ */
+ populateConditions(filterBy, cond, condCombo, patternField);
+ condCombo.setPreferredSize(new Dimension(150, 20));
+ condCombo.addItemListener(itemListener);
+ filterRow.add(condCombo);
+
+ /*
+ * pattern to match against
+ */
+ patternField.addActionListener(actionListener);
+ patternField.addFocusListener(new FocusAdapter()
+ {
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ actionListener.actionPerformed(null);
+ }
+ });
+ filterRow.add(patternField);
+
+ /*
+ * disable pattern field for condition 'Present / NotPresent'
+ */
+ Condition selectedCondition = (Condition) condCombo.getSelectedItem();
+ patternField.setEnabled(selectedCondition.needsAPattern());
+
+ /*
+ * if a numeric condition is selected, show the value range
+ * as a tooltip on the value input field
+ */
+ setNumericHints(filterBy, selectedCondition, patternField);
+
+ /*
+ * add remove button if filter is populated (non-empty pattern)
+ */
+ if (!patternField.isEnabled()
+ || (pattern != null && pattern.trim().length() > 0))
+ {
+ // todo: gif for button drawing '-' or 'x'
+ JButton removeCondition = new BasicArrowButton(SwingConstants.WEST);
+ removeCondition
+ .setToolTipText(MessageManager.getString("label.delete_row"));
+ removeCondition.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ filters.remove(filterIndex);
+ filtersChanged();
+ }
+ });
+ filterRow.add(removeCondition);
+ }
+
+ return filterRow;
+ }
+
+ /**
+ * Sets the selected item in the Label/Score/Attribute drop-down to match the
+ * filter
+ *
+ * @param attCombo
+ * @param filter
+ */
+ private String setSelectedAttribute(JComboBox<String> attCombo,
+ FeatureMatcherI filter)
+ {
+ String item = null;
+ if (filter.isByScore())
+ {
+ item = SCORE_18N;
+ }
+ else if (filter.isByLabel())
+ {
+ item = LABEL_18N;
+ }
+ else
+ {
+ item = FeatureMatcher.toAttributeDisplayName(filter.getAttribute());
+ }
+ attCombo.setSelectedItem(item);
+ return item;
+ }
+
+ /**
+ * If a numeric comparison condition is selected, retrieves the min-max range
+ * for the value (score or attribute), and sets it as a tooltip on the value
+ * field. If the field is currently empty, then pre-populates it with
+ * <ul>
+ * <li>the minimum value, if condition is > or >=</li>
+ * <li>the maximum value, if condition is < or <=</li>
+ * </ul>
+ *
+ * @param attName
+ * @param selectedCondition
+ * @param patternField
+ */
+ private void setNumericHints(String attName, Condition selectedCondition,
+ JTextField patternField)
+ {
+ patternField.setToolTipText("");
+
+ if (selectedCondition.isNumeric())
+ {
+ float[] minMax = getMinMax(attName);
+ if (minMax != null)
+ {
+ String minFormatted = DECFMT_2_2.format(minMax[0]);
+ String maxFormatted = DECFMT_2_2.format(minMax[1]);
+ String tip = String.format("(%s - %s)", minFormatted, maxFormatted);
+ patternField.setToolTipText(tip);
+ if (patternField.getText().isEmpty())
+ {
+ if (selectedCondition == Condition.GE
+ || selectedCondition == Condition.GT)
+ {
+ patternField.setText(minFormatted);
+ }
+ else
+ {
+ if (selectedCondition == Condition.LE
+ || selectedCondition == Condition.LT)
+ {
+ patternField.setText(maxFormatted);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Populates the drop-down list of comparison conditions for the given
+ * attribute name. The conditions added depend on the datatype of the
+ * attribute values. The supplied condition is set as the selected item in the
+ * list, provided it is in the list. If the pattern is now invalid
+ * (non-numeric pattern for a numeric condition), it is cleared.
+ *
+ * @param attName
+ * @param cond
+ * @param condCombo
+ * @param patternField
+ */
+ private void populateConditions(String attName, Condition cond,
+ JComboBox<Condition> condCombo, JTextField patternField)
+ {
+ Datatype type = FeatureAttributes.getInstance().getDatatype(featureType,
+ FeatureMatcher.fromAttributeDisplayName(attName));
+ if (LABEL_18N.equals(attName))
+ {
+ type = Datatype.Character;
+ }
+ else if (SCORE_18N.equals(attName))
+ {
+ type = Datatype.Number;
+ }
+
+ /*
+ * remove itemListener before starting
+ */
+ ItemListener listener = condCombo.getItemListeners()[0];
+ condCombo.removeItemListener(listener);
+ boolean condIsValid = false;
+
+ condCombo.removeAllItems();
+ for (Condition c : Condition.values())
+ {
+ if ((c.isNumeric() && type == Datatype.Number)
+ || (!c.isNumeric() && type != Datatype.Number))
+ {
+ condCombo.addItem(c);
+ if (c == cond)
+ {
+ condIsValid = true;
+ }
+ }
+ }
+
+ /*
+ * set the selected condition (does nothing if not in the list)
+ */
+ if (condIsValid)
+ {
+ condCombo.setSelectedItem(cond);
+ }
+ else
+ {
+ condCombo.setSelectedIndex(0);
+ }
+
+ /*
+ * clear pattern if it is now invalid for condition
+ */
+ if (((Condition) condCombo.getSelectedItem()).isNumeric())
+ {
+ try
+ {
+ String pattern = patternField.getText().trim();
+ if (pattern.length() > 0)
+ {
+ Float.valueOf(pattern);
+ }
+ } catch (NumberFormatException e)
+ {
+ patternField.setText("");
+ }
+ }
+
+ /*
+ * restore the listener
+ */
+ condCombo.addItemListener(listener);
+ }
+
+ /**
+ * Answers true unless a numeric condition has been selected with a
+ * non-numeric value. Sets the value field to RED with a tooltip if in error.
+ * <p>
+ * If the pattern is expected but is empty, this method returns false, but
+ * does not mark the field as invalid. This supports selecting an attribute
+ * for a new condition before a match pattern has been entered.
+ *
+ * @param value
+ * @param condCombo
+ */
+ protected boolean validateFilter(JTextField value,
+ JComboBox<Condition> condCombo)
+ {
+ if (value == null || condCombo == null)
+ {
+ return true; // fields not populated
+ }
+
+ Condition cond = (Condition) condCombo.getSelectedItem();
+ if (!cond.needsAPattern())
+ {
+ return true;
+ }
+
+ value.setBackground(Color.white);
+ value.setToolTipText("");
+ String v1 = value.getText().trim();
+ if (v1.length() == 0)
+ {
+ // return false;
+ }
+
+ if (cond.isNumeric() && v1.length() > 0)
+ {
+ try
+ {
+ Float.valueOf(v1);
+ } catch (NumberFormatException e)
+ {
+ value.setBackground(Color.red);
+ value.setToolTipText(
+ MessageManager.getString("label.numeric_required"));
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Constructs a filter condition from the given input fields, and replaces the
+ * condition at filterIndex with the new one. Does nothing if the pattern
+ * field is blank (unless the match condition is one that doesn't require a
+ * pattern, e.g. 'Is present'). Answers true if the filter was updated, else
+ * false.
+ * <p>
+ * This method may update the tooltip on the filter value field to show the
+ * value range, if a numeric condition is selected. This ensures the tooltip
+ * is updated when a numeric valued attribute is chosen on the last 'add a
+ * filter' row.
+ *
+ * @param attCombo
+ * @param condCombo
+ * @param valueField
+ * @param filterIndex
+ */
+ protected boolean updateFilter(JComboBox<String> attCombo,
+ JComboBox<Condition> condCombo, JTextField valueField,
+ int filterIndex)
+ {
+ String attName = (String) attCombo.getSelectedItem();
+ Condition cond = (Condition) condCombo.getSelectedItem();
+ String pattern = valueField.getText().trim();
+
+ setNumericHints(attName, cond, valueField);
+
+ if (pattern.length() == 0 && cond.needsAPattern())
+ {
+ valueField.setEnabled(true); // ensure pattern field is enabled!
+ return false;
+ }
+
+ /*
+ * Construct a matcher that operates on Label, Score,
+ * or named attribute
+ */
+ FeatureMatcherI km = null;
+ if (LABEL_18N.equals(attName))
+ {
+ km = FeatureMatcher.byLabel(cond, pattern);
+ }
+ else if (SCORE_18N.equals(attName))
+ {
+ km = FeatureMatcher.byScore(cond, pattern);
+ }
+ else
+ {
+ km = FeatureMatcher.byAttribute(cond, pattern,
+ FeatureMatcher.fromAttributeDisplayName(attName));
+ }
+
+ filters.set(filterIndex, km);
+
+ return true;
+ }
+
+ /**
+ * Action on any change to feature filtering, namely
+ * <ul>
+ * <li>change of selected attribute</li>
+ * <li>change of selected condition</li>
+ * <li>change of match pattern</li>
+ * <li>removal of a condition</li>
+ * </ul>
+ * The inputs are parsed into a combined filter and this is set for the
+ * feature type, and the alignment redrawn.
+ */
+ protected void filtersChanged()
+ {
+ /*
+ * update the filter conditions for the feature type
+ */
+ boolean anded = andFilters.isSelected();
+ FeatureMatcherSetI combined = new FeatureMatcherSet();
+
+ for (FeatureMatcherI filter : filters)
+ {
+ String pattern = filter.getMatcher().getPattern();
+ Condition condition = filter.getMatcher().getCondition();
+ if (pattern.trim().length() > 0 || !condition.needsAPattern())
+ {
+ if (anded)
+ {
+ combined.and(filter);
+ }
+ else
+ {
+ combined.or(filter);
+ }
+ }
+ }
+
+ /*
+ * save the filter conditions in the FeatureRenderer
+ * (note this might now be an empty filter with no conditions)
+ */
+ fr.setFeatureFilter(featureType, combined.isEmpty() ? null : combined);
+ ap.paintAlignment(true, true);
+
+ updateFiltersTab();
+ }
+}
fontAsCdna.setSelected(ap.av.isProteinFontAsCdna());
}
- if (tp != null)
+ if (isTreeFont())
{
Desktop.addInternalFrame(frame,
MessageManager.getString("action.change_font_tree_panel"),
@Override
protected void cancel_actionPerformed()
{
- if (ap != null)
+ if (isTreeFont())
+ {
+ tp.setTreeFont(oldFont);
+ }
+ else if (ap != null)
{
ap.av.setFont(oldFont, true);
ap.av.setScaleProteinAsCdna(oldProteinScale);
splitFrame.repaint();
}
}
- else if (tp != null)
- {
- tp.setTreeFont(oldFont);
- }
try
{
}
}
+ private boolean isTreeFont()
+ {
+ return tp != null;
+ }
+
/**
* DOCUMENT ME!
*/
}
return;
}
- if (tp != null)
+ if (isTreeFont())
{
tp.setTreeFont(newFont);
}
List<SequenceI> searchResults;
- FontMetrics fm;
-
- AnnotationLabels labels = null;
-
AnnotationPanel ap;
private Font idfont;
this.av = av;
PaintRefresher.Register(this, av.getSequenceSetId());
av.getRanges().addPropertyChangeListener(this);
- }
+ }
/**
* DOCUMENT ME!
*
- * @param gg
+ * @param g
* DOCUMENT ME!
* @param hiddenRows
* true - check and display hidden row marker if need be
* @param ypos
* DOCUMENT ME!
*/
- public void drawIdString(Graphics2D gg, boolean hiddenRows, SequenceI s,
+ public void drawIdString(Graphics2D g, boolean hiddenRows, SequenceI s,
int i, int starty, int ypos)
{
int xPos = 0;
if ((searchResults != null) && searchResults.contains(s))
{
- gg.setColor(Color.black);
- gg.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
+ g.setColor(Color.black);
+ g.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
charHeight);
- gg.setColor(Color.white);
+ g.setColor(Color.white);
}
else if ((av.getSelectionGroup() != null)
&& av.getSelectionGroup().getSequences(null).contains(s))
{
- gg.setColor(Color.lightGray);
- gg.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
+ g.setColor(Color.lightGray);
+ g.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
charHeight);
- gg.setColor(Color.white);
+ g.setColor(Color.white);
}
else
{
- gg.setColor(av.getSequenceColour(s));
- gg.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
+ g.setColor(av.getSequenceColour(s));
+ g.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
charHeight);
- gg.setColor(Color.black);
+ g.setColor(Color.black);
}
if (av.isRightAlignIds())
{
+ FontMetrics fm = g.getFontMetrics();
xPos = panelWidth
- fm.stringWidth(s.getDisplayId(av.getShowJVSuffix())) - 4;
}
- gg.drawString(s.getDisplayId(av.getShowJVSuffix()), xPos,
+ g.drawString(s.getDisplayId(av.getShowJVSuffix()), xPos,
(((i - starty + 1) * charHeight) + ypos) - (charHeight / 5));
if (hiddenRows)
{
- drawMarker(i, starty, ypos);
+ drawMarker(g, av, i, starty, ypos);
}
}
gg.translate(0, transY);
- drawIds(ss, es);
+ drawIds(gg, av, ss, es, searchResults);
gg.translate(0, -transY);
fastPaint = true;
- repaint();
+
+ // Call repaint on alignment panel so that repaints from other alignment
+ // panel components can be aggregated. Otherwise performance of the overview
+ // window and others may be adversely affected.
+ av.getAlignPanel().repaint();
}
/**
@Override
public void paintComponent(Graphics g)
{
+ super.paintComponent(g);
+
g.setColor(Color.white);
g.fillRect(0, 0, getWidth(), getHeight());
-
+
if (fastPaint)
{
fastPaint = false;
g.drawImage(image, 0, 0, this);
-
+
return;
}
-
+
int oldHeight = imgHeight;
-
+
imgHeight = getHeight();
imgHeight -= (imgHeight % av.getCharHeight());
-
+
if (imgHeight < 1)
{
return;
}
-
+
if (oldHeight != imgHeight || image.getWidth(this) != getWidth())
{
- image = new BufferedImage(getWidth(), imgHeight,
- BufferedImage.TYPE_INT_RGB);
+ image = new BufferedImage(getWidth(), imgHeight,
+ BufferedImage.TYPE_INT_RGB);
}
-
+
gg = (Graphics2D) image.getGraphics();
-
+
// Fill in the background
gg.setColor(Color.white);
gg.fillRect(0, 0, getWidth(), imgHeight);
-
- drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq());
-
+
+ drawIds(gg, av, av.getRanges().getStartSeq(), av.getRanges().getEndSeq(), searchResults);
+
g.drawImage(image, 0, 0, this);
}
/**
- * DOCUMENT ME!
+ * Draws sequence ids from sequence index startSeq to endSeq (inclusive), with
+ * the font and other display settings configured on the viewport. Ids of
+ * sequences included in the selection are coloured grey, otherwise the
+ * current id colour for the sequence id is used.
*
- * @param starty
- * DOCUMENT ME!
- * @param endy
- * DOCUMENT ME!
+ * @param g
+ * @param alignViewport
+ * @param startSeq
+ * @param endSeq
+ * @param selection
*/
- void drawIds(int starty, int endy)
+ void drawIds(Graphics2D g, AlignViewport alignViewport, final int startSeq,
+ final int endSeq, List<SequenceI> selection)
{
- if (av.isSeqNameItalics())
+ Font font = alignViewport.getFont();
+ if (alignViewport.isSeqNameItalics())
{
- setIdfont(new Font(av.getFont().getName(), Font.ITALIC,
- av.getFont().getSize()));
+ setIdfont(new Font(font.getName(), Font.ITALIC,
+ font.getSize()));
}
else
{
- setIdfont(av.getFont());
+ setIdfont(font);
}
- gg.setFont(getIdfont());
- fm = gg.getFontMetrics();
+ g.setFont(getIdfont());
+ FontMetrics fm = g.getFontMetrics();
- if (av.antiAlias)
+ if (alignViewport.antiAlias)
{
- gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
Color currentColor = Color.white;
Color currentTextColor = Color.black;
- boolean hasHiddenRows = av.hasHiddenRows();
+ boolean hasHiddenRows = alignViewport.hasHiddenRows();
- if (av.getWrapAlignment())
+ if (alignViewport.getWrapAlignment())
{
- drawIdsWrapped(starty, hasHiddenRows);
+ drawIdsWrapped(g, alignViewport, startSeq, getHeight());
return;
}
- // No need to hang on to labels if we're not wrapped
- labels = null;
-
// Now draw the id strings
int panelWidth = getWidth();
int xPos = 0;
- SequenceI sequence;
// Now draw the id strings
- for (int i = starty; i <= endy; i++)
+ for (int i = startSeq; i <= endSeq; i++)
{
- sequence = av.getAlignment().getSequenceAt(i);
+ SequenceI sequence = alignViewport.getAlignment().getSequenceAt(i);
if (sequence == null)
{
continue;
}
- if (hasHiddenRows || av.isDisplayReferenceSeq())
+ if (hasHiddenRows || alignViewport.isDisplayReferenceSeq())
{
- setHiddenFont(sequence);
+ g.setFont(getHiddenFont(sequence, alignViewport));
}
// Selected sequence colours
- if ((searchResults != null) && searchResults.contains(sequence))
+ if (selection != null && selection.contains(sequence))
{
currentColor = Color.black;
currentTextColor = Color.white;
}
- else if ((av.getSelectionGroup() != null) && av.getSelectionGroup()
- .getSequences(null).contains(sequence))
+ else if ((alignViewport.getSelectionGroup() != null) && alignViewport
+ .getSelectionGroup().getSequences(null).contains(sequence))
{
currentColor = Color.lightGray;
currentTextColor = Color.black;
}
else
{
- currentColor = av.getSequenceColour(sequence);
+ currentColor = alignViewport.getSequenceColour(sequence);
currentTextColor = Color.black;
}
- gg.setColor(currentColor);
+ g.setColor(currentColor);
- gg.fillRect(0, (i - starty) * av.getCharHeight(), getWidth(),
- av.getCharHeight());
+ int charHeight = alignViewport.getCharHeight();
+ g.fillRect(0, (i - startSeq) * charHeight,
+ getWidth(), charHeight);
- gg.setColor(currentTextColor);
+ g.setColor(currentTextColor);
- String string = sequence.getDisplayId(av.getShowJVSuffix());
+ String string = sequence
+ .getDisplayId(alignViewport.getShowJVSuffix());
- if (av.isRightAlignIds())
+ if (alignViewport.isRightAlignIds())
{
xPos = panelWidth - fm.stringWidth(string) - 4;
}
- gg.drawString(string, xPos,
- (((i - starty) * av.getCharHeight()) + av.getCharHeight())
- - (av.getCharHeight() / 5));
+ g.drawString(string, xPos, (((i - startSeq) * charHeight) + charHeight)
+ - (charHeight / 5));
if (hasHiddenRows)
{
- drawMarker(i, starty, 0);
+ drawMarker(g, alignViewport, i, startSeq, 0);
}
}
}
/**
- * Draws sequence ids in wrapped mode
+ * Draws sequence ids, and annotation labels if annotations are shown, in
+ * wrapped mode
*
- * @param starty
- * @param hasHiddenRows
+ * @param g
+ * @param alignViewport
+ * @param startSeq
*/
- protected void drawIdsWrapped(int starty, boolean hasHiddenRows)
+ void drawIdsWrapped(Graphics2D g, AlignViewport alignViewport,
+ int startSeq, int pageHeight)
{
- int maxwidth = av.getAlignment().getWidth();
- int alheight = av.getAlignment().getHeight();
+ int alignmentWidth = alignViewport.getAlignment().getWidth();
+ final int alheight = alignViewport.getAlignment().getHeight();
- if (av.hasHiddenColumns())
+ if (alignViewport.hasHiddenColumns())
{
- maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth) - 1;
+ alignmentWidth = alignViewport.getAlignment().getHiddenColumns()
+ .absoluteToVisibleColumn(alignmentWidth) - 1;
}
int annotationHeight = 0;
- if (av.isShowAnnotation())
+ AnnotationLabels labels = null;
+ if (alignViewport.isShowAnnotation())
{
if (ap == null)
{
- ap = new AnnotationPanel(av);
+ ap = new AnnotationPanel(alignViewport);
}
-
annotationHeight = ap.adjustPanelHeight();
- if (labels == null)
- {
- labels = new AnnotationLabels(av);
- }
+ labels = new AnnotationLabels(alignViewport);
}
- int hgap = av.getCharHeight();
- if (av.getScaleAboveWrapped())
+ final int charHeight = alignViewport.getCharHeight();
+ int hgap = charHeight;
+ if (alignViewport.getScaleAboveWrapped())
{
- hgap += av.getCharHeight();
+ hgap += charHeight;
}
- int cHeight = alheight * av.getCharHeight() + hgap + annotationHeight;
+ /*
+ * height of alignment + gap + annotations (if shown)
+ */
+ int cHeight = alheight * charHeight + hgap
+ + annotationHeight;
- ViewportRanges ranges = av.getRanges();
+ ViewportRanges ranges = alignViewport.getRanges();
int rowSize = ranges.getViewportWidth();
* draw repeating sequence ids until out of sequence data or
* out of visible space, whichever comes first
*/
+ boolean hasHiddenRows = alignViewport.hasHiddenRows();
int ypos = hgap;
- int row = ranges.getStartRes();
- while ((ypos <= getHeight()) && (row < maxwidth))
+ int rowStartRes = ranges.getStartRes();
+ while ((ypos <= pageHeight) && (rowStartRes < alignmentWidth))
{
- for (int i = starty; i < alheight; i++)
+ for (int i = startSeq; i < alheight; i++)
{
- SequenceI s = av.getAlignment().getSequenceAt(i);
- if (hasHiddenRows || av.isDisplayReferenceSeq())
+ SequenceI s = alignViewport.getAlignment().getSequenceAt(i);
+ if (hasHiddenRows || alignViewport.isDisplayReferenceSeq())
{
- setHiddenFont(s);
+ g.setFont(getHiddenFont(s, alignViewport));
}
else
{
- gg.setFont(getIdfont());
+ g.setFont(getIdfont());
}
-
- drawIdString(gg, hasHiddenRows, s, i, 0, ypos);
+ drawIdString(g, hasHiddenRows, s, i, 0, ypos);
}
- if (labels != null && av.isShowAnnotation())
+ if (labels != null && alignViewport.isShowAnnotation())
{
- gg.translate(0, ypos + (alheight * av.getCharHeight()));
- labels.drawComponent(gg, getWidth());
- gg.translate(0, -ypos - (alheight * av.getCharHeight()));
+ g.translate(0, ypos + (alheight * charHeight));
+ labels.drawComponent(g, getWidth());
+ g.translate(0, -ypos - (alheight * charHeight));
}
ypos += cHeight;
- row += rowSize;
+ rowStartRes += rowSize;
}
}
- void drawMarker(int i, int starty, int yoffset)
+ /**
+ * Draws a marker (a blue right-pointing triangle) between sequences to
+ * indicate hidden sequences.
+ *
+ * @param g
+ * @param alignViewport
+ * @param seqIndex
+ * @param starty
+ * @param yoffset
+ */
+ void drawMarker(Graphics2D g, AlignViewport alignViewport, int seqIndex, int starty, int yoffset)
{
-
- SequenceI[] hseqs = av.getAlignment()
+ SequenceI[] hseqs = alignViewport.getAlignment()
.getHiddenSequences().hiddenSequences;
// Use this method here instead of calling hiddenSeq adjust
// 3 times.
int hSize = hseqs.length;
- int hiddenIndex = i;
- int lastIndex = i - 1;
- int nextIndex = i + 1;
+ int hiddenIndex = seqIndex;
+ int lastIndex = seqIndex - 1;
+ int nextIndex = seqIndex + 1;
for (int j = 0; j < hSize; j++)
{
}
}
+ /*
+ * are we below or above the hidden sequences?
+ */
boolean below = (hiddenIndex > lastIndex + 1);
boolean above = (nextIndex > hiddenIndex + 1);
- gg.setColor(Color.blue);
+ g.setColor(Color.blue);
+ int charHeight = av.getCharHeight();
+
+ /*
+ * vertices of the triangle, below or above hidden seqs
+ */
+ int[] xPoints = new int[]
+ { getWidth() - charHeight,
+ getWidth() - charHeight, getWidth() };
+ int yShift = seqIndex - starty;
+
if (below)
{
- gg.fillPolygon(
- new int[]
- { getWidth() - av.getCharHeight(),
- getWidth() - av.getCharHeight(), getWidth() },
- new int[]
- { (i - starty) * av.getCharHeight() + yoffset,
- (i - starty) * av.getCharHeight() + yoffset
- + av.getCharHeight() / 4,
- (i - starty) * av.getCharHeight() + yoffset },
- 3);
+ int[] yPoints = new int[] { yShift * charHeight + yoffset,
+ yShift * charHeight + yoffset + charHeight / 4,
+ yShift * charHeight + yoffset };
+ g.fillPolygon(xPoints, yPoints, 3);
}
if (above)
{
- gg.fillPolygon(
- new int[]
- { getWidth() - av.getCharHeight(),
- getWidth() - av.getCharHeight(), getWidth() },
- new int[]
- { (i - starty + 1) * av.getCharHeight() + yoffset,
- (i - starty + 1) * av.getCharHeight() + yoffset
- - av.getCharHeight() / 4,
- (i - starty + 1) * av.getCharHeight() + yoffset },
- 3);
-
+ yShift++;
+ int[] yPoints = new int[] { yShift * charHeight + yoffset,
+ yShift * charHeight + yoffset - charHeight / 4,
+ yShift * charHeight + yoffset };
+ g.fillPolygon(xPoints, yPoints, 3);
}
}
- void setHiddenFont(SequenceI seq)
+ /**
+ * Answers the standard sequence id font, or a bold font if the sequence is
+ * set as reference or a hidden group representative
+ *
+ * @param seq
+ * @param alignViewport
+ * @return
+ */
+ private Font getHiddenFont(SequenceI seq, AlignViewport alignViewport)
{
- Font bold = new Font(av.getFont().getName(), Font.BOLD,
- av.getFont().getSize());
-
if (av.isReferenceSeq(seq) || av.isHiddenRepSequence(seq))
{
- gg.setFont(bold);
- }
- else
- {
- gg.setFont(getIdfont());
+ return new Font(av.getFont().getName(), Font.BOLD,
+ av.getFont().getSize());
}
+ return getIdfont();
}
/**
SequenceI sequence = av.getAlignment().getSequenceAt(seq);
StringBuilder tip = new StringBuilder(64);
seqAnnotReport.createTooltipAnnotationReport(tip, sequence,
- av.isShowDBRefs(), av.isShowNPFeats(),
- sp.seqCanvas.fr.getMinMax());
+ av.isShowDBRefs(), av.isShowNPFeats(), sp.seqCanvas.fr);
setToolTipText(JvSwingUtils.wrapTooltip(true,
sequence.getDisplayId(true) + " " + tip.toString()));
}
public void mouseWheelMoved(MouseWheelEvent e)
{
e.consume();
- if (e.getWheelRotation() > 0)
+ double wheelRotation = e.getPreciseWheelRotation();
+ if (wheelRotation > 0)
{
if (e.isShiftDown())
{
av.getRanges().scrollUp(false);
}
}
- else
+ else if (wheelRotation < 0)
{
if (e.isShiftDown())
{
* and any non-positional features
*/
List<String> nlinks = Preferences.sequenceUrlLinks.getLinksForMenu();
- for (SequenceFeature sf : sq.getFeatures().getNonPositionalFeatures())
+ List<SequenceFeature> features = sq.getFeatures().getNonPositionalFeatures();
+ for (SequenceFeature sf : features)
{
if (sf.links != null)
{
}
}
- PopupMenu pop = new PopupMenu(alignPanel, sq, nlinks,
+ PopupMenu pop = new PopupMenu(alignPanel, sq, features,
Preferences.getGroupURLLinks());
pop.show(this, e.getX(), e.getY());
}
import jalview.api.AlignViewportI;
import java.awt.Color;
+import java.awt.Cursor;
import java.awt.Graphics;
-import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
int oldX = 0;
- Image image;
-
AlignmentPanel ap;
/**
public IdwidthAdjuster(AlignmentPanel ap)
{
this.ap = ap;
-
- java.net.URL url = getClass().getResource("/images/idwidth.gif");
-
- if (url != null)
- {
- image = java.awt.Toolkit.getDefaultToolkit().createImage(url);
- }
-
+ setBackground(Color.white);
addMouseListener(this);
addMouseMotionListener(this);
}
if (active)
{
- if (image != null)
- {
- g.drawImage(image, getWidth() - 20, 2, this);
- }
+ setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
}
}
}
*/
package jalview.gui;
-import jalview.bin.Cache;
import jalview.util.MessageManager;
import jalview.ws.seqfetcher.DbSourceProxy;
import java.util.Vector;
import javax.swing.JButton;
-import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
* identical DB sources, and should be collapsed.
*/
DefaultMutableTreeNode tn = null, root = new DefaultMutableTreeNode();
- Hashtable<String, DefaultMutableTreeNode> source = new Hashtable<String, DefaultMutableTreeNode>();
+ Hashtable<String, DefaultMutableTreeNode> source = new Hashtable<>();
sfetcher = sfetch;
String dbs[] = sfetch.getSupportedDb();
- Hashtable<String, String> ht = new Hashtable<String, String>();
+ Hashtable<String, String> ht = new Hashtable<>();
for (int i = 0; i < dbs.length; i++)
{
tn = source.get(dbs[i]);
tsel = dbviews.getSelectionPaths();
boolean forcedFirstChild = false;
- List<DbSourceProxy> srcs = new ArrayList<DbSourceProxy>();
+ List<DbSourceProxy> srcs = new ArrayList<>();
if (tsel != null)
{
for (TreePath tp : tsel)
return null;
}
StringBuffer sb = new StringBuffer();
- HashSet<String> hs = new HashSet<String>();
+ HashSet<String> hs = new HashSet<>();
for (DbSourceProxy dbs : getSelectedSources())
{
String tq = dbs.getTestQuery();
return sb.toString();
}
- List<ActionListener> lstners = new Vector<ActionListener>();
+ List<ActionListener> lstners = new Vector<>();
public void addActionListener(ActionListener actionListener)
{
lstners.remove(actionListener);
}
- public static void main(String args[])
- {
- Cache.getDasSourceRegistry();
- JDatabaseTree jdt = new JDatabaseTree(new jalview.ws.SequenceFetcher());
- JFrame foo = new JFrame();
- foo.setLayout(new BorderLayout());
- foo.add(jdt.getDatabaseSelectorButton(), BorderLayout.CENTER);
- foo.pack();
- foo.setVisible(true);
- int nultimes = 5;
- final Thread us = Thread.currentThread();
- jdt.addActionListener(new ActionListener()
- {
-
- @Override
- public void actionPerformed(ActionEvent e)
- {
- us.interrupt();
- }
- });
- do
- {
- try
- {
- Thread.sleep(50);
- } catch (InterruptedException x)
- {
- nultimes--;
- if (!jdt.hasSelection())
- {
- System.out.println("No Selection");
- }
- else
- {
- System.out.println("Selection: " + jdt.getSelectedItem());
- int s = 1;
- for (DbSourceProxy pr : jdt.getSelectedSources())
- {
- System.out.println("Source " + s++ + ": " + pr.getDbName()
- + " (" + pr.getDbSource() + ") Version "
- + pr.getDbVersion() + ". Test:\t" + pr.getTestQuery());
- }
- System.out.println("Test queries: " + jdt.getExampleQueries());
- }
- }
- } while (nultimes > 0 && foo.isVisible());
- foo.setVisible(false);
- }
@Override
public void keyPressed(KeyEvent arg0)
// TODO Auto-generated method stub
}
+
+ @Override
+ public void setVisible(boolean arg0)
+ {
+ System.out.println("setVisible: " + arg0);
+ super.setVisible(arg0);
+ }
}
import jalview.datamodel.SequenceI;
import jalview.datamodel.StructureViewerModel;
import jalview.datamodel.StructureViewerModel.StructureData;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.datamodel.features.FeatureMatcherI;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.ext.varna.RnaModel;
import jalview.gui.StructureViewer.ViewerType;
import jalview.io.DataSourceType;
import jalview.schemabinding.version2.AnnotationColours;
import jalview.schemabinding.version2.AnnotationElement;
import jalview.schemabinding.version2.CalcIdParam;
+import jalview.schemabinding.version2.Colour;
+import jalview.schemabinding.version2.CompoundMatcher;
import jalview.schemabinding.version2.DBRef;
import jalview.schemabinding.version2.Features;
import jalview.schemabinding.version2.Group;
import jalview.schemabinding.version2.MapListTo;
import jalview.schemabinding.version2.Mapping;
import jalview.schemabinding.version2.MappingChoice;
+import jalview.schemabinding.version2.MatchCondition;
+import jalview.schemabinding.version2.MatcherSet;
import jalview.schemabinding.version2.OtherData;
import jalview.schemabinding.version2.PdbentryItem;
import jalview.schemabinding.version2.Pdbids;
import jalview.schemabinding.version2.Tree;
import jalview.schemabinding.version2.UserColours;
import jalview.schemabinding.version2.Viewport;
+import jalview.schemabinding.version2.types.ColourThreshTypeType;
+import jalview.schemabinding.version2.types.FeatureMatcherByType;
+import jalview.schemabinding.version2.types.NoValueColour;
import jalview.schemes.AnnotationColourGradient;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemeProperty;
import jalview.schemes.UserColourScheme;
import jalview.structure.StructureSelectionManager;
import jalview.structures.models.AAStructureBindingModel;
+import jalview.util.Format;
import jalview.util.MessageManager;
import jalview.util.Platform;
import jalview.util.StringUtils;
import jalview.util.jarInputStreamProvider;
+import jalview.util.matcher.Condition;
import jalview.viewmodel.AlignmentViewport;
import jalview.viewmodel.ViewportRanges;
import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
}
if (sf.otherDetails != null)
{
- String key;
- Iterator<String> keys = sf.otherDetails.keySet().iterator();
- while (keys.hasNext())
+ /*
+ * save feature attributes, which may be simple strings or
+ * map valued (have sub-attributes)
+ */
+ for (Entry<String, Object> entry : sf.otherDetails.entrySet())
{
- key = keys.next();
- OtherData keyValue = new OtherData();
- keyValue.setKey(key);
- keyValue.setValue(sf.otherDetails.get(key).toString());
- features.addOtherData(keyValue);
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if (value instanceof Map<?, ?>)
+ {
+ for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
+ .entrySet())
+ {
+ OtherData otherData = new OtherData();
+ otherData.setKey(key);
+ otherData.setKey2(subAttribute.getKey());
+ otherData.setValue(subAttribute.getValue().toString());
+ features.addOtherData(otherData);
+ }
+ }
+ else
+ {
+ OtherData otherData = new OtherData();
+ otherData.setKey(key);
+ otherData.setValue(value.toString());
+ features.addOtherData(otherData);
+ }
}
}
{
jalview.schemabinding.version2.FeatureSettings fs = new jalview.schemabinding.version2.FeatureSettings();
- String[] renderOrder = ap.getSeqPanel().seqCanvas
- .getFeatureRenderer().getRenderOrder()
- .toArray(new String[0]);
+ FeatureRenderer fr = ap.getSeqPanel().seqCanvas
+ .getFeatureRenderer();
+ String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
Vector<String> settingsAdded = new Vector<>();
if (renderOrder != null)
{
for (String featureType : renderOrder)
{
- FeatureColourI fcol = ap.getSeqPanel().seqCanvas
- .getFeatureRenderer().getFeatureStyle(featureType);
Setting setting = new Setting();
setting.setType(featureType);
+
+ /*
+ * save any filter for the feature type
+ */
+ FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
+ if (filter != null) {
+ Iterator<FeatureMatcherI> filters = filter.getMatchers().iterator();
+ FeatureMatcherI firstFilter = filters.next();
+ setting.setMatcherSet(Jalview2XML.marshalFilter(
+ firstFilter, filters, filter.isAnded()));
+ }
+
+ /*
+ * save colour scheme for the feature type
+ */
+ FeatureColourI fcol = fr.getFeatureStyle(featureType);
if (!fcol.isSimpleColour())
{
setting.setColour(fcol.getMaxColour().getRGB());
setting.setMin(fcol.getMin());
setting.setMax(fcol.getMax());
setting.setColourByLabel(fcol.isColourByLabel());
+ if (fcol.isColourByAttribute())
+ {
+ setting.setAttributeName(fcol.getAttributeName());
+ }
setting.setAutoScale(fcol.isAutoScaled());
setting.setThreshold(fcol.getThreshold());
+ Color noColour = fcol.getNoColour();
+ if (noColour == null)
+ {
+ setting.setNoValueColour(NoValueColour.NONE);
+ }
+ else if (noColour.equals(fcol.getMaxColour()))
+ {
+ setting.setNoValueColour(NoValueColour.MAX);
+ }
+ else
+ {
+ setting.setNoValueColour(NoValueColour.MIN);
+ }
// -1 = No threshold, 0 = Below, 1 = Above
setting.setThreshstate(fcol.isAboveThreshold() ? 1
: (fcol.isBelowThreshold() ? 0 : -1));
setting.setDisplay(
av.getFeaturesDisplayed().isVisible(featureType));
- float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
+ float rorder = fr
.getOrder(featureType);
if (rorder > -1)
{
}
// is groups actually supposed to be a map here ?
- Iterator<String> en = ap.getSeqPanel().seqCanvas
- .getFeatureRenderer().getFeatureGroups().iterator();
+ Iterator<String> en = fr.getFeatureGroups().iterator();
Vector<String> groupsAdded = new Vector<>();
while (en.hasNext())
{
}
Group g = new Group();
g.setName(grp);
- g.setDisplay(((Boolean) ap.getSeqPanel().seqCanvas
- .getFeatureRenderer().checkGroupVisibility(grp, false))
+ g.setDisplay(((Boolean) fr.checkGroupVisibility(grp, false))
.booleanValue());
fs.addGroup(g);
groupsAdded.addElement(grp);
}
else
{
- ArrayList<int[]> hiddenRegions = hidden.getHiddenColumnsCopy();
- for (int[] region : hiddenRegions)
+ Iterator<int[]> hiddenRegions = hidden.iterator();
+ while (hiddenRegions.hasNext())
{
+ int[] region = hiddenRegions.next();
HiddenColumns hc = new HiddenColumns();
hc.setStart(region[0]);
hc.setEnd(region[1]);
features[f].getEnd(), features[f].getScore(),
features[f].getFeatureGroup());
sf.setStatus(features[f].getStatus());
+
+ /*
+ * load any feature attributes - include map-valued attributes
+ */
+ Map<String, Map<String, String>> mapAttributes = new HashMap<>();
for (int od = 0; od < features[f].getOtherDataCount(); od++)
{
OtherData keyValue = features[f].getOtherData(od);
- if (keyValue.getKey().startsWith("LINK"))
+ String attributeName = keyValue.getKey();
+ String attributeValue = keyValue.getValue();
+ if (attributeName.startsWith("LINK"))
{
- sf.addLink(keyValue.getValue());
+ sf.addLink(attributeValue);
}
else
{
- sf.setValue(keyValue.getKey(), keyValue.getValue());
+ String subAttribute = keyValue.getKey2();
+ if (subAttribute == null)
+ {
+ // simple string-valued attribute
+ sf.setValue(attributeName, attributeValue);
+ }
+ else
+ {
+ // attribute 'key' has sub-attribute 'key2'
+ if (!mapAttributes.containsKey(attributeName))
+ {
+ mapAttributes.put(attributeName, new HashMap<>());
+ }
+ mapAttributes.get(attributeName).put(subAttribute,
+ attributeValue);
+ }
}
-
}
+ for (Entry<String, Map<String, String>> mapAttribute : mapAttributes
+ .entrySet())
+ {
+ sf.setValue(mapAttribute.getKey(), mapAttribute.getValue());
+ }
+
// adds feature to datasequence's feature set (since Jalview 2.10)
al.getSequenceAt(i).addSequenceFeature(sf);
}
af.viewport.setShowGroupConservation(false);
}
- // recover featre settings
+ // recover feature settings
if (jms.getFeatureSettings() != null)
{
+ FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
+ .getFeatureRenderer();
FeaturesDisplayed fdi;
af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
String[] renderOrder = new String[jms.getFeatureSettings()
.getSettingCount(); fs++)
{
Setting setting = jms.getFeatureSettings().getSetting(fs);
+ String featureType = setting.getType();
+
+ /*
+ * restore feature filters (if any)
+ */
+ MatcherSet filters = setting.getMatcherSet();
+ if (filters != null)
+ {
+ FeatureMatcherSetI filter = Jalview2XML
+ .unmarshalFilter(featureType, filters);
+ if (!filter.isEmpty())
+ {
+ fr.setFeatureFilter(featureType, filter);
+ }
+ }
+
+ /*
+ * restore feature colour scheme
+ */
+ Color maxColour = new Color(setting.getColour());
if (setting.hasMincolour())
{
- FeatureColourI gc = setting.hasMin()
- ? new FeatureColour(new Color(setting.getMincolour()),
- new Color(setting.getColour()), setting.getMin(),
- setting.getMax())
- : new FeatureColour(new Color(setting.getMincolour()),
- new Color(setting.getColour()), 0, 1);
+ /*
+ * minColour is always set unless a simple colour
+ * (including for colour by label though it doesn't use it)
+ */
+ Color minColour = new Color(setting.getMincolour());
+ Color noValueColour = minColour;
+ NoValueColour noColour = setting.getNoValueColour();
+ if (noColour == NoValueColour.NONE)
+ {
+ noValueColour = null;
+ }
+ else if (noColour == NoValueColour.MAX)
+ {
+ noValueColour = maxColour;
+ }
+ float min = setting.hasMin() ? setting.getMin() : 0f;
+ float max = setting.hasMin() ? setting.getMax() : 1f;
+ FeatureColourI gc = new FeatureColour(minColour, maxColour,
+ noValueColour, min, max);
+ if (setting.getAttributeNameCount() > 0)
+ {
+ gc.setAttributeName(setting.getAttributeName());
+ }
if (setting.hasThreshold())
{
gc.setThreshold(setting.getThreshold());
gc.setColourByLabel(setting.getColourByLabel());
}
// and put in the feature colour table.
- featureColours.put(setting.getType(), gc);
+ featureColours.put(featureType, gc);
}
else
{
- featureColours.put(setting.getType(),
- new FeatureColour(new Color(setting.getColour())));
+ featureColours.put(featureType,
+ new FeatureColour(maxColour));
}
- renderOrder[fs] = setting.getType();
+ renderOrder[fs] = featureType;
if (setting.hasOrder())
{
- featureOrder.put(setting.getType(), setting.getOrder());
+ featureOrder.put(featureType, setting.getOrder());
}
else
{
- featureOrder.put(setting.getType(), new Float(
+ featureOrder.put(featureType, new Float(
fs / jms.getFeatureSettings().getSettingCount()));
}
if (setting.getDisplay())
{
- fdi.setVisible(setting.getType());
+ fdi.setVisible(featureType);
}
}
Map<String, Boolean> fgtable = new Hashtable<>();
// jms.getFeatureSettings().getTransparency() : 0.0, featureOrder);
FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
fgtable, featureColours, 1.0f, featureOrder);
- af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
- .transferSettings(frs);
-
+ fr.transferSettings(frs);
}
if (view.getHiddenColumnsCount() > 0)
if (this.frefedSequence == null)
{
- frefedSequence = new Vector<SeqFref>();
+ frefedSequence = new Vector<>();
}
viewportsAdded.clear();
{
return counter++;
}
+
+ /**
+ * Populates an XML model of the feature colour scheme for one feature type
+ *
+ * @param featureType
+ * @param fcol
+ * @return
+ */
+ protected static jalview.schemabinding.version2.Colour marshalColour(
+ String featureType, FeatureColourI fcol)
+ {
+ jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
+ if (fcol.isSimpleColour())
+ {
+ col.setRGB(Format.getHexString(fcol.getColour()));
+ }
+ else
+ {
+ col.setRGB(Format.getHexString(fcol.getMaxColour()));
+ col.setMin(fcol.getMin());
+ col.setMax(fcol.getMax());
+ col.setMinRGB(jalview.util.Format.getHexString(fcol.getMinColour()));
+ col.setAutoScale(fcol.isAutoScaled());
+ col.setThreshold(fcol.getThreshold());
+ col.setColourByLabel(fcol.isColourByLabel());
+ col.setThreshType(fcol.isAboveThreshold() ? ColourThreshTypeType.ABOVE
+ : (fcol.isBelowThreshold() ? ColourThreshTypeType.BELOW
+ : ColourThreshTypeType.NONE));
+ if (fcol.isColourByAttribute())
+ {
+ col.setAttributeName(fcol.getAttributeName());
+ }
+ Color noColour = fcol.getNoColour();
+ if (noColour == null)
+ {
+ col.setNoValueColour(NoValueColour.NONE);
+ }
+ else if (noColour == fcol.getMaxColour())
+ {
+ col.setNoValueColour(NoValueColour.MAX);
+ }
+ else
+ {
+ col.setNoValueColour(NoValueColour.MIN);
+ }
+ }
+ col.setName(featureType);
+ return col;
+ }
+
+ /**
+ * Populates an XML model of the feature filter(s) for one feature type
+ *
+ * @param firstMatcher
+ * the first (or only) match condition)
+ * @param filter
+ * remaining match conditions (if any)
+ * @param and
+ * if true, conditions are and-ed, else or-ed
+ */
+ protected static MatcherSet marshalFilter(FeatureMatcherI firstMatcher,
+ Iterator<FeatureMatcherI> filters, boolean and)
+ {
+ MatcherSet result = new MatcherSet();
+
+ if (filters.hasNext())
+ {
+ /*
+ * compound matcher
+ */
+ CompoundMatcher compound = new CompoundMatcher();
+ compound.setAnd(and);
+ MatcherSet matcher1 = marshalFilter(firstMatcher,
+ Collections.emptyIterator(), and);
+ compound.addMatcherSet(matcher1);
+ FeatureMatcherI nextMatcher = filters.next();
+ MatcherSet matcher2 = marshalFilter(nextMatcher, filters, and);
+ compound.addMatcherSet(matcher2);
+ result.setCompoundMatcher(compound);
+ }
+ else
+ {
+ /*
+ * single condition matcher
+ */
+ MatchCondition matcherModel = new MatchCondition();
+ matcherModel.setCondition(
+ firstMatcher.getMatcher().getCondition().getStableName());
+ matcherModel.setValue(firstMatcher.getMatcher().getPattern());
+ if (firstMatcher.isByAttribute())
+ {
+ matcherModel.setBy(FeatureMatcherByType.BYATTRIBUTE);
+ matcherModel.setAttributeName(firstMatcher.getAttribute());
+ }
+ else if (firstMatcher.isByLabel())
+ {
+ matcherModel.setBy(FeatureMatcherByType.BYLABEL);
+ }
+ else if (firstMatcher.isByScore())
+ {
+ matcherModel.setBy(FeatureMatcherByType.BYSCORE);
+ }
+ result.setMatchCondition(matcherModel);
+ }
+
+ return result;
+ }
+
+ /**
+ * Loads one XML model of a feature filter to a Jalview object
+ *
+ * @param featureType
+ * @param matcherSetModel
+ * @return
+ */
+ protected static FeatureMatcherSetI unmarshalFilter(
+ String featureType, MatcherSet matcherSetModel)
+ {
+ FeatureMatcherSetI result = new FeatureMatcherSet();
+ try
+ {
+ unmarshalFilterConditions(result, matcherSetModel, true);
+ } catch (IllegalStateException e)
+ {
+ // mixing AND and OR conditions perhaps
+ System.err.println(
+ String.format("Error reading filter conditions for '%s': %s",
+ featureType, e.getMessage()));
+ // return as much as was parsed up to the error
+ }
+
+ return result;
+ }
+
+ /**
+ * Adds feature match conditions to matcherSet as unmarshalled from XML
+ * (possibly recursively for compound conditions)
+ *
+ * @param matcherSet
+ * @param matcherSetModel
+ * @param and
+ * if true, multiple conditions are AND-ed, else they are OR-ed
+ * @throws IllegalStateException
+ * if AND and OR conditions are mixed
+ */
+ protected static void unmarshalFilterConditions(
+ FeatureMatcherSetI matcherSet, MatcherSet matcherSetModel,
+ boolean and)
+ {
+ MatchCondition mc = matcherSetModel.getMatchCondition();
+ if (mc != null)
+ {
+ /*
+ * single condition
+ */
+ FeatureMatcherByType filterBy = mc.getBy();
+ Condition cond = Condition.fromString(mc.getCondition());
+ String pattern = mc.getValue();
+ FeatureMatcherI matchCondition = null;
+ if (filterBy == FeatureMatcherByType.BYLABEL)
+ {
+ matchCondition = FeatureMatcher.byLabel(cond, pattern);
+ }
+ else if (filterBy == FeatureMatcherByType.BYSCORE)
+ {
+ matchCondition = FeatureMatcher.byScore(cond, pattern);
+
+ }
+ else if (filterBy == FeatureMatcherByType.BYATTRIBUTE)
+ {
+ String[] attNames = mc.getAttributeName();
+ matchCondition = FeatureMatcher.byAttribute(cond, pattern,
+ attNames);
+ }
+
+ /*
+ * note this throws IllegalStateException if AND-ing to a
+ * previously OR-ed compound condition, or vice versa
+ */
+ if (and)
+ {
+ matcherSet.and(matchCondition);
+ }
+ else
+ {
+ matcherSet.or(matchCondition);
+ }
+ }
+ else
+ {
+ /*
+ * compound condition
+ */
+ MatcherSet[] matchers = matcherSetModel.getCompoundMatcher()
+ .getMatcherSet();
+ boolean anded = matcherSetModel.getCompoundMatcher().getAnd();
+ if (matchers.length == 2)
+ {
+ unmarshalFilterConditions(matcherSet, matchers[0], anded);
+ unmarshalFilterConditions(matcherSet, matchers[1], anded);
+ }
+ else
+ {
+ System.err.println("Malformed compound filter condition");
+ }
+ }
+ }
+
+ /**
+ * Loads one XML model of a feature colour to a Jalview object
+ *
+ * @param colourModel
+ * @return
+ */
+ protected static FeatureColourI unmarshalColour(
+ jalview.schemabinding.version2.Colour colourModel)
+ {
+ FeatureColourI colour = null;
+
+ if (colourModel.hasMax())
+ {
+ Color mincol = null;
+ Color maxcol = null;
+ Color noValueColour = null;
+
+ try
+ {
+ mincol = new Color(Integer.parseInt(colourModel.getMinRGB(), 16));
+ maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
+ } catch (Exception e)
+ {
+ Cache.log.warn("Couldn't parse out graduated feature color.", e);
+ }
+
+ NoValueColour noCol = colourModel.getNoValueColour();
+ if (noCol == NoValueColour.MIN)
+ {
+ noValueColour = mincol;
+ }
+ else if (noCol == NoValueColour.MAX)
+ {
+ noValueColour = maxcol;
+ }
+
+ colour = new FeatureColour(mincol, maxcol, noValueColour,
+ colourModel.getMin(),
+ colourModel.getMax());
+ String[] attributes = colourModel.getAttributeName();
+ if (attributes != null && attributes.length > 0)
+ {
+ colour.setAttributeName(attributes);
+ }
+ if (colourModel.hasAutoScale())
+ {
+ colour.setAutoScaled(colourModel.getAutoScale());
+ }
+ if (colourModel.hasColourByLabel())
+ {
+ colour.setColourByLabel(colourModel.getColourByLabel());
+ }
+ if (colourModel.hasThreshold())
+ {
+ colour.setThreshold(colourModel.getThreshold());
+ }
+ ColourThreshTypeType ttyp = colourModel.getThreshType();
+ if (ttyp != null)
+ {
+ if (ttyp == ColourThreshTypeType.ABOVE)
+ {
+ colour.setAboveThreshold(true);
+ }
+ else if (ttyp == ColourThreshTypeType.BELOW)
+ {
+ colour.setBelowThreshold(true);
+ }
+ }
+ }
+ else
+ {
+ Color color = new Color(Integer.parseInt(colourModel.getRGB(), 16));
+ colour = new FeatureColour(color);
+ }
+
+ return colour;
+ }
}
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
-import java.awt.event.WindowListener;
import javax.swing.JButton;
import javax.swing.JDialog;
closeDialog();
}
});
- frame.addWindowListener(new WindowListener()
+ frame.addWindowListener(new WindowAdapter()
{
-
- @Override
- public void windowOpened(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void windowIconified(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void windowDeiconified(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void windowDeactivated(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
-
@Override
public void windowClosing(WindowEvent e)
{
// user has cancelled the dialog
closeDialog();
}
-
- @Override
- public void windowClosed(WindowEvent e)
- {
- }
-
- @Override
- public void windowActivated(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
});
}
{
try
{
- frame.dispose();
raiseClosed();
+ frame.dispose();
} catch (Exception ex)
{
}
import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Component;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.List;
import java.util.Objects;
import javax.swing.AbstractButton;
+import javax.swing.BorderFactory;
import javax.swing.JButton;
+import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.SwingConstants;
+import javax.swing.border.Border;
+import javax.swing.border.TitledBorder;
/**
* useful functions for building Swing GUIs
comp.setFont(JvSwingUtils.getLabelFont());
}
+ /**
+ * A helper method to build a drop-down choice of values, with tooltips for
+ * the entries
+ *
+ * @param entries
+ * @param tooltips
+ */
+ public static JComboBox<String> buildComboWithTooltips(
+ List<String> entries, List<String> tooltips)
+ {
+ JComboBox<String> combo = new JComboBox<>();
+ final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer();
+ combo.setRenderer(renderer);
+ for (String attName : entries)
+ {
+ combo.addItem(attName);
+ }
+ renderer.setTooltips(tooltips);
+ final MouseAdapter mouseListener = new MouseAdapter()
+ {
+ @Override
+ public void mouseEntered(MouseEvent e)
+ {
+ int j = combo.getSelectedIndex();
+ if (j > -1)
+ {
+ combo.setToolTipText(tooltips.get(j));
+ }
+ }
+ @Override
+ public void mouseExited(MouseEvent e)
+ {
+ combo.setToolTipText(null);
+ }
+ };
+ for (Component c : combo.getComponents())
+ {
+ c.addMouseListener(mouseListener);
+ }
+ return combo;
+ }
+
+ /**
+ * Adds a titled border to the component in the default font and position (top
+ * left), optionally witht italic text
+ *
+ * @param comp
+ * @param title
+ * @param italic
+ */
+ public static TitledBorder createTitledBorder(JComponent comp,
+ String title, boolean italic)
+ {
+ Font font = comp.getFont();
+ if (italic)
+ {
+ font = new Font(font.getName(), Font.ITALIC, font.getSize());
+ }
+ Border border = BorderFactory.createTitledBorder("");
+ TitledBorder titledBorder = BorderFactory.createTitledBorder(border,
+ title, TitledBorder.LEADING, TitledBorder.DEFAULT_POSITION,
+ font);
+ comp.setBorder(titledBorder);
+
+ return titledBorder;
+ }
+
}
{
mg.translate(0, od.getSequencesHeight());
or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
- av.getCharWidth(), od.getGraphHeight(),
- od.getColumns(av.getAlignment()));
+ od.getGraphHeight(), od.getColumns(av.getAlignment()));
mg.translate(0, -od.getSequencesHeight());
}
- System.gc();
or.removePropertyChangeListener(progressPanel);
or = null;
@Override
public void paintComponent(Graphics g)
{
- // super.paintComponent(g);
+ super.paintComponent(g);
if (restart)
{
public void dispose()
{
dispose = true;
+ od = null;
synchronized (this)
{
restart = true;
@Override
public void mouseMoved(MouseEvent evt)
{
- if (od.isPositionInBox(evt.getX(), evt.getY()))
+ if (!draggingBox)
+ // don't bother changing the cursor if we're dragging the box
+ // as we can't have moved inside or out of the box in that case
{
- // display drag cursor at mouse position
- setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
- }
- else
- {
- // reset cursor
- setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ if (od.isPositionInBox(evt.getX(), evt.getY()))
+ {
+ // display drag cursor at mouse position
+ setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+ }
+ else
+ {
+ // reset cursor
+ setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ }
}
}
});
if (!od.isPositionInBox(evt.getX(), evt.getY()))
{
draggingBox = false;
+
+ // display drag cursor at mouse position
+ setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+
od.updateViewportFromMouse(evt.getX(), evt.getY(),
av.getAlignment().getHiddenSequences(),
av.getAlignment().getHiddenColumns());
showPopupMenu(evt);
}
}
+
+ @Override
+ public void mouseReleased(MouseEvent evt)
+ {
+ draggingBox = false;
+ }
+
});
}
public void run()
{
PrinterJob printJob = PrinterJob.getPrinterJob();
- PageFormat pf = printJob.pageDialog(printJob.defaultPage());
+ PageFormat defaultPage = printJob.defaultPage();
+ PageFormat pf = printJob.pageDialog(defaultPage);
+
+ if (defaultPage == pf)
+ {
+ /*
+ * user cancelled
+ */
+ return;
+ }
printJob.setPrintable(this, pf);
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
-import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.util.GroupUrlLink;
import jalview.util.GroupUrlLink.UrlStringTooLongException;
import jalview.util.MessageManager;
+import jalview.util.StringUtils;
import jalview.util.UrlLink;
import java.awt.Color;
* Creates a new PopupMenu object.
*
* @param ap
- * DOCUMENT ME!
* @param seq
- * DOCUMENT ME!
+ * @param features
+ * non-positional features (for seq not null), or positional features
+ * at residue (for seq equal to null)
*/
- public PopupMenu(final AlignmentPanel ap, Sequence seq,
- List<String> links)
+ public PopupMenu(final AlignmentPanel ap, SequenceI seq,
+ List<SequenceFeature> features)
{
- this(ap, seq, links, null);
+ this(ap, seq, features, null);
}
/**
+ * Constructor
*
- * @param ap
+ * @param alignPanel
* @param seq
- * @param links
+ * the sequence under the cursor if in the Id panel, null if in the
+ * sequence panel
+ * @param features
+ * non-positional features if in the Id panel, features at the
+ * clicked residue if in the sequence panel
* @param groupLinks
*/
- public PopupMenu(final AlignmentPanel ap, final SequenceI seq,
- List<String> links, List<String> groupLinks)
+ public PopupMenu(final AlignmentPanel alignPanel, final SequenceI seq,
+ List<SequenceFeature> features, List<String> groupLinks)
{
// /////////////////////////////////////////////////////////
// If this is activated from the sequence panel, the user may want to
//
// If from the IDPanel, we must display the sequence menu
// ////////////////////////////////////////////////////////
- this.ap = ap;
+ this.ap = alignPanel;
sequence = seq;
for (String ff : FileFormats.getInstance().getWritableFormats(true))
/*
* And repeat for the current selection group (if there is one):
*/
- final List<SequenceI> selectedGroup = (ap.av.getSelectionGroup() == null
+ final List<SequenceI> selectedGroup = (alignPanel.av.getSelectionGroup() == null
? Collections.<SequenceI> emptyList()
- : ap.av.getSelectionGroup().getSequences());
+ : alignPanel.av.getSelectionGroup().getSequences());
buildAnnotationTypesMenus(groupShowAnnotationsMenu,
groupHideAnnotationsMenu, selectedGroup);
configureReferenceAnnotationsMenu(groupAddReferenceAnnotations,
if (seq != null)
{
sequenceMenu.setText(sequence.getName());
- if (seq == ap.av.getAlignment().getSeqrep())
+ if (seq == alignPanel.av.getAlignment().getSeqrep())
{
makeReferenceSeq.setText(
MessageManager.getString("action.unmark_as_reference"));
MessageManager.getString("action.set_as_reference"));
}
- if (!ap.av.getAlignment().isNucleotide())
+ if (!alignPanel.av.getAlignment().isNucleotide())
{
remove(rnaStructureMenu);
}
* add menu items to 2D-render any alignment or sequence secondary
* structure annotation
*/
- AlignmentAnnotation[] aas = ap.av.getAlignment()
+ AlignmentAnnotation[] aas = alignPanel.av.getAlignment()
.getAlignmentAnnotation();
if (aas != null)
{
@Override
public void actionPerformed(ActionEvent e)
{
- new AppVarna(seq, aa, ap);
+ new AppVarna(seq, aa, alignPanel);
}
});
rnaStructureMenu.add(menuItem);
public void actionPerformed(ActionEvent e)
{
// TODO: VARNA does'nt print gaps in the sequence
- new AppVarna(seq, aa, ap);
+ new AppVarna(seq, aa, alignPanel);
}
});
rnaStructureMenu.add(menuItem);
});
add(menuItem);
- if (ap.av.getSelectionGroup() != null
- && ap.av.getSelectionGroup().getSize() > 1)
+ if (alignPanel.av.getSelectionGroup() != null
+ && alignPanel.av.getSelectionGroup().getSize() > 1)
{
menuItem = new JMenuItem(MessageManager
.formatMessage("label.represent_group_with", new Object[]
sequenceMenu.add(menuItem);
}
- if (ap.av.hasHiddenRows())
+ if (alignPanel.av.hasHiddenRows())
{
- final int index = ap.av.getAlignment().findIndex(seq);
+ final int index = alignPanel.av.getAlignment().findIndex(seq);
- if (ap.av.adjustForHiddenSeqs(index)
- - ap.av.adjustForHiddenSeqs(index - 1) > 1)
+ if (alignPanel.av.adjustForHiddenSeqs(index)
+ - alignPanel.av.adjustForHiddenSeqs(index - 1) > 1)
{
menuItem = new JMenuItem(
MessageManager.getString("action.reveal_sequences"));
@Override
public void actionPerformed(ActionEvent e)
{
- ap.av.showSequence(index);
- if (ap.overviewPanel != null)
+ alignPanel.av.showSequence(index);
+ if (alignPanel.overviewPanel != null)
{
- ap.overviewPanel.updateOverviewImage();
+ alignPanel.overviewPanel.updateOverviewImage();
}
}
});
}
}
// for the case when no sequences are even visible
- if (ap.av.hasHiddenRows())
+ if (alignPanel.av.hasHiddenRows())
{
{
menuItem = new JMenuItem(
@Override
public void actionPerformed(ActionEvent e)
{
- ap.av.showAllHiddenSeqs();
- if (ap.overviewPanel != null)
+ alignPanel.av.showAllHiddenSeqs();
+ if (alignPanel.overviewPanel != null)
{
- ap.overviewPanel.updateOverviewImage();
+ alignPanel.overviewPanel.updateOverviewImage();
}
}
});
}
}
- SequenceGroup sg = ap.av.getSelectionGroup();
+ SequenceGroup sg = alignPanel.av.getSelectionGroup();
boolean isDefinedGroup = (sg != null)
- ? ap.av.getAlignment().getGroups().contains(sg)
+ ? alignPanel.av.getAlignment().getGroups().contains(sg)
: false;
if (sg != null && sg.getSize() > 0)
Hashtable<String, PDBEntry> pdbe = new Hashtable<>(), reppdb = new Hashtable<>();
SequenceI sqass = null;
- for (SequenceI sq : ap.av.getSequenceSelection())
+ for (SequenceI sq : alignPanel.av.getSequenceSelection())
{
Vector<PDBEntry> pes = sq.getDatasetSequence().getAllPDBEntries();
if (pes != null && pes.size() > 0)
rnaStructureMenu.setVisible(false);
}
- if (links != null && links.size() > 0)
+ addLinks(seq, features);
+
+ if (seq == null)
+ {
+ addFeatureDetails(features);
+ }
+ }
+
+ /**
+ * Add a link to show feature details for each sequence feature
+ *
+ * @param features
+ */
+ protected void addFeatureDetails(List<SequenceFeature> features)
+ {
+ if (features == null || features.isEmpty())
{
- addFeatureLinks(seq, links);
+ return;
}
+ JMenu details = new JMenu(
+ MessageManager.getString("label.feature_details"));
+ add(details);
+
+ for (final SequenceFeature sf : features)
+ {
+ int start = sf.getBegin();
+ int end = sf.getEnd();
+ String desc = null;
+ if (start == end)
+ {
+ desc = String.format("%s %d", sf.getType(), start);
+ }
+ else
+ {
+ desc = String.format("%s %d-%d", sf.getType(), start, end);
+ }
+ String tooltip = desc;
+ String description = sf.getDescription();
+ if (description != null)
+ {
+ description = StringUtils.stripHtmlTags(description);
+ if (description.length() > 12)
+ {
+ desc = desc + " " + description.substring(0, 12) + "..";
+ }
+ else
+ {
+ desc = desc + " " + description;
+ }
+ tooltip = tooltip + " " + description;
+ }
+ if (sf.getFeatureGroup() != null)
+ {
+ tooltip = tooltip + (" (" + sf.getFeatureGroup() + ")");
+ }
+ JMenuItem item = new JMenuItem(desc);
+ item.setToolTipText(tooltip);
+ item.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ showFeatureDetails(sf);
+ }
+ });
+ details.add(item);
+ }
+ }
+
+ /**
+ * Opens a panel showing a text report of feature dteails
+ *
+ * @param sf
+ */
+ protected void showFeatureDetails(SequenceFeature sf)
+ {
+ CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer();
+ // it appears Java's CSS does not support border-collaps :-(
+ cap.addStylesheetRule("table { border-collapse: collapse;}");
+ cap.addStylesheetRule("table, td, th {border: 1px solid black;}");
+ cap.setText(sf.getDetailsReport());
+
+ Desktop.addInternalFrame(cap,
+ MessageManager.getString("label.feature_details"), 500, 500);
}
/**
* Adds a 'Link' menu item with a sub-menu item for each hyperlink provided.
+ * When seq is not null, these are links for the sequence id, which may be to
+ * external web sites for the sequence accession, and/or links embedded in
+ * non-positional features. When seq is null, only links embedded in the
+ * provided features are added.
*
* @param seq
- * @param links
+ * @param features
*/
- void addFeatureLinks(final SequenceI seq, List<String> links)
+ void addLinks(final SequenceI seq, List<SequenceFeature> features)
{
JMenu linkMenu = new JMenu(MessageManager.getString("action.link"));
+
+ List<String> nlinks = null;
+ if (seq != null)
+ {
+ nlinks = Preferences.sequenceUrlLinks.getLinksForMenu();
+ }
+ else
+ {
+ nlinks = new ArrayList<>();
+ }
+
+ if (features != null)
+ {
+ for (SequenceFeature sf : features)
+ {
+ if (sf.links != null)
+ {
+ for (String link : sf.links)
+ {
+ nlinks.add(link);
+ }
+ }
+ }
+ }
+
Map<String, List<String>> linkset = new LinkedHashMap<>();
- for (String link : links)
+ for (String link : nlinks)
{
UrlLink urlLink = null;
try
addshowLinks(linkMenu, linkset.values());
- // disable link menu if there are no valid entries
+ // only add link menu if it has entries
if (linkMenu.getItemCount() > 0)
{
- linkMenu.setEnabled(true);
- }
- else
- {
- linkMenu.setEnabled(false);
- }
-
- if (sequence != null)
- {
- sequenceMenu.add(linkMenu);
- }
- else
- {
- add(linkMenu);
+ if (sequence != null)
+ {
+ sequenceMenu.add(linkMenu);
+ }
+ else
+ {
+ add(linkMenu);
+ }
}
-
}
/**
protected void hideInsertions_actionPerformed(ActionEvent actionEvent)
{
-
- HiddenColumns hidden = new HiddenColumns();
- BitSet inserts = new BitSet(), mask = new BitSet();
-
- // set mask to preserve existing hidden columns outside selected group
- if (ap.av.hasHiddenColumns())
- {
- ap.av.getAlignment().getHiddenColumns().markHiddenRegions(mask);
- }
+ HiddenColumns hidden = ap.av.getAlignment().getHiddenColumns();
+ BitSet inserts = new BitSet();
boolean markedPopup = false;
// mark inserts in current selection
{
// mark just the columns in the selection group to be hidden
inserts.set(ap.av.getSelectionGroup().getStartRes(),
- ap.av.getSelectionGroup().getEndRes() + 1);
-
- // and clear that part of the mask
- mask.andNot(inserts);
+ ap.av.getSelectionGroup().getEndRes() + 1); // TODO why +1?
// now clear columns without gaps
for (SequenceI sq : ap.av.getSelectionGroup().getSequences())
}
inserts.and(sq.getInsertionsAsBits());
}
- }
- else
- {
- // initially, mark all columns to be hidden
- inserts.set(0, ap.av.getAlignment().getWidth());
-
- // and clear out old hidden regions completely
- mask.clear();
+ hidden.clearAndHideColumns(inserts, ap.av.getSelectionGroup().getStartRes(),
+ ap.av.getSelectionGroup().getEndRes());
}
// now mark for sequence under popup if we haven't already done it
- if (!markedPopup && sequence != null)
+ else if (!markedPopup && sequence != null)
{
- inserts.and(sequence.getInsertionsAsBits());
- }
-
- // finally, preserve hidden regions outside selection
- inserts.or(mask);
+ inserts.or(sequence.getInsertionsAsBits());
- // and set hidden columns accordingly
- hidden.hideMarkedBits(inserts);
-
- ap.av.getAlignment().setHiddenColumns(hidden);
+ // and set hidden columns accordingly
+ hidden.hideColumns(inserts);
+ }
refresh();
}
new Object[]
{ seq.getDisplayId(true) }) + "</h2></p><p>");
new SequenceAnnotationReport(null).createSequenceAnnotationReport(
- contents, seq, true, true,
- (ap.getSeqPanel().seqCanvas.fr != null)
- ? ap.getSeqPanel().seqCanvas.fr.getMinMax()
- : null);
+ contents, seq, true, true, ap.getSeqPanel().seqCanvas.fr);
contents.append("</p>");
}
cap.setText("<html>" + contents.toString() + "</html>");
JInternalFrame frame;
- DasSourceBrowser dasSource;
-
private WsPreferences wsPrefs;
private OptionsParam promptEachTimeOpt = new OptionsParam(
super();
frame = new JInternalFrame();
frame.setContentPane(this);
- dasSource = new DasSourceBrowser();
- dasTab.add(dasSource, BorderLayout.CENTER);
wsPrefs = new WsPreferences();
wsTab.add(wsPrefs, BorderLayout.CENTER);
int width = 500, height = 450;
autoIdWidth.setSelected(Cache.getDefault("FIGURE_AUTOIDWIDTH", false));
userIdWidth.setEnabled(!autoIdWidth.isSelected());
userIdWidthlabel.setEnabled(!autoIdWidth.isSelected());
- Integer wi = Cache.getIntegerProperty("FIGURE_USERIDWIDTH");
+ Integer wi = Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH");
userIdWidth.setText(wi == null ? "" : wi.toString());
+ // TODO: refactor to use common enum via FormatAdapter and allow extension
+ // for new flat file formats
blcjv.setSelected(Cache.getDefault("BLC_JVSUFFIX", true));
clustaljv.setSelected(Cache.getDefault("CLUSTAL_JVSUFFIX", true));
fastajv.setSelected(Cache.getDefault("FASTA_JVSUFFIX", true));
Cache.applicationProperties.setProperty("FIGURE_AUTOIDWIDTH",
Boolean.toString(autoIdWidth.isSelected()));
userIdWidth_actionPerformed();
- Cache.applicationProperties.setProperty("FIGURE_USERIDWIDTH",
+ Cache.applicationProperties.setProperty("FIGURE_FIXEDIDWIDTH",
userIdWidth.getText());
/*
Cache.applicationProperties.setProperty("PAD_GAPS",
Boolean.toString(padGaps.isSelected()));
- dasSource.saveProperties(Cache.applicationProperties);
wsPrefs.updateAndRefreshWsMenuConfig(false);
Cache.saveProperties();
Desktop.instance.doConfigureStructurePrefs();
boolean applyToAllViews = false;
- // Controller controller;
public RotatableCanvas(AlignmentPanel ap)
{
this.av = ap.av;
addMouseWheelListener(new MouseWheelListener()
{
+ @Override
public void mouseWheelMoved(MouseWheelEvent e)
{
- if (e.getWheelRotation() > 0)
+ double wheelRotation = e.getPreciseWheelRotation();
+ if (wheelRotation > 0)
{
+ /*
+ * zoom in
+ */
scale = (float) (scale * 1.1);
repaint();
}
-
- else
+ else if (wheelRotation < 0)
{
+ /*
+ * zoom out
+ */
scale = (float) (scale * 0.9);
repaint();
}
boolean first = true;
+ @Override
public void setPoints(Vector points, int npoint)
{
this.points = points;
dim = height;
}
- return (float) ((dim * scalefactor) / (2 * maxwidth));
+ return (dim * scalefactor) / (2 * maxwidth);
}
/**
*
* @return DOCUMENT ME!
*/
+ @Override
public Dimension getPreferredSize()
{
if (prefsize != null)
*
* @return DOCUMENT ME!
*/
+ @Override
public Dimension getMinimumSize()
{
return getPreferredSize();
* @param g
* DOCUMENT ME!
*/
+ @Override
public void paintComponent(Graphics g1)
{
for (int i = 0; i < npoint; i++)
{
SequencePoint sp = (SequencePoint) points.elementAt(i);
- int x = (int) ((float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
- int y = (int) ((float) (sp.coord[1] - centre[1]) * scale)
+ int x = (int) ((sp.coord[0] - centre[0]) * scale) + halfwidth;
+ int y = (int) ((sp.coord[1] - centre[1]) * scale)
+ halfheight;
float z = sp.coord[1] - centre[2];
* @param evt
* DOCUMENT ME!
*/
+ @Override
public void keyTyped(KeyEvent evt)
{
}
* @param evt
* DOCUMENT ME!
*/
+ @Override
public void keyReleased(KeyEvent evt)
{
}
* @param evt
* DOCUMENT ME!
*/
+ @Override
public void keyPressed(KeyEvent evt)
{
if (evt.getKeyCode() == KeyEvent.VK_UP)
* @param evt
* DOCUMENT ME!
*/
+ @Override
public void mouseClicked(MouseEvent evt)
{
}
* @param evt
* DOCUMENT ME!
*/
+ @Override
public void mouseEntered(MouseEvent evt)
{
}
* @param evt
* DOCUMENT ME!
*/
+ @Override
public void mouseExited(MouseEvent evt)
{
}
* @param evt
* DOCUMENT ME!
*/
+ @Override
public void mouseReleased(MouseEvent evt)
{
}
* @param evt
* DOCUMENT ME!
*/
+ @Override
public void mousePressed(MouseEvent evt)
{
int x = evt.getX();
// controller.handleSequenceSelectionEvent(new
// SequenceSelectionEvent(this,sel));
// }
+ @Override
public void mouseMoved(MouseEvent evt)
{
SequenceI found = findPoint(evt.getX(), evt.getY());
* @param evt
* DOCUMENT ME!
*/
+ @Override
public void mouseDragged(MouseEvent evt)
{
mx = evt.getX();
{
rotmat.setIdentity();
- rotmat.rotate((float) (my - omy), 'x');
- rotmat.rotate((float) (mx - omx), 'y');
+ rotmat.rotate(my - omy, 'x');
+ rotmat.rotate(mx - omx, 'y');
for (int i = 0; i < npoint; i++)
{
{
SequencePoint sp = (SequencePoint) points.elementAt(i);
int tmp1 = (int) (((sp.coord[0] - centre[0]) * scale)
- + ((float) getWidth() / 2.0));
+ + (getWidth() / 2.0));
int tmp2 = (int) (((sp.coord[1] - centre[1]) * scale)
- + ((float) getHeight() / 2.0));
+ + (getHeight() / 2.0));
if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
{
for (int i = 0; i < npoint; i++)
{
SequencePoint sp = (SequencePoint) points.elementAt(i);
- int px = (int) ((float) (sp.coord[0] - centre[0]) * scale)
+ int px = (int) ((sp.coord[0] - centre[0]) * scale)
+ halfwidth;
- int py = (int) ((float) (sp.coord[1] - centre[1]) * scale)
+ int py = (int) ((sp.coord[1] - centre[1]) * scale)
+ halfheight;
if ((Math.abs(px - x) < 3) && (Math.abs(py - y) < 3))
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
+import java.util.Iterator;
import java.util.List;
import javax.swing.JMenuItem;
if (av.hasHiddenColumns())
{
- x = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x);
+ x = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(x);
}
if (x >= av.getAlignment().getWidth())
});
pop.add(item);
- if (av.getAlignment().getHiddenColumns().hasHiddenColumns())
+ if (av.getAlignment().getHiddenColumns().hasMultiHiddenColumnRegions())
{
item = new JMenuItem(MessageManager.getString("action.reveal_all"));
item.addActionListener(new ActionListener()
{
mouseDragging = false;
- int res = (evt.getX() / av.getCharWidth())
+ int xCords = Math.max(0, evt.getX()); // prevent negative X coordinates
+
+ int res = (xCords / av.getCharWidth())
+ av.getRanges().getStartRes();
if (av.hasHiddenColumns())
{
res = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(res);
+ .visibleToAbsoluteColumn(res);
}
if (res >= av.getAlignment().getWidth())
int res = (evt.getX() / av.getCharWidth())
+ av.getRanges().getStartRes();
res = Math.max(0, res);
- res = hidden.adjustForHiddenColumns(res);
+ res = hidden.visibleToAbsoluteColumn(res);
res = Math.min(res, av.getAlignment().getWidth() - 1);
min = Math.min(res, min);
max = Math.max(res, max);
reveal = av.getAlignment().getHiddenColumns()
.getRegionWithEdgeAtRes(res);
- res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
+ res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(res);
ToolTipManager.sharedInstance().registerComponent(this);
this.setToolTipText(
@Override
public void paintComponent(Graphics g)
{
+ super.paintComponent(g);
+
/*
* shouldn't get called in wrapped mode as the scale above is
* drawn instead by SeqCanvas.drawNorthScale
{
if (hidden.isVisible(sel))
{
- sel = hidden.findColumnPosition(sel);
+ sel = hidden.absoluteToVisibleColumn(sel);
}
else
{
if (av.getShowHiddenMarkers())
{
- List<Integer> positions = hidden.findHiddenRegionPositions();
- for (int pos : positions)
+ Iterator<Integer> it = hidden.getStartRegionIterator(startx,
+ startx + widthx + 1);
+ while (it.hasNext())
{
- res = pos - startx;
-
- if (res < 0 || res > widthx)
- {
- continue;
- }
+ res = it.next() - startx;
gg.fillPolygon(
new int[]
- { -1 + res * avCharWidth - avCharHeight / 4,
- -1 + res * avCharWidth + avCharHeight / 4,
- -1 + res * avCharWidth },
- new int[]
- { y, y, y + 2 * yOf }, 3);
+ { -1 + res * avCharWidth - avCharHeight / 4,
+ -1 + res * avCharWidth + avCharHeight / 4,
+ -1 + res * avCharWidth }, new int[]
+ { y, y, y + 2 * yOf }, 3);
}
}
}
|| evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT))
{
// scroll event, repaint panel
- repaint();
+
+ // Call repaint on alignment panel so that repaints from other alignment
+ // panel components can be aggregated. Otherwise performance of the overview
+ // window and others may be adversely affected.
+ av.getAlignPanel().repaint();
}
}
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.VisibleContigsIterator;
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
import jalview.util.Comparison;
import jalview.viewmodel.ViewportListenerI;
import jalview.viewmodel.ViewportRanges;
-import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Shape;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
+import java.util.Iterator;
import java.util.List;
import javax.swing.JComponent;
if (av.hasHiddenColumns())
{
HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns();
- startX = hiddenColumns.adjustForHiddenColumns(startx);
- endX = hiddenColumns.adjustForHiddenColumns(endx);
+ startX = hiddenColumns.visibleToAbsoluteColumn(startx);
+ endX = hiddenColumns.visibleToAbsoluteColumn(endx);
}
FontMetrics fm = getFontMetrics(av.getFont());
int endSeq = ranges.getEndSeq();
int transX = 0;
int transY = 0;
-
+
gg.copyArea(horizontal * charWidth, vertical * charHeight,
img.getWidth(), img.getHeight(), -horizontal * charWidth,
-vertical * charHeight);
drawPanel(gg, startRes, endRes, startSeq, endSeq, 0);
gg.translate(-transX, -transY);
- repaint();
+ // Call repaint on alignment panel so that repaints from other alignment
+ // panel components can be aggregated. Otherwise performance of the
+ // overview window and others may be adversely affected.
+ av.getAlignPanel().repaint();
} finally
{
fastpainting = false;
int charHeight = av.getCharHeight();
int charWidth = av.getCharWidth();
-
+
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);
+ g.drawImage(img, 0, 0, this);
+
+ drawSelectionGroup((Graphics2D) g, ranges.getStartRes(),
+ ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq());
+
fastPaint = false;
}
- else if ((width > 0) && (height > 0))
+ 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
+ /*
+ * 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;
- }
+ img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
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());
ranges.getStartSeq(), ranges.getEndSeq(), 0);
}
- // 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);
+ drawSelectionGroup(gg, ranges.getStartRes(),
+ ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq());
+ g.drawImage(img, 0, 0, this);
}
if (av.cursorMode)
{
drawPanel(g1, startRes, endRes, startSeq, endSeq, 0);
- BufferedImage selectImage = drawSelectionGroup(startRes, endRes,
+ drawSelectionGroup((Graphics2D) g1, startRes, endRes,
startSeq, endSeq);
- if (selectImage != null)
- {
- ((Graphics2D) g1).setComposite(AlphaComposite
- .getInstance(AlphaComposite.SRC_OVER));
- g1.drawImage(selectImage, 0, 0, this);
- }
}
/**
public void drawWrappedPanelForPrinting(Graphics g, int canvasWidth,
int canvasHeight, int startRes)
{
- SequenceGroup group = av.getSelectionGroup();
-
drawWrappedPanel(g, canvasWidth, canvasHeight, startRes);
+ SequenceGroup group = av.getSelectionGroup();
if (group != null)
{
- BufferedImage selectImage = null;
- try
- {
- selectImage = new BufferedImage(canvasWidth, canvasHeight,
- BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works
- } catch (OutOfMemoryError er)
- {
- System.gc();
- 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,
+ drawWrappedSelection((Graphics2D) g, group, canvasWidth, canvasHeight,
startRes);
-
- g2.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
- g.drawImage(selectImage, 0, 0, this);
- g2.dispose();
- }
- }
- }
-
- /*
- * 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)
- {
- g2d.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
- g2d.drawImage(selectImage, 0, 0, this);
- }
-
- g2d.dispose();
-
- return lcimg;
- }
-
- /*
- * Set up a buffered image of the correct height and size for the sequence canvas
- */
- private BufferedImage setupImage()
- {
- BufferedImage lcimg = null;
-
- int charWidth = av.getCharWidth();
- int charHeight = av.getCharHeight();
-
- int width = getWidth();
- int height = getHeight();
-
- width -= (width % charWidth);
- height -= (height % charHeight);
-
- if ((width < 1) || (height < 1))
- {
- return null;
- }
-
- try
- {
- 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);
-
- return null;
}
-
- return lcimg;
}
/**
ViewportRanges ranges = av.getRanges();
ranges.setViewportStartAndWidth(startColumn, wrappedWidthInResidues);
+ // we need to call this again to make sure the startColumn +
+ // wrappedWidthInResidues values are used to calculate wrappedVisibleWidths
+ // correctly.
+ calculateWrappedGeometry(canvasWidth, canvasHeight);
+
/*
- * draw one width at a time (including any scales or annotation shown),
+ * draw one width at a time (excluding any scales or annotation shown),
* until we have run out of either alignment or vertical space available
*/
int ypos = wrappedSpaceAboveAlignment;
*/
wrappedRepeatHeightPx = wrappedSpaceAboveAlignment;
// add sequences
- wrappedRepeatHeightPx += av.getRanges().getViewportHeight()
+ wrappedRepeatHeightPx += av.getAlignment().getHeight()
* charHeight;
// add annotations panel height if shown
wrappedRepeatHeightPx += getAnnotationHeight();
int charWidth = av.getCharWidth();
g.setColor(Color.blue);
+ int res;
HiddenColumns hidden = av.getAlignment().getHiddenColumns();
- List<Integer> positions = hidden.findHiddenRegionPositions();
- for (int pos : positions)
+
+ Iterator<Integer> it = hidden.getStartRegionIterator(startColumn,
+ endColumn);
+ while (it.hasNext())
{
- int res = pos - startColumn;
+ res = it.next() - startColumn;
if (res < 0 || res > endColumn - startColumn + 1)
{
if (av.hasHiddenColumns())
{
maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth);
+ .absoluteToVisibleColumn(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
+ g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_ROUND, 3f, new float[]
+ { 5f, 3f }, 0f));
+ g.setColor(Color.RED);
while ((ypos <= canvasHeight) && (startx < maxwidth))
{
// set end value to be start + width, or maxwidth, whichever is smaller
// update horizontal offset
startx += cWidth;
}
+ g.setStroke(new BasicStroke());
}
int getAnnotationHeight()
else
{
int screenY = 0;
- final int screenYMax = endRes - startRes;
- int blockStart = startRes;
- int blockEnd = endRes;
+ int blockStart;
+ int blockEnd;
- for (int[] region : av.getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy())
- {
- int hideStart = region[0];
- int hideEnd = region[1];
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ VisibleContigsIterator regions = hidden
+ .getVisContigsIterator(startRes, endRes + 1, true);
- if (hideStart <= blockStart)
- {
- blockStart += (hideEnd - hideStart) + 1;
- continue;
- }
+ while (regions.hasNext())
+ {
+ int[] region = regions.next();
+ blockEnd = region[1];
+ blockStart = region[0];
/*
* draw up to just before the next hidden region, or the end of
* the visible region, whichever comes first
*/
- blockEnd = Math.min(hideStart - 1, blockStart + screenYMax
- - screenY);
-
g1.translate(screenY * charWidth, 0);
draw(g1, blockStart, blockEnd, startSeq, endSeq, yOffset);
* draw the downline of the hidden column marker (ScalePanel draws the
* triangle on top) if we reached it
*/
- if (av.getShowHiddenMarkers() && blockEnd == hideStart - 1)
+ if (av.getShowHiddenMarkers()
+ && (regions.hasNext() || regions.endsAtHidden()))
{
g1.setColor(Color.blue);
g1.translate(-screenY * charWidth, 0);
screenY += blockEnd - blockStart + 1;
- blockStart = hideEnd + 1;
-
- if (screenY > screenYMax)
- {
- // already rendered last block
- return;
- }
- }
-
- if (screenY <= screenYMax)
- {
- // remaining visible region to render
- blockEnd = blockStart + screenYMax - screenY;
- g1.translate(screenY * charWidth, 0);
- draw(g1, blockStart, blockEnd, startSeq, endSeq, yOffset);
-
- g1.translate(-screenY * charWidth, 0);
}
}
if (av.hasSearchResults())
{
SearchResultsI searchResults = av.getSearchResults();
- int[] visibleResults = searchResults.getResults(nextSeq,
- startRes, endRes);
+ int[] visibleResults = searchResults.getResults(nextSeq, startRes,
+ endRes);
if (visibleResults != null)
{
for (int r = 0; r < visibleResults.length; r += 2)
{
seqRdr.drawHighlightedText(nextSeq, visibleResults[r],
- visibleResults[r + 1], (visibleResults[r] - startRes)
- * charWidth, offset
- + ((i - startSeq) * charHeight));
+ visibleResults[r + 1],
+ (visibleResults[r] - startRes) * charWidth,
+ offset + ((i - startSeq) * charHeight));
}
}
}
}
+ /**
+ * Draws the outlines of any groups defined on the alignment (excluding the
+ * current selection group, if any)
+ *
+ * @param g1
+ * @param startRes
+ * @param endRes
+ * @param startSeq
+ * @param endSeq
+ * @param offset
+ */
void drawGroupsBoundaries(Graphics g1, int startRes, int endRes,
int startSeq, int endSeq, int offset)
{
Graphics2D g = (Graphics2D) g1;
- //
- // ///////////////////////////////////
- // Now outline any areas if necessary
- // ///////////////////////////////////
SequenceGroup group = null;
int groupIndex = -1;
if (group != null)
{
- g.setStroke(new BasicStroke());
- g.setColor(group.getOutlineColour());
-
do
{
+ g.setColor(group.getOutlineColour());
+
drawPartialGroupOutline(g, group, startRes, endRes, startSeq,
endSeq, offset);
groupIndex++;
- g.setStroke(new BasicStroke());
-
if (groupIndex >= av.getAlignment().getGroups().size())
{
break;
}
-
- /*
- * Draw the selection group as a separate image and overlay
+ /**
+ * Draws the outline of the current selection group (if any)
+ *
+ * @param g
+ * @param startRes
+ * @param endRes
+ * @param startSeq
+ * @param endSeq
*/
- private BufferedImage drawSelectionGroup(int startRes, int endRes,
+ private void drawSelectionGroup(Graphics2D g, int startRes, int endRes,
int startSeq, int endSeq)
{
- // get a new image of the correct size
- BufferedImage selectionImage = setupImage();
-
- if (selectionImage == null)
- {
- return null;
- }
-
SequenceGroup group = av.getSelectionGroup();
if (group == null)
{
- // nothing to draw
- return null;
+ return;
}
- // set up drawing colour
- Graphics2D g = (Graphics2D) selectionImage.getGraphics();
-
- setupSelectionGroup(g, selectionImage);
-
+ g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_ROUND, 3f, new float[]
+ { 5f, 3f }, 0f));
+ g.setColor(Color.RED);
if (!av.getWrapAlignment())
{
drawUnwrappedSelection(g, group, startRes, endRes, startSeq, endSeq,
drawWrappedSelection(g, group, getWidth(), getHeight(),
av.getRanges().getStartRes());
}
-
- g.dispose();
- return selectionImage;
+ g.setStroke(new BasicStroke());
}
/**
// convert the cursorX into a position on the visible alignment
int cursor_xpos = av.getAlignment().getHiddenColumns()
- .findColumnPosition(cursorX);
+ .absoluteToVisibleColumn(cursorX);
if (av.getAlignment().getHiddenColumns().isVisible(cursorX))
{
}
- /*
- * 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)
+ *
+ * @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)
{
// package into blocks of visible columns
int screenY = 0;
- int blockStart = startRes;
- int blockEnd = endRes;
+ int blockStart;
+ int blockEnd;
- for (int[] region : av.getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy())
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ VisibleContigsIterator regions = hidden
+ .getVisContigsIterator(startRes, endRes + 1, true);
+ while (regions.hasNext())
{
- int hideStart = region[0];
- int hideEnd = region[1];
-
- if (hideStart <= blockStart)
- {
- blockStart += (hideEnd - hideStart) + 1;
- continue;
- }
-
- blockEnd = hideStart - 1;
+ int[] region = regions.next();
+ blockEnd = region[1];
+ blockStart = region[0];
g.translate(screenY * charWidth, 0);
drawPartialGroupOutline(g, group,
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
+ /**
+ * Draws part of a selection group outline
+ *
+ * @param g
+ * @param group
+ * @param startRes
+ * @param endRes
+ * @param startSeq
+ * @param endSeq
+ * @param verticalOffset
*/
private void drawPartialGroupOutline(Graphics2D g, SequenceGroup group,
int startRes, int endRes, int startSeq, int endSeq,
if (av.hasHiddenColumns())
{
firstVisibleColumn = alignment.getHiddenColumns()
- .adjustForHiddenColumns(firstVisibleColumn);
+ .visibleToAbsoluteColumn(firstVisibleColumn);
lastVisibleColumn = alignment.getHiddenColumns()
- .adjustForHiddenColumns(lastVisibleColumn);
+ .visibleToAbsoluteColumn(lastVisibleColumn);
}
for (int seqNo = ranges.getStartSeq(); seqNo <= ranges
if (av.hasHiddenColumns())
{
firstCol = alignment.getHiddenColumns()
- .findColumnPosition(firstCol);
- lastCol = alignment.getHiddenColumns().findColumnPosition(lastCol);
+ .absoluteToVisibleColumn(firstCol);
+ lastCol = alignment.getHiddenColumns().absoluteToVisibleColumn(lastCol);
}
int transX = (firstCol - ranges.getStartRes()) * av.getCharWidth();
int transY = (firstSeq - ranges.getStartSeq()) * av.getCharHeight();
{
scrollX = -range;
}
-
+ }
// Both scrolling and resizing change viewport ranges: scrolling changes
// both start and end points, but resize only changes end values.
// Here we only want to fastpaint on a scroll, with resize using a normal
{
fastPaint(scrollX, 0);
}
- // bizarrely, we only need to scroll on the x value here as fastpaint
- // copies the full height of the image anyway. Passing in the y value
- // causes nasty repaint artefacts, which only disappear on a full
- // repaint.
+ }
+ else if (eventName.equals(ViewportRanges.STARTSEQ))
+ {
+ // scroll
+ fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+ }
+ else if (eventName.equals(ViewportRanges.STARTRESANDSEQ))
+ {
+ if (av.getWrapAlignment())
+ {
+ fastPaintWrapped(scrollX);
}
}
}
{
ViewportRanges ranges = av.getRanges();
- // if (Math.abs(scrollX) > ranges.getViewportWidth())
- // JAL-2836, 2836 temporarily removed wrapped fastpaint for release 2.10.3
- if (true)
+ if (Math.abs(scrollX) > ranges.getViewportWidth())
{
/*
* shift of more than one view width is
if (av.hasHiddenColumns())
{
firstVisibleColumn = alignment.getHiddenColumns()
- .adjustForHiddenColumns(firstVisibleColumn);
+ .visibleToAbsoluteColumn(firstVisibleColumn);
lastVisibleColumn = alignment.getHiddenColumns()
- .adjustForHiddenColumns(lastVisibleColumn);
+ .visibleToAbsoluteColumn(lastVisibleColumn);
}
int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
if (av.hasHiddenColumns())
{
displayColumn = alignment.getHiddenColumns()
- .findColumnPosition(displayColumn);
+ .absoluteToVisibleColumn(displayColumn);
}
/*
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SeqPanel extends JPanel
implements MouseListener, MouseMotionListener, MouseWheelListener,
SequenceListener, SelectionListener
-
{
- /** DOCUMENT ME!! */
+ private static final int MAX_TOOLTIP_LENGTH = 300;
+
public SeqCanvas seqCanvas;
- /** DOCUMENT ME!! */
public AlignmentPanel ap;
/*
SearchResultsI lastSearchResults;
/**
- * Creates a new SeqPanel object.
+ * Creates a new SeqPanel object
*
- * @param avp
- * DOCUMENT ME!
- * @param p
- * DOCUMENT ME!
+ * @param viewport
+ * @param alignPanel
*/
- public SeqPanel(AlignViewport av, AlignmentPanel ap)
+ public SeqPanel(AlignViewport viewport, AlignmentPanel alignPanel)
{
linkImageURL = getClass().getResource("/images/link.gif");
seqARep = new SequenceAnnotationReport(linkImageURL.toString());
ToolTipManager.sharedInstance().registerComponent(this);
ToolTipManager.sharedInstance().setInitialDelay(0);
ToolTipManager.sharedInstance().setDismissDelay(10000);
- this.av = av;
+ this.av = viewport;
setBackground(Color.white);
- seqCanvas = new SeqCanvas(ap);
+ seqCanvas = new SeqCanvas(alignPanel);
setLayout(new BorderLayout());
add(seqCanvas, BorderLayout.CENTER);
- this.ap = ap;
+ this.ap = alignPanel;
- if (!av.isDataset())
+ if (!viewport.isDataset())
{
addMouseMotionListener(this);
addMouseListener(this);
addMouseWheelListener(this);
- ssm = av.getStructureSelectionManager();
+ ssm = viewport.getStructureSelectionManager();
ssm.addStructureViewerListener(this);
ssm.addSelectionListener(this);
}
if (av.hasHiddenColumns())
{
res = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(res);
+ .visibleToAbsoluteColumn(res);
}
return res;
int original = seqCanvas.cursorX - dx;
int maxWidth = av.getAlignment().getWidth();
- while (!hidden.isVisible(seqCanvas.cursorX)
- && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0)
+ if (!hidden.isVisible(seqCanvas.cursorX))
{
- seqCanvas.cursorX += dx;
+ int visx = hidden.absoluteToVisibleColumn(seqCanvas.cursorX - dx);
+ int[] region = hidden.getRegionWithEdgeAtRes(visx);
+
+ if (region != null) // just in case
+ {
+ if (dx == 1)
+ {
+ // moving right
+ seqCanvas.cursorX = region[1] + 1;
+ }
+ else if (dx == -1)
+ {
+ // moving left
+ seqCanvas.cursorX = region[0] - 1;
+ }
+ }
+ seqCanvas.cursorX = (seqCanvas.cursorX < 0) ? 0 : seqCanvas.cursorX;
}
if (seqCanvas.cursorX >= maxWidth
{
// scrollToWrappedVisible expects x-value to have hidden cols subtracted
int x = av.getAlignment().getHiddenColumns()
- .findColumnPosition(seqCanvas.cursorX);
+ .absoluteToVisibleColumn(seqCanvas.cursorX);
av.getRanges().scrollToWrappedVisible(x);
}
else
List<SequenceFeature> features = ap.getFeatureRenderer()
.findFeaturesAtColumn(sequence, column + 1);
seqARep.appendFeatures(tooltipText, pos, features,
- this.ap.getSeqPanel().seqCanvas.fr.getMinMax());
+ this.ap.getSeqPanel().seqCanvas.fr);
}
if (tooltipText.length() == 6) // <html>
{
}
else
{
+ if (tooltipText.length() > MAX_TOOLTIP_LENGTH) // constant
+ {
+ tooltipText.setLength(MAX_TOOLTIP_LENGTH);
+ tooltipText.append("...");
+ }
String textString = tooltipText.toString();
if (lastTooltip == null || !lastTooltip.equals(textString))
{
{
fixedColumns = true;
int y1 = av.getAlignment().getHiddenColumns()
- .getHiddenBoundaryLeft(startres);
+ .getNextHiddenBoundary(true, startres);
int y2 = av.getAlignment().getHiddenColumns()
- .getHiddenBoundaryRight(startres);
+ .getNextHiddenBoundary(false, startres);
if ((insertGap && startres > y1 && lastres < y1)
|| (!insertGap && startres < y2 && lastres > y2))
if (sg.getSize() == av.getAlignment().getHeight())
{
if ((av.hasHiddenColumns() && startres < av.getAlignment()
- .getHiddenColumns().getHiddenBoundaryRight(startres)))
+ .getHiddenColumns()
+ .getNextHiddenBoundary(false, startres)))
{
endEditing();
return;
public void mouseWheelMoved(MouseWheelEvent e)
{
e.consume();
- if (e.getWheelRotation() > 0)
+ double wheelRotation = e.getPreciseWheelRotation();
+ if (wheelRotation > 0)
{
if (e.isShiftDown())
{
av.getRanges().scrollUp(false);
}
}
- else
+ else if (wheelRotation < 0)
{
if (e.isShiftDown())
{
final int column = findColumn(evt);
final int seq = findSeq(evt);
SequenceI sequence = av.getAlignment().getSequenceAt(seq);
- List<SequenceFeature> allFeatures = ap.getFeatureRenderer()
+ List<SequenceFeature> features = ap.getFeatureRenderer()
.findFeaturesAtColumn(sequence, column + 1);
- List<String> links = new ArrayList<>();
- for (SequenceFeature sf : allFeatures)
- {
- if (sf.links != null)
- {
- for (String link : sf.links)
- {
- links.add(link);
- }
- }
- }
- PopupMenu pop = new PopupMenu(ap, null, links);
+ PopupMenu pop = new PopupMenu(ap, null, features);
pop.show(this, evt.getX(), evt.getY());
}
return true;
}
+
+ /**
+ *
+ * @return null or last search results handled by this panel
+ */
+ public SearchResultsI getLastSearchResults()
+ {
+ return lastSearchResults;
+ }
}
import jalview.util.DBRefUtils;
import jalview.util.MessageManager;
import jalview.util.Platform;
-import jalview.ws.dbsources.das.api.DasSourceRegistryI;
import jalview.ws.seqfetcher.DbSourceProxy;
import java.awt.BorderLayout;
private static jalview.ws.SequenceFetcher sfetch = null;
- private static long lastDasSourceRegistry = -3;
-
- private static DasSourceRegistryI dasRegistry = null;
-
private static boolean _initingFetcher = false;
private static Thread initingThread = null;
Thread.currentThread().hashCode());
}
}
- if (sfetch == null || dasRegistry != Cache.getDasSourceRegistry()
- || lastDasSourceRegistry != (Cache.getDasSourceRegistry()
- .getDasRegistryURL()
- + Cache.getDasSourceRegistry().getLocalSourceString())
- .hashCode())
+ if (sfetch == null)
{
_initingFetcher = true;
initingThread = Thread.currentThread();
"status.init_sequence_database_fetchers"),
Thread.currentThread().hashCode());
}
- dasRegistry = Cache.getDasSourceRegistry();
- dasRegistry.refreshSources();
jalview.ws.SequenceFetcher sf = new jalview.ws.SequenceFetcher();
if (guiWindow != null)
{
guiWindow.setProgressBar(null, Thread.currentThread().hashCode());
}
- lastDasSourceRegistry = (dasRegistry.getDasRegistryURL()
- + dasRegistry.getLocalSourceString()).hashCode();
sfetch = sf;
_initingFetcher = false;
initingThread = null;
return Collections.emptyList();
}
}
- sf.newAlframes = new ArrayList<AlignFrame>();
+ sf.newAlframes = new ArrayList<>();
sf.run();
return sf.newAlframes;
}
dbeg.setText(MessageManager.formatMessage("label.example_query_param",
new String[]
{ eq }));
+ // TODO this should be a property of the SequenceFetcher whether commas are and
+ // colons are allowed in the IDs...
+
boolean enablePunct = !(eq != null && eq.indexOf(",") > -1);
- for (DbSourceProxy dbs : database.getSelectedSources())
- {
- if (dbs instanceof jalview.ws.dbsources.das.datamodel.DasSequenceSource)
- {
- enablePunct = false;
- break;
- }
- }
replacePunctuation.setEnabled(enablePunct);
} catch (Exception ex)
// TODO: Refactor to GUI independent code and write tests.
// indicate if successive sources should be merged into one alignment.
boolean addToLast = false;
- List<String> aresultq = new ArrayList<String>();
- List<String> presultTitle = new ArrayList<String>();
- List<AlignmentI> presult = new ArrayList<AlignmentI>();
- List<AlignmentI> aresult = new ArrayList<AlignmentI>();
+ List<String> aresultq = new ArrayList<>();
+ List<String> presultTitle = new ArrayList<>();
+ List<AlignmentI> presult = new ArrayList<>();
+ List<AlignmentI> aresult = new ArrayList<>();
Iterator<DbSourceProxy> proxies = database.getSelectedSources()
.iterator();
String[] qries;
nqueries = nextFetch.size();
// save the remaining queries in the original array
qries = nextFetch.toArray(new String[nqueries]);
- nextFetch = new ArrayList<String>();
+ nextFetch = new ArrayList<>();
}
DbSourceProxy proxy = proxies.next();
List<AlignmentI> aresult, List<String> nextFetch) throws Exception
{
StringBuilder multiacc = new StringBuilder();
- List<String> tosend = new ArrayList<String>();
+ List<String> tosend = new ArrayList<>();
while (accessions.hasNext())
{
String nel = accessions.next();
package jalview.gui;
+import jalview.api.structures.JalviewStructureDisplayI;
+import jalview.bin.Cache;
import jalview.bin.Jalview;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
/**
public class StructureChooser extends GStructureChooser
implements IProgressIndicator
{
+ private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
+
private static int MAX_QLENGTH = 7820;
private SequenceI selectedSequence;
private boolean cachedPDBExists;
+ private static StructureViewer lastTargetedView = null;
+
public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
AlignmentPanel ap)
{
/**
* Initializes parameters used by the Structure Chooser Panel
*/
- public void init()
+ protected void init()
{
if (!Jalview.isHeadlessMode())
{
progressBar = new ProgressBar(this.statusPanel, this.statusBar);
}
+ chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
+
// ensure a filter option is in force for search
populateFilterComboBox(true, cachedPDBExists);
Thread discoverPDBStructuresThread = new Thread(new Runnable()
fetchStructuresMetaData();
// revise filter options if no results were found
populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
+ discoverStructureViews();
updateProgressIndicator(null, startTime);
mainFrame.setVisible(true);
updateCurrentView();
}
/**
+ * Builds a drop-down choice list of existing structure viewers to which new
+ * structures may be added. If this list is empty then it, and the 'Add'
+ * button, are hidden.
+ */
+ private void discoverStructureViews()
+ {
+ if (Desktop.instance != null)
+ {
+ targetView.removeAllItems();
+ if (lastTargetedView != null && !lastTargetedView.isVisible())
+ {
+ lastTargetedView = null;
+ }
+ int linkedViewsAt = 0;
+ for (StructureViewerBase view : Desktop.instance
+ .getStructureViewers(null, null))
+ {
+ StructureViewer viewHandler = (lastTargetedView != null
+ && lastTargetedView.sview == view) ? lastTargetedView
+ : StructureViewer.reconfigure(view);
+
+ if (view.isLinkedWith(ap))
+ {
+ targetView.insertItemAt(viewHandler,
+ linkedViewsAt++);
+ }
+ else
+ {
+ targetView.addItem(viewHandler);
+ }
+ }
+
+ /*
+ * show option to Add to viewer if at least 1 viewer found
+ */
+ targetView.setVisible(false);
+ if (targetView.getItemCount() > 0)
+ {
+ targetView.setVisible(true);
+ if (lastTargetedView != null)
+ {
+ targetView.setSelectedItem(lastTargetedView);
+ }
+ else
+ {
+ targetView.setSelectedIndex(0);
+ }
+ }
+ btn_add.setVisible(targetView.isVisible());
+ }
+ }
+
+ /**
* Updates the progress indicator with the specified message
*
* @param message
* @param id
* unique handle for this indicator
*/
- public void updateProgressIndicator(String message, long id)
+ protected void updateProgressIndicator(String message, long id)
{
if (progressIndicator != null)
{
* Retrieve meta-data for all the structure(s) for a given sequence(s) in a
* selection group
*/
- public void fetchStructuresMetaData()
+ void fetchStructuresMetaData()
{
long startTime = System.currentTimeMillis();
pdbRestCleint = PDBFTSRestClient.getInstance();
}
}
- public void loadLocalCachedPDBEntries()
+ protected void loadLocalCachedPDBEntries()
{
ArrayList<CachedPDB> entries = new ArrayList<>();
for (SequenceI seq : selectedSequences)
* @return the built query string
*/
- public static String buildQuery(SequenceI seq)
+ static String buildQuery(SequenceI seq)
{
boolean isPDBRefsFound = false;
boolean isUniProtRefsFound = false;
* @param seqName
* @return
*/
- public static boolean isValidSeqName(String seqName)
+ static boolean isValidSeqName(String seqName)
{
// System.out.println("seqName : " + seqName);
String ignoreList = "pdb,uniprot,swiss-prot";
return true;
}
- public static String getDBRefId(DBRefEntry dbRef)
+ static String getDBRefId(DBRefEntry dbRef)
{
String ref = dbRef.getAccessionId().replaceAll("GO:", "");
return ref;
* @param fieldToFilterBy
* the field to filter by
*/
- public void filterResultSet(final String fieldToFilterBy)
+ void filterResultSet(final String fieldToFilterBy)
{
Thread filterThread = new Thread(new Runnable()
{
* Handles action event for btn_pdbFromFile
*/
@Override
- public void pdbFromFile_actionPerformed()
+ protected void pdbFromFile_actionPerformed()
{
jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
* structures
*/
protected void populateFilterComboBox(boolean haveData,
- boolean cachedPDBExists)
+ boolean cachedPDBExist)
{
/*
* temporarily suspend the change listener behaviour
cmb_filterOption.removeAllItems();
if (haveData)
{
- cmb_filterOption.addItem(new FilterOption("Best Quality",
+ cmb_filterOption.addItem(new FilterOption(
+ MessageManager.getString("label.best_quality"),
"overall_quality", VIEWS_FILTER, false));
- cmb_filterOption.addItem(new FilterOption("Best Resolution",
+ cmb_filterOption.addItem(new FilterOption(
+ MessageManager.getString("label.best_resolution"),
"resolution", VIEWS_FILTER, false));
- cmb_filterOption.addItem(new FilterOption("Most Protein Chain",
+ cmb_filterOption.addItem(new FilterOption(
+ MessageManager.getString("label.most_protein_chain"),
"number_of_protein_chains", VIEWS_FILTER, false));
- cmb_filterOption.addItem(new FilterOption("Most Bound Molecules",
+ cmb_filterOption.addItem(new FilterOption(
+ MessageManager.getString("label.most_bound_molecules"),
"number_of_bound_molecules", VIEWS_FILTER, false));
- cmb_filterOption.addItem(new FilterOption("Most Polymer Residues",
+ cmb_filterOption.addItem(new FilterOption(
+ MessageManager.getString("label.most_polymer_residues"),
"number_of_polymer_residues", VIEWS_FILTER, true));
}
cmb_filterOption.addItem(
- new FilterOption("Enter PDB Id", "-", VIEWS_ENTER_ID, false));
+ new FilterOption(MessageManager.getString("label.enter_pdb_id"),
+ "-", VIEWS_ENTER_ID, false));
cmb_filterOption.addItem(
- new FilterOption("From File", "-", VIEWS_FROM_FILE, false));
+ new FilterOption(MessageManager.getString("label.from_file"),
+ "-", VIEWS_FROM_FILE, false));
- if (cachedPDBExists)
+ if (cachedPDBExist)
{
- FilterOption cachedOption = new FilterOption("Cached Structures",
+ FilterOption cachedOption = new FilterOption(
+ MessageManager.getString("label.cached_structures"),
"-", VIEWS_LOCAL_PDB, false);
cmb_filterOption.addItem(cachedOption);
cmb_filterOption.setSelectedItem(cachedOption);
}
/**
- * Validates user selection and activates the view button if all parameters
- * are correct
+ * Validates user selection and enables the 'Add' and 'New View' buttons if
+ * all parameters are correct (the Add button will only be visible if there is
+ * at least one existing structure viewer open). This basically means at least
+ * one structure selected and no error messages.
+ * <p>
+ * The 'Superpose Structures' option is enabled if either more than one
+ * structure is selected, or the 'Add' to existing view option is enabled, and
+ * disabled if the only option is to open a new view of a single structure.
*/
@Override
- public void validateSelections()
+ protected void validateSelections()
{
FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
.getSelectedItem());
- btn_view.setEnabled(false);
+ btn_add.setEnabled(false);
String currentView = selectedFilterOpt.getView();
+ int selectedCount = 0;
if (currentView == VIEWS_FILTER)
{
- if (getResultTable().getSelectedRows().length > 0)
+ selectedCount = getResultTable().getSelectedRows().length;
+ if (selectedCount > 0)
{
- btn_view.setEnabled(true);
+ btn_add.setEnabled(true);
}
}
else if (currentView == VIEWS_LOCAL_PDB)
{
- if (tbl_local_pdb.getSelectedRows().length > 0)
+ selectedCount = tbl_local_pdb.getSelectedRows().length;
+ if (selectedCount > 0)
{
- btn_view.setEnabled(true);
+ btn_add.setEnabled(true);
}
}
else if (currentView == VIEWS_ENTER_ID)
{
validateAssociationFromFile();
}
+
+ btn_newView.setEnabled(btn_add.isEnabled());
+
+ /*
+ * enable 'Superpose' option if more than one structure is selected,
+ * or there are view(s) available to add structure(s) to
+ */
+ chk_superpose
+ .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
}
/**
* Validates inputs from the Manual PDB entry panel
*/
- public void validateAssociationEnterPdb()
+ protected void validateAssociationEnterPdb()
{
AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
.getCmb_assSeq().getSelectedItem();
txt_search.setEnabled(true);
if (isValidPBDEntry)
{
- btn_view.setEnabled(true);
+ btn_add.setEnabled(true);
lbl_pdbManualFetchStatus.setToolTipText("");
lbl_pdbManualFetchStatus.setIcon(goodImage);
}
/**
* Validates inputs for the manual PDB file selection options
*/
- public void validateAssociationFromFile()
+ protected void validateAssociationFromFile()
{
AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
.getCmb_assSeq().getSelectedItem();
btn_pdbFromFile.setEnabled(true);
if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
{
- btn_view.setEnabled(true);
+ btn_add.setEnabled(true);
lbl_fromFileStatus.setIcon(goodImage);
}
}
}
@Override
- public void cmbAssSeqStateChanged()
+ protected void cmbAssSeqStateChanged()
{
validateSelections();
}
}
/**
- * Handles action event for btn_ok
+ * select structures for viewing by their PDB IDs
+ *
+ * @param pdbids
+ * @return true if structures were found and marked as selected
+ */
+ public boolean selectStructure(String... pdbids)
+ {
+ boolean found = false;
+
+ FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+ .getSelectedItem());
+ String currentView = selectedFilterOpt.getView();
+ JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
+ : (currentView == VIEWS_LOCAL_PDB) ? tbl_local_pdb : null;
+
+ if (restable == null)
+ {
+ // can't select (enter PDB ID, or load file - need to also select which
+ // sequence to associate with)
+ return false;
+ }
+
+ int pdbIdColIndex = restable.getColumn("PDB Id").getModelIndex();
+ for (int r = 0; r < restable.getRowCount(); r++)
+ {
+ for (int p = 0; p < pdbids.length; p++)
+ {
+ if (String.valueOf(restable.getValueAt(r, pdbIdColIndex))
+ .equalsIgnoreCase(pdbids[p]))
+ {
+ restable.setRowSelectionInterval(r, r);
+ found = true;
+ }
+ }
+ }
+ return found;
+ }
+
+ /**
+ * Handles the 'New View' action
*/
@Override
- public void ok_ActionPerformed()
+ protected void newView_ActionPerformed()
{
+ targetView.setSelectedItem(null);
+ showStructures(false);
+ }
+
+ /**
+ * Handles the 'Add to existing viewer' action
+ */
+ @Override
+ protected void add_ActionPerformed()
+ {
+ showStructures(false);
+ }
+
+ /**
+ * structure viewer opened by this dialog, or null
+ */
+ private StructureViewer sViewer = null;
+
+ public void showStructures(boolean waitUntilFinished)
+ {
+
final StructureSelectionManager ssm = ap.getStructureSelectionManager();
final int preferredHeight = pnl_filter.getHeight();
- new Thread(new Runnable()
+ Runnable viewStruc = new Runnable()
{
@Override
public void run()
FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
.getSelectedItem());
String currentView = selectedFilterOpt.getView();
+ JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
+ : tbl_local_pdb;
+
if (currentView == VIEWS_FILTER)
{
- int pdbIdColIndex = getResultTable().getColumn("PDB Id")
+ int pdbIdColIndex = restable.getColumn("PDB Id")
.getModelIndex();
- int refSeqColIndex = getResultTable().getColumn("Ref Sequence")
+ int refSeqColIndex = restable.getColumn("Ref Sequence")
.getModelIndex();
- int[] selectedRows = getResultTable().getSelectedRows();
+ int[] selectedRows = restable.getSelectedRows();
PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
int count = 0;
List<SequenceI> selectedSeqsToView = new ArrayList<>();
for (int row : selectedRows)
{
- String pdbIdStr = getResultTable()
+ String pdbIdStr = restable
.getValueAt(row, pdbIdColIndex).toString();
- SequenceI selectedSeq = (SequenceI) getResultTable()
+ SequenceI selectedSeq = (SequenceI) restable
.getValueAt(row, refSeqColIndex);
selectedSeqsToView.add(selectedSeq);
PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
}
SequenceI[] selectedSeqs = selectedSeqsToView
.toArray(new SequenceI[selectedSeqsToView.size()]);
- launchStructureViewer(ssm, pdbEntriesToView, ap, selectedSeqs);
+ sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
+ selectedSeqs);
}
else if (currentView == VIEWS_LOCAL_PDB)
{
}
SequenceI[] selectedSeqs = selectedSeqsToView
.toArray(new SequenceI[selectedSeqsToView.size()]);
- launchStructureViewer(ssm, pdbEntriesToView, ap, selectedSeqs);
+ sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
+ selectedSeqs);
}
else if (currentView == VIEWS_ENTER_ID)
{
}
PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
- launchStructureViewer(ssm, pdbEntriesToView, ap,
+ sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
new SequenceI[]
{ selectedSequence });
}
DataSourceType.FILE, selectedSequence, true,
Desktop.instance);
- launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
+ sViewer = launchStructureViewer(
+ ssm, new PDBEntry[]
+ { fileEntry }, ap,
new SequenceI[]
{ selectedSequence });
}
- closeAction(preferredHeight);
- mainFrame.dispose();
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ closeAction(preferredHeight);
+ mainFrame.dispose();
+ }
+ });
}
- }).start();
+ };
+ Thread runner = new Thread(viewStruc);
+ runner.start();
+ if (waitUntilFinished)
+ {
+ while (sViewer == null ? runner.isAlive()
+ : (sViewer.sview == null ? true
+ : !sViewer.sview.hasMapping()))
+ {
+ try
+ {
+ Thread.sleep(300);
+ } catch (InterruptedException ie)
+ {
+
+ }
+ }
+ }
}
private PDBEntry getFindEntry(String id, Vector<PDBEntry> pdbEntries)
return foundEntry;
}
- private void launchStructureViewer(StructureSelectionManager ssm,
+ /**
+ * Answers a structure viewer (new or existing) configured to superimpose
+ * added structures or not according to the user's choice
+ *
+ * @param ssm
+ * @return
+ */
+ StructureViewer getTargetedStructureViewer(
+ StructureSelectionManager ssm)
+ {
+ Object sv = targetView.getSelectedItem();
+
+ return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
+ }
+
+ /**
+ * Adds PDB structures to a new or existing structure viewer
+ *
+ * @param ssm
+ * @param pdbEntriesToView
+ * @param alignPanel
+ * @param sequences
+ * @return
+ */
+ private StructureViewer launchStructureViewer(
+ StructureSelectionManager ssm,
final PDBEntry[] pdbEntriesToView,
final AlignmentPanel alignPanel, SequenceI[] sequences)
{
long progressId = sequences.hashCode();
setProgressBar(MessageManager
.getString("status.launching_3d_structure_viewer"), progressId);
- final StructureViewer sViewer = new StructureViewer(ssm);
- setProgressBar(null, progressId);
+ final StructureViewer theViewer = getTargetedStructureViewer(ssm);
+ boolean superimpose = chk_superpose.isSelected();
+ theViewer.setSuperpose(superimpose);
+ /*
+ * remember user's choice of superimpose or not
+ */
+ Cache.setProperty(AUTOSUPERIMPOSE,
+ Boolean.valueOf(superimpose).toString());
+
+ setProgressBar(null, progressId);
if (SiftsSettings.isMapWithSifts())
{
List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
}
}
}
- if (seq.getPrimaryDBRefs().size() == 0)
+ if (seq.getPrimaryDBRefs().isEmpty())
{
seqsWithoutSourceDBRef.add(seq);
continue;
setProgressBar(MessageManager.formatMessage(
"status.fetching_dbrefs_for_sequences_without_valid_refs",
y), progressId);
- SequenceI[] seqWithoutSrcDBRef = new SequenceI[y];
- int x = 0;
- for (SequenceI fSeq : seqsWithoutSourceDBRef)
- {
- seqWithoutSrcDBRef[x++] = fSeq;
- }
-
+ SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
+ .toArray(new SequenceI[y]);
DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
dbRefFetcher.fetchDBRefs(true);
setProgressBar(MessageManager.getString(
"status.fetching_3d_structures_for_selected_entries"),
progressId);
- sViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
+ theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
}
else
{
setProgressBar(MessageManager.formatMessage(
"status.fetching_3d_structures_for",
pdbEntriesToView[0].getId()),progressId);
- sViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
+ theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
}
setProgressBar(null, progressId);
+ // remember the last viewer we used...
+ lastTargetedView = theViewer;
+ return theViewer;
}
/**
* a unique sequence when more than one sequence selection is made.
*/
@Override
- public void populateCmbAssociateSeqOptions(
+ protected void populateCmbAssociateSeqOptions(
JComboBox<AssociateSeqOptions> cmb_assSeq,
JLabel lbl_associateSeq)
{
}
}
- public boolean isStructuresDiscovered()
+ protected boolean isStructuresDiscovered()
{
return discoveredStructuresSet != null
&& !discoveredStructuresSet.isEmpty();
}
- public Collection<FTSData> getDiscoveredStructuresSet()
- {
- return discoveredStructuresSet;
- }
-
@Override
protected void txt_search_ActionPerformed()
{
}
@Override
- public void tabRefresh()
+ protected void tabRefresh()
{
if (selectedSequences != null)
{
{
return progressBar.operationInProgress();
}
+
+ public JalviewStructureDisplayI getOpenedStructureViewer()
+ {
+ return sViewer == null ? null : sViewer.sview;
+ }
}
StructureSelectionManager ssm;
+ /**
+ * decide if new structures are aligned to existing ones
+ */
+ private boolean superposeAdded = true;
+
public enum ViewerType
{
JMOL, CHIMERA
ssm = structureSelectionManager;
}
+ /**
+ * Factory to create a proxy for modifying existing structure viewer
+ *
+ */
+ public static StructureViewer reconfigure(
+ JalviewStructureDisplayI display)
+ {
+ StructureViewer sv = new StructureViewer(display.getBinding().getSsm());
+ sv.sview = display;
+ return sv;
+ }
+
+ @Override
+ public String toString()
+ {
+ if (sview != null)
+ {
+ return sview.toString();
+ }
+ return "New View";
+ }
public ViewerType getViewerType()
{
String viewType = Cache.getDefault(Preferences.STRUCTURE_DISPLAY,
new PDBEntry[seqsForPdbs.size()]);
SequenceI[][] theSeqs = seqsForPdbs.values().toArray(
new SequenceI[seqsForPdbs.size()][]);
- JalviewStructureDisplayI sview = null;
+ if (sview != null)
+ {
+ sview.setAlignAddedStructures(superposeAdded);
+ new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+
+ for (int pdbep = 0; pdbep < pdbsForFile.length; pdbep++)
+ {
+ PDBEntry pdb = pdbsForFile[pdbep];
+ if (!sview.addAlreadyLoadedFile(theSeqs[pdbep], null, ap,
+ pdb.getId()))
+ {
+ sview.addToExistingViewer(pdb, theSeqs[pdbep], null, ap,
+ pdb.getId());
+ }
+ }
+
+ sview.updateTitleAndMenus();
+ }
+ }).start();
+ return sview;
+ }
+
if (viewerType.equals(ViewerType.JMOL))
{
- sview = new AppJmol(ap, pdbsForFile, theSeqs);
+ sview = new AppJmol(ap, superposeAdded, pdbsForFile, theSeqs);
}
else if (viewerType.equals(ViewerType.CHIMERA))
{
- sview = new ChimeraViewFrame(pdbsForFile, theSeqs, ap);
+ sview = new ChimeraViewFrame(pdbsForFile, superposeAdded, theSeqs,
+ ap);
}
else
{
PDBEntry pdb = pdbs[i];
SequenceI seq = seqs[i];
String pdbFile = pdb.getFile();
+ if (pdbFile == null || pdbFile.length() == 0)
+ {
+ pdbFile = pdb.getId();
+ }
if (!pdbsSeen.containsKey(pdbFile))
{
pdbsSeen.put(pdbFile, pdb);
private JalviewStructureDisplayI onlyOnePdb(PDBEntry[] pdbs,
SequenceI[] seqsForPdbs, AlignmentPanel ap)
{
- List<SequenceI> seqs = new ArrayList<SequenceI>();
+ List<SequenceI> seqs = new ArrayList<>();
if (pdbs == null || pdbs.length == 0)
{
return null;
ap);
}
+ JalviewStructureDisplayI sview = null;
+
public JalviewStructureDisplayI viewStructures(PDBEntry pdb,
SequenceI[] seqsForPdb, AlignmentPanel ap)
{
+ if (sview != null)
+ {
+ sview.setAlignAddedStructures(superposeAdded);
+ String pdbId = pdb.getId();
+ if (!sview.addAlreadyLoadedFile(seqsForPdb, null, ap, pdbId))
+ {
+ sview.addToExistingViewer(pdb, seqsForPdb, null, ap, pdbId);
+ }
+ sview.updateTitleAndMenus();
+ sview.raiseViewer();
+ return sview;
+ }
ViewerType viewerType = getViewerType();
- JalviewStructureDisplayI sview = null;
if (viewerType.equals(ViewerType.JMOL))
{
sview = new AppJmol(pdb, seqsForPdb, null, ap);
final boolean usetoColourbyseq = viewerData.isColourWithAlignPanel();
final boolean viewerColouring = viewerData.isColourByViewer();
- JalviewStructureDisplayI sview = null;
switch (type)
{
case JMOL:
return sview;
}
+ public boolean isBusy()
+ {
+ if (sview != null)
+ {
+ if (!sview.hasMapping())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ * @param pDBid
+ * @return true if view is already showing PDBid
+ */
+ public boolean hasPdbId(String pDBid)
+ {
+ if (sview == null)
+ {
+ return false;
+ }
+
+ return sview.getBinding().hasPdbId(pDBid);
+ }
+
+ public boolean isVisible()
+ {
+ return sview != null && sview.isVisible();
+ }
+
+ public void setSuperpose(boolean alignAddedStructures)
+ {
+ superposeAdded = alignAddedStructures;
+ }
+
}
*/
package jalview.gui;
+import jalview.api.AlignmentViewPanel;
import jalview.bin.Cache;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
import jalview.jbgui.GStructureViewer;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemes;
+import jalview.structure.StructureMapping;
import jalview.structures.models.AAStructureBindingModel;
import jalview.util.MessageManager;
protected boolean alignAddedStructures = false;
- protected boolean _started = false;
+ protected volatile boolean _started = false;
- protected boolean addingStructures = false;
+ protected volatile boolean addingStructures = false;
protected Thread worker = null;
protected JMenu viewSelectionMenu;
/**
+ * set after sequence colouring has been applied for this structure viewer.
+ * used to determine if the final sequence/structure mapping has been
+ * determined
+ */
+ protected volatile boolean seqColoursApplied = false;
+
+ /**
* Default constructor
*/
public StructureViewerBase()
}
/**
+ * @return true if added structures should be aligned to existing one(s)
+ */
+ @Override
+ public boolean isAlignAddedStructures()
+ {
+ return alignAddedStructures;
+ }
+
+ /**
+ *
+ * @param true
+ * if added structures should be aligned to existing one(s)
+ */
+ @Override
+ public void setAlignAddedStructures(boolean alignAdded)
+ {
+ alignAddedStructures = alignAdded;
+ }
+
+ /**
*
* @param ap2
* @return true if this Jmol instance is linked with the given alignPanel
*/
protected void addStructure(final PDBEntry pdbentry,
final SequenceI[] seqs, final String[] chains,
- final boolean align, final IProgressIndicator alignFrame)
+ final IProgressIndicator alignFrame)
{
if (pdbentry.getFile() == null)
{
}
}
// and call ourselves again.
- addStructure(pdbentry, seqs, chains, align, alignFrame);
+ addStructure(pdbentry, seqs, chains, alignFrame);
}
}).start();
return;
{ seqs }, new String[][] { chains });
addingStructures = true;
_started = false;
- alignAddedStructures = align;
worker = new Thread(this);
worker.start();
return;
}
- /**
- * Presents a dialog with the option to add an align a structure to an
- * existing structure view
- *
- * @param pdbId
- * @param view
- * @return YES, NO or CANCEL JvOptionPane code
- */
- protected int chooseAlignStructureToViewer(String pdbId,
- StructureViewerBase view)
- {
- int option = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
- MessageManager.formatMessage("label.add_pdbentry_to_view",
- new Object[]
- { pdbId, view.getTitle() }),
- MessageManager
- .getString("label.align_to_existing_structure_view"),
- JvOptionPane.YES_NO_CANCEL_OPTION);
- return option;
- }
-
protected boolean hasPdbId(String pdbId)
{
return getBinding().hasPdbId(pdbId);
}
- protected abstract List<StructureViewerBase> getViewersFor(
- AlignmentPanel alp);
-
/**
- * Check for any existing views involving this alignment and give user the
- * option to add and align this molecule to one of them
- *
- * @param pdbentry
- * @param seq
- * @param chains
- * @param apanel
- * @param pdbId
- * @return true if user adds to a view, or cancels entirely, else false
+ * Returns a list of any viewer of the instantiated type. The list is
+ * restricted to those linked to the given alignment panel if it is not null.
*/
- protected boolean addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq,
- String[] chains, final AlignmentPanel apanel, String pdbId)
+ protected List<StructureViewerBase> getViewersFor(AlignmentPanel alp)
{
- for (StructureViewerBase view : getViewersFor(apanel))
- {
- // TODO: highlight the view somehow
- /*
- * JAL-1742 exclude view with this structure already mapped (don't offer
- * to align chain B to chain A of the same structure)
- */
- if (view.hasPdbId(pdbId))
- {
- continue;
- }
- int option = chooseAlignStructureToViewer(pdbId, view);
- if (option == JvOptionPane.CANCEL_OPTION)
- {
- return true;
- }
- else if (option == JvOptionPane.YES_OPTION)
- {
- view.useAlignmentPanelForSuperposition(apanel);
- view.addStructure(pdbentry, seq, chains, true, apanel.alignFrame);
- return true;
- }
- else
- {
- // NO_OPTION - offer the next viewer if any
- }
- }
+ return Desktop.instance.getStructureViewers(alp, this.getClass());
+ }
+ @Override
+ public void addToExistingViewer(PDBEntry pdbentry, SequenceI[] seq,
+ String[] chains, final AlignmentViewPanel apanel, String pdbId)
+ {
/*
- * nothing offered and selected
+ * JAL-1742 exclude view with this structure already mapped (don't offer
+ * to align chain B to chain A of the same structure); code may defend
+ * against this possibility before we reach here
*/
- return false;
+ if (hasPdbId(pdbId))
+ {
+ return;
+ }
+ AlignmentPanel alignPanel = (AlignmentPanel) apanel; // Implementation error if this
+ // cast fails
+ useAlignmentPanelForSuperposition(alignPanel);
+ addStructure(pdbentry, seq, chains, alignPanel.alignFrame);
}
/**
* @param apanel
* @param pdbFilename
*/
- protected void addSequenceMappingsToStructure(SequenceI[] seq,
- String[] chains, final AlignmentPanel apanel, String pdbFilename)
+ public void addSequenceMappingsToStructure(SequenceI[] seq,
+ String[] chains, final AlignmentViewPanel alpanel,
+ String pdbFilename)
{
+ AlignmentPanel apanel = (AlignmentPanel) alpanel;
+
// TODO : Fix multiple seq to one chain issue here.
/*
* create the mappings
}
}
- /**
- * Check if the PDB file is already loaded, if so offer to add it to the
- * existing viewer
- *
- * @param seq
- * @param chains
- * @param apanel
- * @param pdbId
- * @return true if the user chooses to add to a viewer, or to cancel entirely
- */
- protected boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains,
- final AlignmentPanel apanel, String pdbId)
+ @Override
+ public boolean addAlreadyLoadedFile(SequenceI[] seq, String[] chains,
+ final AlignmentViewPanel apanel, String pdbId)
{
- boolean finished = false;
String alreadyMapped = apanel.getStructureSelectionManager()
.alreadyMappedToFile(pdbId);
- if (alreadyMapped != null)
+ if (alreadyMapped == null)
{
- /*
- * the PDB file is already loaded
- */
- int option = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
- MessageManager.formatMessage(
- "label.pdb_entry_is_already_displayed", new Object[]
- { pdbId }),
- MessageManager.formatMessage(
- "label.map_sequences_to_visible_window", new Object[]
- { pdbId }),
- JvOptionPane.YES_NO_CANCEL_OPTION);
- if (option == JvOptionPane.CANCEL_OPTION)
- {
- finished = true;
- }
- else if (option == JvOptionPane.YES_OPTION)
- {
- addSequenceMappingsToStructure(seq, chains, apanel, alreadyMapped);
- finished = true;
- }
+ return false;
}
- return finished;
+
+ addSequenceMappingsToStructure(seq, chains, apanel, alreadyMapped);
+ return true;
}
void setChainMenuItems(List<String> chainNames)
int[] alm = new int[_alignwith.size()];
int a = 0;
- for (AlignmentPanel ap : _alignwith)
+ for (AlignmentPanel alignPanel : _alignwith)
{
- als[a] = ap.av.getAlignment();
+ als[a] = alignPanel.av.getAlignment();
alm[a] = -1;
- alc[a++] = ap.av.getAlignment().getHiddenColumns();
+ alc[a++] = alignPanel.av.getAlignment().getHiddenColumns();
}
reply = getBinding().superposeStructures(als, alm, alc);
if (reply != null)
} catch (Exception e)
{
StringBuffer sp = new StringBuffer();
- for (AlignmentPanel ap : _alignwith)
+ for (AlignmentPanel alignPanel : _alignwith)
{
- sp.append("'" + ap.alignFrame.getTitle() + "' ");
+ sp.append("'" + alignPanel.alignFrame.getTitle() + "' ");
}
Cache.log.info("Couldn't align structures with the " + sp.toString()
+ "associated alignment panels.", e);
}
}
// Set the colour using the current view for the associated alignframe
- for (AlignmentPanel ap : _colourwith)
+ for (AlignmentPanel alignPanel : _colourwith)
{
- binding.colourBySequence(ap);
+ binding.colourBySequence(alignPanel);
}
+ seqColoursApplied = true;
}
}
/**
* Configures the title and menu items of the viewer panel.
*/
+ @Override
public void updateTitleAndMenus()
{
AAStructureBindingModel binding = getBinding();
seqColour_actionPerformed(null);
}
}
+
+ @Override
+ public String toString()
+ {
+ return getTitle();
+ }
+
+ @Override
+ public boolean hasMapping()
+ {
+ if (worker != null && (addingStructures || _started))
+ {
+ return false;
+ }
+ if (getBinding() == null)
+ {
+ if (_aps == null || _aps.size() == 0)
+ {
+ // viewer has been closed, but we did at some point run.
+ return true;
+ }
+ return false;
+ }
+ String[] pdbids = getBinding().getStructureFiles();
+ if (pdbids == null)
+ {
+ return false;
+ }
+ int p=0;
+ for (String pdbid:pdbids) {
+ StructureMapping sm[] = getBinding().getSsm().getMapping(pdbid);
+ if (sm!=null && sm.length>0 && sm[0]!=null) {
+ p++;
+ }
+ }
+ // only return true if there is a mapping for every structure file we have loaded
+ if (p == 0 || p != pdbids.length)
+ {
+ return false;
+ }
+ // and that coloring has been applied
+ return seqColoursApplied;
+ }
+
+ @Override
+ public void raiseViewer()
+ {
+ toFront();
+ }
+
}
}
}
colourGroups(groups);
+
+ /*
+ * clear partition (don't show vertical line) if
+ * it is to the right of all nodes
+ */
+ if (groups.isEmpty())
+ {
+ threshold = 0f;
+ }
}
PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
Vector<SequenceNode> l = tree.findLeaves(groups.get(i));
- Vector<SequenceI> sequences = new Vector<SequenceI>();
+ Vector<SequenceI> sequences = new Vector<>();
for (int j = 0; j < l.size(); j++)
{
}
else
{
- // int[] intervals = colsel.getVisibleContigs(
- // seqsel.getStartRes(), seqsel.getEndRes() + 1);
- int[] intervals = hidden.getVisibleContigs(
- seqsel.getStartRes(), seqsel.getEndRes() + 1);
- for (int iv = 0; iv < intervals.length; iv += 2)
+ Iterator<int[]> intervals = hidden
+ .getVisContigsIterator(seqsel.getStartRes(),
+ seqsel.getEndRes() + 1, false);
+ while (intervals.hasNext())
{
+ int[] region = intervals.next();
Seg s = new Seg();
- s.setStart(intervals[iv] + 1); // vamsas indices begin at
- // 1, not zero.
- s.setEnd(intervals[iv + 1] + 1);
+ s.setStart(region[0] + 1); // vamsas indices begin at 1,
+ // not zero.
+ s.setEnd(region[1] + 1);
s.setInclusive(true);
range.addSeg(s);
}
long end;
- private boolean parseCalled;
+ /**
+ * true if parse() has been called
+ */
+ private boolean parseCalled = false;
+
+ private boolean parseImmediately = true;
+
+ /**
+ * @return if doParse() was called at construction time
+ */
+ protected boolean isParseImmediately()
+ {
+ return parseImmediately;
+ }
/**
* Creates a new AlignFile object.
{
super(source);
initData();
+
+ // stash flag in case parse needs to know if it has to autoconfigure or was
+ // configured after construction
+ this.parseImmediately = parseImmediately;
+
if (parseImmediately)
{
doParse();
else
{
// consider deferring this till after the file has been parsed ?
- hidden.hideInsertionsFor(sr);
+ hidden.hideList(sr.getInsertions());
}
}
modified = true;
import jalview.util.Format;
import java.io.IOException;
-import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
{
int i = 0;
boolean flag = false;
- boolean rna = false;
boolean top = false;
- StringBuffer pssecstr = new StringBuffer(),
- consstr = new StringBuffer();
- Vector headers = new Vector();
- Hashtable seqhash = new Hashtable();
+ StringBuffer pssecstr = new StringBuffer();
+ StringBuffer consstr = new StringBuffer();
+ Vector<String> headers = new Vector<>();
+ Map<String, StringBuffer> seqhash = new HashMap<>();
StringBuffer tempseq;
String line, id;
StringTokenizer str;
{
top = true;
}
- if (line.indexOf(" ") != 0)
+ boolean isConservation = line.startsWith(SPACE)
+ || line.startsWith(TAB);
+ if (!isConservation)
{
- str = new StringTokenizer(line, " ");
+ str = new StringTokenizer(line);
if (str.hasMoreTokens())
{
{
if (seqhash.containsKey(id))
{
- tempseq = (StringBuffer) seqhash.get(id);
+ tempseq = seqhash.get(id);
}
else
{
AlignmentAnnotation lastssa = null;
if (pssecstr.length() == maxLength)
{
- Vector ss = new Vector();
+ Vector<AlignmentAnnotation> ss = new Vector<>();
AlignmentAnnotation ssa = lastssa = StockholmFile
.parseAnnotationRow(ss, "secondary structure",
pssecstr.toString());
}
if (consstr.length() == maxLength)
{
- Vector ss = new Vector();
+ Vector<AlignmentAnnotation> ss = new Vector<>();
AlignmentAnnotation ssa = StockholmFile.parseAnnotationRow(ss,
"secondary structure", consstr.toString());
ssa.label = "Consensus Secondary Structure";
out.append(new Format("%-" + maxid + "s")
.form(printId(s[j], jvsuffix) + " "));
- int start = i * len;
- int end = start + len;
+ int chunkStart = i * len;
+ int chunkEnd = chunkStart + len;
int length = s[j].getLength();
- if ((end < length) && (start < length))
+ if ((chunkEnd < length) && (chunkStart < length))
{
- out.append(s[j].getSequenceAsString(start, end));
+ out.append(s[j].getSequenceAsString(chunkStart, chunkEnd));
}
else
{
- if (start < length)
+ if (chunkStart < length)
{
- out.append(s[j].getSequenceAsString().substring(start));
+ out.append(s[j].getSequenceAsString().substring(chunkStart));
}
}
import jalview.datamodel.SequenceDummy;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.io.gff.GffHelperBase;
import jalview.io.gff.GffHelperFactory;
import jalview.io.gff.GffHelperI;
*/
public class FeaturesFile extends AlignFile implements FeaturesSourceI
{
+ private static final String TAB_REGEX = "\\t";
+
+ private static final String STARTGROUP = "STARTGROUP";
+
+ private static final String ENDGROUP = "ENDGROUP";
+
+ private static final String STARTFILTERS = "STARTFILTERS";
+
+ private static final String ENDFILTERS = "ENDFILTERS";
+
private static final String ID_NOT_SPECIFIED = "ID_NOT_SPECIFIED";
private static final String NOTE = "Note";
- protected static final String TAB = "\t";
-
protected static final String GFF_VERSION = "##gff-version";
private AlignmentI lastmatchedAl = null;
* @param align
* - alignment/dataset containing sequences that are to be annotated
* @param colours
- * - hashtable to store feature colour definitions
+ * - map to store feature colour definitions
* @param removeHTML
* - process html strings into plain text
* @param relaxedIdmatching
Map<String, FeatureColourI> colours, boolean removeHTML,
boolean relaxedIdmatching)
{
- Map<String, String> gffProps = new HashMap<String, String>();
+ return parse(align, colours, null, removeHTML, relaxedIdmatching);
+ }
+
+ /**
+ * Parse GFF or Jalview format sequence features file
+ *
+ * @param align
+ * - alignment/dataset containing sequences that are to be annotated
+ * @param colours
+ * - map to store feature colour definitions
+ * @param filters
+ * - map to store feature filter definitions
+ * @param removeHTML
+ * - process html strings into plain text
+ * @param relaxedIdmatching
+ * - when true, ID matches to compound sequence IDs are allowed
+ * @return true if features were added
+ */
+ public boolean parse(AlignmentI align,
+ Map<String, FeatureColourI> colours,
+ Map<String, FeatureMatcherSetI> filters, boolean removeHTML,
+ boolean relaxedIdmatching)
+ {
+ Map<String, String> gffProps = new HashMap<>();
/*
* keep track of any sequences we try to create from the data
*/
- List<SequenceI> newseqs = new ArrayList<SequenceI>();
+ List<SequenceI> newseqs = new ArrayList<>();
String line = null;
try
continue;
}
- gffColumns = line.split("\\t"); // tab as regex
+ gffColumns = line.split(TAB_REGEX);
if (gffColumns.length == 1)
{
if (line.trim().equalsIgnoreCase("GFF"))
}
}
- if (gffColumns.length > 1 && gffColumns.length < 4)
+ if (gffColumns.length > 0 && gffColumns.length < 4)
{
/*
* if 2 or 3 tokens, we anticipate either 'startgroup', 'endgroup' or
* a feature type colour specification
*/
String ft = gffColumns[0];
- if (ft.equalsIgnoreCase("startgroup"))
+ if (ft.equalsIgnoreCase(STARTFILTERS))
+ {
+ parseFilters(filters);
+ continue;
+ }
+ if (ft.equalsIgnoreCase(STARTGROUP))
{
featureGroup = gffColumns[1];
}
- else if (ft.equalsIgnoreCase("endgroup"))
+ else if (ft.equalsIgnoreCase(ENDGROUP))
{
// We should check whether this is the current group,
// but at present there's no way of showing more than 1 group
}
/**
+ * Reads input lines from STARTFILTERS to ENDFILTERS and adds a feature type
+ * filter to the map for each line parsed. After exit from this method,
+ * nextLine() should return the line after ENDFILTERS (or we are already at
+ * end of file if ENDFILTERS was missing).
+ *
+ * @param filters
+ * @throws IOException
+ */
+ protected void parseFilters(Map<String, FeatureMatcherSetI> filters)
+ throws IOException
+ {
+ String line;
+ while ((line = nextLine()) != null)
+ {
+ if (line.toUpperCase().startsWith(ENDFILTERS))
+ {
+ return;
+ }
+ String[] tokens = line.split(TAB_REGEX);
+ if (tokens.length != 2)
+ {
+ System.err.println(String.format("Invalid token count %d for %d",
+ tokens.length, line));
+ }
+ else
+ {
+ String featureType = tokens[0];
+ FeatureMatcherSetI fm = FeatureMatcherSet.fromString(tokens[1]);
+ if (fm != null && filters != null)
+ {
+ filters.put(featureType, fm);
+ }
+ }
+ }
+ }
+
+ /**
* Try to parse a Jalview format feature specification and add it as a
* sequence feature to any matching sequences in the alignment. Returns true
* if successful (a feature was added), or false if not.
}
/**
- * Returns contents of a Jalview format features file, for visible features,
- * as filtered by type and group. Features with a null group are displayed if
- * their feature type is visible. Non-positional features may optionally be
- * included (with no check on type or group).
+ * Returns contents of a Jalview format features file, for visible features, as
+ * filtered by type and group. Features with a null group are displayed if their
+ * feature type is visible. Non-positional features may optionally be included
+ * (with no check on type or group).
*
* @param sequences
* source of features
* @param visible
* map of colour for each visible feature type
+ * @param featureFilters
* @param visibleFeatureGroups
* @param includeNonPositional
* if true, include non-positional features (regardless of group or
*/
public String printJalviewFormat(SequenceI[] sequences,
Map<String, FeatureColourI> visible,
+ Map<String, FeatureMatcherSetI> featureFilters,
List<String> visibleFeatureGroups, boolean includeNonPositional)
{
if (!includeNonPositional && (visible == null || visible.isEmpty()))
.toArray(new String[visible.keySet().size()]);
/*
+ * feature filters if any
+ */
+ outputFeatureFilters(out, visible, featureFilters);
+
+ /*
* sort groups alphabetically, and ensure that features with a
* null or empty group are output after those in named groups
*/
- List<String> sortedGroups = new ArrayList<String>(visibleFeatureGroups);
+ List<String> sortedGroups = new ArrayList<>(visibleFeatureGroups);
sortedGroups.remove(null);
sortedGroups.remove("");
Collections.sort(sortedGroups);
}
}
- for (String group : sortedGroups)
+ /*
+ * positional features within groups
+ */
+ foundSome |= outputFeaturesByGroup(out, sortedGroups, types, sequences);
+
+ return foundSome ? out.toString() : "No Features Visible";
+ }
+
+ /**
+ * Outputs any feature filters defined for visible feature types, sandwiched by
+ * STARTFILTERS and ENDFILTERS lines
+ *
+ * @param out
+ * @param visible
+ * @param featureFilters
+ */
+ void outputFeatureFilters(StringBuilder out,
+ Map<String, FeatureColourI> visible,
+ Map<String, FeatureMatcherSetI> featureFilters)
+ {
+ if (visible == null || featureFilters == null
+ || featureFilters.isEmpty())
+ {
+ return;
+ }
+
+ boolean first = true;
+ for (String featureType : visible.keySet())
+ {
+ FeatureMatcherSetI filter = featureFilters.get(featureType);
+ if (filter != null)
+ {
+ if (first)
+ {
+ first = false;
+ out.append(newline).append(STARTFILTERS).append(newline);
+ }
+ out.append(featureType).append(TAB).append(filter.toStableString())
+ .append(newline);
+ }
+ }
+ if (!first)
+ {
+ out.append(ENDFILTERS).append(newline).append(newline);
+ }
+
+ }
+
+ /**
+ * Appends output of sequence features within feature groups to the output
+ * buffer. Groups other than the null or empty group are sandwiched by
+ * STARTGROUP and ENDGROUP lines.
+ *
+ * @param out
+ * @param groups
+ * @param featureTypes
+ * @param sequences
+ * @return
+ */
+ private boolean outputFeaturesByGroup(StringBuilder out,
+ List<String> groups, String[] featureTypes, SequenceI[] sequences)
+ {
+ boolean foundSome = false;
+ for (String group : groups)
{
boolean isNamedGroup = (group != null && !"".equals(group));
if (isNamedGroup)
{
out.append(newline);
- out.append("STARTGROUP").append(TAB);
+ out.append(STARTGROUP).append(TAB);
out.append(group);
out.append(newline);
}
for (int i = 0; i < sequences.length; i++)
{
String sequenceName = sequences[i].getName();
- List<SequenceFeature> features = new ArrayList<SequenceFeature>();
- if (types.length > 0)
+ List<SequenceFeature> features = new ArrayList<>();
+ if (featureTypes.length > 0)
{
features.addAll(sequences[i].getFeatures().getFeaturesForGroup(
- true, group, types));
+ true, group, featureTypes));
}
for (SequenceFeature sequenceFeature : features)
if (isNamedGroup)
{
- out.append("ENDGROUP").append(TAB);
+ out.append(ENDGROUP).append(TAB);
out.append(group);
out.append(newline);
}
}
-
- return foundSome ? out.toString() : "No Features Visible";
+ return foundSome;
}
/**
dataset = new Alignment(new SequenceI[] {});
}
- Map<String, FeatureColourI> featureColours = new HashMap<String, FeatureColourI>();
+ Map<String, FeatureColourI> featureColours = new HashMap<>();
boolean parseResult = parse(dataset, featureColours, false, true);
if (!parseResult)
{
for (SequenceI seq : sequences)
{
- List<SequenceFeature> features = new ArrayList<SequenceFeature>();
+ List<SequenceFeature> features = new ArrayList<>();
if (includeNonPositionalFeatures)
{
features.addAll(seq.getFeatures().getNonPositionalFeatures());
return true;
}
},
- Jalview("Jalview", "jar,jvp", true, true)
+ Jalview("Jalview", "jvp, jar", true, true)
{
@Override
public AlignmentFileReaderI getReader(FileParse source)
*/
public class FileParse
{
+ protected static final String SPACE = " ";
+
+ protected static final String TAB = "\t";
+
/**
* text specifying source of data. usually filename or url.
*/
public boolean getCacheSuffixDefault(FileFormatI format)
{
- return Cache.getDefault(format.getName() + "_JVSUFFIX", true);
+ return Cache.getDefault(format.getName().toUpperCase() + "_JVSUFFIX",
+ true);
}
public String formatSequences(FileFormatI format, AlignmentI alignment,
AlignmentAnnotation na = new AlignmentAnnotation(ala[i]);
if (selgp != null)
{
- hidden.makeVisibleAnnotation(selgp.getStartRes(),
- selgp.getEndRes(), na);
+ na.makeVisibleAnnotation(selgp.getStartRes(), selgp.getEndRes(),
+ hidden);
}
else
{
- hidden.makeVisibleAnnotation(na);
+ na.makeVisibleAnnotation(hidden);
}
alv.addAnnotation(na);
}
public static JalviewFileChooser forRead(String directory,
String selected)
{
- List<String> extensions = new ArrayList<String>();
- List<String> descs = new ArrayList<String>();
+ List<String> extensions = new ArrayList<>();
+ List<String> descs = new ArrayList<>();
for (FileFormatI format : FileFormats.getInstance().getFormats())
{
if (format.isReadable())
{
// TODO in Java 8, forRead and forWrite can be a single method
// with a lambda expression parameter for isReadable/isWritable
- List<String> extensions = new ArrayList<String>();
- List<String> descs = new ArrayList<String>();
+ List<String> extensions = new ArrayList<>();
+ List<String> descs = new ArrayList<>();
for (FileFormatI format : FileFormats.getInstance().getFormats())
{
if (format.isWritable())
super(safePath(dir));
if (extensions.length == descs.length)
{
- List<String[]> formats = new ArrayList<String[]>();
+ List<String[]> formats = new ArrayList<>();
for (int i = 0; i < extensions.length; i++)
{
formats.add(new String[] { extensions[i], descs[i] });
return null;
}
+ File ourselectedFile = null;
+
+ @Override
+ public File getSelectedFile()
+ {
+ File selfile = super.getSelectedFile();
+ if (selfile == null && ourselectedFile != null)
+ {
+ return ourselectedFile;
+ }
+ return selfile;
+ }
+
@Override
public int showSaveDialog(Component parent) throws HeadlessException
{
setDialogType(SAVE_DIALOG);
+ this.setSelectedFile(null);
int ret = showDialog(parent, MessageManager.getString("action.save"));
+ ourselectedFile = getSelectedFile();
+ if (getSelectedFile() == null)
+ {
+ // Workaround for Java 9,10 on OSX - no selected file, but there is a
+ // filename typed in
+ try
+ {
+ String filename = ((BasicFileChooserUI) getUI()).getFileName();
+ if (filename != null && filename.length() > 0)
+ {
+ ourselectedFile = new File(getCurrentDirectory(), filename);
+ }
+ } catch (Throwable x)
+ {
+ System.err.println(
+ "Unexpected exception when trying to get filename.");
+ x.printStackTrace();
+ }
+ }
+ if (ourselectedFile == null)
+ {
+ return JalviewFileChooser.CANCEL_OPTION;
+ }
if (getFileFilter() instanceof JalviewFileFilter)
{
JalviewFileFilter jvf = (JalviewFileFilter) getFileFilter();
- if (!jvf.accept(getSelectedFile()))
+ if (!jvf.accept(ourselectedFile))
{
- String withExtension = getSelectedFile() + "."
+ String withExtension = getSelectedFile().getName() + "."
+ jvf.getAcceptableExtension();
- setSelectedFile(new File(withExtension));
+ ourselectedFile = (new File(getCurrentDirectory(), withExtension));
+ setSelectedFile(ourselectedFile);
}
}
// TODO: ENSURE THAT FILES SAVED WITH A ':' IN THE NAME ARE REFUSED AND THE
// USER PROMPTED FOR A NEW FILENAME
if ((ret == JalviewFileChooser.APPROVE_OPTION)
- && getSelectedFile().exists())
+ && ourselectedFile.exists())
{
int confirm = JvOptionPane.showConfirmDialog(parent,
MessageManager.getString("label.overwrite_existing_file"),
package jalview.io;
import java.io.File;
-import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.StringTokenizer;
import javax.swing.filechooser.FileFilter;
{
public static Hashtable suffixHash = new Hashtable();
- private Hashtable filters = null;
+ private Map<String, JalviewFileFilter> filters = null;
private String description = "no description";
public String getAcceptableExtension()
{
- return filters.keys().nextElement().toString();
+ return filters.keySet().iterator().next().toString();
}
// takes account of the fact that database is a directory
+ @Override
public boolean accept(File f)
{
if (f != null)
return true;
}
- if ((extension != null) && (filters.get(getExtension(f)) != null))
+ if ((extension != null) && (filters.get(extension) != null))
{
return true;
}
{
if (filters == null)
{
- filters = new Hashtable(5);
+ filters = new LinkedHashMap<>(5);
}
filters.put(extension.toLowerCase(), this);
fullDescription = null;
}
+ @Override
public String getDescription()
{
if (fullDescription == null)
: (description + " (");
// build the description from the extension list
- Enumeration extensions = filters.keys();
+ Iterator<String> extensions = filters.keySet().iterator();
if (extensions != null)
{
- fullDescription += ("." + (String) extensions.nextElement());
+ fullDescription += ("." + extensions.next());
- while (extensions.hasMoreElements())
+ while (extensions.hasNext())
{
- fullDescription += (", " + (String) extensions.nextElement());
+ fullDescription += (", " + extensions.next());
}
}
private void loadExtensions()
{
- extensions = new HashMap<String, String>();
+ extensions = new HashMap<>();
for (FileFormatI ff : FileFormats.getInstance().getFormats())
{
String desc = ff.getName() + " file";
String exts = ff.getExtensions();
for (String ext : exts.split(","))
{
- extensions.put(ext.trim().toLowerCase(),
+ ext = ext.trim().toLowerCase();
+ extensions.put(ext,
desc + ("jar".equals(ext) ? " (old)" : ""));
}
}
{
if (icons == null)
{
- icons = new HashMap<String, ImageIcon>();
+ icons = new HashMap<>();
}
if (!icons.containsKey(filePath))
{
*/
package jalview.io;
+import jalview.api.FeatureColourI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
-import jalview.io.gff.GffConstants;
import jalview.util.MessageManager;
+import jalview.util.StringUtils;
import jalview.util.UrlLink;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import java.util.Arrays;
import java.util.Collection;
/*
* Comparator to order DBRefEntry by Source + accession id (case-insensitive),
- * with 'Primary' sources placed before others
+ * with 'Primary' sources placed before others, and 'chromosome' first of all
*/
private static Comparator<DBRefEntry> comparator = new Comparator<DBRefEntry>()
{
@Override
public int compare(DBRefEntry ref1, DBRefEntry ref2)
{
+ if (ref1.isChromosome())
+ {
+ return -1;
+ }
+ if (ref2.isChromosome())
+ {
+ return 1;
+ }
String s1 = ref1.getSource();
String s2 = ref2.getSource();
boolean s1Primary = isPrimarySource(s1);
{
return 1;
}
- int comp = s1 == null ? -1
- : (s2 == null ? 1 : s1.compareToIgnoreCase(s2));
+ int comp = s1 == null ? -1 : (s2 == null ? 1 : s1
+ .compareToIgnoreCase(s2));
if (comp == 0)
{
String a1 = ref1.getAccessionId();
String a2 = ref2.getAccessionId();
- comp = a1 == null ? -1
- : (a2 == null ? 1 : a1.compareToIgnoreCase(a2));
+ comp = a1 == null ? -1 : (a2 == null ? 1 : a1
+ .compareToIgnoreCase(a2));
}
return comp;
}
}
};
- public SequenceAnnotationReport(String linkImageURL)
+ public SequenceAnnotationReport(String linkURL)
{
- this.linkImageURL = linkImageURL;
+ this.linkImageURL = linkURL;
}
/**
* @param minmax
*/
public void appendFeatures(final StringBuilder sb, int rpos,
- List<SequenceFeature> features, Map<String, float[][]> minmax)
+ List<SequenceFeature> features, FeatureRendererModel fr)
{
if (features != null)
{
for (SequenceFeature feature : features)
{
- appendFeature(sb, rpos, minmax, feature);
+ appendFeature(sb, rpos, fr, feature);
}
}
}
* @param feature
*/
void appendFeature(final StringBuilder sb, int rpos,
- Map<String, float[][]> minmax, SequenceFeature feature)
+ FeatureRendererModel fr, SequenceFeature feature)
{
if (feature.isContactFeature())
{
sb.append(feature.getType()).append(" ").append(feature.getBegin())
.append(":").append(feature.getEnd());
}
+ return;
}
- else
+
+ if (sb.length() > 6)
{
- if (sb.length() > 6)
+ sb.append("<br>");
+ }
+ // TODO: remove this hack to display link only features
+ boolean linkOnly = feature.getValue("linkonly") != null;
+ if (!linkOnly)
+ {
+ sb.append(feature.getType()).append(" ");
+ if (rpos != 0)
{
- sb.append("<br>");
+ // we are marking a positional feature
+ sb.append(feature.begin);
}
- // TODO: remove this hack to display link only features
- boolean linkOnly = feature.getValue("linkonly") != null;
- if (!linkOnly)
+ if (feature.begin != feature.end)
{
- sb.append(feature.getType()).append(" ");
- if (rpos != 0)
- {
- // we are marking a positional feature
- sb.append(feature.begin);
- }
- if (feature.begin != feature.end)
- {
- sb.append(" ").append(feature.end);
- }
+ sb.append(" ").append(feature.end);
+ }
- if (feature.getDescription() != null
- && !feature.description.equals(feature.getType()))
- {
- String tmpString = feature.getDescription();
- String tmp2up = tmpString.toUpperCase();
- int startTag = tmp2up.indexOf("<HTML>");
- if (startTag > -1)
- {
- tmpString = tmpString.substring(startTag + 6);
- tmp2up = tmp2up.substring(startTag + 6);
- }
- int endTag = tmp2up.indexOf("</BODY>");
- if (endTag > -1)
- {
- tmpString = tmpString.substring(0, endTag);
- tmp2up = tmp2up.substring(0, endTag);
- }
- endTag = tmp2up.indexOf("</HTML>");
- if (endTag > -1)
- {
- tmpString = tmpString.substring(0, endTag);
- }
+ String description = feature.getDescription();
+ if (description != null && !description.equals(feature.getType()))
+ {
+ description = StringUtils.stripHtmlTags(description);
+ sb.append("; ").append(description);
+ }
- if (startTag > -1)
- {
- sb.append("; ").append(tmpString);
- }
- else
- {
- if (tmpString.indexOf("<") > -1 || tmpString.indexOf(">") > -1)
- {
- // The description does not specify html is to
- // be used, so we must remove < > symbols
- tmpString = tmpString.replaceAll("<", "<");
- tmpString = tmpString.replaceAll(">", ">");
+ if (showScore(feature, fr))
+ {
+ sb.append(" Score=").append(String.valueOf(feature.getScore()));
+ }
+ String status = (String) feature.getValue("status");
+ if (status != null && status.length() > 0)
+ {
+ sb.append("; (").append(status).append(")");
+ }
- sb.append("; ");
- sb.append(tmpString);
- }
- else
- {
- sb.append("; ").append(tmpString);
- }
- }
- }
- // check score should be shown
- if (!Float.isNaN(feature.getScore()))
+ /*
+ * add attribute value if coloured by attribute
+ */
+ if (fr != null)
+ {
+ FeatureColourI fc = fr.getFeatureColours().get(feature.getType());
+ if (fc != null && fc.isColourByAttribute())
{
- float[][] rng = (minmax == null) ? null
- : minmax.get(feature.getType());
- if (rng != null && rng[0] != null && rng[0][0] != rng[0][1])
+ String[] attName = fc.getAttributeName();
+ String attVal = feature.getValueAsString(attName);
+ if (attVal != null)
{
- sb.append(" Score=").append(String.valueOf(feature.getScore()));
+ sb.append("; ").append(String.join(":", attName)).append("=")
+ .append(attVal);
}
}
- String status = (String) feature.getValue("status");
- if (status != null && status.length() > 0)
- {
- sb.append("; (").append(status).append(")");
- }
- String clinSig = (String) feature
- .getValue(GffConstants.CLINICAL_SIGNIFICANCE);
- if (clinSig != null)
- {
- sb.append("; ").append(clinSig);
- }
}
}
}
/**
+ * Answers true if score should be shown, else false. Score is shown if it is
+ * not NaN, and the feature type has a non-trivial min-max score range
+ */
+ boolean showScore(SequenceFeature feature, FeatureRendererModel fr)
+ {
+ if (Float.isNaN(feature.getScore()))
+ {
+ return false;
+ }
+ if (fr == null)
+ {
+ return true;
+ }
+ float[][] minMax = fr.getMinMax().get(feature.getType());
+
+ /*
+ * minMax[0] is the [min, max] score range for positional features
+ */
+ if (minMax == null || minMax[0] == null || minMax[0][0] == minMax[0][1])
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Format and appends any hyperlinks for the sequence feature to the string
* buffer
*
{
for (List<String> urllink : createLinksFrom(null, urlstring))
{
- sb.append("<br/> <a href=\"" + urllink.get(3) + "\" target=\""
- + urllink.get(0) + "\">"
+ sb.append("<br/> <a href=\""
+ + urllink.get(3)
+ + "\" target=\""
+ + urllink.get(0)
+ + "\">"
+ (urllink.get(0).toLowerCase()
- .equals(urllink.get(1).toLowerCase())
- ? urllink.get(0)
- : (urllink.get(0) + ":"
- + urllink.get(1)))
- + "</a></br>");
+ .equals(urllink.get(1).toLowerCase()) ? urllink
+ .get(0) : (urllink.get(0) + ":" + urllink
+ .get(1))) + "</a></br>");
}
} catch (Exception x)
{
- System.err.println(
- "problem when creating links from " + urlstring);
+ System.err.println("problem when creating links from "
+ + urlstring);
x.printStackTrace();
}
}
*/
Collection<List<String>> createLinksFrom(SequenceI seq, String link)
{
- Map<String, List<String>> urlSets = new LinkedHashMap<String, List<String>>();
+ Map<String, List<String>> urlSets = new LinkedHashMap<>();
UrlLink urlLink = new UrlLink(link);
if (!urlLink.isValid())
{
public void createSequenceAnnotationReport(final StringBuilder tip,
SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
- Map<String, float[][]> minmax)
+ FeatureRendererModel fr)
{
createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats,
- minmax, false);
+ fr, false);
}
/**
* whether to include database references for the sequence
* @param showNpFeats
* whether to include non-positional sequence features
- * @param minmax
+ * @param fr
* @param summary
* @return
*/
int createSequenceAnnotationReport(final StringBuilder sb,
SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
- Map<String, float[][]> minmax, boolean summary)
+ FeatureRendererModel fr, boolean summary)
{
String tmp;
sb.append("<i>");
{
ds = ds.getDatasetSequence();
}
-
+
if (showDbRefs)
{
maxWidth = Math.max(maxWidth, appendDbRefs(sb, ds, summary));
.getNonPositionalFeatures())
{
int sz = -sb.length();
- appendFeature(sb, 0, minmax, sf);
+ appendFeature(sb, 0, fr, sf);
sz += sb.length();
maxWidth = Math.max(maxWidth, sz);
}
}
if (moreSources)
{
- sb.append("<br>").append(source)
- .append(COMMA).append(ELLIPSIS);
+ sb.append("<br>").append(source).append(COMMA).append(ELLIPSIS);
}
if (ellipsis)
{
public void createTooltipAnnotationReport(final StringBuilder tip,
SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
- Map<String, float[][]> minmax)
+ FeatureRendererModel fr)
{
- int maxWidth = createSequenceAnnotationReport(tip, sequence, showDbRefs,
- showNpFeats, minmax, true);
+ int maxWidth = createSequenceAnnotationReport(tip, sequence,
+ showDbRefs, showNpFeats, fr, true);
if (maxWidth > 60)
{
public static final Regex DETECT_BRACKETS = new Regex(
"(<|>|\\[|\\]|\\(|\\)|\\{|\\})");
+ // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using NOT_RNASS first.
+ public static final String RNASS_BRACKETS = "<>[](){}AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
+
+ // use the following regex to decide an annotations (whole) line is NOT an RNA
+ // SS (it contains only E,H,e,h and other non-brace/non-alpha chars)
+ private static final Regex NOT_RNASS = new Regex(
+ "^[^<>[\\](){}A-DF-Za-df-z]*$");
+
StringBuffer out; // output buffer
AlignmentI al;
String version;
// String id;
Hashtable seqAnn = new Hashtable(); // Sequence related annotations
- LinkedHashMap<String, String> seqs = new LinkedHashMap<String, String>();
+ LinkedHashMap<String, String> seqs = new LinkedHashMap<>();
Regex p, r, rend, s, x;
// Temporary line for processing RNA annotation
// String RNAannot = "";
strucAnn = new Hashtable();
}
- Vector<AlignmentAnnotation> newStruc = new Vector<AlignmentAnnotation>();
+ Vector<AlignmentAnnotation> newStruc = new Vector<>();
parseAnnotationRow(newStruc, type, ns);
for (AlignmentAnnotation alan : newStruc)
{
private void guessDatabaseFor(Sequence seqO, String dbr, String dbsource)
{
DBRefEntry dbrf = null;
- List<DBRefEntry> dbrs = new ArrayList<DBRefEntry>();
+ List<DBRefEntry> dbrs = new ArrayList<>();
String seqdb = "Unknown", sdbac = "" + dbr;
int st = -1, en = -1, p;
if ((st = sdbac.indexOf("/")) > -1)
}
boolean ss = false, posterior = false;
type = id2type(type);
+
+ boolean isrnass = false;
if (type.equalsIgnoreCase("secondary structure"))
{
ss = true;
+ isrnass = !NOT_RNASS.search(annots); // sorry about the double negative
+ // here (it's easier for dealing with
+ // other non-alpha-non-brace chars)
}
if (type.equalsIgnoreCase("posterior probability"))
{
{
// if (" .-_".indexOf(pos) == -1)
{
- if (DETECT_BRACKETS.search(pos))
+ if (isrnass && RNASS_BRACKETS.indexOf(pos) >= 0)
{
ann.secondaryStructure = Rna.getRNASecStrucState(pos).charAt(0);
ann.displayCharacter = "" + pos.charAt(0);
String ch = (annot == null)
? ((sequenceI == null) ? "-"
: Character.toString(sequenceI.getCharAt(k)))
- : annot.displayCharacter;
+ : (annot.displayCharacter == null
+ ? String.valueOf(annot.secondaryStructure)
+ : annot.displayCharacter);
+ if (ch == null)
+ {
+ ch = " ";
+ }
if (key != null && key.equals("SS"))
{
+ char ssannotchar = ' ';
+ boolean charset = false;
if (annot == null)
{
// sensible gap character
- return ' ';
+ ssannotchar = ' ';
+ charset = true;
}
else
{
// valid secondary structure AND no alternative label (e.g. ' B')
if (annot.secondaryStructure > ' ' && ch.length() < 2)
{
- return annot.secondaryStructure;
+ ssannotchar = annot.secondaryStructure;
+ charset = true;
}
}
+ if (charset)
+ {
+ return (ssannotchar == ' ' && isrna) ? '.' : ssannotchar;
+ }
}
if (ch.length() == 0)
{
seq = ch.charAt(1);
}
- return seq;
+
+ return (seq == ' ' && key != null && key.equals("SS") && isrna) ? '.'
+ : seq;
}
public String print()
import jalview.bin.Cache;
import jalview.util.MessageManager;
-import java.awt.Color;
-import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Set;
-import javax.swing.BorderFactory;
import javax.swing.JComboBox;
-import javax.swing.JLabel;
import javax.swing.JMenuItem;
-import javax.swing.JPanel;
import javax.swing.JPopupMenu;
-import javax.swing.JTextField;
import javax.swing.SwingUtilities;
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.PlainDocument;
public class JvCacheableInputBox<E> extends JComboBox<String>
{
private static final long serialVersionUID = 5774610435079326695L;
- private static final int INPUT_LIMIT = 2;
-
private static final int LEFT_BOARDER_WIDTH = 16;
private String cacheKey;
private AppCache appCache;
- private JPanel pnlDefaultCache = new JPanel();
-
- private JLabel lblDefaultCacheSize = new JLabel();
-
- private JTextField txtDefaultCacheSize = new JTextField();
-
private JPopupMenu popup = new JPopupMenu();
private JMenuItem menuItemClearCache = new JMenuItem();
}
/**
- * Method for initialising cache items for a given cache key and populating
- * the in-memory cache with persisted cache items
+ * Method for initialising cache items for a given cache key and populating the
+ * in-memory cache with persisted cache items
*
* @param cacheKey
*/
.getAllCachedItemsFor(cacheKey);
if (foundCacheItems == null)
{
- foundCacheItems = new LinkedHashSet<String>();
+ foundCacheItems = new LinkedHashSet<>();
}
// populate memory cache
for (String cacheItem : persistedCacheItems)
*/
private void initCachePopupMenu()
{
- pnlDefaultCache.setBackground(Color.WHITE);
- // pad panel so as to align with other menu items
- pnlDefaultCache.setBorder(
- BorderFactory.createEmptyBorder(0, LEFT_BOARDER_WIDTH, 0, 0));
- txtDefaultCacheSize.setPreferredSize(new Dimension(45, 20));
- txtDefaultCacheSize.setFont(new java.awt.Font("Verdana", 0, 12));
- lblDefaultCacheSize
- .setText(MessageManager.getString("label.default_cache_size"));
- lblDefaultCacheSize.setFont(new java.awt.Font("Verdana", 0, 12));
- // Force input to accept only Integer entries up to length - INPUT_LIMIT
- txtDefaultCacheSize.setDocument(new PlainDocument()
- {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void insertString(int offs, String str, AttributeSet a)
- throws BadLocationException
- {
- if (getLength() + str.length() <= INPUT_LIMIT && isInteger(str))
- {
- super.insertString(offs, str, a);
- }
- }
- });
- txtDefaultCacheSize.addKeyListener(new java.awt.event.KeyAdapter()
- {
- @Override
- public void keyPressed(KeyEvent e)
- {
- if (e.getKeyCode() == KeyEvent.VK_ENTER)
- {
- e.consume();
- updateCache();
- closePopup();
- }
- }
- });
-
- txtDefaultCacheSize.setText(appCache.getCacheLimit(cacheKey));
- pnlDefaultCache.add(lblDefaultCacheSize);
menuItemClearCache.setFont(new java.awt.Font("Verdana", 0, 12));
- pnlDefaultCache.add(txtDefaultCacheSize);
menuItemClearCache
.setText(MessageManager.getString("action.clear_cached_items"));
menuItemClearCache.addActionListener(new ActionListener()
}
});
- popup.insert(pnlDefaultCache, 0);
popup.add(menuItemClearCache);
setComponentPopupMenu(popup);
add(popup);
}
- private void closePopup()
- {
- popup.setVisible(false);
- popup.transferFocus();
- }
-
/**
* Answers true if input text is an integer
*
@Override
public void run()
{
- int userLimit = txtDefaultCacheSize.getText().trim().isEmpty()
- ? Integer.valueOf(AppCache.DEFAULT_LIMIT)
- : Integer.valueOf(txtDefaultCacheSize.getText());
- int cacheLimit = appCache.updateCacheLimit(cacheKey, userLimit);
+ int cacheLimit = Integer.parseInt(appCache.getCacheLimit(cacheKey));
String userInput = getUserInput();
if (userInput != null && !userInput.isEmpty())
{
removeAllItems();
}
Set<String> cacheItems = appCache.getAllCachedItemsFor(cacheKey);
- List<String> reversedCacheItems = new ArrayList<String>();
+ List<String> reversedCacheItems = new ArrayList<>();
reversedCacheItems.addAll(cacheItems);
cacheItems = null;
Collections.reverse(reversedCacheItems);
public void persistCache()
{
appCache.persistCache(cacheKey);
- int userLimit = txtDefaultCacheSize.getText().trim().isEmpty()
- ? Integer.valueOf(AppCache.DEFAULT_LIMIT)
- : Integer.valueOf(txtDefaultCacheSize.getText());
- appCache.updateCacheLimit(cacheKey, userLimit);
}
/**
*/
public class Gff3Helper extends GffHelperBase
{
+ public static final String ALLELES = "alleles";
+
protected static final String TARGET = "Target";
protected static final String ID = "ID";
/*
* Ensembl returns dna variants as 'alleles'
*/
- desc = StringUtils.listToDelimitedString(attributes.get("alleles"),
+ desc = StringUtils.listToDelimitedString(attributes.get(ALLELES),
",");
}
// SO:0001060
public static final String SEQUENCE_VARIANT = "sequence_variant";
+ // SO:0001819
+ public static final String SYNONYMOUS_VARIANT = "synonymous_variant";
+
+ // SO:0001992
+ public static final String NONSYNONYMOUS_VARIANT = "nonsynonymous_variant";
+
+ // SO:0001587
+ public static final String STOP_GAINED = "stop_gained";
+
// SO:0000147
public static final String EXON = "exon";
* initial selection of types of interest when processing Ensembl features
* NB unlike the full SequenceOntology we don't traverse indirect
* child-parent relationships here so e.g. need to list every sub-type
- * of gene (direct or indirect) that is of interest
+ * (direct or indirect) that is of interest
*/
// @formatter:off
private final String[][] TERMS = new String[][] {
// there are many more sub-types of ncRNA...
/*
- * sequence_variant sub-types:
+ * sequence_variant sub-types
*/
{ "sequence_variant", "sequence_variant" },
+ { "structural_variant", "sequence_variant" },
{ "feature_variant", "sequence_variant" },
{ "gene_variant", "sequence_variant" },
+ { "transcript_variant", "sequence_variant" },
// NB Ensembl uses NMD_transcript_variant as if a 'transcript'
// but we model it here correctly as per the SO
{ "NMD_transcript_variant", "sequence_variant" },
- { "transcript_variant", "sequence_variant" },
- { "structural_variant", "sequence_variant" },
+ { "missense_variant", "sequence_variant" },
+ { "synonymous_variant", "sequence_variant" },
+ { "frameshift_variant", "sequence_variant" },
+ { "5_prime_UTR_variant", "sequence_variant" },
+ { "3_prime_UTR_variant", "sequence_variant" },
+ { "stop_gained", "sequence_variant" },
+ { "stop_lost", "sequence_variant" },
+ { "inframe_deletion", "sequence_variant" },
+ { "inframe_insertion", "sequence_variant" },
+ { "splice_region_variant", "sequence_variant" },
/*
* no sub-types of exon or CDS yet seen in Ensembl
public SequenceOntologyLite()
{
- termsFound = new ArrayList<String>();
- termsNotFound = new ArrayList<String>();
+ termsFound = new ArrayList<>();
+ termsNotFound = new ArrayList<>();
loadStaticData();
}
*/
private void loadStaticData()
{
- parents = new HashMap<String, List<String>>();
+ parents = new HashMap<>();
for (String[] pair : TERMS)
{
List<String> p = parents.get(pair[0]);
if (p == null)
{
- p = new ArrayList<String>();
+ p = new ArrayList<>();
parents.put(pair[0], p);
}
p.add(pair[1]);
--- /dev/null
+package jalview.io.vcf;
+
+import jalview.analysis.AlignmentUtils;
+import jalview.analysis.Dna;
+import jalview.api.AlignViewControllerGuiI;
+import jalview.bin.Cache;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.GeneLociI;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureAttributeType;
+import jalview.datamodel.features.FeatureSource;
+import jalview.datamodel.features.FeatureSources;
+import jalview.ext.ensembl.EnsemblMap;
+import jalview.ext.htsjdk.HtsContigDb;
+import jalview.ext.htsjdk.VCFReader;
+import jalview.io.gff.Gff3Helper;
+import jalview.io.gff.SequenceOntologyI;
+import jalview.util.MapList;
+import jalview.util.MappingUtils;
+import jalview.util.MessageManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import htsjdk.samtools.SAMException;
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import htsjdk.variant.vcf.VCFHeaderLineCount;
+import htsjdk.variant.vcf.VCFHeaderLineType;
+import htsjdk.variant.vcf.VCFInfoHeaderLine;
+
+/**
+ * A class to read VCF data (using the htsjdk) and add variants as sequence
+ * features on dna and any related protein product sequences
+ *
+ * @author gmcarstairs
+ */
+public class VCFLoader
+{
+ /**
+ * A class to model the mapping from sequence to VCF coordinates. Cases include
+ * <ul>
+ * <li>a direct 1:1 mapping where the sequence is one of the VCF contigs</li>
+ * <li>a mapping of sequence to chromosomal coordinates, where sequence and VCF
+ * use the same reference assembly</li>
+ * <li>a modified mapping of sequence to chromosomal coordinates, where sequence
+ * and VCF use different reference assembles</li>
+ * </ul>
+ */
+ class VCFMap
+ {
+ final String chromosome;
+
+ final MapList map;
+
+ VCFMap(String chr, MapList m)
+ {
+ chromosome = chr;
+ map = m;
+ }
+
+ @Override
+ public String toString()
+ {
+ return chromosome + ":" + map.toString();
+ }
+ }
+
+ /*
+ * Lookup keys, and default values, for Preference entries that describe
+ * patterns for VCF and VEP fields to capture
+ */
+ private static final String VEP_FIELDS_PREF = "VEP_FIELDS";
+
+ private static final String VCF_FIELDS_PREF = "VCF_FIELDS";
+
+ private static final String DEFAULT_VCF_FIELDS = ".*";
+
+ private static final String DEFAULT_VEP_FIELDS = ".*";// "Allele,Consequence,IMPACT,SWISSPROT,SIFT,PolyPhen,CLIN_SIG";
+
+ /*
+ * keys to fields of VEP CSQ consequence data
+ * see https://www.ensembl.org/info/docs/tools/vep/vep_formats.html
+ */
+ private static final String CSQ_CONSEQUENCE_KEY = "Consequence";
+ private static final String CSQ_ALLELE_KEY = "Allele";
+ private static final String CSQ_ALLELE_NUM_KEY = "ALLELE_NUM"; // 0 (ref), 1...
+ private static final String CSQ_FEATURE_KEY = "Feature"; // Ensembl stable id
+
+ /*
+ * default VCF INFO key for VEP consequence data
+ * NB this can be overridden running VEP with --vcf_info_field
+ * - we don't handle this case (require identifier to be CSQ)
+ */
+ private static final String CSQ_FIELD = "CSQ";
+
+ /*
+ * separator for fields in consequence data is '|'
+ */
+ private static final String PIPE_REGEX = "\\|";
+
+ /*
+ * key for Allele Frequency output by VEP
+ * see http://www.ensembl.org/info/docs/tools/vep/vep_formats.html
+ */
+ private static final String ALLELE_FREQUENCY_KEY = "AF";
+
+ /*
+ * delimiter that separates multiple consequence data blocks
+ */
+ private static final String COMMA = ",";
+
+ /*
+ * the feature group assigned to a VCF variant in Jalview
+ */
+ private static final String FEATURE_GROUP_VCF = "VCF";
+
+ /*
+ * internal delimiter used to build keys for assemblyMappings
+ *
+ */
+ private static final String EXCL = "!";
+
+ /*
+ * the VCF file we are processing
+ */
+ protected String vcfFilePath;
+
+ /*
+ * mappings between VCF and sequence reference assembly regions, as
+ * key = "species!chromosome!fromAssembly!toAssembly
+ * value = Map{fromRange, toRange}
+ */
+ private Map<String, Map<int[], int[]>> assemblyMappings;
+
+ private VCFReader reader;
+
+ /*
+ * holds details of the VCF header lines (metadata)
+ */
+ private VCFHeader header;
+
+ /*
+ * a Dictionary of contigs (if present) referenced in the VCF file
+ */
+ private SAMSequenceDictionary dictionary;
+
+ /*
+ * the position (0...) of field in each block of
+ * CSQ (consequence) data (if declared in the VCF INFO header for CSQ)
+ * see http://www.ensembl.org/info/docs/tools/vep/vep_formats.html
+ */
+ private int csqConsequenceFieldIndex = -1;
+ private int csqAlleleFieldIndex = -1;
+ private int csqAlleleNumberFieldIndex = -1;
+ private int csqFeatureFieldIndex = -1;
+
+ // todo the same fields for SnpEff ANN data if wanted
+ // see http://snpeff.sourceforge.net/SnpEff_manual.html#input
+
+ /*
+ * a unique identifier under which to save metadata about feature
+ * attributes (selected INFO field data)
+ */
+ private String sourceId;
+
+ /*
+ * The INFO IDs of data that is both present in the VCF file, and
+ * also matched by any filters for data of interest
+ */
+ List<String> vcfFieldsOfInterest;
+
+ /*
+ * The field offsets and identifiers for VEP (CSQ) data that is both present
+ * in the VCF file, and also matched by any filters for data of interest
+ * for example 0 -> Allele, 1 -> Consequence, ..., 36 -> SIFT, ...
+ */
+ Map<Integer, String> vepFieldsOfInterest;
+
+ /**
+ * Constructor given a VCF file
+ *
+ * @param alignment
+ */
+ public VCFLoader(String vcfFile)
+ {
+ try
+ {
+ initialise(vcfFile);
+ } catch (IOException e)
+ {
+ System.err.println("Error opening VCF file: " + e.getMessage());
+ }
+
+ // map of species!chromosome!fromAssembly!toAssembly to {fromRange, toRange}
+ assemblyMappings = new HashMap<>();
+ }
+
+ /**
+ * Starts a new thread to query and load VCF variant data on to the given
+ * sequences
+ * <p>
+ * This method is not thread safe - concurrent threads should use separate
+ * instances of this class.
+ *
+ * @param seqs
+ * @param gui
+ */
+ public void loadVCF(SequenceI[] seqs, final AlignViewControllerGuiI gui)
+ {
+ if (gui != null)
+ {
+ gui.setStatus(MessageManager.getString("label.searching_vcf"));
+ }
+
+ new Thread()
+ {
+ @Override
+ public void run()
+ {
+ VCFLoader.this.doLoad(seqs, gui);
+ }
+ }.start();
+ }
+
+ /**
+ * Reads the specified contig sequence and adds its VCF variants to it
+ *
+ * @param contig
+ * the id of a single sequence (contig) to load
+ * @return
+ */
+ public SequenceI loadVCFContig(String contig)
+ {
+ String ref = header.getOtherHeaderLine(VCFHeader.REFERENCE_KEY)
+ .getValue();
+ if (ref.startsWith("file://"))
+ {
+ ref = ref.substring(7);
+ }
+
+ SequenceI seq = null;
+ File dbFile = new File(ref);
+
+ if (dbFile.exists())
+ {
+ HtsContigDb db = new HtsContigDb("", dbFile);
+ seq = db.getSequenceProxy(contig);
+ loadSequenceVCF(seq, ref);
+ db.close();
+ }
+ else
+ {
+ System.err.println("VCF reference not found: " + ref);
+ }
+
+ return seq;
+ }
+
+ /**
+ * Loads VCF on to one or more sequences
+ *
+ * @param seqs
+ * @param gui
+ * optional callback handler for messages
+ */
+ protected void doLoad(SequenceI[] seqs, AlignViewControllerGuiI gui)
+ {
+ try
+ {
+ VCFHeaderLine ref = header
+ .getOtherHeaderLine(VCFHeader.REFERENCE_KEY);
+ String vcfAssembly = ref.getValue();
+
+ int varCount = 0;
+ int seqCount = 0;
+
+ /*
+ * query for VCF overlapping each sequence in turn
+ */
+ for (SequenceI seq : seqs)
+ {
+ int added = loadSequenceVCF(seq, vcfAssembly);
+ if (added > 0)
+ {
+ seqCount++;
+ varCount += added;
+ transferAddedFeatures(seq);
+ }
+ }
+ if (gui != null)
+ {
+ String msg = MessageManager.formatMessage("label.added_vcf",
+ varCount, seqCount);
+ gui.setStatus(msg);
+ if (gui.getFeatureSettingsUI() != null)
+ {
+ gui.getFeatureSettingsUI().discoverAllFeatureData();
+ }
+ }
+ } catch (Throwable e)
+ {
+ System.err.println("Error processing VCF: " + e.getMessage());
+ e.printStackTrace();
+ if (gui != null)
+ {
+ gui.setStatus("Error occurred - see console for details");
+ }
+ } finally
+ {
+ if (reader != null)
+ {
+ try
+ {
+ reader.close();
+ } catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ header = null;
+ dictionary = null;
+ }
+ }
+
+ /**
+ * Opens the VCF file and parses header data
+ *
+ * @param filePath
+ * @throws IOException
+ */
+ private void initialise(String filePath) throws IOException
+ {
+ vcfFilePath = filePath;
+
+ reader = new VCFReader(filePath);
+
+ header = reader.getFileHeader();
+
+ try
+ {
+ dictionary = header.getSequenceDictionary();
+ } catch (SAMException e)
+ {
+ // ignore - thrown if any contig line lacks length info
+ }
+
+ sourceId = filePath;
+
+ saveMetadata(sourceId);
+
+ /*
+ * get offset of CSQ ALLELE_NUM and Feature if declared
+ */
+ parseCsqHeader();
+ }
+
+ /**
+ * Reads metadata (such as INFO field descriptions and datatypes) and saves
+ * them for future reference
+ *
+ * @param theSourceId
+ */
+ void saveMetadata(String theSourceId)
+ {
+ List<Pattern> vcfFieldPatterns = getFieldMatchers(VCF_FIELDS_PREF,
+ DEFAULT_VCF_FIELDS);
+ vcfFieldsOfInterest = new ArrayList<>();
+
+ FeatureSource metadata = new FeatureSource(theSourceId);
+
+ for (VCFInfoHeaderLine info : header.getInfoHeaderLines())
+ {
+ String attributeId = info.getID();
+ String desc = info.getDescription();
+ VCFHeaderLineType type = info.getType();
+ FeatureAttributeType attType = null;
+ switch (type)
+ {
+ case Character:
+ attType = FeatureAttributeType.Character;
+ break;
+ case Flag:
+ attType = FeatureAttributeType.Flag;
+ break;
+ case Float:
+ attType = FeatureAttributeType.Float;
+ break;
+ case Integer:
+ attType = FeatureAttributeType.Integer;
+ break;
+ case String:
+ attType = FeatureAttributeType.String;
+ break;
+ }
+ metadata.setAttributeName(attributeId, desc);
+ metadata.setAttributeType(attributeId, attType);
+
+ if (isFieldWanted(attributeId, vcfFieldPatterns))
+ {
+ vcfFieldsOfInterest.add(attributeId);
+ }
+ }
+
+ FeatureSources.getInstance().addSource(theSourceId, metadata);
+ }
+
+ /**
+ * Answers true if the field id is matched by any of the filter patterns, else
+ * false. Matching is against regular expression patterns, and is not
+ * case-sensitive.
+ *
+ * @param id
+ * @param filters
+ * @return
+ */
+ private boolean isFieldWanted(String id, List<Pattern> filters)
+ {
+ for (Pattern p : filters)
+ {
+ if (p.matcher(id.toUpperCase()).matches())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Records 'wanted' fields defined in the CSQ INFO header (if there is one).
+ * Also records the position of selected fields (Allele, ALLELE_NUM, Feature)
+ * required for processing.
+ * <p>
+ * CSQ fields are declared in the CSQ INFO Description e.g.
+ * <p>
+ * Description="Consequence ...from ... VEP. Format: Allele|Consequence|...
+ */
+ protected void parseCsqHeader()
+ {
+ List<Pattern> vepFieldFilters = getFieldMatchers(VEP_FIELDS_PREF,
+ DEFAULT_VEP_FIELDS);
+ vepFieldsOfInterest = new HashMap<>();
+
+ VCFInfoHeaderLine csqInfo = header.getInfoHeaderLine(CSQ_FIELD);
+ if (csqInfo == null)
+ {
+ return;
+ }
+
+ /*
+ * parse out the pipe-separated list of CSQ fields; we assume here that
+ * these form the last part of the description, and contain no spaces
+ */
+ String desc = csqInfo.getDescription();
+ int spacePos = desc.lastIndexOf(" ");
+ desc = desc.substring(spacePos + 1);
+
+ if (desc != null)
+ {
+ String[] format = desc.split(PIPE_REGEX);
+ int index = 0;
+ for (String field : format)
+ {
+ if (CSQ_CONSEQUENCE_KEY.equals(field))
+ {
+ csqConsequenceFieldIndex = index;
+ }
+ if (CSQ_ALLELE_NUM_KEY.equals(field))
+ {
+ csqAlleleNumberFieldIndex = index;
+ }
+ if (CSQ_ALLELE_KEY.equals(field))
+ {
+ csqAlleleFieldIndex = index;
+ }
+ if (CSQ_FEATURE_KEY.equals(field))
+ {
+ csqFeatureFieldIndex = index;
+ }
+
+ if (isFieldWanted(field, vepFieldFilters))
+ {
+ vepFieldsOfInterest.put(index, field);
+ }
+
+ index++;
+ }
+ }
+ }
+
+ /**
+ * Reads the Preference value for the given key, with default specified if no
+ * preference set. The value is interpreted as a comma-separated list of
+ * regular expressions, and converted into a list of compiled patterns ready
+ * for matching. Patterns are forced to upper-case for non-case-sensitive
+ * matching.
+ * <p>
+ * This supports user-defined filters for fields of interest to capture while
+ * processing data. For example, VCF_FIELDS = AF,AC* would mean that VCF INFO
+ * fields with an ID of AF, or starting with AC, would be matched.
+ *
+ * @param key
+ * @param def
+ * @return
+ */
+ private List<Pattern> getFieldMatchers(String key, String def)
+ {
+ String pref = Cache.getDefault(key, def);
+ List<Pattern> patterns = new ArrayList<>();
+ String[] tokens = pref.split(",");
+ for (String token : tokens)
+ {
+ try
+ {
+ patterns.add(Pattern.compile(token.toUpperCase()));
+ } catch (PatternSyntaxException e)
+ {
+ System.err.println("Invalid pattern ignored: " + token);
+ }
+ }
+ return patterns;
+ }
+
+ /**
+ * Transfers VCF features to sequences to which this sequence has a mapping.
+ * If the mapping is 3:1, computes peptide variants from nucleotide variants.
+ *
+ * @param seq
+ */
+ protected void transferAddedFeatures(SequenceI seq)
+ {
+ DBRefEntry[] dbrefs = seq.getDBRefs();
+ if (dbrefs == null)
+ {
+ return;
+ }
+ for (DBRefEntry dbref : dbrefs)
+ {
+ Mapping mapping = dbref.getMap();
+ if (mapping == null || mapping.getTo() == null)
+ {
+ continue;
+ }
+
+ SequenceI mapTo = mapping.getTo();
+ MapList map = mapping.getMap();
+ if (map.getFromRatio() == 3)
+ {
+ /*
+ * dna-to-peptide product mapping
+ */
+ AlignmentUtils.computeProteinFeatures(seq, mapTo, map);
+ }
+ else
+ {
+ /*
+ * nucleotide-to-nucleotide mapping e.g. transcript to CDS
+ */
+ List<SequenceFeature> features = seq.getFeatures()
+ .getPositionalFeatures(SequenceOntologyI.SEQUENCE_VARIANT);
+ for (SequenceFeature sf : features)
+ {
+ if (FEATURE_GROUP_VCF.equals(sf.getFeatureGroup()))
+ {
+ transferFeature(sf, mapTo, map);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Tries to add overlapping variants read from a VCF file to the given sequence,
+ * and returns the number of variant features added
+ *
+ * @param seq
+ * @param vcfAssembly
+ * @return
+ */
+ protected int loadSequenceVCF(SequenceI seq, String vcfAssembly)
+ {
+ VCFMap vcfMap = getVcfMap(seq, vcfAssembly);
+ if (vcfMap == null)
+ {
+ return 0;
+ }
+
+ /*
+ * work with the dataset sequence here
+ */
+ SequenceI dss = seq.getDatasetSequence();
+ if (dss == null)
+ {
+ dss = seq;
+ }
+ return addVcfVariants(dss, vcfMap);
+ }
+
+ /**
+ * Answers a map from sequence coordinates to VCF chromosome ranges
+ *
+ * @param seq
+ * @param vcfAssembly
+ * @return
+ */
+ private VCFMap getVcfMap(SequenceI seq, String vcfAssembly)
+ {
+ /*
+ * simplest case: sequence has id and length matching a VCF contig
+ */
+ VCFMap vcfMap = null;
+ if (dictionary != null)
+ {
+ vcfMap = getContigMap(seq);
+ }
+ if (vcfMap != null)
+ {
+ return vcfMap;
+ }
+
+ /*
+ * otherwise, map to VCF from chromosomal coordinates
+ * of the sequence (if known)
+ */
+ GeneLociI seqCoords = seq.getGeneLoci();
+ if (seqCoords == null)
+ {
+ Cache.log.warn(String.format(
+ "Can't query VCF for %s as chromosome coordinates not known",
+ seq.getName()));
+ return null;
+ }
+
+ String species = seqCoords.getSpeciesId();
+ String chromosome = seqCoords.getChromosomeId();
+ String seqRef = seqCoords.getAssemblyId();
+ MapList map = seqCoords.getMap();
+
+ if (!vcfSpeciesMatchesSequence(vcfAssembly, species))
+ {
+ return null;
+ }
+
+ if (vcfAssemblyMatchesSequence(vcfAssembly, seqRef))
+ {
+ return new VCFMap(chromosome, map);
+ }
+
+ if (!"GRCh38".equalsIgnoreCase(seqRef) // Ensembl
+ || !vcfAssembly.contains("Homo_sapiens_assembly19")) // gnomAD
+ {
+ return null;
+ }
+
+ /*
+ * map chromosomal coordinates from sequence to VCF if the VCF
+ * data has a different reference assembly to the sequence
+ */
+ // TODO generalise for cases other than GRCh38 -> GRCh37 !
+ // - or get the user to choose in a dialog
+
+ List<int[]> toVcfRanges = new ArrayList<>();
+ List<int[]> fromSequenceRanges = new ArrayList<>();
+ String toRef = "GRCh37";
+
+ for (int[] range : map.getToRanges())
+ {
+ int[] fromRange = map.locateInFrom(range[0], range[1]);
+ if (fromRange == null)
+ {
+ // corrupted map?!?
+ continue;
+ }
+
+ int[] newRange = mapReferenceRange(range, chromosome, "human", seqRef,
+ toRef);
+ if (newRange == null)
+ {
+ Cache.log.error(
+ String.format("Failed to map %s:%s:%s:%d:%d to %s", species,
+ chromosome, seqRef, range[0], range[1], toRef));
+ continue;
+ }
+ else
+ {
+ toVcfRanges.add(newRange);
+ fromSequenceRanges.add(fromRange);
+ }
+ }
+
+ return new VCFMap(chromosome,
+ new MapList(fromSequenceRanges, toVcfRanges, 1, 1));
+ }
+
+ /**
+ * If the sequence id matches a contig declared in the VCF file, and the
+ * sequence length matches the contig length, then returns a 1:1 map of the
+ * sequence to the contig, else returns null
+ *
+ * @param seq
+ * @return
+ */
+ private VCFMap getContigMap(SequenceI seq)
+ {
+ String id = seq.getName();
+ SAMSequenceRecord contig = dictionary.getSequence(id);
+ if (contig != null)
+ {
+ int len = seq.getLength();
+ if (len == contig.getSequenceLength())
+ {
+ MapList map = new MapList(new int[] { 1, len },
+ new int[]
+ { 1, len }, 1, 1);
+ return new VCFMap(id, map);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Answers true if we determine that the VCF data uses the same reference
+ * assembly as the sequence, else false
+ *
+ * @param vcfAssembly
+ * @param seqRef
+ * @return
+ */
+ private boolean vcfAssemblyMatchesSequence(String vcfAssembly,
+ String seqRef)
+ {
+ // TODO improve on this stub, which handles gnomAD and
+ // hopes for the best for other cases
+
+ if ("GRCh38".equalsIgnoreCase(seqRef) // Ensembl
+ && vcfAssembly.contains("Homo_sapiens_assembly19")) // gnomAD
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Answers true if the species inferred from the VCF reference identifier
+ * matches that for the sequence
+ *
+ * @param vcfAssembly
+ * @param speciesId
+ * @return
+ */
+ boolean vcfSpeciesMatchesSequence(String vcfAssembly, String speciesId)
+ {
+ // PROBLEM 1
+ // there are many aliases for species - how to equate one with another?
+ // PROBLEM 2
+ // VCF ##reference header is an unstructured URI - how to extract species?
+ // perhaps check if ref includes any (Ensembl) alias of speciesId??
+ // TODO ask the user to confirm this??
+
+ if (vcfAssembly.contains("Homo_sapiens") // gnomAD exome data example
+ && "HOMO_SAPIENS".equals(speciesId)) // Ensembl species id
+ {
+ return true;
+ }
+
+ if (vcfAssembly.contains("c_elegans") // VEP VCF response example
+ && "CAENORHABDITIS_ELEGANS".equals(speciesId)) // Ensembl
+ {
+ return true;
+ }
+
+ // this is not a sustainable solution...
+
+ return false;
+ }
+
+ /**
+ * Queries the VCF reader for any variants that overlap the mapped chromosome
+ * ranges of the sequence, and adds as variant features. Returns the number of
+ * overlapping variants found.
+ *
+ * @param seq
+ * @param map
+ * mapping from sequence to VCF coordinates
+ * @return
+ */
+ protected int addVcfVariants(SequenceI seq, VCFMap map)
+ {
+ boolean forwardStrand = map.map.isToForwardStrand();
+
+ /*
+ * query the VCF for overlaps of each contiguous chromosomal region
+ */
+ int count = 0;
+
+ for (int[] range : map.map.getToRanges())
+ {
+ int vcfStart = Math.min(range[0], range[1]);
+ int vcfEnd = Math.max(range[0], range[1]);
+ CloseableIterator<VariantContext> variants = reader
+ .query(map.chromosome, vcfStart, vcfEnd);
+ while (variants.hasNext())
+ {
+ VariantContext variant = variants.next();
+
+ int[] featureRange = map.map.locateInFrom(variant.getStart(),
+ variant.getEnd());
+
+ if (featureRange != null)
+ {
+ int featureStart = Math.min(featureRange[0], featureRange[1]);
+ int featureEnd = Math.max(featureRange[0], featureRange[1]);
+ count += addAlleleFeatures(seq, variant, featureStart, featureEnd,
+ forwardStrand);
+ }
+ }
+ variants.close();
+ }
+
+ return count;
+ }
+
+ /**
+ * A convenience method to get the AF value for the given alternate allele
+ * index
+ *
+ * @param variant
+ * @param alleleIndex
+ * @return
+ */
+ protected float getAlleleFrequency(VariantContext variant, int alleleIndex)
+ {
+ float score = 0f;
+ String attributeValue = getAttributeValue(variant,
+ ALLELE_FREQUENCY_KEY, alleleIndex);
+ if (attributeValue != null)
+ {
+ try
+ {
+ score = Float.parseFloat(attributeValue);
+ } catch (NumberFormatException e)
+ {
+ // leave as 0
+ }
+ }
+
+ return score;
+ }
+
+ /**
+ * A convenience method to get an attribute value for an alternate allele
+ *
+ * @param variant
+ * @param attributeName
+ * @param alleleIndex
+ * @return
+ */
+ protected String getAttributeValue(VariantContext variant,
+ String attributeName, int alleleIndex)
+ {
+ Object att = variant.getAttribute(attributeName);
+
+ if (att instanceof String)
+ {
+ return (String) att;
+ }
+ else if (att instanceof ArrayList)
+ {
+ return ((List<String>) att).get(alleleIndex);
+ }
+
+ return null;
+ }
+
+ /**
+ * Adds one variant feature for each allele in the VCF variant record, and
+ * returns the number of features added.
+ *
+ * @param seq
+ * @param variant
+ * @param featureStart
+ * @param featureEnd
+ * @param forwardStrand
+ * @return
+ */
+ protected int addAlleleFeatures(SequenceI seq, VariantContext variant,
+ int featureStart, int featureEnd, boolean forwardStrand)
+ {
+ int added = 0;
+
+ /*
+ * Javadoc says getAlternateAlleles() imposes no order on the list returned
+ * so we proceed defensively to get them in strict order
+ */
+ int altAlleleCount = variant.getAlternateAlleles().size();
+ for (int i = 0; i < altAlleleCount; i++)
+ {
+ added += addAlleleFeature(seq, variant, i, featureStart, featureEnd,
+ forwardStrand);
+ }
+ return added;
+ }
+
+ /**
+ * Inspects one allele and attempts to add a variant feature for it to the
+ * sequence. The additional data associated with this allele is extracted to
+ * store in the feature's key-value map. Answers the number of features added (0
+ * or 1).
+ *
+ * @param seq
+ * @param variant
+ * @param altAlleleIndex
+ * (0, 1..)
+ * @param featureStart
+ * @param featureEnd
+ * @param forwardStrand
+ * @return
+ */
+ protected int addAlleleFeature(SequenceI seq, VariantContext variant,
+ int altAlleleIndex, int featureStart, int featureEnd,
+ boolean forwardStrand)
+ {
+ String reference = variant.getReference().getBaseString();
+ Allele alt = variant.getAlternateAllele(altAlleleIndex);
+ String allele = alt.getBaseString();
+
+ /*
+ * insertion after a genomic base, if on reverse strand, has to be
+ * converted to insertion of complement after the preceding position
+ */
+ int referenceLength = reference.length();
+ if (!forwardStrand && allele.length() > referenceLength
+ && allele.startsWith(reference))
+ {
+ featureStart -= referenceLength;
+ featureEnd = featureStart;
+ char insertAfter = seq.getCharAt(featureStart - seq.getStart());
+ reference = Dna.reverseComplement(String.valueOf(insertAfter));
+ allele = allele.substring(referenceLength) + reference;
+ }
+
+ /*
+ * build the ref,alt allele description e.g. "G,A", using the base
+ * complement if the sequence is on the reverse strand
+ */
+ StringBuilder sb = new StringBuilder();
+ sb.append(forwardStrand ? reference : Dna.reverseComplement(reference));
+ sb.append(COMMA);
+ sb.append(forwardStrand ? allele : Dna.reverseComplement(allele));
+ String alleles = sb.toString(); // e.g. G,A
+
+ /*
+ * pick out the consequence data (if any) that is for the current allele
+ * and feature (transcript) that matches the current sequence
+ */
+ String consequence = getConsequenceForAlleleAndFeature(variant, CSQ_FIELD,
+ altAlleleIndex, csqAlleleFieldIndex,
+ csqAlleleNumberFieldIndex, seq.getName().toLowerCase(),
+ csqFeatureFieldIndex);
+
+ /*
+ * pick out the ontology term for the consequence type
+ */
+ String type = SequenceOntologyI.SEQUENCE_VARIANT;
+ if (consequence != null)
+ {
+ type = getOntologyTerm(consequence);
+ }
+
+ float score = getAlleleFrequency(variant, altAlleleIndex);
+
+ SequenceFeature sf = new SequenceFeature(type, alleles, featureStart,
+ featureEnd, score, FEATURE_GROUP_VCF);
+ sf.setSource(sourceId);
+
+ sf.setValue(Gff3Helper.ALLELES, alleles);
+
+ addAlleleProperties(variant, sf, altAlleleIndex, consequence);
+
+ seq.addSequenceFeature(sf);
+
+ return 1;
+ }
+
+ /**
+ * Determines the Sequence Ontology term to use for the variant feature type in
+ * Jalview. The default is 'sequence_variant', but a more specific term is used
+ * if:
+ * <ul>
+ * <li>VEP (or SnpEff) Consequence annotation is included in the VCF</li>
+ * <li>sequence id can be matched to VEP Feature (or SnpEff Feature_ID)</li>
+ * </ul>
+ *
+ * @param consequence
+ * @return
+ * @see http://www.sequenceontology.org/browser/current_svn/term/SO:0001060
+ */
+ String getOntologyTerm(String consequence)
+ {
+ String type = SequenceOntologyI.SEQUENCE_VARIANT;
+
+ /*
+ * could we associate Consequence data with this allele and feature (transcript)?
+ * if so, prefer the consequence term from that data
+ */
+ if (csqAlleleFieldIndex == -1) // && snpEffAlleleFieldIndex == -1
+ {
+ /*
+ * no Consequence data so we can't refine the ontology term
+ */
+ return type;
+ }
+
+ if (consequence != null)
+ {
+ String[] csqFields = consequence.split(PIPE_REGEX);
+ if (csqFields.length > csqConsequenceFieldIndex)
+ {
+ type = csqFields[csqConsequenceFieldIndex];
+ }
+ }
+ else
+ {
+ // todo the same for SnpEff consequence data matching if wanted
+ }
+
+ /*
+ * if of the form (e.g.) missense_variant&splice_region_variant,
+ * just take the first ('most severe') consequence
+ */
+ if (type != null)
+ {
+ int pos = type.indexOf('&');
+ if (pos > 0)
+ {
+ type = type.substring(0, pos);
+ }
+ }
+ return type;
+ }
+
+ /**
+ * Returns matched consequence data if it can be found, else null.
+ * <ul>
+ * <li>inspects the VCF data for key 'vcfInfoId'</li>
+ * <li>splits this on comma (to distinct consequences)</li>
+ * <li>returns the first consequence (if any) where</li>
+ * <ul>
+ * <li>the allele matches the altAlleleIndex'th allele of variant</li>
+ * <li>the feature matches the sequence name (e.g. transcript id)</li>
+ * </ul>
+ * </ul>
+ * If matched, the consequence is returned (as pipe-delimited fields).
+ *
+ * @param variant
+ * @param vcfInfoId
+ * @param altAlleleIndex
+ * @param alleleFieldIndex
+ * @param alleleNumberFieldIndex
+ * @param seqName
+ * @param featureFieldIndex
+ * @return
+ */
+ private String getConsequenceForAlleleAndFeature(VariantContext variant,
+ String vcfInfoId, int altAlleleIndex, int alleleFieldIndex,
+ int alleleNumberFieldIndex,
+ String seqName, int featureFieldIndex)
+ {
+ if (alleleFieldIndex == -1 || featureFieldIndex == -1)
+ {
+ return null;
+ }
+ Object value = variant.getAttribute(vcfInfoId);
+
+ if (value == null || !(value instanceof List<?>))
+ {
+ return null;
+ }
+
+ /*
+ * inspect each consequence in turn (comma-separated blocks
+ * extracted by htsjdk)
+ */
+ List<String> consequences = (List<String>) value;
+
+ for (String consequence : consequences)
+ {
+ String[] csqFields = consequence.split(PIPE_REGEX);
+ if (csqFields.length > featureFieldIndex)
+ {
+ String featureIdentifier = csqFields[featureFieldIndex];
+ if (featureIdentifier.length() > 4
+ && seqName.indexOf(featureIdentifier.toLowerCase()) > -1)
+ {
+ /*
+ * feature (transcript) matched - now check for allele match
+ */
+ if (matchAllele(variant, altAlleleIndex, csqFields,
+ alleleFieldIndex, alleleNumberFieldIndex))
+ {
+ return consequence;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private boolean matchAllele(VariantContext variant, int altAlleleIndex,
+ String[] csqFields, int alleleFieldIndex,
+ int alleleNumberFieldIndex)
+ {
+ /*
+ * if ALLELE_NUM is present, it must match altAlleleIndex
+ * NB first alternate allele is 1 for ALLELE_NUM, 0 for altAlleleIndex
+ */
+ if (alleleNumberFieldIndex > -1)
+ {
+ if (csqFields.length <= alleleNumberFieldIndex)
+ {
+ return false;
+ }
+ String alleleNum = csqFields[alleleNumberFieldIndex];
+ return String.valueOf(altAlleleIndex + 1).equals(alleleNum);
+ }
+
+ /*
+ * else consequence allele must match variant allele
+ */
+ if (alleleFieldIndex > -1 && csqFields.length > alleleFieldIndex)
+ {
+ String csqAllele = csqFields[alleleFieldIndex];
+ String vcfAllele = variant.getAlternateAllele(altAlleleIndex)
+ .getBaseString();
+ return csqAllele.equals(vcfAllele);
+ }
+ return false;
+ }
+
+ /**
+ * Add any allele-specific VCF key-value data to the sequence feature
+ *
+ * @param variant
+ * @param sf
+ * @param altAlelleIndex
+ * (0, 1..)
+ * @param consequence
+ * if not null, the consequence specific to this sequence (transcript
+ * feature) and allele
+ */
+ protected void addAlleleProperties(VariantContext variant,
+ SequenceFeature sf, final int altAlelleIndex, String consequence)
+ {
+ Map<String, Object> atts = variant.getAttributes();
+
+ for (Entry<String, Object> att : atts.entrySet())
+ {
+ String key = att.getKey();
+
+ /*
+ * extract Consequence data (if present) that we are able to
+ * associated with the allele for this variant feature
+ */
+ if (CSQ_FIELD.equals(key))
+ {
+ addConsequences(variant, sf, consequence);
+ continue;
+ }
+
+ /*
+ * filter out fields we don't want to capture
+ */
+ if (!vcfFieldsOfInterest.contains(key))
+ {
+ continue;
+ }
+
+ /*
+ * filter out fields we don't want to capture
+ */
+ if (!vcfFieldsOfInterest.contains(key))
+ {
+ continue;
+ }
+
+ /*
+ * we extract values for other data which are allele-specific;
+ * these may be per alternate allele (INFO[key].Number = 'A')
+ * or per allele including reference (INFO[key].Number = 'R')
+ */
+ VCFInfoHeaderLine infoHeader = header.getInfoHeaderLine(key);
+ if (infoHeader == null)
+ {
+ /*
+ * can't be sure what data belongs to this allele, so
+ * play safe and don't take any
+ */
+ continue;
+ }
+
+ VCFHeaderLineCount number = infoHeader.getCountType();
+ int index = altAlelleIndex;
+ if (number == VCFHeaderLineCount.R)
+ {
+ /*
+ * one value per allele including reference, so bump index
+ * e.g. the 3rd value is for the 2nd alternate allele
+ */
+ index++;
+ }
+ else if (number != VCFHeaderLineCount.A)
+ {
+ /*
+ * don't save other values as not allele-related
+ */
+ continue;
+ }
+
+ /*
+ * take the index'th value
+ */
+ String value = getAttributeValue(variant, key, index);
+ if (value != null)
+ {
+ sf.setValue(key, value);
+ }
+ }
+ }
+
+ /**
+ * Inspects CSQ data blocks (consequences) and adds attributes on the sequence
+ * feature.
+ * <p>
+ * If <code>myConsequence</code> is not null, then this is the specific
+ * consequence data (pipe-delimited fields) that is for the current allele and
+ * transcript (sequence) being processed)
+ *
+ * @param variant
+ * @param sf
+ * @param myConsequence
+ */
+ protected void addConsequences(VariantContext variant, SequenceFeature sf,
+ String myConsequence)
+ {
+ Object value = variant.getAttribute(CSQ_FIELD);
+
+ if (value == null || !(value instanceof List<?>))
+ {
+ return;
+ }
+
+ List<String> consequences = (List<String>) value;
+
+ /*
+ * inspect CSQ consequences; restrict to the consequence
+ * associated with the current transcript (Feature)
+ */
+ Map<String, String> csqValues = new HashMap<>();
+
+ for (String consequence : consequences)
+ {
+ if (myConsequence == null || myConsequence.equals(consequence))
+ {
+ String[] csqFields = consequence.split(PIPE_REGEX);
+
+ /*
+ * inspect individual fields of this consequence, copying non-null
+ * values which are 'fields of interest'
+ */
+ int i = 0;
+ for (String field : csqFields)
+ {
+ if (field != null && field.length() > 0)
+ {
+ String id = vepFieldsOfInterest.get(i);
+ if (id != null)
+ {
+ csqValues.put(id, field);
+ }
+ }
+ i++;
+ }
+ }
+ }
+
+ if (!csqValues.isEmpty())
+ {
+ sf.setValue(CSQ_FIELD, csqValues);
+ }
+ }
+
+ /**
+ * A convenience method to complement a dna base and return the string value
+ * of its complement
+ *
+ * @param reference
+ * @return
+ */
+ protected String complement(byte[] reference)
+ {
+ return String.valueOf(Dna.getComplement((char) reference[0]));
+ }
+
+ /**
+ * Determines the location of the query range (chromosome positions) in a
+ * different reference assembly.
+ * <p>
+ * If the range is just a subregion of one for which we already have a mapping
+ * (for example, an exon sub-region of a gene), then the mapping is just
+ * computed arithmetically.
+ * <p>
+ * Otherwise, calls the Ensembl REST service that maps from one assembly
+ * reference's coordinates to another's
+ *
+ * @param queryRange
+ * start-end chromosomal range in 'fromRef' coordinates
+ * @param chromosome
+ * @param species
+ * @param fromRef
+ * assembly reference for the query coordinates
+ * @param toRef
+ * assembly reference we wish to translate to
+ * @return the start-end range in 'toRef' coordinates
+ */
+ protected int[] mapReferenceRange(int[] queryRange, String chromosome,
+ String species, String fromRef, String toRef)
+ {
+ /*
+ * first try shorcut of computing the mapping as a subregion of one
+ * we already have (e.g. for an exon, if we have the gene mapping)
+ */
+ int[] mappedRange = findSubsumedRangeMapping(queryRange, chromosome,
+ species, fromRef, toRef);
+ if (mappedRange != null)
+ {
+ return mappedRange;
+ }
+
+ /*
+ * call (e.g.) http://rest.ensembl.org/map/human/GRCh38/17:45051610..45109016:1/GRCh37
+ */
+ EnsemblMap mapper = new EnsemblMap();
+ int[] mapping = mapper.getAssemblyMapping(species, chromosome, fromRef,
+ toRef, queryRange);
+
+ if (mapping == null)
+ {
+ // mapping service failure
+ return null;
+ }
+
+ /*
+ * save mapping for possible future re-use
+ */
+ String key = makeRangesKey(chromosome, species, fromRef, toRef);
+ if (!assemblyMappings.containsKey(key))
+ {
+ assemblyMappings.put(key, new HashMap<int[], int[]>());
+ }
+
+ assemblyMappings.get(key).put(queryRange, mapping);
+
+ return mapping;
+ }
+
+ /**
+ * If we already have a 1:1 contiguous mapping which subsumes the given query
+ * range, this method just calculates and returns the subset of that mapping,
+ * else it returns null. In practical terms, if a gene has a contiguous
+ * mapping between (for example) GRCh37 and GRCh38, then we assume that its
+ * subsidiary exons occupy unchanged relative positions, and just compute
+ * these as offsets, rather than do another lookup of the mapping.
+ * <p>
+ * If in future these assumptions prove invalid (e.g. for bacterial dna?!),
+ * simply remove this method or let it always return null.
+ * <p>
+ * Warning: many rapid calls to the /map service map result in a 429 overload
+ * error response
+ *
+ * @param queryRange
+ * @param chromosome
+ * @param species
+ * @param fromRef
+ * @param toRef
+ * @return
+ */
+ protected int[] findSubsumedRangeMapping(int[] queryRange, String chromosome,
+ String species, String fromRef, String toRef)
+ {
+ String key = makeRangesKey(chromosome, species, fromRef, toRef);
+ if (assemblyMappings.containsKey(key))
+ {
+ Map<int[], int[]> mappedRanges = assemblyMappings.get(key);
+ for (Entry<int[], int[]> mappedRange : mappedRanges.entrySet())
+ {
+ int[] fromRange = mappedRange.getKey();
+ int[] toRange = mappedRange.getValue();
+ if (fromRange[1] - fromRange[0] == toRange[1] - toRange[0])
+ {
+ /*
+ * mapping is 1:1 in length, so we trust it to have no discontinuities
+ */
+ if (MappingUtils.rangeContains(fromRange, queryRange))
+ {
+ /*
+ * fromRange subsumes our query range
+ */
+ int offset = queryRange[0] - fromRange[0];
+ int mappedRangeFrom = toRange[0] + offset;
+ int mappedRangeTo = mappedRangeFrom + (queryRange[1] - queryRange[0]);
+ return new int[] { mappedRangeFrom, mappedRangeTo };
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Transfers the sequence feature to the target sequence, locating its start
+ * and end range based on the mapping. Features which do not overlap the
+ * target sequence are ignored.
+ *
+ * @param sf
+ * @param targetSequence
+ * @param mapping
+ * mapping from the feature's coordinates to the target sequence
+ */
+ protected void transferFeature(SequenceFeature sf,
+ SequenceI targetSequence, MapList mapping)
+ {
+ int[] mappedRange = mapping.locateInTo(sf.getBegin(), sf.getEnd());
+
+ if (mappedRange != null)
+ {
+ String group = sf.getFeatureGroup();
+ int newBegin = Math.min(mappedRange[0], mappedRange[1]);
+ int newEnd = Math.max(mappedRange[0], mappedRange[1]);
+ SequenceFeature copy = new SequenceFeature(sf, newBegin, newEnd,
+ group, sf.getScore());
+ targetSequence.addSequenceFeature(copy);
+ }
+ }
+
+ /**
+ * Formats a ranges map lookup key
+ *
+ * @param chromosome
+ * @param species
+ * @param fromRef
+ * @param toRef
+ * @return
+ */
+ protected static String makeRangesKey(String chromosome, String species,
+ String fromRef, String toRef)
+ {
+ return species + EXCL + chromosome + EXCL + fromRef + EXCL
+ + toRef;
+ }
+}
protected JMenuItem runGroovy = new JMenuItem();
+ protected JMenuItem loadVcf;
+
protected JCheckBoxMenuItem autoCalculate = new JCheckBoxMenuItem();
protected JCheckBoxMenuItem sortByTree = new JCheckBoxMenuItem();
associatedData_actionPerformed(e);
}
});
+ loadVcf = new JMenuItem(MessageManager.getString("label.load_vcf_file"));
+ loadVcf.setToolTipText(MessageManager.getString("label.load_vcf"));
+ loadVcf.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ loadVcf_actionPerformed();
+ }
+ });
autoCalculate.setText(
MessageManager.getString("label.autocalculate_consensus"));
autoCalculate.setState(
fileMenu.add(exportAnnotations);
fileMenu.add(loadTreeMenuItem);
fileMenu.add(associatedData);
+ fileMenu.add(loadVcf);
fileMenu.addSeparator();
fileMenu.add(closeMenuItem);
// selectMenu.add(listenToViewSelections);
}
+ protected void loadVcf_actionPerformed()
+ {
+ }
+
/**
* Constructs the entries on the Colour menu (but does not add them to the
* menu).
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
+import javax.swing.text.EditorKit;
+import javax.swing.text.html.HTMLEditorKit;
/**
* DOCUMENT ME!
{
try
{
+ textarea.setEditorKit(new HTMLEditorKit());
setJMenuBar(editMenubar);
jbInit();
} catch (Exception e)
{
}
+
+ /**
+ * Adds the given stylesheet rule to the Html editor. However note that CSS
+ * support is limited.
+ *
+ * @param rule
+ * @see javax.swing.text.html.CSS
+ */
+ public void addStylesheetRule(String rule)
+ {
+ EditorKit editorKit = textarea.getEditorKit();
+ if (editorKit != null)
+ {
+ ((HTMLEditorKit) editorKit).getStyleSheet().addRule(rule);
+ }
+ }
}
protected JCheckBox sortByTree = new JCheckBox();
- /*
- * DAS Settings tab
- */
- protected JPanel dasTab = new JPanel();
/*
* Web Services tab
MessageManager.getString("label.editing"));
/*
- * See DasSourceBrowser for the real work of configuring this tab.
- */
- dasTab.setLayout(new BorderLayout());
- tabbedPane.add(dasTab, MessageManager.getString("label.das_settings"));
-
- /*
* See WsPreferences for the real work of configuring this tab.
*/
wsTab.setLayout(new BorderLayout());
MessageManager.getString("label.default_browser_unix"));
defaultBrowser.setFont(LABEL_FONT);
defaultBrowser.setText("");
-
+ final String tooltip = JvSwingUtils.wrapTooltip(true,
+ MessageManager.getString("label.double_click_to_browse"));
+ defaultBrowser.setToolTipText(tooltip);
defaultBrowser.addMouseListener(new MouseAdapter()
{
@Override
pathLabel.setFont(new java.awt.Font("SansSerif", 0, 11));
pathLabel.setHorizontalAlignment(SwingConstants.LEFT);
pathLabel.setText(MessageManager.getString("label.chimera_path"));
- final String tooltip = JvSwingUtils.wrapTooltip(true,
- MessageManager.getString("label.chimera_path_tip"));
- pathLabel.setToolTipText(tooltip);
pathLabel.setBounds(new Rectangle(10, ypos, 140, height));
structureTab.add(pathLabel);
chimeraPath.setFont(LABEL_FONT);
chimeraPath.setText("");
+ final String tooltip = JvSwingUtils.wrapTooltip(true,
+ MessageManager.getString("label.chimera_path_tip"));
+ chimeraPath.setToolTipText(tooltip);
chimeraPath.setBounds(new Rectangle(160, ypos, 300, height));
chimeraPath.addMouseListener(new MouseAdapter()
{
startupCheckbox.setSelected(true);
startupFileTextfield.setFont(LABEL_FONT);
startupFileTextfield.setBounds(new Rectangle(172, 310, 330, 20));
+ final String tooltip = JvSwingUtils.wrapTooltip(true,
+ MessageManager.getString("label.double_click_to_browse"));
+ startupFileTextfield.setToolTipText(tooltip);
startupFileTextfield.addMouseListener(new MouseAdapter()
{
@Override
/*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
import jalview.gui.AlignmentPanel;
import jalview.gui.Desktop;
import jalview.gui.JvSwingUtils;
+import jalview.gui.StructureViewer;
import jalview.util.MessageManager;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
+import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import javax.swing.event.InternalFrameEvent;
import javax.swing.table.TableColumn;
+import net.miginfocom.swing.MigLayout;
+
@SuppressWarnings("serial")
/**
* GUI layout for structure chooser
public abstract class GStructureChooser extends JPanel
implements ItemListener
{
+ private static final Font VERDANA_12 = new Font("Verdana", 0, 12);
+
+ protected static final String VIEWS_FILTER = "VIEWS_FILTER";
+
+ protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
+
+ protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
+
+ /*
+ * 'cached' structure view
+ */
+ protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
+
protected JPanel statusPanel = new JPanel();
public JLabel statusBar = new JLabel();
- private JPanel pnl_actionsAndStatus = new JPanel(new BorderLayout());
-
protected String frameTitle = MessageManager
.getString("label.structure_chooser");
protected JInternalFrame mainFrame = new JInternalFrame(frameTitle);
- protected JComboBox<FilterOption> cmb_filterOption = new JComboBox<FilterOption>();
+ protected JComboBox<FilterOption> cmb_filterOption = new JComboBox<>();
protected AlignmentPanel ap;
protected StringBuilder errorWarning = new StringBuilder();
- protected JLabel lbl_result = new JLabel(
- MessageManager.getString("label.select"));
-
- protected JButton btn_view = new JButton();
+ protected JButton btn_add;
- protected JButton btn_cancel = new JButton();
+ protected JButton btn_newView;
protected JButton btn_pdbFromFile = new JButton();
- protected JTextField txt_search = new JTextField(14);
-
- private JPanel pnl_actions = new JPanel();
-
- private JPanel pnl_main = new JPanel();
-
- private JPanel pnl_idInput = new JPanel(new FlowLayout());
+ protected JCheckBox chk_superpose = new JCheckBox(
+ MessageManager.getString("label.superpose_structures"));
- private JPanel pnl_fileChooser = new JPanel(new FlowLayout());
-
- private JPanel pnl_idInputBL = new JPanel(new BorderLayout());
-
- private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
-
- private JPanel pnl_locPDB = new JPanel(new BorderLayout());
+ protected JTextField txt_search = new JTextField(14);
protected JPanel pnl_switchableViews = new JPanel(new CardLayout());
protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews
.getLayout());
- private BorderLayout mainLayout = new BorderLayout();
-
- protected JCheckBox chk_rememberSettings = new JCheckBox(
- MessageManager.getString("label.dont_ask_me_again"));
-
protected JCheckBox chk_invertFilter = new JCheckBox(
MessageManager.getString("label.invert"));
protected ImageIcon warningImage = new ImageIcon(
getClass().getResource("/images/warning.gif"));
- protected JLabel lbl_warning = new JLabel(warningImage);
-
protected JLabel lbl_loading = new JLabel(loadingImage);
protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
protected JLabel lbl_fromFileStatus = new JLabel(errorImage);
- protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel();
-
- protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel();
-
- protected static final String VIEWS_FILTER = "VIEWS_FILTER";
+ protected AssociateSeqPanel idInputAssSeqPanel = new AssociateSeqPanel();
- protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
+ protected AssociateSeqPanel fileChooserAssSeqPanel = new AssociateSeqPanel();
- protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
-
- /**
- * 'cached' structure view
- */
- protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
+ protected JComboBox<StructureViewer> targetView = new JComboBox<>();
protected JTable tbl_local_pdb = new JTable();
- protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
-
protected JTabbedPane pnl_filter = new JTabbedPane();
protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
protected FTSDataColumnI[] previousWantedFields;
- protected static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
+ protected static Map<String, Integer> tempUserPrefs = new HashMap<>();
private JTable tbl_summary = new JTable()
{
}
};
- protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
-
public GStructureChooser()
{
try
mainFrame.dispose();
break;
case KeyEvent.VK_ENTER: // enter key
- if (btn_view.isEnabled())
+ if (btn_add.isEnabled())
{
- ok_ActionPerformed();
+ add_ActionPerformed();
}
break;
case KeyEvent.VK_TAB: // tab key
}
else
{
- btn_view.requestFocus();
+ btn_add.requestFocus();
}
evt.consume();
break;
}
}
});
+
+ JButton btn_cancel = new JButton(
+ MessageManager.getString("action.cancel"));
+ btn_cancel.setFont(VERDANA_12);
+ btn_cancel.addActionListener(new java.awt.event.ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ closeAction(pnl_filter.getHeight());
+ }
+ });
+ btn_cancel.addKeyListener(new KeyAdapter()
+ {
+ @Override
+ public void keyPressed(KeyEvent evt)
+ {
+ if (evt.getKeyCode() == KeyEvent.VK_ENTER)
+ {
+ closeAction(pnl_filter.getHeight());
+ }
+ }
+ });
+
tbl_local_pdb.setAutoCreateRowSorter(true);
tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
tbl_local_pdb.addMouseListener(new MouseAdapter()
mainFrame.dispose();
break;
case KeyEvent.VK_ENTER: // enter key
- if (btn_view.isEnabled())
+ if (btn_add.isEnabled())
{
- ok_ActionPerformed();
+ add_ActionPerformed();
}
break;
case KeyEvent.VK_TAB: // tab key
}
else
{
- if (btn_view.isEnabled())
+ if (btn_add.isEnabled())
{
- btn_view.requestFocus();
+ btn_add.requestFocus();
}
else
{
}
}
});
- btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
- btn_view.setText(MessageManager.getString("action.view"));
- btn_view.addActionListener(new java.awt.event.ActionListener()
+
+ btn_newView = new JButton(MessageManager.getString("action.new_view"));
+ btn_newView.setFont(VERDANA_12);
+ btn_newView.addActionListener(new java.awt.event.ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- ok_ActionPerformed();
+ newView_ActionPerformed();
}
});
- btn_view.addKeyListener(new KeyAdapter()
+ btn_newView.addKeyListener(new KeyAdapter()
{
@Override
public void keyPressed(KeyEvent evt)
{
if (evt.getKeyCode() == KeyEvent.VK_ENTER)
{
- ok_ActionPerformed();
+ newView_ActionPerformed();
}
}
});
- btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
- btn_cancel.setText(MessageManager.getString("action.cancel"));
- btn_cancel.addActionListener(new java.awt.event.ActionListener()
+ btn_add = new JButton(MessageManager.getString("action.add"));
+ btn_add.setFont(VERDANA_12);
+ btn_add.addActionListener(new java.awt.event.ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- closeAction(pnl_filter.getHeight());
+ add_ActionPerformed();
}
});
- btn_cancel.addKeyListener(new KeyAdapter()
+ btn_add.addKeyListener(new KeyAdapter()
{
@Override
public void keyPressed(KeyEvent evt)
{
if (evt.getKeyCode() == KeyEvent.VK_ENTER)
{
- closeAction(pnl_filter.getHeight());
+ add_ActionPerformed();
}
}
});
- btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
+ btn_pdbFromFile.setFont(VERDANA_12);
String btn_title = MessageManager.getString("label.select_pdb_file");
btn_pdbFromFile.setText(btn_title + " ");
btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
}
});
+ JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
scrl_foundStructures.setPreferredSize(new Dimension(width, height));
+ JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
scrl_localPDB.setPreferredSize(new Dimension(width, height));
scrl_localPDB.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
- cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
- chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
- chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
- chk_rememberSettings.setVisible(false);
+ chk_invertFilter.setFont(VERDANA_12);
txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
- MessageManager.getString("label.enter_pdb_id")));
- cmb_filterOption.setToolTipText(
- MessageManager.getString("info.select_filter_option"));
+ MessageManager.getString("label.enter_pdb_id_tip")));
txt_search.getDocument().addDocumentListener(new DocumentListener()
{
@Override
}
});
+ cmb_filterOption.setFont(VERDANA_12);
+ cmb_filterOption.setToolTipText(
+ MessageManager.getString("info.select_filter_option"));
cmb_filterOption.addItemListener(this);
-
// add CustomComboSeparatorsRenderer to filter option combo-box
cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
(ListCellRenderer<Object>) cmb_filterOption.getRenderer())
chk_invertFilter.addItemListener(this);
- pnl_actions.add(chk_rememberSettings);
- pnl_actions.add(btn_view);
- pnl_actions.add(btn_cancel);
+ targetView.setVisible(false);
- // pnl_filter.add(lbl_result);
+ JPanel actionsPanel = new JPanel(new MigLayout());
+ actionsPanel.add(targetView, "left");
+ actionsPanel.add(btn_add, "wrap");
+ actionsPanel.add(chk_superpose, "left");
+ actionsPanel.add(btn_newView);
+ actionsPanel.add(btn_cancel, "right");
+
+ JPanel pnl_main = new JPanel();
pnl_main.add(cmb_filterOption);
pnl_main.add(lbl_loading);
pnl_main.add(chk_invertFilter);
lbl_loading.setVisible(false);
+ JPanel pnl_fileChooser = new JPanel(new FlowLayout());
pnl_fileChooser.add(btn_pdbFromFile);
pnl_fileChooser.add(lbl_fromFileStatus);
+ JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
+ JPanel pnl_idInput = new JPanel(new FlowLayout());
pnl_idInput.add(txt_search);
pnl_idInput.add(lbl_pdbManualFetchStatus);
+
+ JPanel pnl_idInputBL = new JPanel(new BorderLayout());
pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
.getSource();
int index = sourceTabbedPane.getSelectedIndex();
- btn_view.setVisible(true);
+ btn_add.setVisible(targetView.isVisible());
+ btn_newView.setVisible(true);
btn_cancel.setVisible(true);
if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
{
- btn_view.setEnabled(false);
+ btn_add.setEnabled(false);
btn_cancel.setEnabled(false);
- btn_view.setVisible(false);
+ btn_add.setVisible(false);
+ btn_newView.setEnabled(false);
btn_cancel.setVisible(false);
previousWantedFields = pdbDocFieldPrefs
.getStructureSummaryFields()
pnl_filter.add(foundStructureSummary, scrl_foundStructures);
pnl_filter.add(configureCols, pdbDocFieldPrefs);
+ JPanel pnl_locPDB = new JPanel(new BorderLayout());
pnl_locPDB.add(scrl_localPDB);
pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
- this.setLayout(mainLayout);
+ this.setLayout(new BorderLayout());
this.add(pnl_main, java.awt.BorderLayout.NORTH);
this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
// this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
statusPanel.setLayout(new GridLayout());
- pnl_actionsAndStatus.add(pnl_actions, BorderLayout.CENTER);
+
+ JPanel pnl_actionsAndStatus = new JPanel(new BorderLayout());
+ pnl_actionsAndStatus.add(actionsPanel, BorderLayout.CENTER);
pnl_actionsAndStatus.add(statusPanel, BorderLayout.SOUTH);
statusPanel.add(statusBar, null);
this.add(pnl_actionsAndStatus, java.awt.BorderLayout.SOUTH);
* @author tcnofoegbu
*
*/
- public class AssciateSeqPanel extends JPanel implements ItemListener
+ public class AssociateSeqPanel extends JPanel implements ItemListener
{
- private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<AssociateSeqOptions>();
+ private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<>();
private JLabel lbl_associateSeq = new JLabel();
- public AssciateSeqPanel()
+ public AssociateSeqPanel()
{
this.setLayout(new FlowLayout());
this.add(cmb_assSeq);
protected abstract void stateChanged(ItemEvent e);
- protected abstract void ok_ActionPerformed();
+ protected abstract void add_ActionPerformed();
+
+ protected abstract void newView_ActionPerformed();
protected abstract void pdbFromFile_actionPerformed();
protected abstract void txt_search_ActionPerformed();
- public abstract void populateCmbAssociateSeqOptions(
+ protected abstract void populateCmbAssociateSeqOptions(
JComboBox<AssociateSeqOptions> cmb_assSeq,
JLabel lbl_associateSeq);
- public abstract void cmbAssSeqStateChanged();
+ protected abstract void cmbAssSeqStateChanged();
- public abstract void tabRefresh();
+ protected abstract void tabRefresh();
- public abstract void validateSelections();
+ protected abstract void validateSelections();
}
\ No newline at end of file
boolean validRes, boolean validEnd)
{
g.setColor(STEM_COLOUR);
- int sCol = (lastSSX / charWidth) + startRes;
+ int sCol = (lastSSX / charWidth)
+ + hiddenColumns.visibleToAbsoluteColumn(startRes);
int x1 = lastSSX;
int x2 = (x * charWidth);
// System.out.println(nonCanColor);
g.setColor(nonCanColor);
- int sCol = (lastSSX / charWidth) + startRes;
+ int sCol = (lastSSX / charWidth)
+ + hiddenColumns.visibleToAbsoluteColumn(startRes);
int x1 = lastSSX;
int x2 = (x * charWidth);
{
if (hasHiddenColumns)
{
- column = hiddenColumns.adjustForHiddenColumns(startRes + x);
+ column = hiddenColumns.visibleToAbsoluteColumn(startRes + x);
if (column > row_annotations.length - 1)
{
break;
{
g.setColor(HELIX_COLOUR);
- int sCol = (lastSSX / charWidth) + startRes;
+ int sCol = (lastSSX / charWidth)
+ + hiddenColumns.visibleToAbsoluteColumn(startRes);
int x1 = lastSSX;
int x2 = (x * charWidth);
column = sRes + x;
if (hasHiddenColumns)
{
- column = hiddenColumns.adjustForHiddenColumns(column);
+ column = hiddenColumns.visibleToAbsoluteColumn(column);
}
if (column > aaMax)
column = sRes + x;
if (hasHiddenColumns)
{
- column = hiddenColumns.adjustForHiddenColumns(column);
+ column = hiddenColumns.visibleToAbsoluteColumn(column);
}
if (column > aaMax)
// 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;
if (pixelCol <= endCol)
{
rgbcolor = getColumnColourFromSequence(allGroups, seq,
- alignmentCol, finder);
+ alignmentCol);
// fill in the appropriate number of pixels
for (int row = pixelRow; row <= endRow; ++row)
}
/*
- * Find the colour of a sequence at a specified column position
+ * Find the RGB value of 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(SequenceGroup[] allGroups,
- jalview.datamodel.SequenceI seq,
- int lastcol, FeatureColourFinder fcfinder)
+ int getColumnColourFromSequence(SequenceGroup[] allGroups,
+ SequenceI seq, int lastcol)
{
- Color color = Color.white;
+ Color color = resColFinder.GAP_COLOUR;
if ((seq != null) && (seq.getLength() > lastcol))
{
color = resColFinder.getResidueColour(true, shader, allGroups, seq,
- lastcol,
- fcfinder);
+ lastcol, finder);
}
return color.getRGB();
* the graphics object to draw on
* @param anno
* alignment annotation information
- * @param charWidth
- * alignment character width value
* @param y
* y-position for the annotation graph
* @param cols
* the collection of columns used in the overview panel
*/
- public void drawGraph(Graphics g, AlignmentAnnotation anno, int charWidth,
- int y, AlignmentColsCollectionI cols)
+ public void drawGraph(Graphics g, AlignmentAnnotation anno, int y,
+ AlignmentColsCollectionI cols)
{
Annotation[] annotations = anno.annotations;
g.setColor(Color.white);
package jalview.renderer;
import jalview.api.AlignViewportI;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
/**
column = col;
text = txt;
}
-
- /**
- * String representation for inspection when debugging only
- */
- @Override
- public String toString()
- {
- return String.format("%s:%d:%s", major ? "major" : "minor", column,
- text);
- }
}
/**
- * Calculates position markers on the alignment ruler
+ * calculate positions markers on the alignment ruler
*
* @param av
* @param startx
- * left-most column in visible view (0..)
+ * left-most column in visible view
* @param endx
- * - right-most column in visible view (0..)
- * @return
+ * - right-most column in visible view
+ * @return List of ScaleMark holding boolean: true/false for major/minor mark,
+ * marker position in alignment column coords, a String to be rendered
+ * at the position (or null)
*/
public List<ScaleMark> calculateMarks(AlignViewportI av, int startx,
int endx)
int scalestartx = (startx / 10) * 10;
SequenceI refSeq = av.getAlignment().getSeqrep();
- int refSp = 0, refStartI = 0, refEndI = -1;
+ int refSp = 0;
+ int refStartI = 0;
+ int refEndI = -1;
+
+ HiddenColumns hc = av.getAlignment().getHiddenColumns();
+
if (refSeq != null)
{
- // find bounds and set origin appopriately
- // locate first visible position for this sequence
- int[] refbounds = av.getAlignment().getHiddenColumns()
- .locateVisibleBoundsOfSequence(refSeq);
+ // find bounds and set origin appropriately
+ // locate first residue in sequence which is not hidden
+ Iterator<int[]> it = hc.iterator();
+ int index = refSeq.firstResidueOutsideIterator(it);
+ refSp = hc.absoluteToVisibleColumn(index);
+
+ refStartI = refSeq.findIndex(refSeq.getStart()) - 1;
+
+ int seqlength = refSeq.getLength();
+ // get sequence position past the end of the sequence
+ int pastEndPos = refSeq.findPosition(seqlength + 1);
+ refEndI = refSeq.findIndex(pastEndPos - 1) - 1;
- refSp = refbounds[0];
- refStartI = refbounds[4];
- refEndI = refbounds[5];
scalestartx = refSp + ((scalestartx - refSp) / 10) * 10;
}
{
scalestartx += 5;
}
- List<ScaleMark> marks = new ArrayList<ScaleMark>();
+ List<ScaleMark> marks = new ArrayList<>();
+ String string;
+ int refN, iadj;
// todo: add a 'reference origin column' to set column number relative to
for (int i = scalestartx; i <= endx; i += 5)
{
if (((i - refSp) % 10) == 0)
{
- String text;
if (refSeq == null)
{
- int iadj = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(i - 1) + 1;
- text = String.valueOf(iadj);
+ iadj = hc.visibleToAbsoluteColumn(i - 1) + 1;
+ string = String.valueOf(iadj);
}
else
{
- int iadj = av.getAlignment().getHiddenColumns()
- .adjustForHiddenColumns(i - 1);
- int refN = refSeq.findPosition(iadj);
+ iadj = hc.visibleToAbsoluteColumn(i - 1);
+ refN = refSeq.findPosition(iadj);
// TODO show bounds if position is a gap
// - ie L--R -> "1L|2R" for
// marker
if (iadj < refStartI)
{
- text = String.valueOf(iadj - refStartI);
+ string = String.valueOf(iadj - refStartI);
}
else if (iadj > refEndI)
{
- text = "+" + String.valueOf(iadj - refEndI);
+ string = "+" + String.valueOf(iadj - refEndI);
}
else
{
- text = String.valueOf(refN) + refSeq.getCharAt(iadj);
+ string = String.valueOf(refN) + refSeq.getCharAt(iadj);
}
}
- marks.add(new ScaleMark(true, i - startx - 1, text));
+ marks.add(new ScaleMark(true, i - startx - 1, string));
}
else
{
List<SequenceFeature> overlaps = seq.getFeatures().findFeatures(
visiblePositions.getBegin(), visiblePositions.getEnd(), type);
- filterFeaturesForDisplay(overlaps, fc);
+ if (fc.isSimpleColour())
+ {
+ filterFeaturesForDisplay(overlaps);
+ }
for (SequenceFeature sf : overlaps)
{
- Color featureColour = fc.getColor(sf);
+ Color featureColour = getColor(sf, fc);
if (featureColour == null)
{
- // score feature outwith threshold for colouring
+ /*
+ * feature excluded by visibility settings, filters, or colour threshold
+ */
continue;
}
-#Mon Jun 20 15:44:52 BST 2016
+#Thu Dec 14 09:10:14 GMT 2017
jalview.schemabinding.version2.ThresholdLine=jalview.schemabinding.version2.descriptors.ThresholdLineDescriptor
jalview.schemabinding.version2.SequenceSetProperties=jalview.schemabinding.version2.descriptors.SequenceSetPropertiesDescriptor
jalview.schemabinding.version2.StructureState=jalview.schemabinding.version2.descriptors.StructureStateDescriptor
jalview.schemabinding.version2.Setting=jalview.schemabinding.version2.descriptors.SettingDescriptor
jalview.schemabinding.version2.AlcodonFrame=jalview.schemabinding.version2.descriptors.AlcodonFrameDescriptor
jalview.schemabinding.version2.AnnotationElement=jalview.schemabinding.version2.descriptors.AnnotationElementDescriptor
+jalview.schemabinding.version2.FeatureMatcherSet=jalview.schemabinding.version2.descriptors.FeatureMatcherSetDescriptor
jalview.schemabinding.version2.SecondaryStructure=jalview.schemabinding.version2.descriptors.SecondaryStructureDescriptor
+jalview.schemabinding.version2.MatchCondition=jalview.schemabinding.version2.descriptors.MatchConditionDescriptor
jalview.schemabinding.version2.SequenceSet=jalview.schemabinding.version2.descriptors.SequenceSetDescriptor
jalview.schemabinding.version2.Viewport=jalview.schemabinding.version2.descriptors.ViewportDescriptor
jalview.schemabinding.version2.RnaViewer=jalview.schemabinding.version2.descriptors.RnaViewerDescriptor
jalview.schemabinding.version2.DBRef=jalview.schemabinding.version2.descriptors.DBRefDescriptor
jalview.schemabinding.version2.AlcodMap=jalview.schemabinding.version2.descriptors.AlcodMapDescriptor
jalview.schemabinding.version2.Annotation=jalview.schemabinding.version2.descriptors.AnnotationDescriptor
-jalview.schemabinding.version2.Wsparameters=jalview.schemabinding.version2.descriptors.WsparametersDescriptor
jalview.schemabinding.version2.JSeq=jalview.schemabinding.version2.descriptors.JSeqDescriptor
+jalview.schemabinding.version2.MatcherSet=jalview.schemabinding.version2.descriptors.MatcherSetDescriptor
jalview.schemabinding.version2.Sequence=jalview.schemabinding.version2.descriptors.SequenceDescriptor
jalview.schemabinding.version2.WebServiceParameterSet=jalview.schemabinding.version2.descriptors.WebServiceParameterSetDescriptor
jalview.schemabinding.version2.Alcodon=jalview.schemabinding.version2.descriptors.AlcodonDescriptor
+jalview.schemabinding.version2.Filter=jalview.schemabinding.version2.descriptors.FilterDescriptor
jalview.schemabinding.version2.AnnotationColours=jalview.schemabinding.version2.descriptors.AnnotationColoursDescriptor
jalview.schemabinding.version2.Pdbids=jalview.schemabinding.version2.descriptors.PdbidsDescriptor
jalview.schemabinding.version2.AnnotationColourScheme=jalview.schemabinding.version2.descriptors.AnnotationColourSchemeDescriptor
jalview.schemabinding.version2.Mapping=jalview.schemabinding.version2.descriptors.MappingDescriptor
-jalview.schemabinding.version2.MappingChoice=jalview.schemabinding.version2.descriptors.MappingChoiceDescriptor
+jalview.schemabinding.version2.CompoundMatcher=jalview.schemabinding.version2.descriptors.CompoundMatcherDescriptor
+jalview.schemabinding.version2.JalviewModelSequence=jalview.schemabinding.version2.descriptors.JalviewModelSequenceDescriptor
jalview.schemabinding.version2.Group=jalview.schemabinding.version2.descriptors.GroupDescriptor
+jalview.schemabinding.version2.MappingChoice=jalview.schemabinding.version2.descriptors.MappingChoiceDescriptor
jalview.schemabinding.version2.Feature=jalview.schemabinding.version2.descriptors.FeatureDescriptor
-jalview.schemabinding.version2.JalviewModelSequence=jalview.schemabinding.version2.descriptors.JalviewModelSequenceDescriptor
jalview.schemabinding.version2.UserColours=jalview.schemabinding.version2.descriptors.UserColoursDescriptor
jalview.schemabinding.version2.Colour=jalview.schemabinding.version2.descriptors.ColourDescriptor
-jalview.schemabinding.version2.MapListFrom=jalview.schemabinding.version2.descriptors.MapListFromDescriptor
jalview.schemabinding.version2.PdbentryItem=jalview.schemabinding.version2.descriptors.PdbentryItemDescriptor
-jalview.schemabinding.version2.JGroup=jalview.schemabinding.version2.descriptors.JGroupDescriptor
+jalview.schemabinding.version2.MapListFrom=jalview.schemabinding.version2.descriptors.MapListFromDescriptor
jalview.schemabinding.version2.FeatureSettings=jalview.schemabinding.version2.descriptors.FeatureSettingsDescriptor
-jalview.schemabinding.version2.VamsasModel=jalview.schemabinding.version2.descriptors.VamsasModelDescriptor
-jalview.schemabinding.version2.JalviewUserColours=jalview.schemabinding.version2.descriptors.JalviewUserColoursDescriptor
+jalview.schemabinding.version2.JGroup=jalview.schemabinding.version2.descriptors.JGroupDescriptor
jalview.schemabinding.version2.MapListTo=jalview.schemabinding.version2.descriptors.MapListToDescriptor
+jalview.schemabinding.version2.JalviewUserColours=jalview.schemabinding.version2.descriptors.JalviewUserColoursDescriptor
+jalview.schemabinding.version2.VamsasModel=jalview.schemabinding.version2.descriptors.VamsasModelDescriptor
jalview.schemabinding.version2.Pdbentry=jalview.schemabinding.version2.descriptors.PdbentryDescriptor
jalview.schemabinding.version2.HiddenColumns=jalview.schemabinding.version2.descriptors.HiddenColumnsDescriptor
jalview.schemabinding.version2.Features=jalview.schemabinding.version2.descriptors.FeaturesDescriptor
-jalview.schemabinding.version2.DseqFor=jalview.schemabinding.version2.descriptors.DseqForDescriptor
jalview.schemabinding.version2.VAMSAS=jalview.schemabinding.version2.descriptors.VAMSASDescriptor
-jalview.schemabinding.version2.MappingChoiceItem=jalview.schemabinding.version2.descriptors.MappingChoiceItemDescriptor
+jalview.schemabinding.version2.FeatureMatcher=jalview.schemabinding.version2.descriptors.FeatureMatcherDescriptor
// --------------------------/
/**
- * Field _name.
+ * Single letter residue code for an alignment colour scheme, or feature type
+ * for a feature colour scheme
*/
private java.lang.String _name;
private java.lang.String _minRGB;
/**
- * loosely specified enumeration: NONE,ABOVE, or BELOW
+ * Field _noValueColour.
*/
- private java.lang.String _threshType;
+ private jalview.schemabinding.version2.types.NoValueColour _noValueColour = jalview.schemabinding.version2.types.NoValueColour
+ .valueOf("Min");
+
+ /**
+ * Field _threshType.
+ */
+ private jalview.schemabinding.version2.types.ColourThreshTypeType _threshType;
/**
* Field _threshold.
*/
private boolean _has_autoScale;
+ /**
+ * name of feature attribute to colour by, or attribute and sub-attribute
+ */
+ private java.util.Vector _attributeNameList;
+
// ----------------/
// - Constructors -/
// ----------------/
public Colour()
{
super();
+ setNoValueColour(jalview.schemabinding.version2.types.NoValueColour
+ .valueOf("Min"));
+ this._attributeNameList = new java.util.Vector();
}
// -----------/
// -----------/
/**
- */
+ *
+ *
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.addElement(vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.add(index, vAttributeName);
+ }
+
+ /**
+ */
public void deleteAutoScale()
{
this._has_autoScale = false;
}
/**
- */
+ */
public void deleteColourByLabel()
{
this._has_colourByLabel = false;
}
/**
- */
+ */
public void deleteMax()
{
this._has_max = false;
}
/**
- */
+ */
public void deleteMin()
{
this._has_min = false;
}
/**
- */
+ */
public void deleteThreshold()
{
this._has_threshold = false;
}
/**
+ * Method enumerateAttributeName.
+ *
+ * @return an Enumeration over all java.lang.String elements
+ */
+ public java.util.Enumeration enumerateAttributeName()
+ {
+ return this._attributeNameList.elements();
+ }
+
+ /**
+ * Method getAttributeName.
+ *
+ * @param index
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ * @return the value of the java.lang.String at the given index
+ */
+ public java.lang.String getAttributeName(final int index)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("getAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ return (java.lang.String) _attributeNameList.get(index);
+ }
+
+ /**
+ * Method getAttributeName.Returns the contents of the collection in an Array.
+ * <p>
+ * Note: Just in case the collection contents are changing in another thread,
+ * we pass a 0-length Array of the correct type into the API call. This way we
+ * <i>know</i> that the Array returned is of exactly the correct length.
+ *
+ * @return this collection as an Array
+ */
+ public java.lang.String[] getAttributeName()
+ {
+ java.lang.String[] array = new java.lang.String[0];
+ return (java.lang.String[]) this._attributeNameList.toArray(array);
+ }
+
+ /**
+ * Method getAttributeNameCount.
+ *
+ * @return the size of this collection
+ */
+ public int getAttributeNameCount()
+ {
+ return this._attributeNameList.size();
+ }
+
+ /**
* Returns the value of field 'autoScale'.
*
* @return the value of field 'AutoScale'.
}
/**
- * Returns the value of field 'name'.
+ * Returns the value of field 'name'. The field 'name' has the following
+ * description: Single letter residue code for an alignment colour scheme, or
+ * feature type for a feature colour scheme
*
* @return the value of field 'Name'.
*/
}
/**
+ * Returns the value of field 'noValueColour'.
+ *
+ * @return the value of field 'NoValueColour'.
+ */
+ public jalview.schemabinding.version2.types.NoValueColour getNoValueColour()
+ {
+ return this._noValueColour;
+ }
+
+ /**
* Returns the value of field 'RGB'.
*
* @return the value of field 'RGB'.
}
/**
- * Returns the value of field 'threshType'. The field 'threshType' has the
- * following description: loosely specified enumeration: NONE,ABOVE, or BELOW
+ * Returns the value of field 'threshType'.
*
* @return the value of field 'ThreshType'.
*/
- public java.lang.String getThreshType()
+ public jalview.schemabinding.version2.types.ColourThreshTypeType getThreshType()
{
return this._threshType;
}
}
/**
+ */
+ public void removeAllAttributeName()
+ {
+ this._attributeNameList.clear();
+ }
+
+ /**
+ * Method removeAttributeName.
+ *
+ * @param vAttributeName
+ * @return true if the object was removed from the collection.
+ */
+ public boolean removeAttributeName(final java.lang.String vAttributeName)
+ {
+ boolean removed = _attributeNameList.remove(vAttributeName);
+ return removed;
+ }
+
+ /**
+ * Method removeAttributeNameAt.
+ *
+ * @param index
+ * @return the element removed from the collection
+ */
+ public java.lang.String removeAttributeNameAt(final int index)
+ {
+ java.lang.Object obj = this._attributeNameList.remove(index);
+ return (java.lang.String) obj;
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void setAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("setAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ this._attributeNameList.set(index, vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param vAttributeNameArray
+ */
+ public void setAttributeName(final java.lang.String[] vAttributeNameArray)
+ {
+ // -- copy array
+ _attributeNameList.clear();
+
+ for (int i = 0; i < vAttributeNameArray.length; i++)
+ {
+ this._attributeNameList.add(vAttributeNameArray[i]);
+ }
+ }
+
+ /**
* Sets the value of field 'autoScale'.
*
* @param autoScale
}
/**
- * Sets the value of field 'name'.
+ * Sets the value of field 'name'. The field 'name' has the following
+ * description: Single letter residue code for an alignment colour scheme, or
+ * feature type for a feature colour scheme
*
* @param name
* the value of field 'name'.
}
/**
+ * Sets the value of field 'noValueColour'.
+ *
+ * @param noValueColour
+ * the value of field 'noValueColour'.
+ */
+ public void setNoValueColour(
+ final jalview.schemabinding.version2.types.NoValueColour noValueColour)
+ {
+ this._noValueColour = noValueColour;
+ }
+
+ /**
* Sets the value of field 'RGB'.
*
* @param RGB
}
/**
- * Sets the value of field 'threshType'. The field 'threshType' has the
- * following description: loosely specified enumeration: NONE,ABOVE, or BELOW
+ * Sets the value of field 'threshType'.
*
* @param threshType
* the value of field 'threshType'.
*/
- public void setThreshType(final java.lang.String threshType)
+ public void setThreshType(
+ final jalview.schemabinding.version2.types.ColourThreshTypeType threshType)
{
this._threshType = threshType;
}
throws org.exolab.castor.xml.MarshalException,
org.exolab.castor.xml.ValidationException
{
- return (jalview.schemabinding.version2.Colour) Unmarshaller.unmarshal(
- jalview.schemabinding.version2.Colour.class, reader);
+ return (jalview.schemabinding.version2.Colour) Unmarshaller
+ .unmarshal(jalview.schemabinding.version2.Colour.class, reader);
}
/**
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class CompoundMatcher.
+ *
+ * @version $Revision$ $Date$
+ */
+public class CompoundMatcher implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * If true, matchers are AND-ed, if false they are OR-ed
+ */
+ private boolean _and;
+
+ /**
+ * keeps track of state for field: _and
+ */
+ private boolean _has_and;
+
+ /**
+ * Field _matcherSetList.
+ */
+ private java.util.Vector _matcherSetList;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public CompoundMatcher()
+ {
+ super();
+ this._matcherSetList = new java.util.Vector();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ *
+ *
+ * @param vMatcherSet
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addMatcherSet(
+ final jalview.schemabinding.version2.MatcherSet vMatcherSet)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._matcherSetList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addMatcherSet has a maximum of 2");
+ }
+
+ this._matcherSetList.addElement(vMatcherSet);
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vMatcherSet
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addMatcherSet(final int index,
+ final jalview.schemabinding.version2.MatcherSet vMatcherSet)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._matcherSetList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addMatcherSet has a maximum of 2");
+ }
+
+ this._matcherSetList.add(index, vMatcherSet);
+ }
+
+ /**
+ */
+ public void deleteAnd()
+ {
+ this._has_and = false;
+ }
+
+ /**
+ * Method enumerateMatcherSet.
+ *
+ * @return an Enumeration over all jalview.schemabinding.version2.MatcherSet
+ * elements
+ */
+ public java.util.Enumeration enumerateMatcherSet()
+ {
+ return this._matcherSetList.elements();
+ }
+
+ /**
+ * Returns the value of field 'and'. The field 'and' has the following
+ * description: If true, matchers are AND-ed, if false they are OR-ed
+ *
+ * @return the value of field 'And'.
+ */
+ public boolean getAnd()
+ {
+ return this._and;
+ }
+
+ /**
+ * Method getMatcherSet.
+ *
+ * @param index
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ * @return the value of the jalview.schemabinding.version2.MatcherSet at the
+ * given index
+ */
+ public jalview.schemabinding.version2.MatcherSet getMatcherSet(
+ final int index) throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._matcherSetList.size())
+ {
+ throw new IndexOutOfBoundsException(
+ "getMatcherSet: Index value '" + index + "' not in range [0.."
+ + (this._matcherSetList.size() - 1) + "]");
+ }
+
+ return (jalview.schemabinding.version2.MatcherSet) _matcherSetList
+ .get(index);
+ }
+
+ /**
+ * Method getMatcherSet.Returns the contents of the collection in an Array.
+ * <p>
+ * Note: Just in case the collection contents are changing in another thread,
+ * we pass a 0-length Array of the correct type into the API call. This way we
+ * <i>know</i> that the Array returned is of exactly the correct length.
+ *
+ * @return this collection as an Array
+ */
+ public jalview.schemabinding.version2.MatcherSet[] getMatcherSet()
+ {
+ jalview.schemabinding.version2.MatcherSet[] array = new jalview.schemabinding.version2.MatcherSet[0];
+ return (jalview.schemabinding.version2.MatcherSet[]) this._matcherSetList
+ .toArray(array);
+ }
+
+ /**
+ * Method getMatcherSetCount.
+ *
+ * @return the size of this collection
+ */
+ public int getMatcherSetCount()
+ {
+ return this._matcherSetList.size();
+ }
+
+ /**
+ * Method hasAnd.
+ *
+ * @return true if at least one And has been added
+ */
+ public boolean hasAnd()
+ {
+ return this._has_and;
+ }
+
+ /**
+ * Returns the value of field 'and'. The field 'and' has the following
+ * description: If true, matchers are AND-ed, if false they are OR-ed
+ *
+ * @return the value of field 'And'.
+ */
+ public boolean isAnd()
+ {
+ return this._and;
+ }
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ */
+ public void removeAllMatcherSet()
+ {
+ this._matcherSetList.clear();
+ }
+
+ /**
+ * Method removeMatcherSet.
+ *
+ * @param vMatcherSet
+ * @return true if the object was removed from the collection.
+ */
+ public boolean removeMatcherSet(
+ final jalview.schemabinding.version2.MatcherSet vMatcherSet)
+ {
+ boolean removed = _matcherSetList.remove(vMatcherSet);
+ return removed;
+ }
+
+ /**
+ * Method removeMatcherSetAt.
+ *
+ * @param index
+ * @return the element removed from the collection
+ */
+ public jalview.schemabinding.version2.MatcherSet removeMatcherSetAt(
+ final int index)
+ {
+ java.lang.Object obj = this._matcherSetList.remove(index);
+ return (jalview.schemabinding.version2.MatcherSet) obj;
+ }
+
+ /**
+ * Sets the value of field 'and'. The field 'and' has the following
+ * description: If true, matchers are AND-ed, if false they are OR-ed
+ *
+ * @param and
+ * the value of field 'and'.
+ */
+ public void setAnd(final boolean and)
+ {
+ this._and = and;
+ this._has_and = true;
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vMatcherSet
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void setMatcherSet(final int index,
+ final jalview.schemabinding.version2.MatcherSet vMatcherSet)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._matcherSetList.size())
+ {
+ throw new IndexOutOfBoundsException(
+ "setMatcherSet: Index value '" + index + "' not in range [0.."
+ + (this._matcherSetList.size() - 1) + "]");
+ }
+
+ this._matcherSetList.set(index, vMatcherSet);
+ }
+
+ /**
+ *
+ *
+ * @param vMatcherSetArray
+ */
+ public void setMatcherSet(
+ final jalview.schemabinding.version2.MatcherSet[] vMatcherSetArray)
+ {
+ // -- copy array
+ _matcherSetList.clear();
+
+ for (int i = 0; i < vMatcherSetArray.length; i++)
+ {
+ this._matcherSetList.add(vMatcherSetArray[i]);
+ }
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.schemabinding.version2.CompoundMatcher
+ */
+ public static jalview.schemabinding.version2.CompoundMatcher unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.schemabinding.version2.CompoundMatcher) Unmarshaller
+ .unmarshal(jalview.schemabinding.version2.CompoundMatcher.class,
+ reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class FeatureMatcher.
+ *
+ * @version $Revision$ $Date$
+ */
+public class FeatureMatcher implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _by.
+ */
+ private jalview.schemabinding.version2.types.FeatureMatcherByType _by;
+
+ /**
+ * name of feature attribute to filter on, or attribute and sub-attribute
+ */
+ private java.util.Vector _attributeNameList;
+
+ /**
+ * Field _condition.
+ */
+ private java.lang.String _condition;
+
+ /**
+ * Field _value.
+ */
+ private java.lang.String _value;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public FeatureMatcher()
+ {
+ super();
+ this._attributeNameList = new java.util.Vector();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ *
+ *
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.addElement(vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.add(index, vAttributeName);
+ }
+
+ /**
+ * Method enumerateAttributeName.
+ *
+ * @return an Enumeration over all java.lang.String elements
+ */
+ public java.util.Enumeration enumerateAttributeName()
+ {
+ return this._attributeNameList.elements();
+ }
+
+ /**
+ * Method getAttributeName.
+ *
+ * @param index
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ * @return the value of the java.lang.String at the given index
+ */
+ public java.lang.String getAttributeName(final int index)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("getAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ return (java.lang.String) _attributeNameList.get(index);
+ }
+
+ /**
+ * Method getAttributeName.Returns the contents of the collection in an Array.
+ * <p>
+ * Note: Just in case the collection contents are changing in another thread,
+ * we pass a 0-length Array of the correct type into the API call. This way we
+ * <i>know</i> that the Array returned is of exactly the correct length.
+ *
+ * @return this collection as an Array
+ */
+ public java.lang.String[] getAttributeName()
+ {
+ java.lang.String[] array = new java.lang.String[0];
+ return (java.lang.String[]) this._attributeNameList.toArray(array);
+ }
+
+ /**
+ * Method getAttributeNameCount.
+ *
+ * @return the size of this collection
+ */
+ public int getAttributeNameCount()
+ {
+ return this._attributeNameList.size();
+ }
+
+ /**
+ * Returns the value of field 'by'.
+ *
+ * @return the value of field 'By'.
+ */
+ public jalview.schemabinding.version2.types.FeatureMatcherByType getBy()
+ {
+ return this._by;
+ }
+
+ /**
+ * Returns the value of field 'condition'.
+ *
+ * @return the value of field 'Condition'.
+ */
+ public java.lang.String getCondition()
+ {
+ return this._condition;
+ }
+
+ /**
+ * Returns the value of field 'value'.
+ *
+ * @return the value of field 'Value'.
+ */
+ public java.lang.String getValue()
+ {
+ return this._value;
+ }
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ */
+ public void removeAllAttributeName()
+ {
+ this._attributeNameList.clear();
+ }
+
+ /**
+ * Method removeAttributeName.
+ *
+ * @param vAttributeName
+ * @return true if the object was removed from the collection.
+ */
+ public boolean removeAttributeName(final java.lang.String vAttributeName)
+ {
+ boolean removed = _attributeNameList.remove(vAttributeName);
+ return removed;
+ }
+
+ /**
+ * Method removeAttributeNameAt.
+ *
+ * @param index
+ * @return the element removed from the collection
+ */
+ public java.lang.String removeAttributeNameAt(final int index)
+ {
+ java.lang.Object obj = this._attributeNameList.remove(index);
+ return (java.lang.String) obj;
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void setAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("setAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ this._attributeNameList.set(index, vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param vAttributeNameArray
+ */
+ public void setAttributeName(final java.lang.String[] vAttributeNameArray)
+ {
+ // -- copy array
+ _attributeNameList.clear();
+
+ for (int i = 0; i < vAttributeNameArray.length; i++)
+ {
+ this._attributeNameList.add(vAttributeNameArray[i]);
+ }
+ }
+
+ /**
+ * Sets the value of field 'by'.
+ *
+ * @param by
+ * the value of field 'by'.
+ */
+ public void setBy(
+ final jalview.schemabinding.version2.types.FeatureMatcherByType by)
+ {
+ this._by = by;
+ }
+
+ /**
+ * Sets the value of field 'condition'.
+ *
+ * @param condition
+ * the value of field 'condition'.
+ */
+ public void setCondition(final java.lang.String condition)
+ {
+ this._condition = condition;
+ }
+
+ /**
+ * Sets the value of field 'value'.
+ *
+ * @param value
+ * the value of field 'value'.
+ */
+ public void setValue(final java.lang.String value)
+ {
+ this._value = value;
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.schemabinding.version2.FeatureMatcher
+ */
+ public static jalview.schemabinding.version2.FeatureMatcher unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.schemabinding.version2.FeatureMatcher) Unmarshaller
+ .unmarshal(jalview.schemabinding.version2.FeatureMatcher.class,
+ reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * A feature match condition, which may be simple or compound
+ *
+ * @version $Revision$ $Date$
+ */
+public class FeatureMatcherSet implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Internal choice value storage
+ */
+ private java.lang.Object _choiceValue;
+
+ /**
+ * Field _matchCondition.
+ */
+ private MatchCondition _matchCondition;
+
+ /**
+ * Field _compoundMatcher.
+ */
+ private CompoundMatcher _compoundMatcher;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public FeatureMatcherSet()
+ {
+ super();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Returns the value of field 'choiceValue'. The field 'choiceValue' has the
+ * following description: Internal choice value storage
+ *
+ * @return the value of field 'ChoiceValue'.
+ */
+ public java.lang.Object getChoiceValue()
+ {
+ return this._choiceValue;
+ }
+
+ /**
+ * Returns the value of field 'compoundMatcher'.
+ *
+ * @return the value of field 'CompoundMatcher'.
+ */
+ public CompoundMatcher getCompoundMatcher()
+ {
+ return this._compoundMatcher;
+ }
+
+ /**
+ * Returns the value of field 'matchCondition'.
+ *
+ * @return the value of field 'MatchCondition'.
+ */
+ public MatchCondition getMatchCondition()
+ {
+ return this._matchCondition;
+ }
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ * Sets the value of field 'compoundMatcher'.
+ *
+ * @param compoundMatcher
+ * the value of field 'compoundMatcher'.
+ */
+ public void setCompoundMatcher(final CompoundMatcher compoundMatcher)
+ {
+ this._compoundMatcher = compoundMatcher;
+ this._choiceValue = compoundMatcher;
+ }
+
+ /**
+ * Sets the value of field 'matchCondition'.
+ *
+ * @param matchCondition
+ * the value of field 'matchCondition'.
+ */
+ public void setMatchCondition(final MatchCondition matchCondition)
+ {
+ this._matchCondition = matchCondition;
+ this._choiceValue = matchCondition;
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.schemabinding.version2.FeatureMatcherSet
+ */
+ public static jalview.schemabinding.version2.FeatureMatcherSet unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.schemabinding.version2.FeatureMatcherSet) Unmarshaller
+ .unmarshal(
+ jalview.schemabinding.version2.FeatureMatcherSet.class,
+ reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class Filter.
+ *
+ * @version $Revision$ $Date$
+ */
+public class Filter implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _featureType.
+ */
+ private java.lang.String _featureType;
+
+ /**
+ * Field _matcherSet.
+ */
+ private jalview.schemabinding.version2.MatcherSet _matcherSet;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public Filter()
+ {
+ super();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Returns the value of field 'featureType'.
+ *
+ * @return the value of field 'FeatureType'.
+ */
+ public java.lang.String getFeatureType()
+ {
+ return this._featureType;
+ }
+
+ /**
+ * Returns the value of field 'matcherSet'.
+ *
+ * @return the value of field 'MatcherSet'.
+ */
+ public jalview.schemabinding.version2.MatcherSet getMatcherSet()
+ {
+ return this._matcherSet;
+ }
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ * Sets the value of field 'featureType'.
+ *
+ * @param featureType
+ * the value of field 'featureType'.
+ */
+ public void setFeatureType(final java.lang.String featureType)
+ {
+ this._featureType = featureType;
+ }
+
+ /**
+ * Sets the value of field 'matcherSet'.
+ *
+ * @param matcherSet
+ * the value of field 'matcherSet'.
+ */
+ public void setMatcherSet(
+ final jalview.schemabinding.version2.MatcherSet matcherSet)
+ {
+ this._matcherSet = matcherSet;
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.schemabinding.version2.Filter
+ */
+ public static jalview.schemabinding.version2.Filter unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.schemabinding.version2.Filter) Unmarshaller
+ .unmarshal(jalview.schemabinding.version2.Filter.class, reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
*/
private java.util.Vector _colourList;
+ /**
+ * Field _filterList.
+ */
+ private java.util.Vector _filterList;
+
// ----------------/
// - Constructors -/
// ----------------/
{
super();
this._colourList = new java.util.Vector();
+ this._filterList = new java.util.Vector();
}
// -----------/
}
/**
+ *
+ *
+ * @param vFilter
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addFilter(final Filter vFilter)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ this._filterList.addElement(vFilter);
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vFilter
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addFilter(final int index, final Filter vFilter)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ this._filterList.add(index, vFilter);
+ }
+
+ /**
* Method enumerateColour.
*
* @return an Enumeration over all Colour elements
}
/**
+ * Method enumerateFilter.
+ *
+ * @return an Enumeration over all Filter elements
+ */
+ public java.util.Enumeration enumerateFilter()
+ {
+ return this._filterList.elements();
+ }
+
+ /**
* Method getColour.
*
* @param index
// check bounds for index
if (index < 0 || index >= this._colourList.size())
{
- throw new IndexOutOfBoundsException("getColour: Index value '"
- + index + "' not in range [0.."
- + (this._colourList.size() - 1) + "]");
+ throw new IndexOutOfBoundsException(
+ "getColour: Index value '" + index + "' not in range [0.."
+ + (this._colourList.size() - 1) + "]");
}
return (Colour) _colourList.get(index);
}
/**
+ * Method getFilter.
+ *
+ * @param index
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ * @return the value of the Filter at the given index
+ */
+ public Filter getFilter(final int index)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._filterList.size())
+ {
+ throw new IndexOutOfBoundsException(
+ "getFilter: Index value '" + index + "' not in range [0.."
+ + (this._filterList.size() - 1) + "]");
+ }
+
+ return (Filter) _filterList.get(index);
+ }
+
+ /**
+ * Method getFilter.Returns the contents of the collection in an Array.
+ * <p>
+ * Note: Just in case the collection contents are changing in another thread,
+ * we pass a 0-length Array of the correct type into the API call. This way we
+ * <i>know</i> that the Array returned is of exactly the correct length.
+ *
+ * @return this collection as an Array
+ */
+ public Filter[] getFilter()
+ {
+ Filter[] array = new Filter[0];
+ return (Filter[]) this._filterList.toArray(array);
+ }
+
+ /**
+ * Method getFilterCount.
+ *
+ * @return the size of this collection
+ */
+ public int getFilterCount()
+ {
+ return this._filterList.size();
+ }
+
+ /**
* Returns the value of field 'schemeName'.
*
* @return the value of field 'SchemeName'.
}
/**
- */
+ */
public void removeAllColour()
{
this._colourList.clear();
}
/**
+ */
+ public void removeAllFilter()
+ {
+ this._filterList.clear();
+ }
+
+ /**
* Method removeColour.
*
* @param vColour
}
/**
+ * Method removeFilter.
+ *
+ * @param vFilter
+ * @return true if the object was removed from the collection.
+ */
+ public boolean removeFilter(final Filter vFilter)
+ {
+ boolean removed = _filterList.remove(vFilter);
+ return removed;
+ }
+
+ /**
+ * Method removeFilterAt.
+ *
+ * @param index
+ * @return the element removed from the collection
+ */
+ public Filter removeFilterAt(final int index)
+ {
+ java.lang.Object obj = this._filterList.remove(index);
+ return (Filter) obj;
+ }
+
+ /**
*
*
* @param index
// check bounds for index
if (index < 0 || index >= this._colourList.size())
{
- throw new IndexOutOfBoundsException("setColour: Index value '"
- + index + "' not in range [0.."
- + (this._colourList.size() - 1) + "]");
+ throw new IndexOutOfBoundsException(
+ "setColour: Index value '" + index + "' not in range [0.."
+ + (this._colourList.size() - 1) + "]");
}
this._colourList.set(index, vColour);
}
/**
+ *
+ *
+ * @param index
+ * @param vFilter
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void setFilter(final int index, final Filter vFilter)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._filterList.size())
+ {
+ throw new IndexOutOfBoundsException(
+ "setFilter: Index value '" + index + "' not in range [0.."
+ + (this._filterList.size() - 1) + "]");
+ }
+
+ this._filterList.set(index, vFilter);
+ }
+
+ /**
+ *
+ *
+ * @param vFilterArray
+ */
+ public void setFilter(final Filter[] vFilterArray)
+ {
+ // -- copy array
+ _filterList.clear();
+
+ for (int i = 0; i < vFilterArray.length; i++)
+ {
+ this._filterList.add(vFilterArray[i]);
+ }
+ }
+
+ /**
* Sets the value of field 'schemeName'.
*
* @param schemeName
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * Class MatchCondition.
+ *
+ * @version $Revision$ $Date$
+ */
+public class MatchCondition extends FeatureMatcher
+ implements java.io.Serializable
+{
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public MatchCondition()
+ {
+ super();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.schemabinding.version2.FeatureMatcher
+ */
+ public static jalview.schemabinding.version2.FeatureMatcher unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.schemabinding.version2.FeatureMatcher) Unmarshaller
+ .unmarshal(jalview.schemabinding.version2.MatchCondition.class,
+ reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import org.exolab.castor.xml.Marshaller;
+import org.exolab.castor.xml.Unmarshaller;
+
+/**
+ * optional filter(s) applied to the feature type
+ *
+ * @version $Revision$ $Date$
+ */
+public class MatcherSet extends FeatureMatcherSet
+ implements java.io.Serializable
+{
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public MatcherSet()
+ {
+ super();
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid()
+ {
+ try
+ {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void marshal(final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException
+ * if an IOException occurs during marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ */
+ public void marshal(final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException,
+ org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException
+ * if object is null or if any SAXException is thrown during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ * @return the unmarshaled jalview.schemabinding.version2.FeatureMatcherSet
+ */
+ public static jalview.schemabinding.version2.FeatureMatcherSet unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException,
+ org.exolab.castor.xml.ValidationException
+ {
+ return (jalview.schemabinding.version2.FeatureMatcherSet) Unmarshaller
+ .unmarshal(jalview.schemabinding.version2.MatcherSet.class,
+ reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException
+ * if this object is an invalid instance according to the schema
+ */
+ public void validate() throws org.exolab.castor.xml.ValidationException
+ {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
+ }
+
+}
package jalview.schemabinding.version2;
-//---------------------------------/
-//- Imported classes and packages -/
+ //---------------------------------/
+ //- Imported classes and packages -/
//---------------------------------/
import org.exolab.castor.xml.Marshaller;
*
* @version $Revision$ $Date$
*/
-public class OtherData implements java.io.Serializable
-{
-
- // --------------------------/
- // - Class/Member Variables -/
- // --------------------------/
-
- /**
- * Field _key.
- */
- private java.lang.String _key;
-
- /**
- * Field _value.
- */
- private java.lang.String _value;
-
- // ----------------/
- // - Constructors -/
- // ----------------/
-
- public OtherData()
- {
- super();
- }
-
- // -----------/
- // - Methods -/
- // -----------/
-
- /**
- * Returns the value of field 'key'.
- *
- * @return the value of field 'Key'.
- */
- public java.lang.String getKey()
- {
- return this._key;
- }
-
- /**
- * Returns the value of field 'value'.
- *
- * @return the value of field 'Value'.
- */
- public java.lang.String getValue()
- {
- return this._value;
- }
-
- /**
- * Method isValid.
- *
- * @return true if this object is valid according to the schema
- */
- public boolean isValid()
- {
- try
- {
- validate();
- } catch (org.exolab.castor.xml.ValidationException vex)
- {
- return false;
+public class OtherData implements java.io.Serializable {
+
+
+ //--------------------------/
+ //- Class/Member Variables -/
+ //--------------------------/
+
+ /**
+ * Field _key.
+ */
+ private java.lang.String _key;
+
+ /**
+ * key2 may be used for a sub-attribute of key
+ */
+ private java.lang.String _key2;
+
+ /**
+ * Field _value.
+ */
+ private java.lang.String _value;
+
+
+ //----------------/
+ //- Constructors -/
+ //----------------/
+
+ public OtherData() {
+ super();
+ }
+
+
+ //-----------/
+ //- Methods -/
+ //-----------/
+
+ /**
+ * Returns the value of field 'key'.
+ *
+ * @return the value of field 'Key'.
+ */
+ public java.lang.String getKey(
+ ) {
+ return this._key;
+ }
+
+ /**
+ * Returns the value of field 'key2'. The field 'key2' has the
+ * following description: key2 may be used for a sub-attribute
+ * of key
+ *
+ * @return the value of field 'Key2'.
+ */
+ public java.lang.String getKey2(
+ ) {
+ return this._key2;
+ }
+
+ /**
+ * Returns the value of field 'value'.
+ *
+ * @return the value of field 'Value'.
+ */
+ public java.lang.String getValue(
+ ) {
+ return this._value;
+ }
+
+ /**
+ * Method isValid.
+ *
+ * @return true if this object is valid according to the schema
+ */
+ public boolean isValid(
+ ) {
+ try {
+ validate();
+ } catch (org.exolab.castor.xml.ValidationException vex) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ *
+ * @param out
+ * @throws org.exolab.castor.xml.MarshalException if object is
+ * null or if any SAXException is thrown during marshaling
+ * @throws org.exolab.castor.xml.ValidationException if this
+ * object is an invalid instance according to the schema
+ */
+ public void marshal(
+ final java.io.Writer out)
+ throws org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
+ Marshaller.marshal(this, out);
+ }
+
+ /**
+ *
+ *
+ * @param handler
+ * @throws java.io.IOException if an IOException occurs during
+ * marshaling
+ * @throws org.exolab.castor.xml.ValidationException if this
+ * object is an invalid instance according to the schema
+ * @throws org.exolab.castor.xml.MarshalException if object is
+ * null or if any SAXException is thrown during marshaling
+ */
+ public void marshal(
+ final org.xml.sax.ContentHandler handler)
+ throws java.io.IOException, org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
+ Marshaller.marshal(this, handler);
+ }
+
+ /**
+ * Sets the value of field 'key'.
+ *
+ * @param key the value of field 'key'.
+ */
+ public void setKey(
+ final java.lang.String key) {
+ this._key = key;
+ }
+
+ /**
+ * Sets the value of field 'key2'. The field 'key2' has the
+ * following description: key2 may be used for a sub-attribute
+ * of key
+ *
+ * @param key2 the value of field 'key2'.
+ */
+ public void setKey2(
+ final java.lang.String key2) {
+ this._key2 = key2;
+ }
+
+ /**
+ * Sets the value of field 'value'.
+ *
+ * @param value the value of field 'value'.
+ */
+ public void setValue(
+ final java.lang.String value) {
+ this._value = value;
+ }
+
+ /**
+ * Method unmarshal.
+ *
+ * @param reader
+ * @throws org.exolab.castor.xml.MarshalException if object is
+ * null or if any SAXException is thrown during marshaling
+ * @throws org.exolab.castor.xml.ValidationException if this
+ * object is an invalid instance according to the schema
+ * @return the unmarshaled
+ * jalview.schemabinding.version2.OtherData
+ */
+ public static jalview.schemabinding.version2.OtherData unmarshal(
+ final java.io.Reader reader)
+ throws org.exolab.castor.xml.MarshalException, org.exolab.castor.xml.ValidationException {
+ return (jalview.schemabinding.version2.OtherData) Unmarshaller.unmarshal(jalview.schemabinding.version2.OtherData.class, reader);
+ }
+
+ /**
+ *
+ *
+ * @throws org.exolab.castor.xml.ValidationException if this
+ * object is an invalid instance according to the schema
+ */
+ public void validate(
+ )
+ throws org.exolab.castor.xml.ValidationException {
+ org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
+ validator.validate(this);
}
- return true;
- }
-
- /**
- *
- *
- * @param out
- * @throws org.exolab.castor.xml.MarshalException
- * if object is null or if any SAXException is thrown during
- * marshaling
- * @throws org.exolab.castor.xml.ValidationException
- * if this object is an invalid instance according to the schema
- */
- public void marshal(final java.io.Writer out)
- throws org.exolab.castor.xml.MarshalException,
- org.exolab.castor.xml.ValidationException
- {
- Marshaller.marshal(this, out);
- }
-
- /**
- *
- *
- * @param handler
- * @throws java.io.IOException
- * if an IOException occurs during marshaling
- * @throws org.exolab.castor.xml.ValidationException
- * if this object is an invalid instance according to the schema
- * @throws org.exolab.castor.xml.MarshalException
- * if object is null or if any SAXException is thrown during
- * marshaling
- */
- public void marshal(final org.xml.sax.ContentHandler handler)
- throws java.io.IOException,
- org.exolab.castor.xml.MarshalException,
- org.exolab.castor.xml.ValidationException
- {
- Marshaller.marshal(this, handler);
- }
-
- /**
- * Sets the value of field 'key'.
- *
- * @param key
- * the value of field 'key'.
- */
- public void setKey(final java.lang.String key)
- {
- this._key = key;
- }
-
- /**
- * Sets the value of field 'value'.
- *
- * @param value
- * the value of field 'value'.
- */
- public void setValue(final java.lang.String value)
- {
- this._value = value;
- }
-
- /**
- * Method unmarshal.
- *
- * @param reader
- * @throws org.exolab.castor.xml.MarshalException
- * if object is null or if any SAXException is thrown during
- * marshaling
- * @throws org.exolab.castor.xml.ValidationException
- * if this object is an invalid instance according to the schema
- * @return the unmarshaled jalview.schemabinding.version2.OtherData
- */
- public static jalview.schemabinding.version2.OtherData unmarshal(
- final java.io.Reader reader)
- throws org.exolab.castor.xml.MarshalException,
- org.exolab.castor.xml.ValidationException
- {
- return (jalview.schemabinding.version2.OtherData) Unmarshaller
- .unmarshal(jalview.schemabinding.version2.OtherData.class,
- reader);
- }
-
- /**
- *
- *
- * @throws org.exolab.castor.xml.ValidationException
- * if this object is an invalid instance according to the schema
- */
- public void validate() throws org.exolab.castor.xml.ValidationException
- {
- org.exolab.castor.xml.Validator validator = new org.exolab.castor.xml.Validator();
- validator.validate(this);
- }
}
private boolean _has_mincolour;
/**
+ * Field _noValueColour.
+ */
+ private jalview.schemabinding.version2.types.NoValueColour _noValueColour = jalview.schemabinding.version2.types.NoValueColour
+ .valueOf("Min");
+
+ /**
* threshold value for graduated feature colour
*
*/
*/
private boolean _has_autoScale;
+ /**
+ * name of feature attribute to colour by, or attribute and sub-attribute
+ */
+ private java.util.Vector _attributeNameList;
+
+ /**
+ * optional filter(s) applied to the feature type
+ */
+ private jalview.schemabinding.version2.MatcherSet _matcherSet;
+
// ----------------/
// - Constructors -/
// ----------------/
public Setting()
{
super();
+ setNoValueColour(jalview.schemabinding.version2.types.NoValueColour
+ .valueOf("Min"));
+ this._attributeNameList = new java.util.Vector();
}
// -----------/
// -----------/
/**
- */
+ *
+ *
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.addElement(vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void addAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check for the maximum size
+ if (this._attributeNameList.size() >= 2)
+ {
+ throw new IndexOutOfBoundsException(
+ "addAttributeName has a maximum of 2");
+ }
+
+ this._attributeNameList.add(index, vAttributeName);
+ }
+
+ /**
+ */
public void deleteAutoScale()
{
this._has_autoScale = false;
}
/**
- */
+ */
public void deleteColour()
{
this._has_colour = false;
}
/**
- */
+ */
public void deleteColourByLabel()
{
this._has_colourByLabel = false;
}
/**
- */
+ */
public void deleteDisplay()
{
this._has_display = false;
}
/**
- */
+ */
public void deleteMax()
{
this._has_max = false;
}
/**
- */
+ */
public void deleteMin()
{
this._has_min = false;
}
/**
- */
+ */
public void deleteMincolour()
{
this._has_mincolour = false;
}
/**
- */
+ */
public void deleteOrder()
{
this._has_order = false;
}
/**
- */
+ */
public void deleteThreshold()
{
this._has_threshold = false;
}
/**
- */
+ */
public void deleteThreshstate()
{
this._has_threshstate = false;
}
/**
+ * Method enumerateAttributeName.
+ *
+ * @return an Enumeration over all java.lang.String elements
+ */
+ public java.util.Enumeration enumerateAttributeName()
+ {
+ return this._attributeNameList.elements();
+ }
+
+ /**
+ * Method getAttributeName.
+ *
+ * @param index
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ * @return the value of the java.lang.String at the given index
+ */
+ public java.lang.String getAttributeName(final int index)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("getAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ return (java.lang.String) _attributeNameList.get(index);
+ }
+
+ /**
+ * Method getAttributeName.Returns the contents of the collection in an Array.
+ * <p>
+ * Note: Just in case the collection contents are changing in another thread,
+ * we pass a 0-length Array of the correct type into the API call. This way we
+ * <i>know</i> that the Array returned is of exactly the correct length.
+ *
+ * @return this collection as an Array
+ */
+ public java.lang.String[] getAttributeName()
+ {
+ java.lang.String[] array = new java.lang.String[0];
+ return (java.lang.String[]) this._attributeNameList.toArray(array);
+ }
+
+ /**
+ * Method getAttributeNameCount.
+ *
+ * @return the size of this collection
+ */
+ public int getAttributeNameCount()
+ {
+ return this._attributeNameList.size();
+ }
+
+ /**
* Returns the value of field 'autoScale'.
*
* @return the value of field 'AutoScale'.
}
/**
+ * Returns the value of field 'matcherSet'. The field 'matcherSet' has the
+ * following description: optional filter(s) applied to the feature type
+ *
+ * @return the value of field 'MatcherSet'.
+ */
+ public jalview.schemabinding.version2.MatcherSet getMatcherSet()
+ {
+ return this._matcherSet;
+ }
+
+ /**
* Returns the value of field 'max'.
*
* @return the value of field 'Max'.
}
/**
+ * Returns the value of field 'noValueColour'.
+ *
+ * @return the value of field 'NoValueColour'.
+ */
+ public jalview.schemabinding.version2.types.NoValueColour getNoValueColour()
+ {
+ return this._noValueColour;
+ }
+
+ /**
* Returns the value of field 'order'.
*
* @return the value of field 'Order'.
}
/**
+ */
+ public void removeAllAttributeName()
+ {
+ this._attributeNameList.clear();
+ }
+
+ /**
+ * Method removeAttributeName.
+ *
+ * @param vAttributeName
+ * @return true if the object was removed from the collection.
+ */
+ public boolean removeAttributeName(final java.lang.String vAttributeName)
+ {
+ boolean removed = _attributeNameList.remove(vAttributeName);
+ return removed;
+ }
+
+ /**
+ * Method removeAttributeNameAt.
+ *
+ * @param index
+ * @return the element removed from the collection
+ */
+ public java.lang.String removeAttributeNameAt(final int index)
+ {
+ java.lang.Object obj = this._attributeNameList.remove(index);
+ return (java.lang.String) obj;
+ }
+
+ /**
+ *
+ *
+ * @param index
+ * @param vAttributeName
+ * @throws java.lang.IndexOutOfBoundsException
+ * if the index given is outside the bounds of the collection
+ */
+ public void setAttributeName(final int index,
+ final java.lang.String vAttributeName)
+ throws java.lang.IndexOutOfBoundsException
+ {
+ // check bounds for index
+ if (index < 0 || index >= this._attributeNameList.size())
+ {
+ throw new IndexOutOfBoundsException("setAttributeName: Index value '"
+ + index + "' not in range [0.."
+ + (this._attributeNameList.size() - 1) + "]");
+ }
+
+ this._attributeNameList.set(index, vAttributeName);
+ }
+
+ /**
+ *
+ *
+ * @param vAttributeNameArray
+ */
+ public void setAttributeName(final java.lang.String[] vAttributeNameArray)
+ {
+ // -- copy array
+ _attributeNameList.clear();
+
+ for (int i = 0; i < vAttributeNameArray.length; i++)
+ {
+ this._attributeNameList.add(vAttributeNameArray[i]);
+ }
+ }
+
+ /**
* Sets the value of field 'autoScale'.
*
* @param autoScale
}
/**
+ * Sets the value of field 'matcherSet'. The field 'matcherSet' has the
+ * following description: optional filter(s) applied to the feature type
+ *
+ * @param matcherSet
+ * the value of field 'matcherSet'.
+ */
+ public void setMatcherSet(
+ final jalview.schemabinding.version2.MatcherSet matcherSet)
+ {
+ this._matcherSet = matcherSet;
+ }
+
+ /**
* Sets the value of field 'max'.
*
* @param max
}
/**
+ * Sets the value of field 'noValueColour'.
+ *
+ * @param noValueColour
+ * the value of field 'noValueColour'.
+ */
+ public void setNoValueColour(
+ final jalview.schemabinding.version2.types.NoValueColour noValueColour)
+ {
+ this._noValueColour = noValueColour;
+ }
+
+ /**
* Sets the value of field 'order'.
*
* @param order
*
* @version $Revision$ $Date$
*/
-public class ColourDescriptor extends
- org.exolab.castor.xml.util.XMLClassDescriptorImpl
+public class ColourDescriptor
+ extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
{
// --------------------------/
super();
_xmlName = "colour";
_elementDefinition = true;
+
+ // -- set grouping compositor
+ setCompositorAsSequence();
org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
org.exolab.castor.mapping.FieldHandler handler = null;
org.exolab.castor.xml.FieldValidator fieldValidator = null;
typeValidator.setWhiteSpace("preserve");
}
desc.setValidator(fieldValidator);
- // -- _threshType
+ // -- _noValueColour
desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
- java.lang.String.class, "_threshType", "threshType",
+ jalview.schemabinding.version2.types.NoValueColour.class,
+ "_noValueColour", "noValueColour",
org.exolab.castor.xml.NodeType.Attribute);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ Colour target = (Colour) object;
+ return target.getNoValueColour();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ Colour target = (Colour) object;
+ target.setNoValueColour(
+ (jalview.schemabinding.version2.types.NoValueColour) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ handler = new org.exolab.castor.xml.handlers.EnumFieldHandler(
+ jalview.schemabinding.version2.types.NoValueColour.class,
+ handler);
desc.setImmutable(true);
+ desc.setHandler(handler);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _noValueColour
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ { // -- local scope
+ }
+ desc.setValidator(fieldValidator);
+ // -- _threshType
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ jalview.schemabinding.version2.types.ColourThreshTypeType.class,
+ "_threshType", "threshType",
+ org.exolab.castor.xml.NodeType.Attribute);
handler = new org.exolab.castor.xml.XMLFieldHandler()
{
public java.lang.Object getValue(java.lang.Object object)
try
{
Colour target = (Colour) object;
- target.setThreshType((java.lang.String) value);
+ target.setThreshType(
+ (jalview.schemabinding.version2.types.ColourThreshTypeType) value);
} catch (java.lang.Exception ex)
{
throw new IllegalStateException(ex.toString());
return null;
}
};
+ handler = new org.exolab.castor.xml.handlers.EnumFieldHandler(
+ jalview.schemabinding.version2.types.ColourThreshTypeType.class,
+ handler);
+ desc.setImmutable(true);
desc.setHandler(handler);
desc.setMultivalued(false);
addFieldDescriptor(desc);
// -- validation code for: _threshType
fieldValidator = new org.exolab.castor.xml.FieldValidator();
{ // -- local scope
- org.exolab.castor.xml.validators.StringValidator typeValidator;
- typeValidator = new org.exolab.castor.xml.validators.StringValidator();
- fieldValidator.setValidator(typeValidator);
- typeValidator.setWhiteSpace("preserve");
}
desc.setValidator(fieldValidator);
// -- _threshold
target.deleteColourByLabel();
return;
}
- target.setColourByLabel(((java.lang.Boolean) value)
- .booleanValue());
+ target.setColourByLabel(
+ ((java.lang.Boolean) value).booleanValue());
} catch (java.lang.Exception ex)
{
throw new IllegalStateException(ex.toString());
desc.setValidator(fieldValidator);
// -- initialize element descriptors
+ // -- _attributeNameList
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ java.lang.String.class, "_attributeNameList", "attributeName",
+ org.exolab.castor.xml.NodeType.Element);
+ desc.setImmutable(true);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ Colour target = (Colour) object;
+ return target.getAttributeName();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ Colour target = (Colour) object;
+ target.addAttributeName((java.lang.String) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public void resetValue(Object object)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ Colour target = (Colour) object;
+ target.removeAllAttributeName();
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setMultivalued(true);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _attributeNameList
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(0);
+ fieldValidator.setMaxOccurs(2);
+ { // -- local scope
+ org.exolab.castor.xml.validators.StringValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+ fieldValidator.setValidator(typeValidator);
+ typeValidator.setWhiteSpace("preserve");
+ }
+ desc.setValidator(fieldValidator);
}
// -----------/
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.CompoundMatcher;
+
+/**
+ * Class CompoundMatcherDescriptor.
+ *
+ * @version $Revision$ $Date$
+ */
+public class CompoundMatcherDescriptor
+ extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public CompoundMatcherDescriptor()
+ {
+ super();
+ _xmlName = "compoundMatcher";
+ _elementDefinition = true;
+
+ // -- set grouping compositor
+ setCompositorAsSequence();
+ org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+ org.exolab.castor.mapping.FieldHandler handler = null;
+ org.exolab.castor.xml.FieldValidator fieldValidator = null;
+ // -- initialize attribute descriptors
+
+ // -- _and
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ java.lang.Boolean.TYPE, "_and", "and",
+ org.exolab.castor.xml.NodeType.Attribute);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ CompoundMatcher target = (CompoundMatcher) object;
+ if (!target.hasAnd())
+ {
+ return null;
+ }
+ return (target.getAnd() ? java.lang.Boolean.TRUE
+ : java.lang.Boolean.FALSE);
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ CompoundMatcher target = (CompoundMatcher) object;
+ // ignore null values for non optional primitives
+ if (value == null)
+ {
+ return;
+ }
+
+ target.setAnd(((java.lang.Boolean) value).booleanValue());
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _and
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(1);
+ { // -- local scope
+ org.exolab.castor.xml.validators.BooleanValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.BooleanValidator();
+ fieldValidator.setValidator(typeValidator);
+ }
+ desc.setValidator(fieldValidator);
+ // -- initialize element descriptors
+
+ // -- _matcherSetList
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ jalview.schemabinding.version2.MatcherSet.class,
+ "_matcherSetList", "matcherSet",
+ org.exolab.castor.xml.NodeType.Element);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ CompoundMatcher target = (CompoundMatcher) object;
+ return target.getMatcherSet();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ CompoundMatcher target = (CompoundMatcher) object;
+ target.addMatcherSet(
+ (jalview.schemabinding.version2.MatcherSet) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public void resetValue(Object object)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ CompoundMatcher target = (CompoundMatcher) object;
+ target.removeAllMatcherSet();
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return new jalview.schemabinding.version2.MatcherSet();
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(true);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _matcherSetList
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(2);
+ fieldValidator.setMaxOccurs(2);
+ { // -- local scope
+ }
+ desc.setValidator(fieldValidator);
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ public org.exolab.castor.mapping.AccessMode getAccessMode()
+ {
+ return null;
+ }
+
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no identity.
+ */
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+ {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ public java.lang.Class getJavaClass()
+ {
+ return jalview.schemabinding.version2.CompoundMatcher.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ public java.lang.String getNameSpacePrefix()
+ {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and unmarshaling as XML.
+ */
+ public java.lang.String getNameSpaceURI()
+ {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ public org.exolab.castor.xml.TypeValidator getValidator()
+ {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ public java.lang.String getXMLName()
+ {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that of a global
+ * element or element with anonymous type definition.
+ */
+ public boolean isElementDefinition()
+ {
+ return _elementDefinition;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.FeatureMatcher;
+
+/**
+ * Class FeatureMatcherDescriptor.
+ *
+ * @version $Revision$ $Date$
+ */
+public class FeatureMatcherDescriptor
+ extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public FeatureMatcherDescriptor()
+ {
+ super();
+ _nsURI = "www.jalview.org/colours";
+ _xmlName = "FeatureMatcher";
+ _elementDefinition = false;
+
+ // -- set grouping compositor
+ setCompositorAsSequence();
+ org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+ org.exolab.castor.mapping.FieldHandler handler = null;
+ org.exolab.castor.xml.FieldValidator fieldValidator = null;
+ // -- initialize attribute descriptors
+
+ // -- _by
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ jalview.schemabinding.version2.types.FeatureMatcherByType.class,
+ "_by", "by", org.exolab.castor.xml.NodeType.Attribute);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ FeatureMatcher target = (FeatureMatcher) object;
+ return target.getBy();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ FeatureMatcher target = (FeatureMatcher) object;
+ target.setBy(
+ (jalview.schemabinding.version2.types.FeatureMatcherByType) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ handler = new org.exolab.castor.xml.handlers.EnumFieldHandler(
+ jalview.schemabinding.version2.types.FeatureMatcherByType.class,
+ handler);
+ desc.setImmutable(true);
+ desc.setHandler(handler);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _by
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ { // -- local scope
+ }
+ desc.setValidator(fieldValidator);
+ // -- initialize element descriptors
+
+ // -- _attributeNameList
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ java.lang.String.class, "_attributeNameList", "attributeName",
+ org.exolab.castor.xml.NodeType.Element);
+ desc.setImmutable(true);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ FeatureMatcher target = (FeatureMatcher) object;
+ return target.getAttributeName();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ FeatureMatcher target = (FeatureMatcher) object;
+ target.addAttributeName((java.lang.String) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public void resetValue(Object object)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ FeatureMatcher target = (FeatureMatcher) object;
+ target.removeAllAttributeName();
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setMultivalued(true);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _attributeNameList
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(0);
+ fieldValidator.setMaxOccurs(2);
+ { // -- local scope
+ org.exolab.castor.xml.validators.StringValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+ fieldValidator.setValidator(typeValidator);
+ typeValidator.setWhiteSpace("preserve");
+ }
+ desc.setValidator(fieldValidator);
+ // -- _condition
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ java.lang.String.class, "_condition", "condition",
+ org.exolab.castor.xml.NodeType.Element);
+ desc.setImmutable(true);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ FeatureMatcher target = (FeatureMatcher) object;
+ return target.getCondition();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ FeatureMatcher target = (FeatureMatcher) object;
+ target.setCondition((java.lang.String) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _condition
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(1);
+ { // -- local scope
+ org.exolab.castor.xml.validators.StringValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+ fieldValidator.setValidator(typeValidator);
+ typeValidator.setWhiteSpace("preserve");
+ }
+ desc.setValidator(fieldValidator);
+ // -- _value
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ java.lang.String.class, "_value", "value",
+ org.exolab.castor.xml.NodeType.Element);
+ desc.setImmutable(true);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ FeatureMatcher target = (FeatureMatcher) object;
+ return target.getValue();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ FeatureMatcher target = (FeatureMatcher) object;
+ target.setValue((java.lang.String) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _value
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(1);
+ { // -- local scope
+ org.exolab.castor.xml.validators.StringValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+ fieldValidator.setValidator(typeValidator);
+ typeValidator.setWhiteSpace("preserve");
+ }
+ desc.setValidator(fieldValidator);
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ public org.exolab.castor.mapping.AccessMode getAccessMode()
+ {
+ return null;
+ }
+
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no identity.
+ */
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+ {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ public java.lang.Class getJavaClass()
+ {
+ return jalview.schemabinding.version2.FeatureMatcher.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ public java.lang.String getNameSpacePrefix()
+ {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and unmarshaling as XML.
+ */
+ public java.lang.String getNameSpaceURI()
+ {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ public org.exolab.castor.xml.TypeValidator getValidator()
+ {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ public java.lang.String getXMLName()
+ {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that of a global
+ * element or element with anonymous type definition.
+ */
+ public boolean isElementDefinition()
+ {
+ return _elementDefinition;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+import jalview.schemabinding.version2.CompoundMatcher;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.FeatureMatcherSet;
+import jalview.schemabinding.version2.MatchCondition;
+
+/**
+ * Class FeatureMatcherSetDescriptor.
+ *
+ * @version $Revision$ $Date$
+ */
+public class FeatureMatcherSetDescriptor
+ extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public FeatureMatcherSetDescriptor()
+ {
+ super();
+ _nsURI = "www.jalview.org/colours";
+ _xmlName = "FeatureMatcherSet";
+ _elementDefinition = false;
+
+ // -- set grouping compositor
+ setCompositorAsChoice();
+ org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+ org.exolab.castor.mapping.FieldHandler handler = null;
+ org.exolab.castor.xml.FieldValidator fieldValidator = null;
+ // -- initialize attribute descriptors
+
+ // -- initialize element descriptors
+
+ // -- _matchCondition
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ MatchCondition.class, "_matchCondition", "matchCondition",
+ org.exolab.castor.xml.NodeType.Element);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ @Override
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ FeatureMatcherSet target = (FeatureMatcherSet) object;
+ return target.getMatchCondition();
+ }
+
+ @Override
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ FeatureMatcherSet target = (FeatureMatcherSet) object;
+ target.setMatchCondition((MatchCondition) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ @Override
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return new MatchCondition();
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _matchCondition
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(1);
+ { // -- local scope
+ }
+ desc.setValidator(fieldValidator);
+ // -- _compoundMatcher
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ CompoundMatcher.class, "_compoundMatcher", "compoundMatcher",
+ org.exolab.castor.xml.NodeType.Element);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ @Override
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ FeatureMatcherSet target = (FeatureMatcherSet) object;
+ return target.getCompoundMatcher();
+ }
+
+ @Override
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ FeatureMatcherSet target = (FeatureMatcherSet) object;
+ target.setCompoundMatcher((CompoundMatcher) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ @Override
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return new CompoundMatcher();
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _compoundMatcher
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(1);
+ { // -- local scope
+ }
+ desc.setValidator(fieldValidator);
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ @Override
+ public org.exolab.castor.mapping.AccessMode getAccessMode()
+ {
+ return null;
+ }
+
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no identity.
+ */
+ @Override
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+ {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ @Override
+ public java.lang.Class getJavaClass()
+ {
+ return jalview.schemabinding.version2.FeatureMatcherSet.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ @Override
+ public java.lang.String getNameSpacePrefix()
+ {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and unmarshaling as XML.
+ */
+ @Override
+ public java.lang.String getNameSpaceURI()
+ {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ @Override
+ public org.exolab.castor.xml.TypeValidator getValidator()
+ {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ @Override
+ public java.lang.String getXMLName()
+ {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that of a global
+ * element or element with anonymous type definition.
+ */
+ @Override
+ public boolean isElementDefinition()
+ {
+ return _elementDefinition;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.Filter;
+
+/**
+ * Class FilterDescriptor.
+ *
+ * @version $Revision$ $Date$
+ */
+public class FilterDescriptor
+ extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public FilterDescriptor()
+ {
+ super();
+ _xmlName = "filter";
+ _elementDefinition = true;
+
+ // -- set grouping compositor
+ setCompositorAsSequence();
+ org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+ org.exolab.castor.mapping.FieldHandler handler = null;
+ org.exolab.castor.xml.FieldValidator fieldValidator = null;
+ // -- initialize attribute descriptors
+
+ // -- _featureType
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ java.lang.String.class, "_featureType", "featureType",
+ org.exolab.castor.xml.NodeType.Attribute);
+ desc.setImmutable(true);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ Filter target = (Filter) object;
+ return target.getFeatureType();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ Filter target = (Filter) object;
+ target.setFeatureType((java.lang.String) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _featureType
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(1);
+ { // -- local scope
+ org.exolab.castor.xml.validators.StringValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+ fieldValidator.setValidator(typeValidator);
+ typeValidator.setWhiteSpace("preserve");
+ }
+ desc.setValidator(fieldValidator);
+ // -- initialize element descriptors
+
+ // -- _matcherSet
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ jalview.schemabinding.version2.MatcherSet.class, "_matcherSet",
+ "matcherSet", org.exolab.castor.xml.NodeType.Element);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ Filter target = (Filter) object;
+ return target.getMatcherSet();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ Filter target = (Filter) object;
+ target.setMatcherSet(
+ (jalview.schemabinding.version2.MatcherSet) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return new jalview.schemabinding.version2.MatcherSet();
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _matcherSet
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(1);
+ { // -- local scope
+ }
+ desc.setValidator(fieldValidator);
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ public org.exolab.castor.mapping.AccessMode getAccessMode()
+ {
+ return null;
+ }
+
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no identity.
+ */
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+ {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ public java.lang.Class getJavaClass()
+ {
+ return jalview.schemabinding.version2.Filter.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ public java.lang.String getNameSpacePrefix()
+ {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and unmarshaling as XML.
+ */
+ public java.lang.String getNameSpaceURI()
+ {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ public org.exolab.castor.xml.TypeValidator getValidator()
+ {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ public java.lang.String getXMLName()
+ {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that of a global
+ * element or element with anonymous type definition.
+ */
+ public boolean isElementDefinition()
+ {
+ return _elementDefinition;
+ }
+
+}
package jalview.schemabinding.version2.descriptors;
+import jalview.schemabinding.version2.Colour;
+import jalview.schemabinding.version2.Filter;
+
//---------------------------------/
//- Imported classes and packages -/
//---------------------------------/
-import jalview.schemabinding.version2.Colour;
import jalview.schemabinding.version2.JalviewUserColours;
/**
*
* @version $Revision$ $Date$
*/
-public class JalviewUserColoursDescriptor extends
- org.exolab.castor.xml.util.XMLClassDescriptorImpl
+public class JalviewUserColoursDescriptor
+ extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
{
// --------------------------/
}
@Override
- public void resetValue(Object object) throws IllegalStateException,
- IllegalArgumentException
+ public void resetValue(Object object)
+ throws IllegalStateException, IllegalArgumentException
{
try
{
{ // -- local scope
}
desc.setValidator(fieldValidator);
+ // -- _filterList
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ Filter.class, "_filterList", "filter",
+ org.exolab.castor.xml.NodeType.Element);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ @Override
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ JalviewUserColours target = (JalviewUserColours) object;
+ return target.getFilter();
+ }
+
+ @Override
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ JalviewUserColours target = (JalviewUserColours) object;
+ target.addFilter((Filter) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ @Override
+ public void resetValue(Object object)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ JalviewUserColours target = (JalviewUserColours) object;
+ target.removeAllFilter();
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ @Override
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return new Filter();
+ }
+ };
+ desc.setHandler(handler);
+ desc.setMultivalued(true);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _filterList
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(0);
+ { // -- local scope
+ }
+ desc.setValidator(fieldValidator);
}
// -----------/
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.MatchCondition;
+
+/**
+ * Class MatchConditionDescriptor.
+ *
+ * @version $Revision$ $Date$
+ */
+public class MatchConditionDescriptor extends
+ jalview.schemabinding.version2.descriptors.FeatureMatcherDescriptor
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public MatchConditionDescriptor()
+ {
+ super();
+ setExtendsWithoutFlatten(
+ new jalview.schemabinding.version2.descriptors.FeatureMatcherDescriptor());
+ _xmlName = "matchCondition";
+ _elementDefinition = true;
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ public org.exolab.castor.mapping.AccessMode getAccessMode()
+ {
+ return null;
+ }
+
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no identity.
+ */
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+ {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ public java.lang.Class getJavaClass()
+ {
+ return jalview.schemabinding.version2.MatchCondition.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ public java.lang.String getNameSpacePrefix()
+ {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and unmarshaling as XML.
+ */
+ public java.lang.String getNameSpaceURI()
+ {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ public org.exolab.castor.xml.TypeValidator getValidator()
+ {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ public java.lang.String getXMLName()
+ {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that of a global
+ * element or element with anonymous type definition.
+ */
+ public boolean isElementDefinition()
+ {
+ return _elementDefinition;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.MatcherSet;
+
+/**
+ * Class MatcherSetDescriptor.
+ *
+ * @version $Revision$ $Date$
+ */
+public class MatcherSetDescriptor extends
+ jalview.schemabinding.version2.descriptors.FeatureMatcherSetDescriptor
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public MatcherSetDescriptor()
+ {
+ super();
+ setExtendsWithoutFlatten(
+ new jalview.schemabinding.version2.descriptors.FeatureMatcherSetDescriptor());
+ _xmlName = "matcherSet";
+ _elementDefinition = true;
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ public org.exolab.castor.mapping.AccessMode getAccessMode()
+ {
+ return null;
+ }
+
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no identity.
+ */
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+ {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ public java.lang.Class getJavaClass()
+ {
+ return jalview.schemabinding.version2.MatcherSet.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ public java.lang.String getNameSpacePrefix()
+ {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and unmarshaling as XML.
+ */
+ public java.lang.String getNameSpaceURI()
+ {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ public org.exolab.castor.xml.TypeValidator getValidator()
+ {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ public java.lang.String getXMLName()
+ {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that of a global
+ * element or element with anonymous type definition.
+ */
+ public boolean isElementDefinition()
+ {
+ return _elementDefinition;
+ }
+
+}
package jalview.schemabinding.version2.descriptors;
-//---------------------------------/
-//- Imported classes and packages -/
+ //---------------------------------/
+ //- Imported classes and packages -/
//---------------------------------/
import jalview.schemabinding.version2.OtherData;
*
* @version $Revision$ $Date$
*/
-public class OtherDataDescriptor extends
- org.exolab.castor.xml.util.XMLClassDescriptorImpl
-{
-
- // --------------------------/
- // - Class/Member Variables -/
- // --------------------------/
-
- /**
- * Field _elementDefinition.
- */
- private boolean _elementDefinition;
-
- /**
- * Field _nsPrefix.
- */
- private java.lang.String _nsPrefix;
-
- /**
- * Field _nsURI.
- */
- private java.lang.String _nsURI;
-
- /**
- * Field _xmlName.
- */
- private java.lang.String _xmlName;
-
- // ----------------/
- // - Constructors -/
- // ----------------/
-
- public OtherDataDescriptor()
- {
- super();
- _nsURI = "www.jalview.org";
- _xmlName = "otherData";
- _elementDefinition = true;
- org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
- org.exolab.castor.mapping.FieldHandler handler = null;
- org.exolab.castor.xml.FieldValidator fieldValidator = null;
- // -- initialize attribute descriptors
-
- // -- _key
- desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
- java.lang.String.class, "_key", "key",
- org.exolab.castor.xml.NodeType.Attribute);
- desc.setImmutable(true);
- handler = new org.exolab.castor.xml.XMLFieldHandler()
- {
- public java.lang.Object getValue(java.lang.Object object)
- throws IllegalStateException
- {
- OtherData target = (OtherData) object;
- return target.getKey();
- }
-
- public void setValue(java.lang.Object object, java.lang.Object value)
- throws IllegalStateException, IllegalArgumentException
- {
- try
- {
- OtherData target = (OtherData) object;
- target.setKey((java.lang.String) value);
- } catch (java.lang.Exception ex)
- {
- throw new IllegalStateException(ex.toString());
+public class OtherDataDescriptor extends org.exolab.castor.xml.util.XMLClassDescriptorImpl {
+
+
+ //--------------------------/
+ //- Class/Member Variables -/
+ //--------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+
+ //----------------/
+ //- Constructors -/
+ //----------------/
+
+ public OtherDataDescriptor() {
+ super();
+ _nsURI = "www.jalview.org";
+ _xmlName = "otherData";
+ _elementDefinition = true;
+ org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
+ org.exolab.castor.mapping.FieldHandler handler = null;
+ org.exolab.castor.xml.FieldValidator fieldValidator = null;
+ //-- initialize attribute descriptors
+
+ //-- _key
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(java.lang.String.class, "_key", "key", org.exolab.castor.xml.NodeType.Attribute);
+ desc.setImmutable(true);
+ handler = new org.exolab.castor.xml.XMLFieldHandler() {
+ public java.lang.Object getValue( java.lang.Object object )
+ throws IllegalStateException
+ {
+ OtherData target = (OtherData) object;
+ return target.getKey();
+ }
+ public void setValue( java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try {
+ OtherData target = (OtherData) object;
+ target.setKey( (java.lang.String) value);
+ } catch (java.lang.Exception ex) {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+ public java.lang.Object newInstance(java.lang.Object parent) {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ //-- validation code for: _key
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(1);
+ { //-- local scope
+ org.exolab.castor.xml.validators.StringValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+ fieldValidator.setValidator(typeValidator);
+ typeValidator.setWhiteSpace("preserve");
+ }
+ desc.setValidator(fieldValidator);
+ //-- _key2
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(java.lang.String.class, "_key2", "key2", org.exolab.castor.xml.NodeType.Attribute);
+ desc.setImmutable(true);
+ handler = new org.exolab.castor.xml.XMLFieldHandler() {
+ public java.lang.Object getValue( java.lang.Object object )
+ throws IllegalStateException
+ {
+ OtherData target = (OtherData) object;
+ return target.getKey2();
+ }
+ public void setValue( java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try {
+ OtherData target = (OtherData) object;
+ target.setKey2( (java.lang.String) value);
+ } catch (java.lang.Exception ex) {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+ public java.lang.Object newInstance(java.lang.Object parent) {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ //-- validation code for: _key2
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ { //-- local scope
+ org.exolab.castor.xml.validators.StringValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+ fieldValidator.setValidator(typeValidator);
+ typeValidator.setWhiteSpace("preserve");
+ }
+ desc.setValidator(fieldValidator);
+ //-- _value
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(java.lang.String.class, "_value", "value", org.exolab.castor.xml.NodeType.Attribute);
+ desc.setImmutable(true);
+ handler = new org.exolab.castor.xml.XMLFieldHandler() {
+ public java.lang.Object getValue( java.lang.Object object )
+ throws IllegalStateException
+ {
+ OtherData target = (OtherData) object;
+ return target.getValue();
+ }
+ public void setValue( java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try {
+ OtherData target = (OtherData) object;
+ target.setValue( (java.lang.String) value);
+ } catch (java.lang.Exception ex) {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+ public java.lang.Object newInstance(java.lang.Object parent) {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setRequired(true);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ //-- validation code for: _value
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(1);
+ { //-- local scope
+ org.exolab.castor.xml.validators.StringValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+ fieldValidator.setValidator(typeValidator);
+ typeValidator.setWhiteSpace("preserve");
}
- }
+ desc.setValidator(fieldValidator);
+ //-- initialize element descriptors
+
+ }
+
+
+ //-----------/
+ //- Methods -/
+ //-----------/
- public java.lang.Object newInstance(java.lang.Object parent)
- {
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ public org.exolab.castor.mapping.AccessMode getAccessMode(
+ ) {
return null;
- }
- };
- desc.setHandler(handler);
- desc.setRequired(true);
- desc.setMultivalued(false);
- addFieldDescriptor(desc);
-
- // -- validation code for: _key
- fieldValidator = new org.exolab.castor.xml.FieldValidator();
- fieldValidator.setMinOccurs(1);
- { // -- local scope
- org.exolab.castor.xml.validators.StringValidator typeValidator;
- typeValidator = new org.exolab.castor.xml.validators.StringValidator();
- fieldValidator.setValidator(typeValidator);
- typeValidator.setWhiteSpace("preserve");
}
- desc.setValidator(fieldValidator);
- // -- _value
- desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
- java.lang.String.class, "_value", "value",
- org.exolab.castor.xml.NodeType.Attribute);
- desc.setImmutable(true);
- handler = new org.exolab.castor.xml.XMLFieldHandler()
- {
- public java.lang.Object getValue(java.lang.Object object)
- throws IllegalStateException
- {
- OtherData target = (OtherData) object;
- return target.getValue();
- }
-
- public void setValue(java.lang.Object object, java.lang.Object value)
- throws IllegalStateException, IllegalArgumentException
- {
- try
- {
- OtherData target = (OtherData) object;
- target.setValue((java.lang.String) value);
- } catch (java.lang.Exception ex)
- {
- throw new IllegalStateException(ex.toString());
- }
- }
- public java.lang.Object newInstance(java.lang.Object parent)
- {
- return null;
- }
- };
- desc.setHandler(handler);
- desc.setRequired(true);
- desc.setMultivalued(false);
- addFieldDescriptor(desc);
-
- // -- validation code for: _value
- fieldValidator = new org.exolab.castor.xml.FieldValidator();
- fieldValidator.setMinOccurs(1);
- { // -- local scope
- org.exolab.castor.xml.validators.StringValidator typeValidator;
- typeValidator = new org.exolab.castor.xml.validators.StringValidator();
- fieldValidator.setValidator(typeValidator);
- typeValidator.setWhiteSpace("preserve");
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no
+ * identity.
+ */
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity(
+ ) {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ public java.lang.Class getJavaClass(
+ ) {
+ return jalview.schemabinding.version2.OtherData.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ public java.lang.String getNameSpacePrefix(
+ ) {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and
+ * unmarshaling as XML.
+ */
+ public java.lang.String getNameSpaceURI(
+ ) {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ public org.exolab.castor.xml.TypeValidator getValidator(
+ ) {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ public java.lang.String getXMLName(
+ ) {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that
+ * of a global
+ * element or element with anonymous type definition.
+ */
+ public boolean isElementDefinition(
+ ) {
+ return _elementDefinition;
}
- desc.setValidator(fieldValidator);
- // -- initialize element descriptors
-
- }
-
- // -----------/
- // - Methods -/
- // -----------/
-
- /**
- * Method getAccessMode.
- *
- * @return the access mode specified for this class.
- */
- public org.exolab.castor.mapping.AccessMode getAccessMode()
- {
- return null;
- }
-
- /**
- * Method getIdentity.
- *
- * @return the identity field, null if this class has no identity.
- */
- public org.exolab.castor.mapping.FieldDescriptor getIdentity()
- {
- return super.getIdentity();
- }
-
- /**
- * Method getJavaClass.
- *
- * @return the Java class represented by this descriptor.
- */
- public java.lang.Class getJavaClass()
- {
- return jalview.schemabinding.version2.OtherData.class;
- }
-
- /**
- * Method getNameSpacePrefix.
- *
- * @return the namespace prefix to use when marshaling as XML.
- */
- public java.lang.String getNameSpacePrefix()
- {
- return _nsPrefix;
- }
-
- /**
- * Method getNameSpaceURI.
- *
- * @return the namespace URI used when marshaling and unmarshaling as XML.
- */
- public java.lang.String getNameSpaceURI()
- {
- return _nsURI;
- }
-
- /**
- * Method getValidator.
- *
- * @return a specific validator for the class described by this
- * ClassDescriptor.
- */
- public org.exolab.castor.xml.TypeValidator getValidator()
- {
- return this;
- }
-
- /**
- * Method getXMLName.
- *
- * @return the XML Name for the Class being described.
- */
- public java.lang.String getXMLName()
- {
- return _xmlName;
- }
-
- /**
- * Method isElementDefinition.
- *
- * @return true if XML schema definition of this Class is that of a global
- * element or element with anonymous type definition.
- */
- public boolean isElementDefinition()
- {
- return _elementDefinition;
- }
}
*
* @version $Revision$ $Date$
*/
-public class SettingDescriptor extends
- org.exolab.castor.xml.util.XMLClassDescriptorImpl
+public class SettingDescriptor
+ extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
{
// --------------------------/
_nsURI = "www.jalview.org";
_xmlName = "setting";
_elementDefinition = true;
+
+ // -- set grouping compositor
+ setCompositorAsSequence();
org.exolab.castor.xml.util.XMLFieldDescriptorImpl desc = null;
org.exolab.castor.mapping.FieldHandler handler = null;
org.exolab.castor.xml.FieldValidator fieldValidator = null;
typeValidator.setMaxInclusive(2147483647);
}
desc.setValidator(fieldValidator);
+ // -- _noValueColour
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ jalview.schemabinding.version2.types.NoValueColour.class,
+ "_noValueColour", "noValueColour",
+ org.exolab.castor.xml.NodeType.Attribute);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ Setting target = (Setting) object;
+ return target.getNoValueColour();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ Setting target = (Setting) object;
+ target.setNoValueColour(
+ (jalview.schemabinding.version2.types.NoValueColour) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ handler = new org.exolab.castor.xml.handlers.EnumFieldHandler(
+ jalview.schemabinding.version2.types.NoValueColour.class,
+ handler);
+ desc.setImmutable(true);
+ desc.setHandler(handler);
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _noValueColour
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ { // -- local scope
+ }
+ desc.setValidator(fieldValidator);
// -- _threshold
desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
java.lang.Float.TYPE, "_threshold", "threshold",
target.deleteColourByLabel();
return;
}
- target.setColourByLabel(((java.lang.Boolean) value)
- .booleanValue());
+ target.setColourByLabel(
+ ((java.lang.Boolean) value).booleanValue());
} catch (java.lang.Exception ex)
{
throw new IllegalStateException(ex.toString());
desc.setValidator(fieldValidator);
// -- initialize element descriptors
+ // -- _attributeNameList
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ java.lang.String.class, "_attributeNameList", "attributeName",
+ org.exolab.castor.xml.NodeType.Element);
+ desc.setImmutable(true);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ Setting target = (Setting) object;
+ return target.getAttributeName();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ Setting target = (Setting) object;
+ target.addAttributeName((java.lang.String) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public void resetValue(Object object)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ Setting target = (Setting) object;
+ target.removeAllAttributeName();
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return null;
+ }
+ };
+ desc.setHandler(handler);
+ desc.setNameSpaceURI("www.jalview.org");
+ desc.setMultivalued(true);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _attributeNameList
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ fieldValidator.setMinOccurs(0);
+ fieldValidator.setMaxOccurs(2);
+ { // -- local scope
+ org.exolab.castor.xml.validators.StringValidator typeValidator;
+ typeValidator = new org.exolab.castor.xml.validators.StringValidator();
+ fieldValidator.setValidator(typeValidator);
+ typeValidator.setWhiteSpace("preserve");
+ }
+ desc.setValidator(fieldValidator);
+ // -- _matcherSet
+ desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+ jalview.schemabinding.version2.MatcherSet.class, "_matcherSet",
+ "matcherSet", org.exolab.castor.xml.NodeType.Element);
+ handler = new org.exolab.castor.xml.XMLFieldHandler()
+ {
+ public java.lang.Object getValue(java.lang.Object object)
+ throws IllegalStateException
+ {
+ Setting target = (Setting) object;
+ return target.getMatcherSet();
+ }
+
+ public void setValue(java.lang.Object object, java.lang.Object value)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ try
+ {
+ Setting target = (Setting) object;
+ target.setMatcherSet(
+ (jalview.schemabinding.version2.MatcherSet) value);
+ } catch (java.lang.Exception ex)
+ {
+ throw new IllegalStateException(ex.toString());
+ }
+ }
+
+ public java.lang.Object newInstance(java.lang.Object parent)
+ {
+ return new jalview.schemabinding.version2.MatcherSet();
+ }
+ };
+ desc.setHandler(handler);
+ desc.setNameSpaceURI("www.jalview.org");
+ desc.setMultivalued(false);
+ addFieldDescriptor(desc);
+
+ // -- validation code for: _matcherSet
+ fieldValidator = new org.exolab.castor.xml.FieldValidator();
+ { // -- local scope
+ }
+ desc.setValidator(fieldValidator);
}
// -----------/
--- /dev/null
+#Thu Dec 14 15:28:22 GMT 2017
+jalview.schemabinding.version2.types.ColourNoValueColourType=jalview.schemabinding.version2.types.descriptors.ColourNoValueColourTypeDescriptor
+jalview.schemabinding.version2.types.FeatureMatcherByType=jalview.schemabinding.version2.types.descriptors.FeatureMatcherByTypeDescriptor
+jalview.schemabinding.version2.types.NoValueColour=jalview.schemabinding.version2.types.descriptors.NoValueColourDescriptor
+jalview.schemabinding.version2.types.ColourThreshTypeType=jalview.schemabinding.version2.types.descriptors.ColourThreshTypeTypeDescriptor
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.types;
+
+ //---------------------------------/
+ //- Imported classes and packages -/
+//---------------------------------/
+
+import java.util.Hashtable;
+
+/**
+ * Class ColourThreshTypeType.
+ *
+ * @version $Revision$ $Date$
+ */
+public class ColourThreshTypeType implements java.io.Serializable {
+
+
+ //--------------------------/
+ //- Class/Member Variables -/
+ //--------------------------/
+
+ /**
+ * The NONE type
+ */
+ public static final int NONE_TYPE = 0;
+
+ /**
+ * The instance of the NONE type
+ */
+ public static final ColourThreshTypeType NONE = new ColourThreshTypeType(NONE_TYPE, "NONE");
+
+ /**
+ * The ABOVE type
+ */
+ public static final int ABOVE_TYPE = 1;
+
+ /**
+ * The instance of the ABOVE type
+ */
+ public static final ColourThreshTypeType ABOVE = new ColourThreshTypeType(ABOVE_TYPE, "ABOVE");
+
+ /**
+ * The BELOW type
+ */
+ public static final int BELOW_TYPE = 2;
+
+ /**
+ * The instance of the BELOW type
+ */
+ public static final ColourThreshTypeType BELOW = new ColourThreshTypeType(BELOW_TYPE, "BELOW");
+
+ /**
+ * Field _memberTable.
+ */
+ private static java.util.Hashtable _memberTable = init();
+
+ /**
+ * Field type.
+ */
+ private int type = -1;
+
+ /**
+ * Field stringValue.
+ */
+ private java.lang.String stringValue = null;
+
+
+ //----------------/
+ //- Constructors -/
+ //----------------/
+
+ private ColourThreshTypeType(final int type, final java.lang.String value) {
+ super();
+ this.type = type;
+ this.stringValue = value;
+ }
+
+
+ //-----------/
+ //- Methods -/
+ //-----------/
+
+ /**
+ * Method enumerate.Returns an enumeration of all possible
+ * instances of ColourThreshTypeType
+ *
+ * @return an Enumeration over all possible instances of
+ * ColourThreshTypeType
+ */
+ public static java.util.Enumeration enumerate(
+ ) {
+ return _memberTable.elements();
+ }
+
+ /**
+ * Method getType.Returns the type of this ColourThreshTypeType
+ *
+ * @return the type of this ColourThreshTypeType
+ */
+ public int getType(
+ ) {
+ return this.type;
+ }
+
+ /**
+ * Method init.
+ *
+ * @return the initialized Hashtable for the member table
+ */
+ private static java.util.Hashtable init(
+ ) {
+ Hashtable members = new Hashtable();
+ members.put("NONE", NONE);
+ members.put("ABOVE", ABOVE);
+ members.put("BELOW", BELOW);
+ return members;
+ }
+
+ /**
+ * Method readResolve. will be called during deserialization to
+ * replace the deserialized object with the correct constant
+ * instance.
+ *
+ * @return this deserialized object
+ */
+ private java.lang.Object readResolve(
+ ) {
+ return valueOf(this.stringValue);
+ }
+
+ /**
+ * Method toString.Returns the String representation of this
+ * ColourThreshTypeType
+ *
+ * @return the String representation of this ColourThreshTypeTyp
+ */
+ public java.lang.String toString(
+ ) {
+ return this.stringValue;
+ }
+
+ /**
+ * Method valueOf.Returns a new ColourThreshTypeType based on
+ * the given String value.
+ *
+ * @param string
+ * @return the ColourThreshTypeType value of parameter 'string'
+ */
+ public static jalview.schemabinding.version2.types.ColourThreshTypeType valueOf(
+ final java.lang.String string) {
+ java.lang.Object obj = null;
+ if (string != null) {
+ obj = _memberTable.get(string);
+ }
+ if (obj == null) {
+ String err = "" + string + " is not a valid ColourThreshTypeType";
+ throw new IllegalArgumentException(err);
+ }
+ return (ColourThreshTypeType) obj;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.types;
+
+ //---------------------------------/
+ //- Imported classes and packages -/
+//---------------------------------/
+
+import java.util.Hashtable;
+
+/**
+ * Class FeatureMatcherByType.
+ *
+ * @version $Revision$ $Date$
+ */
+public class FeatureMatcherByType implements java.io.Serializable {
+
+
+ //--------------------------/
+ //- Class/Member Variables -/
+ //--------------------------/
+
+ /**
+ * The byLabel type
+ */
+ public static final int BYLABEL_TYPE = 0;
+
+ /**
+ * The instance of the byLabel type
+ */
+ public static final FeatureMatcherByType BYLABEL = new FeatureMatcherByType(BYLABEL_TYPE, "byLabel");
+
+ /**
+ * The byScore type
+ */
+ public static final int BYSCORE_TYPE = 1;
+
+ /**
+ * The instance of the byScore type
+ */
+ public static final FeatureMatcherByType BYSCORE = new FeatureMatcherByType(BYSCORE_TYPE, "byScore");
+
+ /**
+ * The byAttribute type
+ */
+ public static final int BYATTRIBUTE_TYPE = 2;
+
+ /**
+ * The instance of the byAttribute type
+ */
+ public static final FeatureMatcherByType BYATTRIBUTE = new FeatureMatcherByType(BYATTRIBUTE_TYPE, "byAttribute");
+
+ /**
+ * Field _memberTable.
+ */
+ private static java.util.Hashtable _memberTable = init();
+
+ /**
+ * Field type.
+ */
+ private int type = -1;
+
+ /**
+ * Field stringValue.
+ */
+ private java.lang.String stringValue = null;
+
+
+ //----------------/
+ //- Constructors -/
+ //----------------/
+
+ private FeatureMatcherByType(final int type, final java.lang.String value) {
+ super();
+ this.type = type;
+ this.stringValue = value;
+ }
+
+
+ //-----------/
+ //- Methods -/
+ //-----------/
+
+ /**
+ * Method enumerate.Returns an enumeration of all possible
+ * instances of FeatureMatcherByType
+ *
+ * @return an Enumeration over all possible instances of
+ * FeatureMatcherByType
+ */
+ public static java.util.Enumeration enumerate(
+ ) {
+ return _memberTable.elements();
+ }
+
+ /**
+ * Method getType.Returns the type of this FeatureMatcherByType
+ *
+ * @return the type of this FeatureMatcherByType
+ */
+ public int getType(
+ ) {
+ return this.type;
+ }
+
+ /**
+ * Method init.
+ *
+ * @return the initialized Hashtable for the member table
+ */
+ private static java.util.Hashtable init(
+ ) {
+ Hashtable members = new Hashtable();
+ members.put("byLabel", BYLABEL);
+ members.put("byScore", BYSCORE);
+ members.put("byAttribute", BYATTRIBUTE);
+ return members;
+ }
+
+ /**
+ * Method readResolve. will be called during deserialization to
+ * replace the deserialized object with the correct constant
+ * instance.
+ *
+ * @return this deserialized object
+ */
+ private java.lang.Object readResolve(
+ ) {
+ return valueOf(this.stringValue);
+ }
+
+ /**
+ * Method toString.Returns the String representation of this
+ * FeatureMatcherByType
+ *
+ * @return the String representation of this FeatureMatcherByTyp
+ */
+ public java.lang.String toString(
+ ) {
+ return this.stringValue;
+ }
+
+ /**
+ * Method valueOf.Returns a new FeatureMatcherByType based on
+ * the given String value.
+ *
+ * @param string
+ * @return the FeatureMatcherByType value of parameter 'string'
+ */
+ public static jalview.schemabinding.version2.types.FeatureMatcherByType valueOf(
+ final java.lang.String string) {
+ java.lang.Object obj = null;
+ if (string != null) {
+ obj = _memberTable.get(string);
+ }
+ if (obj == null) {
+ String err = "" + string + " is not a valid FeatureMatcherByType";
+ throw new IllegalArgumentException(err);
+ }
+ return (FeatureMatcherByType) obj;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.types;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import java.util.Hashtable;
+
+/**
+ * Graduated feature colour if no score (or attribute) value
+ *
+ * @version $Revision$ $Date$
+ */
+public class NoValueColour implements java.io.Serializable
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * The None type
+ */
+ public static final int NONE_TYPE = 0;
+
+ /**
+ * The instance of the None type
+ */
+ public static final NoValueColour NONE = new NoValueColour(NONE_TYPE,
+ "None");
+
+ /**
+ * The Min type
+ */
+ public static final int MIN_TYPE = 1;
+
+ /**
+ * The instance of the Min type
+ */
+ public static final NoValueColour MIN = new NoValueColour(MIN_TYPE,
+ "Min");
+
+ /**
+ * The Max type
+ */
+ public static final int MAX_TYPE = 2;
+
+ /**
+ * The instance of the Max type
+ */
+ public static final NoValueColour MAX = new NoValueColour(MAX_TYPE,
+ "Max");
+
+ /**
+ * Field _memberTable.
+ */
+ private static java.util.Hashtable _memberTable = init();
+
+ /**
+ * Field type.
+ */
+ private int type = -1;
+
+ /**
+ * Field stringValue.
+ */
+ private java.lang.String stringValue = null;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ private NoValueColour(final int type, final java.lang.String value)
+ {
+ super();
+ this.type = type;
+ this.stringValue = value;
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method enumerate.Returns an enumeration of all possible instances of
+ * NoValueColour
+ *
+ * @return an Enumeration over all possible instances of NoValueColour
+ */
+ public static java.util.Enumeration enumerate()
+ {
+ return _memberTable.elements();
+ }
+
+ /**
+ * Method getType.Returns the type of this NoValueColour
+ *
+ * @return the type of this NoValueColour
+ */
+ public int getType()
+ {
+ return this.type;
+ }
+
+ /**
+ * Method init.
+ *
+ * @return the initialized Hashtable for the member table
+ */
+ private static java.util.Hashtable init()
+ {
+ Hashtable members = new Hashtable();
+ members.put("None", NONE);
+ members.put("Min", MIN);
+ members.put("Max", MAX);
+ return members;
+ }
+
+ /**
+ * Method readResolve. will be called during deserialization to replace the
+ * deserialized object with the correct constant instance.
+ *
+ * @return this deserialized object
+ */
+ private java.lang.Object readResolve()
+ {
+ return valueOf(this.stringValue);
+ }
+
+ /**
+ * Method toString.Returns the String representation of this NoValueColour
+ *
+ * @return the String representation of this NoValueColour
+ */
+ public java.lang.String toString()
+ {
+ return this.stringValue;
+ }
+
+ /**
+ * Method valueOf.Returns a new NoValueColour based on the given String value.
+ *
+ * @param string
+ * @return the NoValueColour value of parameter 'string'
+ */
+ public static jalview.schemabinding.version2.types.NoValueColour valueOf(
+ final java.lang.String string)
+ {
+ java.lang.Object obj = null;
+ if (string != null)
+ {
+ obj = _memberTable.get(string);
+ }
+ if (obj == null)
+ {
+ String err = "" + string + " is not a valid NoValueColour";
+ throw new IllegalArgumentException(err);
+ }
+ return (NoValueColour) obj;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.types.descriptors;
+
+ //---------------------------------/
+ //- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.types.ColourThreshTypeType;
+
+/**
+ * Class ColourThreshTypeTypeDescriptor.
+ *
+ * @version $Revision$ $Date$
+ */
+public class ColourThreshTypeTypeDescriptor extends org.exolab.castor.xml.util.XMLClassDescriptorImpl {
+
+
+ //--------------------------/
+ //- Class/Member Variables -/
+ //--------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+
+ //----------------/
+ //- Constructors -/
+ //----------------/
+
+ public ColourThreshTypeTypeDescriptor() {
+ super();
+ _nsURI = "www.jalview.org/colours";
+ _xmlName = "ColourThreshTypeType";
+ _elementDefinition = false;
+ }
+
+
+ //-----------/
+ //- Methods -/
+ //-----------/
+
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ public org.exolab.castor.mapping.AccessMode getAccessMode(
+ ) {
+ return null;
+ }
+
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no
+ * identity.
+ */
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity(
+ ) {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ public java.lang.Class getJavaClass(
+ ) {
+ return jalview.schemabinding.version2.types.ColourThreshTypeType.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ public java.lang.String getNameSpacePrefix(
+ ) {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and
+ * unmarshaling as XML.
+ */
+ public java.lang.String getNameSpaceURI(
+ ) {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ public org.exolab.castor.xml.TypeValidator getValidator(
+ ) {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ public java.lang.String getXMLName(
+ ) {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that
+ * of a global
+ * element or element with anonymous type definition.
+ */
+ public boolean isElementDefinition(
+ ) {
+ return _elementDefinition;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.types.descriptors;
+
+ //---------------------------------/
+ //- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.types.FeatureMatcherByType;
+
+/**
+ * Class FeatureMatcherByTypeDescriptor.
+ *
+ * @version $Revision$ $Date$
+ */
+public class FeatureMatcherByTypeDescriptor extends org.exolab.castor.xml.util.XMLClassDescriptorImpl {
+
+
+ //--------------------------/
+ //- Class/Member Variables -/
+ //--------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+
+ //----------------/
+ //- Constructors -/
+ //----------------/
+
+ public FeatureMatcherByTypeDescriptor() {
+ super();
+ _nsURI = "www.jalview.org/colours";
+ _xmlName = "FeatureMatcherByType";
+ _elementDefinition = false;
+ }
+
+
+ //-----------/
+ //- Methods -/
+ //-----------/
+
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ public org.exolab.castor.mapping.AccessMode getAccessMode(
+ ) {
+ return null;
+ }
+
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no
+ * identity.
+ */
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity(
+ ) {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ public java.lang.Class getJavaClass(
+ ) {
+ return jalview.schemabinding.version2.types.FeatureMatcherByType.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ public java.lang.String getNameSpacePrefix(
+ ) {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and
+ * unmarshaling as XML.
+ */
+ public java.lang.String getNameSpaceURI(
+ ) {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ public org.exolab.castor.xml.TypeValidator getValidator(
+ ) {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ public java.lang.String getXMLName(
+ ) {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that
+ * of a global
+ * element or element with anonymous type definition.
+ */
+ public boolean isElementDefinition(
+ ) {
+ return _elementDefinition;
+ }
+
+}
--- /dev/null
+/*
+ * This class was automatically generated with
+ * <a href="http://www.castor.org">Castor 1.1</a>, using an XML
+ * Schema.
+ * $Id$
+ */
+
+package jalview.schemabinding.version2.types.descriptors;
+
+//---------------------------------/
+//- Imported classes and packages -/
+//---------------------------------/
+
+import jalview.schemabinding.version2.types.NoValueColour;
+
+/**
+ * Class NoValueColourDescriptor.
+ *
+ * @version $Revision$ $Date$
+ */
+public class NoValueColourDescriptor
+ extends org.exolab.castor.xml.util.XMLClassDescriptorImpl
+{
+
+ // --------------------------/
+ // - Class/Member Variables -/
+ // --------------------------/
+
+ /**
+ * Field _elementDefinition.
+ */
+ private boolean _elementDefinition;
+
+ /**
+ * Field _nsPrefix.
+ */
+ private java.lang.String _nsPrefix;
+
+ /**
+ * Field _nsURI.
+ */
+ private java.lang.String _nsURI;
+
+ /**
+ * Field _xmlName.
+ */
+ private java.lang.String _xmlName;
+
+ // ----------------/
+ // - Constructors -/
+ // ----------------/
+
+ public NoValueColourDescriptor()
+ {
+ super();
+ _nsURI = "www.jalview.org/colours";
+ _xmlName = "NoValueColour";
+ _elementDefinition = false;
+ }
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method getAccessMode.
+ *
+ * @return the access mode specified for this class.
+ */
+ public org.exolab.castor.mapping.AccessMode getAccessMode()
+ {
+ return null;
+ }
+
+ /**
+ * Method getIdentity.
+ *
+ * @return the identity field, null if this class has no identity.
+ */
+ public org.exolab.castor.mapping.FieldDescriptor getIdentity()
+ {
+ return super.getIdentity();
+ }
+
+ /**
+ * Method getJavaClass.
+ *
+ * @return the Java class represented by this descriptor.
+ */
+ public java.lang.Class getJavaClass()
+ {
+ return jalview.schemabinding.version2.types.NoValueColour.class;
+ }
+
+ /**
+ * Method getNameSpacePrefix.
+ *
+ * @return the namespace prefix to use when marshaling as XML.
+ */
+ public java.lang.String getNameSpacePrefix()
+ {
+ return _nsPrefix;
+ }
+
+ /**
+ * Method getNameSpaceURI.
+ *
+ * @return the namespace URI used when marshaling and unmarshaling as XML.
+ */
+ public java.lang.String getNameSpaceURI()
+ {
+ return _nsURI;
+ }
+
+ /**
+ * Method getValidator.
+ *
+ * @return a specific validator for the class described by this
+ * ClassDescriptor.
+ */
+ public org.exolab.castor.xml.TypeValidator getValidator()
+ {
+ return this;
+ }
+
+ /**
+ * Method getXMLName.
+ *
+ * @return the XML Name for the Class being described.
+ */
+ public java.lang.String getXMLName()
+ {
+ return _xmlName;
+ }
+
+ /**
+ * Method isElementDefinition.
+ *
+ * @return true if XML schema definition of this Class is that of a global
+ * element or element with anonymous type definition.
+ */
+ public boolean isElementDefinition()
+ {
+ return _elementDefinition;
+ }
+
+}
import jalview.api.FeatureColourI;
import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.features.FeatureMatcher;
import jalview.util.ColorUtils;
import jalview.util.Format;
import java.util.StringTokenizer;
/**
- * A class that wraps either a simple colour or a graduated colour
+ * A class that represents a colour scheme for a feature type. Options supported
+ * are currently
+ * <ul>
+ * <li>a simple colour e.g. Red</li>
+ * <li>colour by label - a colour is generated from the feature description</li>
+ * <li>graduated colour by feature score</li>
+ * <ul>
+ * <li>minimum and maximum score range must be provided</li>
+ * <li>minimum and maximum value colours should be specified</li>
+ * <li>a colour for 'no value' may optionally be provided</li>
+ * <li>colours for intermediate scores are interpolated RGB values</li>
+ * <li>there is an optional threshold above/below which to colour values</li>
+ * <li>the range may be the full value range, or may be limited by the threshold
+ * value</li>
+ * </ul>
+ * <li>colour by (text) value of a named attribute</li> <li>graduated colour by
+ * (numeric) value of a named attribute</li> </ul>
*/
public class FeatureColour implements FeatureColourI
{
+ private static final String ABSOLUTE = "abso";
+
+ private static final String ABOVE = "above";
+
+ private static final String BELOW = "below";
+
+ /*
+ * constants used to read or write a Jalview Features file
+ */
+ private static final String LABEL = "label";
+
+ private static final String SCORE = "score";
+
+ private static final String ATTRIBUTE = "attribute";
+
+ private static final String NO_VALUE_MIN = "noValueMin";
+
+ private static final String NO_VALUE_MAX = "noValueMax";
+
+ private static final String NO_VALUE_NONE = "noValueNone";
+
+ static final Color DEFAULT_NO_COLOUR = null;
+
private static final String BAR = "|";
final private Color colour;
final private Color maxColour;
+ /*
+ * colour to use for colour by attribute when the
+ * attribute value is absent
+ */
+ final private Color noColour;
+
+ /*
+ * if true, then colour has a gradient based on a numerical
+ * range (either feature score, or an attribute value)
+ */
private boolean graduatedColour;
+ /*
+ * if true, colour values are generated from a text string,
+ * either feature description, or an attribute value
+ */
private boolean colourByLabel;
+ /*
+ * if not null, the value of [attribute, [sub-attribute] ...]
+ * is used for colourByLabel or graduatedColour
+ */
+ private String[] attributeName;
+
private float threshold;
private float base;
private boolean aboveThreshold;
- private boolean thresholdIsMinOrMax;
-
private boolean isHighToLow;
private boolean autoScaled;
/**
* Parses a Jalview features file format colour descriptor
- * [label|][mincolour|maxcolour
- * |[absolute|]minvalue|maxvalue|thresholdtype|thresholdvalue] Examples:
+ * <p>
+ * <code>
+ * [label|score|[attribute|attributeName]|][mincolour|maxcolour|
+ * [absolute|]minvalue|maxvalue|[noValueOption|]thresholdtype|thresholdvalue]</code>
+ * <p>
+ * 'Score' is optional (default) for a graduated colour. An attribute with
+ * sub-attribute should be written as (for example) CSQ:Consequence.
+ * noValueOption is one of <code>noValueMin, noValueMax, noValueNone</code>
+ * with default noValueMin.
+ * <p>
+ * Examples:
* <ul>
* <li>red</li>
* <li>a28bbb</li>
* <li>25,125,213</li>
* <li>label</li>
+ * <li>attribute|CSQ:PolyPhen</li>
* <li>label|||0.0|0.0|above|12.5</li>
* <li>label|||0.0|0.0|below|12.5</li>
* <li>red|green|12.0|26.0|none</li>
+ * <li>score|red|green|12.0|26.0|none</li>
+ * <li>attribute|AF|red|green|12.0|26.0|none</li>
+ * <li>attribute|AF|red|green|noValueNone|12.0|26.0|none</li>
* <li>a28bbb|3eb555|12.0|26.0|above|12.5</li>
* <li>a28bbb|3eb555|abso|12.0|26.0|below|12.5</li>
* </ul>
* @throws IllegalArgumentException
* if not parseable
*/
- public static FeatureColour parseJalviewFeatureColour(String descriptor)
+ public static FeatureColourI parseJalviewFeatureColour(String descriptor)
{
- StringTokenizer gcol = new StringTokenizer(descriptor, "|", true);
+ StringTokenizer gcol = new StringTokenizer(descriptor, BAR, true);
float min = Float.MIN_VALUE;
float max = Float.MAX_VALUE;
- boolean labelColour = false;
+ boolean byLabel = false;
+ boolean byAttribute = false;
+ String attName = null;
+ String mincol = null;
+ String maxcol = null;
- String mincol = gcol.nextToken();
- if (mincol == "|")
+ /*
+ * first token should be 'label', or 'score', or an
+ * attribute name, or simple colour, or minimum colour
+ */
+ String nextToken = gcol.nextToken();
+ if (nextToken == BAR)
{
throw new IllegalArgumentException(
"Expected either 'label' or a colour specification in the line: "
+ descriptor);
}
- String maxcol = null;
- if (mincol.toLowerCase().indexOf("label") == 0)
+ if (nextToken.toLowerCase().startsWith(LABEL))
+ {
+ byLabel = true;
+ // get the token after the next delimiter:
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ }
+ else if (nextToken.toLowerCase().startsWith(SCORE))
+ {
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ }
+ else if (nextToken.toLowerCase().startsWith(ATTRIBUTE))
{
- labelColour = true;
+ byAttribute = true;
+ attName = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ attName = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
- // skip '|'
mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
}
+ else
+ {
+ mincol = nextToken;
+ }
- if (!labelColour && !gcol.hasMoreTokens())
+ /*
+ * if only one token, it can validly be label, attributeName,
+ * or a plain colour value
+ */
+ if (!gcol.hasMoreTokens())
{
- /*
- * only a simple colour specification - parse it
- */
+ if (byLabel || byAttribute)
+ {
+ FeatureColourI fc = new FeatureColour();
+ fc.setColourByLabel(true);
+ if (byAttribute)
+ {
+ fc.setAttributeName(
+ FeatureMatcher.fromAttributeDisplayName(attName));
+ }
+ return fc;
+ }
+
Color colour = ColorUtils.parseColourString(descriptor);
if (colour == null)
{
}
/*
+ * continue parsing for min/max/no colour (if graduated)
+ * and for threshold (colour by text or graduated)
+ */
+
+ /*
* autoScaled == true: colours range over actual score range
* autoScaled == false ('abso'): colours range over min/max range
*/
boolean autoScaled = true;
String tok = null, minval, maxval;
+ String noValueColour = NO_VALUE_MIN;
+
if (mincol != null)
{
// at least four more tokens
- if (mincol.equals("|"))
+ if (mincol.equals(BAR))
{
- mincol = "";
+ mincol = null;
}
else
{
gcol.nextToken(); // skip next '|'
}
maxcol = gcol.nextToken();
- if (maxcol.equals("|"))
+ if (maxcol.equals(BAR))
{
- maxcol = "";
+ maxcol = null;
}
else
{
gcol.nextToken(); // skip next '|'
}
tok = gcol.nextToken();
+
+ /*
+ * check for specifier for colour for no attribute value
+ * (new in 2.11, defaults to minColour if not specified)
+ */
+ if (tok.equalsIgnoreCase(NO_VALUE_MIN))
+ {
+ tok = gcol.nextToken();
+ tok = gcol.nextToken();
+ }
+ else if (tok.equalsIgnoreCase(NO_VALUE_MAX))
+ {
+ noValueColour = NO_VALUE_MAX;
+ tok = gcol.nextToken();
+ tok = gcol.nextToken();
+ }
+ else if (tok.equalsIgnoreCase(NO_VALUE_NONE))
+ {
+ noValueColour = NO_VALUE_NONE;
+ tok = gcol.nextToken();
+ tok = gcol.nextToken();
+ }
+
gcol.nextToken(); // skip next '|'
- if (tok.toLowerCase().startsWith("abso"))
+ if (tok.toLowerCase().startsWith(ABSOLUTE))
{
minval = gcol.nextToken();
gcol.nextToken(); // skip next '|'
} catch (Exception e)
{
throw new IllegalArgumentException(
- "Couldn't parse the minimum value for graduated colour ("
- + descriptor + ")");
+ "Couldn't parse the minimum value for graduated colour ('"
+ + minval + "')");
}
try
{
}
else
{
- // add in some dummy min/max colours for the label-only
- // colourscheme.
- mincol = "FFFFFF";
- maxcol = "000000";
+ /*
+ * dummy min/max colours for colour by text
+ * (label or attribute value)
+ */
+ mincol = "white";
+ maxcol = "black";
+ byLabel = true;
}
/*
- * construct the FeatureColour
+ * construct the FeatureColour!
*/
FeatureColour featureColour;
try
{
Color minColour = ColorUtils.parseColourString(mincol);
Color maxColour = ColorUtils.parseColourString(maxcol);
- featureColour = new FeatureColour(minColour, maxColour, min, max);
- featureColour.setColourByLabel(labelColour);
+ Color noColour = noValueColour.equals(NO_VALUE_MAX) ? maxColour
+ : (noValueColour.equals(NO_VALUE_NONE) ? null : minColour);
+ featureColour = new FeatureColour(minColour, maxColour, noColour, min,
+ max);
+ featureColour.setColourByLabel(minColour == null);
featureColour.setAutoScaled(autoScaled);
+ if (byAttribute)
+ {
+ featureColour.setAttributeName(
+ FeatureMatcher.fromAttributeDisplayName(attName));
+ }
// add in any additional parameters
String ttype = null, tval = null;
if (gcol.hasMoreTokens())
{
// threshold type and possibly a threshold value
ttype = gcol.nextToken();
- if (ttype.toLowerCase().startsWith("below"))
+ if (ttype.toLowerCase().startsWith(BELOW))
{
featureColour.setBelowThreshold(true);
}
- else if (ttype.toLowerCase().startsWith("above"))
+ else if (ttype.toLowerCase().startsWith(ABOVE))
{
featureColour.setAboveThreshold(true);
}
"Ignoring additional tokens in parameters in graduated colour specification\n");
while (gcol.hasMoreTokens())
{
- System.err.println("|" + gcol.nextToken());
+ System.err.println(BAR + gcol.nextToken());
}
System.err.println("\n");
}
{
minColour = Color.WHITE;
maxColour = Color.BLACK;
+ noColour = DEFAULT_NO_COLOUR;
minRed = 0f;
minGreen = 0f;
minBlue = 0f;
}
/**
- * Constructor given a colour range and a score range
+ * Constructor given a colour range and a score range, defaulting 'no value
+ * colour' to be the same as minimum colour
*
* @param low
* @param high
*/
public FeatureColour(Color low, Color high, float min, float max)
{
- if (low == null)
- {
- low = Color.white;
- }
- if (high == null)
- {
- high = Color.black;
- }
- graduatedColour = true;
- colour = null;
- minColour = low;
- maxColour = high;
- threshold = Float.NaN;
- isHighToLow = min >= max;
- minRed = low.getRed() / 255f;
- minGreen = low.getGreen() / 255f;
- minBlue = low.getBlue() / 255f;
- deltaRed = (high.getRed() / 255f) - minRed;
- deltaGreen = (high.getGreen() / 255f) - minGreen;
- deltaBlue = (high.getBlue() / 255f) - minBlue;
- if (isHighToLow)
- {
- base = max;
- range = min - max;
- }
- else
- {
- base = min;
- range = max - min;
- }
+ this(low, high, low, min, max);
}
/**
colour = fc.colour;
minColour = fc.minColour;
maxColour = fc.maxColour;
+ noColour = fc.noColour;
minRed = fc.minRed;
minGreen = fc.minGreen;
minBlue = fc.minBlue;
base = fc.base;
range = fc.range;
isHighToLow = fc.isHighToLow;
+ attributeName = fc.attributeName;
setAboveThreshold(fc.isAboveThreshold());
setBelowThreshold(fc.isBelowThreshold());
setThreshold(fc.getThreshold());
public FeatureColour(FeatureColour fc, float min, float max)
{
this(fc);
- graduatedColour = true;
updateBounds(min, max);
}
+ /**
+ * Constructor for a graduated colour
+ *
+ * @param low
+ * @param high
+ * @param noValueColour
+ * @param min
+ * @param max
+ */
+ public FeatureColour(Color low, Color high, Color noValueColour,
+ float min, float max)
+ {
+ if (low == null)
+ {
+ low = Color.white;
+ }
+ if (high == null)
+ {
+ high = Color.black;
+ }
+ graduatedColour = true;
+ colour = null;
+ minColour = low;
+ maxColour = high;
+ noColour = noValueColour;
+ threshold = Float.NaN;
+ isHighToLow = min >= max;
+ minRed = low.getRed() / 255f;
+ minGreen = low.getGreen() / 255f;
+ minBlue = low.getBlue() / 255f;
+ deltaRed = (high.getRed() / 255f) - minRed;
+ deltaGreen = (high.getGreen() / 255f) - minGreen;
+ deltaBlue = (high.getBlue() / 255f) - minBlue;
+ if (isHighToLow)
+ {
+ base = max;
+ range = min - max;
+ }
+ else
+ {
+ base = min;
+ range = max - min;
+ }
+ }
+
@Override
public boolean isGraduatedColour()
{
}
@Override
+ public Color getNoColour()
+ {
+ return noColour;
+ }
+
+ @Override
public boolean isColourByLabel()
{
return colourByLabel;
}
@Override
- public boolean isThresholdMinMax()
- {
- return thresholdIsMinOrMax;
- }
-
- @Override
- public void setThresholdMinMax(boolean b)
- {
- thresholdIsMinOrMax = b;
- }
-
- @Override
public float getThreshold()
{
return threshold;
}
/**
- * Updates the base and range appropriately for the given minmax range
- *
- * @param min
- * @param max
+ * {@inheritDoc}
*/
@Override
public void updateBounds(float min, float max)
{
if (isColourByLabel())
{
- return ColorUtils.createColourFromName(feature.getDescription());
+ String label = attributeName == null ? feature.getDescription()
+ : feature.getValueAsString(attributeName);
+ return label == null ? noColour : ColorUtils
+ .createColourFromName(label);
}
if (!isGraduatedColour())
/*
* graduated colour case, optionally with threshold
- * Float.NaN is assigned minimum visible score colour
+ * may be based on feature score on an attribute value
+ * Float.NaN, or no value, is assigned the 'no value' colour
*/
float scr = feature.getScore();
+ if (attributeName != null)
+ {
+ try
+ {
+ String attVal = feature.getValueAsString(attributeName);
+ scr = Float.valueOf(attVal);
+ } catch (Throwable e)
+ {
+ scr = Float.NaN;
+ }
+ }
if (Float.isNaN(scr))
{
- return getMinColour();
+ return noColour;
}
+
if (isAboveThreshold() && scr <= threshold)
{
return null;
}
+
if (isBelowThreshold() && scr >= threshold)
{
return null;
else
{
StringBuilder sb = new StringBuilder(32);
- if (isColourByLabel())
+ if (isColourByAttribute())
{
- sb.append("label");
- if (hasThreshold())
- {
- sb.append(BAR).append(BAR).append(BAR);
- }
+ sb.append(ATTRIBUTE).append(BAR);
+ sb.append(
+ FeatureMatcher.toAttributeDisplayName(getAttributeName()));
+ }
+ else if (isColourByLabel())
+ {
+ sb.append(LABEL);
+ }
+ else
+ {
+ sb.append(SCORE);
}
if (isGraduatedColour())
{
- sb.append(Format.getHexString(getMinColour())).append(BAR);
+ sb.append(BAR).append(Format.getHexString(getMinColour()))
+ .append(BAR);
sb.append(Format.getHexString(getMaxColour())).append(BAR);
+ String noValue = minColour.equals(noColour) ? NO_VALUE_MIN
+ : (maxColour.equals(noColour) ? NO_VALUE_MAX
+ : NO_VALUE_NONE);
+ sb.append(noValue).append(BAR);
if (!isAutoScaled())
{
- sb.append("abso").append(BAR);
+ sb.append(ABSOLUTE).append(BAR);
+ }
+ }
+ else
+ {
+ /*
+ * colour by text with score threshold: empty fields for
+ * minColour and maxColour (not used)
+ */
+ if (hasThreshold())
+ {
+ sb.append(BAR).append(BAR).append(BAR);
}
}
if (hasThreshold() || isGraduatedColour())
sb.append(getMax()).append(BAR);
if (isBelowThreshold())
{
- sb.append("below").append(BAR).append(getThreshold());
+ sb.append(BELOW).append(BAR).append(getThreshold());
}
else if (isAboveThreshold())
{
- sb.append("above").append(BAR).append(getThreshold());
+ sb.append(ABOVE).append(BAR).append(getThreshold());
}
else
{
return String.format("%s\t%s", featureType, colourString);
}
+ @Override
+ public boolean isColourByAttribute()
+ {
+ return attributeName != null;
+ }
+
+ @Override
+ public String[] getAttributeName()
+ {
+ return attributeName;
+ }
+
+ @Override
+ public void setAttributeName(String... name)
+ {
+ attributeName = name;
+ }
+
}
public static final int[] purinepyrimidineIndex;
- public static final Map<String, Integer> aa3Hash = new HashMap<String, Integer>();
+ public static final Map<String, Integer> aa3Hash = new HashMap<>();
- public static final Map<String, String> aa2Triplet = new HashMap<String, String>();
+ public static final Map<String, String> aa2Triplet = new HashMap<>();
- public static final Map<String, String> nucleotideName = new HashMap<String, String>();
+ public static final Map<String, String> nucleotideName = new HashMap<>();
// lookup from modified amino acid (e.g. MSE) to canonical form (e.g. MET)
- public static final Map<String, String> modifications = new HashMap<String, String>();
+ public static final Map<String, String> modifications = new HashMap<>();
static
{
* Color.white, // R Color.white, // Y Color.white, // N Color.white, // Gap
*/
- public static List<String> STOP = Arrays.asList("TGA", "TAA", "TAG");
+ public static String STOP = "STOP";
+
+ public static List<String> STOP_CODONS = Arrays.asList("TGA", "TAA", "TAG");
public static String START = "ATG";
/**
* Nucleotide Ambiguity Codes
*/
- public static final Map<String, String[]> ambiguityCodes = new Hashtable<String, String[]>();
+ public static final Map<String, String[]> ambiguityCodes = new Hashtable<>();
/**
* Codon triplets with additional symbols for unambiguous codons that include
* ambiguity codes
*/
- public static final Hashtable<String, String> codonHash2 = new Hashtable<String, String>();
+ public static final Hashtable<String, String> codonHash2 = new Hashtable<>();
/**
* all ambiguity codes for a given base
*/
- public final static Hashtable<String, List<String>> _ambiguityCodes = new Hashtable<String, List<String>>();
+ public final static Hashtable<String, List<String>> _ambiguityCodes = new Hashtable<>();
static
{
List<String> codesfor = _ambiguityCodes.get(r);
if (codesfor == null)
{
- _ambiguityCodes.put(r, codesfor = new ArrayList<String>());
+ _ambiguityCodes.put(r, codesfor = new ArrayList<>());
}
if (!codesfor.contains(acode.getKey()))
{
}
// Stores residue codes/names and colours and other things
- public static Map<String, Map<String, Integer>> propHash = new Hashtable<String, Map<String, Integer>>();
+ public static Map<String, Map<String, Integer>> propHash = new Hashtable<>();
- public static Map<String, Integer> hydrophobic = new Hashtable<String, Integer>();
+ public static Map<String, Integer> hydrophobic = new Hashtable<>();
- public static Map<String, Integer> polar = new Hashtable<String, Integer>();
+ public static Map<String, Integer> polar = new Hashtable<>();
- public static Map<String, Integer> small = new Hashtable<String, Integer>();
+ public static Map<String, Integer> small = new Hashtable<>();
- public static Map<String, Integer> positive = new Hashtable<String, Integer>();
+ public static Map<String, Integer> positive = new Hashtable<>();
- public static Map<String, Integer> negative = new Hashtable<String, Integer>();
+ public static Map<String, Integer> negative = new Hashtable<>();
- public static Map<String, Integer> charged = new Hashtable<String, Integer>();
+ public static Map<String, Integer> charged = new Hashtable<>();
- public static Map<String, Integer> aromatic = new Hashtable<String, Integer>();
+ public static Map<String, Integer> aromatic = new Hashtable<>();
- public static Map<String, Integer> aliphatic = new Hashtable<String, Integer>();
+ public static Map<String, Integer> aliphatic = new Hashtable<>();
- public static Map<String, Integer> tiny = new Hashtable<String, Integer>();
+ public static Map<String, Integer> tiny = new Hashtable<>();
- public static Map<String, Integer> proline = new Hashtable<String, Integer>();
+ public static Map<String, Integer> proline = new Hashtable<>();
static
{
String cdn = codonHash2.get(lccodon.toUpperCase());
if ("*".equals(cdn))
{
- return "STOP";
+ return STOP;
}
return cdn;
}
public static Hashtable<String, String> toDssp3State;
static
{
- toDssp3State = new Hashtable<String, String>();
+ toDssp3State = new Hashtable<>();
toDssp3State.put("H", "H");
toDssp3State.put("E", "E");
toDssp3State.put("C", " ");
// / cut here
public static void main(String[] args)
{
- Hashtable<String, Vector<String>> aaProps = new Hashtable<String, Vector<String>>();
+ Hashtable<String, Vector<String>> aaProps = new Hashtable<>();
System.out.println("my %aa = {");
// invert property hashes
for (String pname : propHash.keySet())
Vector<String> aprops = aaProps.get(rname);
if (aprops == null)
{
- aprops = new Vector<String>();
+ aprops = new Vector<>();
aaProps.put(rname, aprops);
}
Integer hasprop = phash.get(rname);
public static List<String> getResidues(boolean forNucleotide,
boolean includeAmbiguous)
{
- List<String> result = new ArrayList<String>();
+ List<String> result = new ArrayList<>();
if (forNucleotide)
{
for (String nuc : nucleotideName.keySet())
package jalview.structure;
import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Mapping;
import jalview.datamodel.SequenceI;
import java.util.ArrayList;
public class StructureMapping
{
+ public static final int UNASSIGNED_VALUE = Integer.MIN_VALUE;
+
+ private static final int PDB_RES_NUM_INDEX = 0;
+
+ private static final int PDB_ATOM_NUM_INDEX = 1;
+
String mappingDetails;
SequenceI sequence;
String pdbchain;
- public static final int UNASSIGNED_VALUE = -1;
-
- private static final int PDB_RES_NUM_INDEX = 0;
-
- private static final int PDB_ATOM_NUM_INDEX = 1;
-
// Mapping key is residue index while value is an array containing PDB resNum,
// and atomNo
HashMap<Integer, int[]> mapping;
+ jalview.datamodel.Mapping seqToPdbMapping = null;
+
/**
* Constructor
*
this.mappingDetails = mappingDetails;
}
+ public StructureMapping(SequenceI seq, String pdbFile2, String pdbId2,
+ String chain, HashMap<Integer, int[]> mapping2,
+ String mappingOutput, Mapping seqToPdbMapping)
+ {
+ this(seq, pdbFile2, pdbId2, chain, mapping2, mappingOutput);
+ this.seqToPdbMapping = seqToPdbMapping;
+ }
+
public SequenceI getSequence()
{
return sequence;
/**
*
* @param seqpos
- * @return 0 or the corresponding residue number for the sequence position
+ * @return UNASSIGNED_VALUE or the corresponding residue number for the
+ * sequence position
*/
public int getPDBResNum(int seqpos)
{
*/
public List<int[]> getPDBResNumRanges(int fromSeqPos, int toSeqPos)
{
- List<int[]> result = new ArrayList<int[]>();
+ List<int[]> result = new ArrayList<>();
int startRes = -1;
int endRes = -1;
{
return mapping;
}
+
+ public Mapping getSeqToPdbMapping()
+ {
+ return seqToPdbMapping;
+ }
+
+ /**
+ * A hash function that satisfies the contract that if two mappings are
+ * equal(), they have the same hashCode
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((mappingDetails == null) ? 0 : mappingDetails.hashCode());
+ result = prime * result
+ + ((pdbchain == null) ? 0 : pdbchain.hashCode());
+ result = prime * result + ((pdbfile == null) ? 0 : pdbfile.hashCode());
+ result = prime * result + ((pdbid == null) ? 0 : pdbid.hashCode());
+ result = prime * result
+ + ((seqToPdbMapping == null) ? 0 : seqToPdbMapping.hashCode());
+ result = prime * result
+ + ((sequence == null) ? 0 : sequence.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ StructureMapping other = (StructureMapping) obj;
+ if (mappingDetails == null)
+ {
+ if (other.mappingDetails != null)
+ {
+ return false;
+ }
+ }
+ else if (!mappingDetails.equals(other.mappingDetails))
+ {
+ return false;
+ }
+ if (pdbchain == null)
+ {
+ if (other.pdbchain != null)
+ {
+ return false;
+ }
+ }
+ else if (!pdbchain.equals(other.pdbchain))
+ {
+ return false;
+ }
+ if (pdbfile == null)
+ {
+ if (other.pdbfile != null)
+ {
+ return false;
+ }
+ }
+ else if (!pdbfile.equals(other.pdbfile))
+ {
+ return false;
+ }
+ if (pdbid == null)
+ {
+ if (other.pdbid != null)
+ {
+ return false;
+ }
+ }
+ else if (!pdbid.equals(other.pdbid))
+ {
+ return false;
+ }
+ if (seqToPdbMapping == null)
+ {
+ if (other.seqToPdbMapping != null)
+ {
+ return false;
+ }
+ }
+ else if (!seqToPdbMapping.equals(other.seqToPdbMapping))
+ {
+ return false;
+ }
+ if (sequence != other.sequence)
+ {
+ return false;
+ }
+
+ return true;
+ }
}
private boolean addTempFacAnnot = false;
- private SiftsClient siftsClient = null;
-
/*
* Set of any registered mappings between (dataset) sequences.
*/
}
/**
- * Returns the file name for a mapped PDB id (or null if not mapped).
+ * Returns the filename the PDB id is already mapped to if known, or null if
+ * it is not mapped
*
* @param pdbid
* @return
{
for (StructureMapping sm : mappings)
{
- if (sm.getPdbId().equals(pdbid))
+ if (sm.getPdbId().equalsIgnoreCase(pdbid))
{
return sm.pdbfile;
}
}
/**
- * create sequence structure mappings between each sequence and the given
- * pdbFile (retrieved via the given protocol).
+ * Import a single structure file and register sequence structure mappings for
+ * broadcasting colouring, mouseovers and selection events (convenience
+ * wrapper).
*
* @param forStructureView
* when true, record the mapping for use in mouseOvers
- *
- * @param sequenceArray
+ * @param sequence
* - one or more sequences to be mapped to pdbFile
- * @param targetChainIds
+ * @param targetChains
* - optional chain specification for mapping each sequence to pdb
- * (may be nill, individual elements may be nill) - JBPNote: JAL-2693
- * - this should be List<List<String>>, empty lists indicate no
- * predefined mappings
+ * (may be nill, individual elements may be nill)
* @param pdbFile
* - structure data resource
- * @param sourceType
+ * @param protocol
* - how to resolve data from resource
* @return null or the structure data parsed as a pdb file
*/
pdbFile, sourceType, null);
}
+ /**
+ * create sequence structure mappings between each sequence and the given
+ * pdbFile (retrieved via the given protocol). Either constructs a mapping
+ * using NW alignment or derives one from any available SIFTS mapping data.
+ *
+ * @param forStructureView
+ * when true, record the mapping for use in mouseOvers
+ *
+ * @param sequenceArray
+ * - 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) - JBPNote: JAL-2693
+ * - this should be List<List<String>>, empty lists indicate no
+ * predefined mappings
+ * @param pdbFile
+ * - structure data resource
+ * @param sourceType
+ * - how to resolve data from resource
+ * @param IProgressIndicator
+ * reference to UI component that maintains a progress bar for the
+ * mapping operation
+ * @return null or the structure data parsed as a pdb file
+ */
synchronized public StructureFile computeMapping(
boolean forStructureView, SequenceI[] sequenceArray,
String[] targetChainIds, String pdbFile, DataSourceType sourceType,
IProgressIndicator progress)
{
long progressSessionId = System.currentTimeMillis() * 3;
- /*
- * There will be better ways of doing this in the future, for now we'll use
- * the tried and tested MCview pdb mapping
+
+ /**
+ * do we extract and transfer annotation from 3D data ?
*/
- boolean parseSecStr = processSecondaryStructure;
- if (isPDBFileRegistered(pdbFile))
- {
- for (SequenceI sq : sequenceArray)
- {
- SequenceI ds = sq;
- while (ds.getDatasetSequence() != null)
- {
- ds = ds.getDatasetSequence();
- }
- ;
- if (ds.getAnnotation() != null)
- {
- for (AlignmentAnnotation ala : ds.getAnnotation())
- {
- // false if any annotation present from this structure
- // JBPNote this fails for jmol/chimera view because the *file* is
- // passed, not the structure data ID -
- if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
- {
- parseSecStr = false;
- }
- }
- }
- }
- }
+ // FIXME: possibly should just delete
+
+ boolean parseSecStr = processSecondaryStructure
+ ? isStructureFileProcessed(pdbFile, sequenceArray)
+ : false;
+
StructureFile pdb = null;
boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
try
{
+ // FIXME if sourceType is not null, we've lost data here
sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
- pdb = new JmolParser(pdbFile, sourceType);
-
+ pdb = new JmolParser(false, pdbFile, sourceType);
+ pdb.addSettings(parseSecStr && processSecondaryStructure,
+ parseSecStr && addTempFacAnnot,
+ parseSecStr && secStructServices);
+ pdb.doParse();
if (pdb.getId() != null && pdb.getId().trim().length() > 0
&& DataSourceType.FILE == sourceType)
{
ex.printStackTrace();
return null;
}
-
+ /*
+ * sifts client - non null if SIFTS mappings are to be used
+ */
+ SiftsClient siftsClient = null;
try
{
if (isMapUsingSIFTs)
{
isMapUsingSIFTs = false;
e.printStackTrace();
+ siftsClient = null;
}
String targetChainId;
try
{
siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
- pdb, maxChain, sqmpping, maxAlignseq);
+ pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
seqToStrucMapping.add(siftsMapping);
- maxChain.makeExactMapping(maxAlignseq, seq);
- maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
+ maxChain.makeExactMapping(siftsMapping, seq);
+ maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
// "IEA:SIFTS" ?
- maxChain.transferResidueAnnotation(siftsMapping, sqmpping);
+ maxChain.transferResidueAnnotation(siftsMapping, null);
ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
} catch (SiftsException e)
targetChainId, maxChain, pdb, maxAlignseq);
seqToStrucMapping.add(nwMapping);
maxChain.makeExactMapping(maxAlignseq, seq);
- maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
+ maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
+ // this
// "IEA:Jalview" ?
maxChain.transferResidueAnnotation(nwMapping, sqmpping);
ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
List<StructureMapping> foundSiftsMappings = new ArrayList<>();
for (PDBChain chain : pdb.getChains())
{
+ StructureMapping siftsMapping = null;
try
{
- StructureMapping siftsMapping = getStructureMapping(seq,
- pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq);
+ siftsMapping = getStructureMapping(seq,
+ pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq,
+ siftsClient);
foundSiftsMappings.add(siftsMapping);
+ chain.makeExactMapping(siftsMapping, seq);
+ chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
+ // "IEA:SIFTS" ?
+ chain.transferResidueAnnotation(siftsMapping, null);
} catch (SiftsException e)
{
System.err.println(e.getMessage());
}
+ catch (Exception e)
+ {
+ System.err
+ .println(
+ "Unexpected exception during SIFTS mapping - falling back to NW for this sequence/structure pair");
+ System.err.println(e.getMessage());
+ }
}
if (!foundSiftsMappings.isEmpty())
{
seqToStrucMapping.addAll(foundSiftsMappings);
- maxChain.makeExactMapping(maxAlignseq, seq);
- maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
- // "IEA:SIFTS" ?
- maxChain.transferResidueAnnotation(foundSiftsMappings.get(0),
- sqmpping);
ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
}
else
}
if (forStructureView)
{
- mappings.addAll(seqToStrucMapping);
+ for (StructureMapping sm : seqToStrucMapping)
+ {
+ addStructureMapping(sm); // not addAll!
+ }
}
if (progress != null)
{
return pdb;
}
+ /**
+ * check if we need to extract secondary structure from given pdbFile and
+ * transfer to sequences
+ *
+ * @param pdbFile
+ * @param sequenceArray
+ * @return
+ */
+ private boolean isStructureFileProcessed(String pdbFile,
+ SequenceI[] sequenceArray)
+ {
+ boolean parseSecStr = true;
+ if (isPDBFileRegistered(pdbFile))
+ {
+ for (SequenceI sq : sequenceArray)
+ {
+ SequenceI ds = sq;
+ while (ds.getDatasetSequence() != null)
+ {
+ ds = ds.getDatasetSequence();
+ }
+ ;
+ if (ds.getAnnotation() != null)
+ {
+ for (AlignmentAnnotation ala : ds.getAnnotation())
+ {
+ // false if any annotation present from this structure
+ // JBPNote this fails for jmol/chimera view because the *file* is
+ // passed, not the structure data ID -
+ if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
+ {
+ parseSecStr = false;
+ }
+ }
+ }
+ }
+ }
+ return parseSecStr;
+ }
+
public void addStructureMapping(StructureMapping sm)
{
- mappings.add(sm);
+ if (!mappings.contains(sm))
+ {
+ mappings.add(sm);
+ }
}
/**
* @param maxChain
* @param sqmpping
* @param maxAlignseq
+ * @param siftsClient
+ * client for retrieval of SIFTS mappings for this structure
* @return
* @throws SiftsException
*/
private StructureMapping getStructureMapping(SequenceI seq,
String pdbFile, String targetChainId, StructureFile pdb,
PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
- AlignSeq maxAlignseq) throws SiftsException
+ AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException
{
StructureMapping curChainMapping = siftsClient
.getSiftsStructureMapping(seq, pdbFile, targetChainId);
PDBChain chain = pdb.findChain(targetChainId);
if (chain != null)
{
- chain.transferResidueAnnotation(curChainMapping, sqmpping);
+ chain.transferResidueAnnotation(curChainMapping, null);
}
} catch (Exception e)
{
package jalview.util;
import java.awt.Color;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Random;
public class ColorUtils
{
+ private static final int MAX_CACHE_SIZE = 1729;
+ /*
+ * a cache for colours generated from text strings
+ */
+ static Map<String, Color> myColours = new HashMap<>();
/**
* Generates a random color, will mix with input color. Code taken from
{
return Color.white;
}
+ if (myColours.containsKey(name))
+ {
+ return myColours.get(name);
+ }
int lsize = name.length();
int start = 0;
int end = lsize / 3;
Color color = new Color(r, g, b);
+ if (myColours.size() < MAX_CACHE_SIZE)
+ {
+ myColours.put(name, color);
+ }
+
return color;
}
+/*
+ * 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.util;
import java.util.Comparator;
*/
public MapList()
{
- fromShifts = new ArrayList<int[]>();
- toShifts = new ArrayList<int[]>();
+ fromShifts = new ArrayList<>();
+ toShifts = new ArrayList<>();
}
/**
{
int hashCode = 31 * fromRatio;
hashCode = 31 * hashCode + toRatio;
- hashCode = 31 * hashCode + fromShifts.toArray().hashCode();
- hashCode = 31 * hashCode + toShifts.toArray().hashCode();
+ for (int[] shift : fromShifts)
+ {
+ hashCode = 31 * hashCode + shift[0];
+ hashCode = 31 * hashCode + shift[1];
+ }
+ for (int[] shift : toShifts)
+ {
+ hashCode = 31 * hashCode + shift[0];
+ hashCode = 31 * hashCode + shift[1];
+ }
+
return hashCode;
}
fromHighest = Integer.MIN_VALUE;
for (int[] range : fromRange)
{
+ if (range.length != 2)
+ {
+ // throw new IllegalArgumentException(range);
+ System.err.println(
+ "Invalid format for fromRange " + Arrays.toString(range)
+ + " may cause errors");
+ }
fromLowest = Math.min(fromLowest, Math.min(range[0], range[1]));
fromHighest = Math.max(fromHighest, Math.max(range[0], range[1]));
}
toHighest = Integer.MIN_VALUE;
for (int[] range : toRange)
{
+ if (range.length != 2)
+ {
+ // throw new IllegalArgumentException(range);
+ System.err.println("Invalid format for toRange "
+ + Arrays.toString(range)
+ + " may cause errors");
+ }
toLowest = Math.min(toLowest, Math.min(range[0], range[1]));
toHighest = Math.max(toHighest, Math.max(range[0], range[1]));
}
}
boolean changed = false;
- List<int[]> merged = new ArrayList<int[]>();
+ List<int[]> merged = new ArrayList<>();
int[] lastRange = ranges.get(0);
int lastDirection = lastRange[1] >= lastRange[0] ? 1 : -1;
lastRange = new int[] { lastRange[0], lastRange[1] };
{
return null;
}
- List<int[]> ranges = new ArrayList<int[]>();
+ List<int[]> ranges = new ArrayList<>();
if (fs <= fe)
{
intv = fs;
*/
public boolean isFromForwardStrand()
{
+ return isForwardStrand(getFromRanges());
+ }
+
+ /**
+ * Returns true if mapping is to forward strand, false if to reverse strand.
+ * Result is just based on the first 'to' range that is not a single position.
+ * Default is true unless proven to be false. Behaviour is not well defined if
+ * the mapping has a mixture of forward and reverse ranges.
+ *
+ * @return
+ */
+ public boolean isToForwardStrand()
+ {
+ return isForwardStrand(getToRanges());
+ }
+
+ /**
+ * A helper method that returns true unless at least one range has start > end.
+ * Behaviour is undefined for a mixture of forward and reverse ranges.
+ *
+ * @param ranges
+ * @return
+ */
+ private boolean isForwardStrand(List<int[]> ranges)
+ {
boolean forwardStrand = true;
- for (int[] range : getFromRanges())
+ for (int[] range : ranges)
{
if (range[1] > range[0])
{
|| (fromRatio == 3 && toRatio == 1);
}
+ /**
+ * Returns a map which is the composite of this one and the input map. That
+ * is, the output map has the fromRanges of this map, and its toRanges are the
+ * toRanges of this map as transformed by the input map.
+ * <p>
+ * Returns null if the mappings cannot be traversed (not all toRanges of this
+ * map correspond to fromRanges of the input), or if this.toRatio does not
+ * match map.fromRatio.
+ *
+ * <pre>
+ * Example 1:
+ * this: from [1-100] to [501-600]
+ * input: from [10-40] to [60-90]
+ * output: from [10-40] to [560-590]
+ * Example 2 ('reverse strand exons'):
+ * this: from [1-100] to [2000-1951], [1000-951] // transcript to loci
+ * input: from [1-50] to [41-90] // CDS to transcript
+ * output: from [10-40] to [1960-1951], [1000-971] // CDS to gene loci
+ * </pre>
+ *
+ * @param map
+ * @return
+ */
+ public MapList traverse(MapList map)
+ {
+ if (map == null)
+ {
+ return null;
+ }
+
+ /*
+ * compound the ratios by this rule:
+ * A:B with M:N gives A*M:B*N
+ * reduced by greatest common divisor
+ * so 1:3 with 3:3 is 3:9 or 1:3
+ * 1:3 with 3:1 is 3:3 or 1:1
+ * 1:3 with 1:3 is 1:9
+ * 2:5 with 3:7 is 6:35
+ */
+ int outFromRatio = getFromRatio() * map.getFromRatio();
+ int outToRatio = getToRatio() * map.getToRatio();
+ int gcd = MathUtils.gcd(outFromRatio, outToRatio);
+ outFromRatio /= gcd;
+ outToRatio /= gcd;
+
+ List<int[]> toRanges = new ArrayList<>();
+ for (int[] range : getToRanges())
+ {
+ int[] transferred = map.locateInTo(range[0], range[1]);
+ if (transferred == null || transferred.length % 2 != 0)
+ {
+ return null;
+ }
+
+ /*
+ * convert [start1, end1, start2, end2, ...]
+ * to [[start1, end1], [start2, end2], ...]
+ */
+ for (int i = 0; i < transferred.length;)
+ {
+ toRanges.add(new int[] { transferred[i], transferred[i + 1] });
+ i += 2;
+ }
+ }
+
+ return new MapList(getFromRanges(), toRanges, outFromRatio, outToRatio);
+ }
+
}
toSequences, fromGapChar);
}
- for (int[] hidden : hiddencols.getHiddenColumnsCopy())
+ Iterator<int[]> regions = hiddencols.iterator();
+ while (regions.hasNext())
{
- mapHiddenColumns(hidden, codonFrames, newHidden, fromSequences,
+ mapHiddenColumns(regions.next(), codonFrames, newHidden,
+ fromSequences,
toSequences, fromGapChar);
}
return; // mappedColumns;
}
/**
+ * Answers true if range's start-end positions include those of queryRange,
+ * where either range might be in reverse direction, else false
+ *
+ * @param range
+ * a start-end range
+ * @param queryRange
+ * a candidate subrange of range (start2-end2)
+ * @return
+ */
+ public static boolean rangeContains(int[] range, int[] queryRange)
+ {
+ if (range == null || queryRange == null || range.length != 2
+ || queryRange.length != 2)
+ {
+ /*
+ * invalid arguments
+ */
+ return false;
+ }
+
+ int min = Math.min(range[0], range[1]);
+ int max = Math.max(range[0], range[1]);
+
+ return (min <= queryRange[0] && max >= queryRange[0]
+ && min <= queryRange[1] && max >= queryRange[1]);
+ }
+
+ /**
* Removes the specified number of positions from the given ranges. Provided
* to allow a stop codon to be stripped from a CDS sequence so that it matches
* the peptide translation length.
--- /dev/null
+package jalview.util;
+
+public class MathUtils
+{
+
+ /**
+ * Returns the greatest common divisor of two integers
+ *
+ * @param a
+ * @param b
+ * @return
+ */
+ public static int gcd(int a, int b)
+ {
+ if (b == 0)
+ {
+ return Math.abs(a);
+ }
+ return gcd(b, a % b);
+ }
+
+}
}
return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
}
+
+ /**
+ * A helper method that strips off any leading or trailing html and body tags.
+ * If no html tag is found, then also html-encodes angle bracket characters.
+ *
+ * @param text
+ * @return
+ */
+ public static String stripHtmlTags(String text)
+ {
+ if (text == null)
+ {
+ return null;
+ }
+ String tmp2up = text.toUpperCase();
+ int startTag = tmp2up.indexOf("<HTML>");
+ if (startTag > -1)
+ {
+ text = text.substring(startTag + 6);
+ tmp2up = tmp2up.substring(startTag + 6);
+ }
+ // is omission of "<BODY>" intentional here??
+ int endTag = tmp2up.indexOf("</BODY>");
+ if (endTag > -1)
+ {
+ text = text.substring(0, endTag);
+ tmp2up = tmp2up.substring(0, endTag);
+ }
+ endTag = tmp2up.indexOf("</HTML>");
+ if (endTag > -1)
+ {
+ text = text.substring(0, endTag);
+ }
+
+ if (startTag == -1 && (text.contains("<") || text.contains(">")))
+ {
+ text = text.replaceAll("<", "<");
+ text = text.replaceAll(">", ">");
+ }
+ return text;
+ }
}
--- /dev/null
+package jalview.util.matcher;
+
+import jalview.util.MessageManager;
+
+/**
+ * An enumeration for binary conditions that a user might choose from when
+ * setting filter or match conditions for values
+ */
+public enum Condition
+{
+ Contains(false, true, "Contains"),
+ NotContains(false, true, "NotContains"), Matches(false, true, "Matches"),
+ NotMatches(false, true, "NotMatches"), Present(false, false, "Present"),
+ NotPresent(false, false, "NotPresent"), EQ(true, true, "EQ"),
+ NE(true, true, "NE"), LT(true, true, "LT"), LE(true, true, "LE"),
+ GT(true, true, "GT"), GE(true, true, "GE");
+
+ private boolean numeric;
+
+ private boolean needsAPattern;
+
+ /*
+ * value used to save a Condition to the
+ * Jalview project file or restore it from project;
+ * it should not be changed even if enum names change in future
+ */
+ private String stableName;
+
+ /**
+ * Answers the enum value whose 'stable name' matches the argument (not case
+ * sensitive), or null if no match
+ *
+ * @param stableName
+ * @return
+ */
+ public static Condition fromString(String stableName)
+ {
+ for (Condition c : values())
+ {
+ if (c.stableName.equalsIgnoreCase(stableName))
+ {
+ return c;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param isNumeric
+ * @param needsPattern
+ * @param stablename
+ */
+ Condition(boolean isNumeric, boolean needsPattern, String stablename)
+ {
+ numeric = isNumeric;
+ needsAPattern = needsPattern;
+ stableName = stablename;
+ }
+
+ /**
+ * Answers true if the condition does a numerical comparison, else false
+ * (string comparison)
+ *
+ * @return
+ */
+ public boolean isNumeric()
+ {
+ return numeric;
+ }
+
+ /**
+ * Answers true if the condition requires a pattern to compare against, else
+ * false
+ *
+ * @return
+ */
+ public boolean needsAPattern()
+ {
+ return needsAPattern;
+ }
+
+ public String getStableName()
+ {
+ return stableName;
+ }
+
+ /**
+ * Answers a display name for the match condition, suitable for showing in
+ * drop-down menus. The value may be internationalized using the resource key
+ * "label.matchCondition_" with the enum name appended.
+ *
+ * @return
+ */
+ @Override
+ public String toString()
+ {
+ return MessageManager.getStringOrReturn("label.matchCondition_",
+ name());
+ }
+}
--- /dev/null
+package jalview.util.matcher;
+
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+/**
+ * A bean to describe one attribute-based filter
+ */
+public class Matcher implements MatcherI
+{
+ /*
+ * the comparison condition
+ */
+ Condition condition;
+
+ /*
+ * the string pattern as entered, or the regex, to compare to
+ * also holds the string form of float value if a numeric condition
+ */
+ String pattern;
+
+ /*
+ * the pattern in upper case, for non-case-sensitive matching
+ */
+ String uppercasePattern;
+
+ /*
+ * the compiled regex if using a pattern match condition
+ * (reserved for possible future enhancement)
+ */
+ Pattern regexPattern;
+
+ /*
+ * the value to compare to for a numerical condition
+ */
+ float value;
+
+ /**
+ * Constructor
+ *
+ * @param cond
+ * @param compareTo
+ * @return
+ * @throws NumberFormatException
+ * if a numerical condition is specified with a non-numeric
+ * comparison value
+ * @throws NullPointerException
+ * if a null condition or comparison string is specified
+ */
+ public Matcher(Condition cond, String compareTo)
+ {
+ Objects.requireNonNull(cond);
+ condition = cond;
+ if (cond.isNumeric())
+ {
+ value = Float.valueOf(compareTo);
+ pattern = String.valueOf(value);
+ uppercasePattern = pattern;
+ }
+ else
+ {
+ pattern = compareTo;
+ if (pattern != null)
+ {
+ uppercasePattern = pattern.toUpperCase();
+ }
+ }
+
+ // if we add regex conditions (e.g. matchesPattern), then
+ // pattern should hold the raw regex, and
+ // regexPattern = Pattern.compile(compareTo);
+ }
+
+ /**
+ * Constructor for a numerical match condition. Note that if a string
+ * comparison condition is specified, this will be converted to a comparison
+ * with the float value as string
+ *
+ * @param cond
+ * @param compareTo
+ */
+ public Matcher(Condition cond, float compareTo)
+ {
+ this(cond, String.valueOf(compareTo));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("incomplete-switch")
+ @Override
+ public boolean matches(String val)
+ {
+ if (condition.isNumeric())
+ {
+ try
+ {
+ /*
+ * treat a null value (no such attribute) as
+ * failing any numerical filter condition
+ */
+ return val == null ? false : matches(Float.valueOf(val));
+ } catch (NumberFormatException e)
+ {
+ return false;
+ }
+ }
+
+ /*
+ * a null value matches a negative condition, fails a positive test
+ */
+ if (val == null)
+ {
+ return condition == Condition.NotContains
+ || condition == Condition.NotMatches
+ || condition == Condition.NotPresent;
+ }
+
+ String upper = val.toUpperCase().trim();
+ boolean matched = false;
+ switch(condition) {
+ case Matches:
+ matched = upper.equals(uppercasePattern);
+ break;
+ case NotMatches:
+ matched = !upper.equals(uppercasePattern);
+ break;
+ case Contains:
+ matched = upper.indexOf(uppercasePattern) > -1;
+ break;
+ case NotContains:
+ matched = upper.indexOf(uppercasePattern) == -1;
+ break;
+ case Present:
+ matched = true;
+ break;
+ default:
+ break;
+ }
+ return matched;
+ }
+
+ /**
+ * Applies a numerical comparison match condition
+ *
+ * @param f
+ * @return
+ */
+ @SuppressWarnings("incomplete-switch")
+ boolean matches(float f)
+ {
+ if (!condition.isNumeric())
+ {
+ return matches(String.valueOf(f));
+ }
+
+ boolean matched = false;
+ switch (condition) {
+ case LT:
+ matched = f < value;
+ break;
+ case LE:
+ matched = f <= value;
+ break;
+ case EQ:
+ matched = f == value;
+ break;
+ case NE:
+ matched = f != value;
+ break;
+ case GT:
+ matched = f > value;
+ break;
+ case GE:
+ matched = f >= value;
+ break;
+ default:
+ break;
+ }
+
+ return matched;
+ }
+
+ /**
+ * A simple hash function that guarantees that when two objects are equal,
+ * they have the same hashcode
+ */
+ @Override
+ public int hashCode()
+ {
+ return pattern.hashCode() + condition.hashCode() + (int) value;
+ }
+
+ /**
+ * equals is overridden so that we can safely remove Matcher objects from
+ * collections (e.g. delete an attribute match condition for a feature colour)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null || !(obj instanceof Matcher))
+ {
+ return false;
+ }
+ Matcher m = (Matcher) obj;
+ if (condition != m.condition || value != m.value)
+ {
+ return false;
+ }
+ if (pattern == null)
+ {
+ return m.pattern == null;
+ }
+ return uppercasePattern.equals(m.uppercasePattern);
+ }
+
+ @Override
+ public Condition getCondition()
+ {
+ return condition;
+ }
+
+ @Override
+ public String getPattern()
+ {
+ return pattern;
+ }
+
+ @Override
+ public float getFloatValue()
+ {
+ return value;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(condition.toString()).append(" ");
+ if (condition.isNumeric())
+ {
+ sb.append(pattern);
+ }
+ else
+ {
+ sb.append("'").append(pattern).append("'");
+ }
+
+ return sb.toString();
+ }
+}
--- /dev/null
+package jalview.util.matcher;
+
+public interface MatcherI
+{
+ /**
+ * Answers true if the given value is matched, else false
+ *
+ * @param s
+ * @return
+ */
+ boolean matches(String s);
+
+ Condition getCondition();
+
+ String getPattern();
+
+ float getFloatValue();
+}
import java.util.Deque;
import java.util.HashMap;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
if (alignment.getHiddenColumns() != null
&& alignment.getHiddenColumns().hasHiddenColumns())
{
- selection = alignment.getHiddenColumns()
- .getVisibleSequenceStrings(start, end, seqs);
+ for (i = 0; i < iSize; i++)
+ {
+ Iterator<int[]> blocks = alignment.getHiddenColumns()
+ .getVisContigsIterator(start, end + 1, false);
+ selection[i] = seqs[i].getSequenceStringFromIterator(blocks);
+ }
}
else
{
{
if (start == 0)
{
- start = hidden.adjustForHiddenColumns(start);
+ start = hidden.visibleToAbsoluteColumn(start);
}
- end = hidden.getHiddenBoundaryRight(start);
+ end = hidden.getNextHiddenBoundary(false, start);
if (start == end)
{
end = max;
if (hidden != null && hidden.hasHiddenColumns())
{
- start = hidden.adjustForHiddenColumns(end);
- start = hidden.getHiddenBoundaryLeft(start) + 1;
+ start = hidden.visibleToAbsoluteColumn(end);
+ start = hidden.getNextHiddenBoundary(true, start) + 1;
}
} while (end < max);
AlignmentAnnotation clone = new AlignmentAnnotation(annot);
if (selectedOnly && selectionGroup != null)
{
- alignment.getHiddenColumns().makeVisibleAnnotation(
+ clone.makeVisibleAnnotation(
selectionGroup.getStartRes(), selectionGroup.getEndRes(),
- clone);
+ alignment.getHiddenColumns());
}
else
{
- alignment.getHiddenColumns().makeVisibleAnnotation(clone);
+ clone.makeVisibleAnnotation(alignment.getHiddenColumns());
}
ala.add(clone);
}
int lastSeq = alignment.getHeight() - 1;
List<AlignedCodonFrame> seqMappings = null;
for (int seqNo = ranges
- .getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++)
+ .getStartSeq(); seqNo <= lastSeq; seqNo++, seqOffset++)
{
sequence = getAlignment().getSequenceAt(seqNo);
if (hiddenSequences != null && hiddenSequences.isHidden(sequence))
protected int alheight;
+ protected float widthRatio;
+
+ protected float heightRatio;
+
/**
* Create an OverviewDimensions object
*
public float getPixelsPerCol()
{
resetAlignmentDims();
- return (float) width / alwidth;
+ return 1 / widthRatio;
}
public float getPixelsPerSeq()
{
resetAlignmentDims();
- return (float) sequencesHeight / alheight;
+ return 1 / heightRatio;
}
public void setWidth(int w)
{
width = w;
+ widthRatio = (float) alwidth / width;
}
public void setHeight(int h)
{
sequencesHeight = h - graphHeight;
+ heightRatio = (float) alheight / sequencesHeight;
}
/**
// boxX, boxY is the x,y location equivalent to startRes, startSeq
int xPos = Math.min(startRes, alwidth - vpwidth + 1);
- boxX = Math.round((float) xPos * width / alwidth);
- boxY = Math.round((float) startSeq * sequencesHeight / alheight);
+ boxX = Math.round(xPos / widthRatio);
+ boxY = Math.round(startSeq / heightRatio);
// boxWidth is the width in residues translated to pixels
- boxWidth = Math.round((float) vpwidth * width / alwidth);
+ boxWidth = Math.round(vpwidth / widthRatio);
// boxHeight is the height in sequences translated to pixels
- boxHeight = Math.round((float) vpheight * sequencesHeight / alheight);
+ boxHeight = Math.round(vpheight / heightRatio);
}
/**
public void updateViewportFromMouse(int mousex, int mousey,
HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
{
+ resetAlignmentDims();
+
int xAsRes = getLeftXFromCentreX(mousex, hiddenCols);
int yAsSeq = getTopYFromCentreY(mousey, hiddenSeqs);
public void adjustViewportFromMouse(int mousex, int mousey,
HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
{
+ resetAlignmentDims();
+
// calculate translation in pixel terms:
// get mouse location in viewport coords, add translation in viewport
// coords, and update viewport as usual
- int vpx = Math.round((float) mousex * alwidth / width);
- int vpy = Math.round((float) mousey * alheight / sequencesHeight);
+ int vpx = Math.round(mousex * widthRatio);
+ int vpy = Math.round(mousey * heightRatio);
updateViewportFromTopLeft(vpx + xdiff, vpy + ydiff, hiddenSeqs,
hiddenCols);
}
+ /**
+ * {@inheritDoc} Callers should have already called resetAlignmentDims to
+ * refresh alwidth, alheight and width/height ratios
+ */
@Override
protected void updateViewportFromTopLeft(int leftx, int topy,
HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
{
int xAsRes = leftx;
int yAsSeq = topy;
- resetAlignmentDims();
if (xAsRes < 0)
{
public AlignmentColsCollectionI getColumns(AlignmentI al)
{
return new VisibleColsCollection(0,
- ranges.getAbsoluteAlignmentWidth() - 1, al);
+ ranges.getAbsoluteAlignmentWidth() - 1, al.getHiddenColumns());
}
@Override
{
alwidth = ranges.getVisibleAlignmentWidth();
alheight = ranges.getVisibleAlignmentHeight();
+
+ widthRatio = (float) alwidth / width;
+ heightRatio = (float) alheight / sequencesHeight;
}
+ /**
+ * {@inheritDoc} Callers should have already called resetAlignmentDims to
+ * refresh widthRatio
+ */
@Override
protected int getLeftXFromCentreX(int mousex, HiddenColumns hidden)
{
- int vpx = Math.round((float) mousex * alwidth / width);
+ int vpx = Math.round(mousex * widthRatio);
return vpx - ranges.getViewportWidth() / 2;
}
+ /**
+ * {@inheritDoc} Callers should have already called resetAlignmentDims to
+ * refresh heightRatio
+ */
@Override
protected int getTopYFromCentreY(int mousey, HiddenSequences hidden)
{
- int vpy = Math.round((float) mousey * alheight / sequencesHeight);
+ int vpy = Math.round(mousey * heightRatio);
return vpy - ranges.getViewportHeight() / 2;
}
public void setDragPoint(int x, int y, HiddenSequences hiddenSeqs,
HiddenColumns hiddenCols)
{
+ resetAlignmentDims();
+
// get alignment position of x and box (can get directly from vpranges) and
// calculate difference between the positions
- int vpx = Math.round((float) x * alwidth / width);
- int vpy = Math.round((float) y * alheight / sequencesHeight);
+ int vpx = Math.round(x * widthRatio);
+ int vpy = Math.round(y * heightRatio);
xdiff = ranges.getStartRes() - vpx;
ydiff = ranges.getStartSeq() - vpy;
public void updateViewportFromMouse(int mousex, int mousey,
HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
{
+ resetAlignmentDims();
+
// convert mousex and mousey to alignment units as well as
// translating to top left corner of viewport - this is an absolute position
int xAsRes = getLeftXFromCentreX(mousex, hiddenCols);
int yAsSeq = getTopYFromCentreY(mousey, hiddenSeqs);
// convert to visible positions
- int visXAsRes = hiddenCols.findColumnPosition(xAsRes);
+ int visXAsRes = hiddenCols.absoluteToVisibleColumn(xAsRes);
yAsSeq = hiddenSeqs.adjustForHiddenSeqs(
hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq));
yAsSeq = Math.max(yAsSeq, 0); // -1 if before first visible sequence
public void adjustViewportFromMouse(int mousex, int mousey,
HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
{
+ resetAlignmentDims();
+
// calculate translation in pixel terms:
// get mouse location in viewport coords, add translation in viewport
// coords,
// convert back to pixel coords
int vpx = Math.round((float) mousex * alwidth / width);
- int visXAsRes = hiddenCols.findColumnPosition(vpx) + xdiff;
+ int visXAsRes = hiddenCols.absoluteToVisibleColumn(vpx) + xdiff;
- int vpy = Math.round((float) mousey * alheight / sequencesHeight);
+ int vpy = Math.round(mousey * heightRatio);
int visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(vpy) + ydiff;
// update viewport accordingly
updateViewportFromTopLeft(visXAsRes, visYAsRes, hiddenSeqs, hiddenCols);
}
+ /**
+ * {@inheritDoc} Callers should have already called resetAlignmentDims to
+ * refresh alwidth, alheight and width/height ratios
+ */
@Override
protected void updateViewportFromTopLeft(int leftx, int topy,
HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
{
int visXAsRes = leftx;
int visYAsSeq = topy;
- resetAlignmentDims();
if (visXAsRes < 0)
{
int vpwidth = ranges.getViewportWidth();
// check in case we went off the edge of the alignment
- int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1);
+ int visAlignWidth = hiddenCols.absoluteToVisibleColumn(alwidth - 1);
if (visXAsRes + vpwidth - 1 > visAlignWidth)
{
// went past the end of the alignment, adjust backwards
// if last position was before the end of the alignment, need to update
if (ranges.getEndRes() < visAlignWidth)
{
- visXAsRes = hiddenCols.findColumnPosition(hiddenCols
- .subtractVisibleColumns(vpwidth - 1, alwidth - 1));
+ visXAsRes = hiddenCols.absoluteToVisibleColumn(hiddenCols
+ .offsetByVisibleColumns(-(vpwidth - 1), alwidth - 1));
}
else
{
HiddenColumns hiddenCols)
{
// work with absolute values of startRes and endRes
- int startRes = hiddenCols.adjustForHiddenColumns(ranges.getStartRes());
- int endRes = hiddenCols.adjustForHiddenColumns(ranges.getEndRes());
+ int startRes = hiddenCols.visibleToAbsoluteColumn(ranges.getStartRes());
+ int endRes = hiddenCols.visibleToAbsoluteColumn(ranges.getEndRes());
// work with absolute values of startSeq and endSeq
int startSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getStartSeq());
{
alwidth = ranges.getAbsoluteAlignmentWidth();
alheight = ranges.getAbsoluteAlignmentHeight();
+
+ widthRatio = (float) alwidth / width;
+ heightRatio = (float) alheight / sequencesHeight;
}
+
+ /**
+ * {@inheritDoc} Callers should have already called resetAlignmentDims to
+ * refresh widthRatio
+ */
@Override
protected int getLeftXFromCentreX(int mousex, HiddenColumns hidden)
{
int vpx = Math.round((float) mousex * alwidth / width);
- return hidden.subtractVisibleColumns(ranges.getViewportWidth() / 2,
+ return hidden.offsetByVisibleColumns(-ranges.getViewportWidth() / 2,
vpx);
}
+ /**
+ * {@inheritDoc} Callers should have already called resetAlignmentDims to
+ * refresh heightRatio
+ */
@Override
protected int getTopYFromCentreY(int mousey, HiddenSequences hidden)
{
- int vpy = Math.round((float) mousey * alheight / sequencesHeight);
+ int vpy = Math.round(mousey * heightRatio);
return hidden.subtractVisibleRows(ranges.getViewportHeight() / 2, vpy);
}
public void setDragPoint(int x, int y, HiddenSequences hiddenSeqs,
HiddenColumns hiddenCols)
{
+ resetAlignmentDims();
+
// get alignment position of x and box (can get directly from vpranges) and
// calculate difference between the positions
- int vpx = Math.round((float) x * alwidth / width);
- int vpy = Math.round((float) y * alheight / sequencesHeight);
+ int vpx = Math.round(x * widthRatio);
+ int vpy = Math.round(y * heightRatio);
- xdiff = ranges.getStartRes() - hiddenCols.findColumnPosition(vpx);
+ xdiff = ranges.getStartRes() - hiddenCols.absoluteToVisibleColumn(vpx);
ydiff = ranges.getStartSeq()
- hiddenSeqs.findIndexWithoutHiddenSeqs(vpy);
}
}
HiddenColumns hidden = al.getHiddenColumns();
- while (x < hidden.adjustForHiddenColumns(startRes))
+ while (x < hidden.visibleToAbsoluteColumn(startRes))
{
if (!scrollRight(false))
{
break;
}
}
- while (x > hidden.adjustForHiddenColumns(endRes))
+ while (x > hidden.visibleToAbsoluteColumn(endRes))
{
if (!scrollRight(true))
{
boolean changedLocation = false;
// convert the x,y location to visible coordinates
- int visX = al.getHiddenColumns().findColumnPosition(x);
+ int visX = al.getHiddenColumns().absoluteToVisibleColumn(x);
int visY = al.getHiddenSequences().findIndexWithoutHiddenSeqs(y);
// if (vis_x,vis_y) is already visible don't do anything
import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.datamodel.features.SequenceFeatures;
import jalview.renderer.seqfeatures.FeatureRenderer;
import jalview.schemes.FeatureColour;
public abstract class FeatureRendererModel
implements jalview.api.FeatureRenderer
{
+ /*
+ * a data bean to hold one row of feature settings from the gui
+ */
+ public static class FeatureSettingsBean
+ {
+ public final String featureType;
- /**
+ public final FeatureColourI featureColour;
+
+ public final FeatureMatcherSetI filter;
+
+ public final Boolean show;
+
+ public FeatureSettingsBean(String type, FeatureColourI colour,
+ FeatureMatcherSetI theFilter, Boolean isShown)
+ {
+ featureType = type;
+ featureColour = colour;
+ filter = theFilter;
+ show = isShown;
+ }
+ }
+
+ /*
* global transparency for feature
*/
protected float transparency = 1.0f;
- protected Map<String, FeatureColourI> featureColours = new ConcurrentHashMap<String, FeatureColourI>();
+ /*
+ * colour scheme for each feature type
+ */
+ protected Map<String, FeatureColourI> featureColours = new ConcurrentHashMap<>();
- protected Map<String, Boolean> featureGroups = new ConcurrentHashMap<String, Boolean>();
+ /*
+ * visibility flag for each feature group
+ */
+ protected Map<String, Boolean> featureGroups = new ConcurrentHashMap<>();
+
+ /*
+ * filters for each feature type
+ */
+ protected Map<String, FeatureMatcherSetI> featureFilters = new HashMap<>();
protected String[] renderOrder;
this.renderOrder = frs.renderOrder;
this.featureGroups = frs.featureGroups;
this.featureColours = frs.featureColours;
+ this.featureFilters = frs.featureFilters;
this.transparency = frs.transparency;
this.featureOrder = frs.featureOrder;
if (av != null && av != fr.getViewport())
{
av.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
}
- List<String> nft = new ArrayList<String>();
+ List<String> nft = new ArrayList<>();
for (String featureType : featureTypes)
{
if (!fdi.isRegistered(featureType))
renderOrder = neworder;
}
- protected Map<String, float[][]> minmax = new Hashtable<String, float[][]>();
+ protected Map<String, float[][]> minmax = new Hashtable<>();
public Map<String, float[][]> getMinMax()
{
* include features at the position provided their feature type is
* displayed, and feature group is null or marked for display
*/
- List<SequenceFeature> result = new ArrayList<SequenceFeature>();
+ List<SequenceFeature> result = new ArrayList<>();
if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null)
{
return result;
List<SequenceFeature> features = sequence.findFeatures(column, column,
visibleTypes);
+ /*
+ * include features unless their feature group is not displayed, or
+ * they are hidden (have no colour) based on a filter or colour threshold
+ */
for (SequenceFeature sf : features)
{
- if (!featureGroupNotShown(sf))
+ if (!featureGroupNotShown(sf) && getColour(sf) != null)
{
result.add(sf);
}
}
FeaturesDisplayedI featuresDisplayed = av.getFeaturesDisplayed();
- Set<String> oldfeatures = new HashSet<String>();
+ Set<String> oldfeatures = new HashSet<>();
if (renderOrder != null)
{
for (int i = 0; i < renderOrder.length; i++)
}
AlignmentI alignment = av.getAlignment();
- List<String> allfeatures = new ArrayList<String>();
+ List<String> allfeatures = new ArrayList<>();
for (int i = 0; i < alignment.getHeight(); i++)
{
*/
if (minmax == null)
{
- minmax = new Hashtable<String, float[][]>();
+ minmax = new Hashtable<>();
}
synchronized (minmax)
{
*/
private void updateRenderOrder(List<String> allFeatures)
{
- List<String> allfeatures = new ArrayList<String>(allFeatures);
+ List<String> allfeatures = new ArrayList<>(allFeatures);
String[] oldRender = renderOrder;
renderOrder = new String[allfeatures.size()];
boolean initOrders = (featureOrder == null);
if (mmrange != null)
{
FeatureColourI fc = featureColours.get(oldRender[j]);
- if (fc != null && !fc.isSimpleColour() && fc.isAutoScaled())
+ if (fc != null && !fc.isSimpleColour() && fc.isAutoScaled()
+ && !fc.isColourByAttribute())
{
fc.updateBounds(mmrange[0][0], mmrange[0][1]);
}
if (mmrange != null)
{
FeatureColourI fc = featureColours.get(newf[i]);
- if (fc != null && !fc.isSimpleColour() && fc.isAutoScaled())
+ if (fc != null && !fc.isSimpleColour() && fc.isAutoScaled()
+ && !fc.isColourByAttribute())
{
fc.updateBounds(mmrange[0][0], mmrange[0][1]);
}
return fc;
}
- /**
- * Returns the configured colour for a particular feature instance. This
- * includes calculation of 'colour by label', or of a graduated score colour,
- * if applicable. It does not take into account feature visibility or colour
- * transparency. Returns null for a score feature whose score value lies
- * outside any colour threshold.
- *
- * @param feature
- * @return
- */
+ @Override
public Color getColour(SequenceFeature feature)
{
FeatureColourI fc = getFeatureStyle(feature.getType());
- return fc.getColor(feature);
+ return getColor(feature, fc);
}
/**
*/
protected boolean showFeatureOfType(String type)
{
- return type == null ? false : av.getFeaturesDisplayed().isVisible(type);
+ return type == null ? false : (av.getFeaturesDisplayed() == null ? true
+ : av.getFeaturesDisplayed().isVisible(type));
}
@Override
{
if (featureOrder == null)
{
- featureOrder = new Hashtable<String, Float>();
+ featureOrder = new Hashtable<>();
}
featureOrder.put(type, new Float(position));
return position;
* Replace current ordering with new ordering
*
* @param data
- * { String(Type), Colour(Type), Boolean(Displayed) }
+ * an array of { Type, Colour, Filter, Boolean }
* @return true if any visible features have been reordered, else false
*/
- public boolean setFeaturePriority(Object[][] data)
+ public boolean setFeaturePriority(FeatureSettingsBean[] data)
{
return setFeaturePriority(data, true);
}
/**
- * Sets the priority order for features, with the highest priority (displayed
- * on top) at the start of the data array
+ * Sets the priority order for features, with the highest priority (displayed on
+ * top) at the start of the data array
*
* @param data
- * { String(Type), Colour(Type), Boolean(Displayed) }
+ * an array of { Type, Colour, Filter, Boolean }
* @param visibleNew
* when true current featureDisplay list will be cleared
- * @return true if any visible features have been reordered or recoloured,
- * else false (i.e. no need to repaint)
+ * @return true if any visible features have been reordered or recoloured, else
+ * false (i.e. no need to repaint)
*/
- public boolean setFeaturePriority(Object[][] data, boolean visibleNew)
+ public boolean setFeaturePriority(FeatureSettingsBean[] data,
+ boolean visibleNew)
{
/*
* note visible feature ordering and colours before update
*/
List<String> visibleFeatures = getDisplayedFeatureTypes();
- Map<String, FeatureColourI> visibleColours = new HashMap<String, FeatureColourI>(
+ Map<String, FeatureColourI> visibleColours = new HashMap<>(
getFeatureColours());
FeaturesDisplayedI av_featuresdisplayed = null;
{
for (int i = 0; i < data.length; i++)
{
- String type = data[i][0].toString();
- setColour(type, (FeatureColourI) data[i][1]);
- if (((Boolean) data[i][2]).booleanValue())
+ String type = data[i].featureType;
+ setColour(type, data[i].featureColour);
+ if (data[i].show)
{
av_featuresdisplayed.setVisible(type);
}
{
if (featureGroups != null)
{
- List<String> gp = new ArrayList<String>();
+ List<String> gp = new ArrayList<>();
for (String grp : featureGroups.keySet())
{
@Override
public Map<String, FeatureColourI> getDisplayedFeatureCols()
{
- Map<String, FeatureColourI> fcols = new Hashtable<String, FeatureColourI>();
+ Map<String, FeatureColourI> fcols = new Hashtable<>();
if (getViewport().getFeaturesDisplayed() == null)
{
return fcols;
public List<String> getDisplayedFeatureTypes()
{
List<String> typ = getRenderOrder();
- List<String> displayed = new ArrayList<String>();
+ List<String> displayed = new ArrayList<>();
FeaturesDisplayedI feature_disp = av.getFeaturesDisplayed();
if (feature_disp != null)
{
@Override
public List<String> getDisplayedFeatureGroups()
{
- List<String> _gps = new ArrayList<String>();
+ List<String> _gps = new ArrayList<>();
for (String gp : getFeatureGroups())
{
if (checkGroupVisibility(gp, false))
public List<SequenceFeature> findFeaturesAtResidue(SequenceI sequence,
int resNo)
{
- List<SequenceFeature> result = new ArrayList<SequenceFeature>();
+ List<SequenceFeature> result = new ArrayList<>();
if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null)
{
return result;
for (SequenceFeature sf : features)
{
- if (!featureGroupNotShown(sf))
+ if (!featureGroupNotShown(sf) && getColour(sf) != null)
{
result.add(sf);
}
}
/**
- * Removes from the list of features any that have a feature group that is not
- * displayed, or duplicate the location of a feature of the same type (unless
- * a graduated colour scheme or colour by label is applied). Should be used
- * only for features of the same feature colour (which normally implies the
- * same feature type).
+ * Removes from the list of features any that duplicate the location of a
+ * feature of the same type. Should be used only for features of the same,
+ * simple, feature colour (which normally implies the same feature type). Does
+ * not check visibility settings for feature type or feature group. No
+ * filtering is done if transparency, or any feature filters, are in force.
*
* @param features
- * @param fc
*/
- public void filterFeaturesForDisplay(List<SequenceFeature> features,
- FeatureColourI fc)
+ public void filterFeaturesForDisplay(List<SequenceFeature> features)
{
- if (features.isEmpty())
+ /*
+ * don't remove 'redundant' features if
+ * - transparency is applied (feature count affects depth of feature colour)
+ * - filters are applied (not all features may be displayable)
+ */
+ if (features.isEmpty() || transparency != 1f
+ || !featureFilters.isEmpty())
{
return;
}
+
SequenceFeatures.sortFeatures(features, true);
- boolean simpleColour = fc == null || fc.isSimpleColour();
SequenceFeature lastFeature = null;
Iterator<SequenceFeature> it = features.iterator();
while (it.hasNext())
{
SequenceFeature sf = it.next();
- if (featureGroupNotShown(sf))
- {
- it.remove();
- continue;
- }
/*
* a feature is redundant for rendering purposes if it has the
* (checking type and isContactFeature as a fail-safe here, although
* currently they are guaranteed to match in this context)
*/
- if (simpleColour)
+ if (lastFeature != null && sf.getBegin() == lastFeature.getBegin()
+ && sf.getEnd() == lastFeature.getEnd()
+ && sf.isContactFeature() == lastFeature.isContactFeature()
+ && sf.getType().equals(lastFeature.getType()))
{
- if (lastFeature != null && sf.getBegin() == lastFeature.getBegin()
- && sf.getEnd() == lastFeature.getEnd()
- && sf.isContactFeature() == lastFeature.isContactFeature()
- && sf.getType().equals(lastFeature.getType()))
- {
- it.remove();
- }
+ it.remove();
}
lastFeature = sf;
}
}
+ @Override
+ public Map<String, FeatureMatcherSetI> getFeatureFilters()
+ {
+ return featureFilters;
+ }
+
+ @Override
+ public void setFeatureFilters(Map<String, FeatureMatcherSetI> filters)
+ {
+ featureFilters = filters;
+ }
+
+ @Override
+ public FeatureMatcherSetI getFeatureFilter(String featureType)
+ {
+ return featureFilters.get(featureType);
+ }
+
+ @Override
+ public void setFeatureFilter(String featureType, FeatureMatcherSetI filter)
+ {
+ if (filter == null || filter.isEmpty())
+ {
+ featureFilters.remove(featureType);
+ }
+ else
+ {
+ featureFilters.put(featureType, filter);
+ }
+ }
+
+ /**
+ * Answers the colour for the feature, or null if the feature is excluded by
+ * feature group visibility, by filters, or by colour threshold settings. This
+ * method does not take feature visibility into account.
+ *
+ * @param sf
+ * @param fc
+ * @return
+ */
+ public Color getColor(SequenceFeature sf, FeatureColourI fc)
+ {
+ /*
+ * is the feature group displayed?
+ */
+ if (featureGroupNotShown(sf))
+ {
+ return null;
+ }
+
+ /*
+ * does the feature pass filters?
+ */
+ if (!featureMatchesFilters(sf))
+ {
+ return null;
+ }
+
+ return fc.getColor(sf);
+ }
+
+ /**
+ * Answers true if there no are filters defined for the feature type, or this
+ * feature matches the filters. Answers false if the feature fails to match
+ * filters.
+ *
+ * @param sf
+ * @return
+ */
+ protected boolean featureMatchesFilters(SequenceFeature sf)
+ {
+ FeatureMatcherSetI filter = featureFilters.get(sf.getType());
+ return filter == null ? true : filter.matches(sf);
+ }
+
}
package jalview.viewmodel.seqfeatures;
import jalview.api.FeatureColourI;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.schemes.FeatureColour;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
*/
Map<String, FeatureColourI> featureColours;
+ /*
+ * map of {featureType, filters}
+ */
+ Map<String, FeatureMatcherSetI> featureFilters;
+
float transparency;
Map<String, Float> featureOrder;
renderOrder = null;
featureGroups = new ConcurrentHashMap<String, Boolean>();
featureColours = new ConcurrentHashMap<String, FeatureColourI>();
+ featureFilters = new HashMap<>();
featureOrder = new ConcurrentHashMap<String, Float>();
+
if (fr.renderOrder != null)
{
this.renderOrder = new String[fr.renderOrder.length];
featureColours.put(next, new FeatureColour((FeatureColour) val));
}
}
+
+ if (fr.featureFilters != null)
+ {
+ this.featureFilters.putAll(fr.featureFilters);
+ }
+
this.transparency = fr.transparency;
if (fr.featureOrder != null)
{
import jalview.datamodel.Mapping;
import jalview.datamodel.SequenceI;
import jalview.gui.CutAndPasteTransfer;
-import jalview.gui.DasSourceBrowser;
import jalview.gui.Desktop;
import jalview.gui.FeatureSettings;
import jalview.gui.IProgressIndicator;
import jalview.gui.OOMWarning;
import jalview.util.DBRefUtils;
import jalview.util.MessageManager;
-import jalview.ws.dbsources.das.api.jalviewSourceI;
-import jalview.ws.dbsources.das.datamodel.DasSequenceSource;
import jalview.ws.seqfetcher.DbSourceProxy;
import java.util.ArrayList;
{
private static final String NEWLINE = System.lineSeparator();
+ public static final String TRIM_RETRIEVED_SEQUENCES = "TRIM_FETCHED_DATASET_SEQS";
+
public interface FetchFinishedListenerI
{
void finished();
DbSourceProxy[] sources, FeatureSettings featureSettings,
boolean isNucleotide)
{
- listeners = new ArrayList<FetchFinishedListenerI>();
+ listeners = new ArrayList<>();
this.progressWindow = progressIndicatorFrame;
alseqs = new SequenceI[seqs.length];
SequenceI[] ds = new SequenceI[seqs.length];
.getSequenceFetcherSingleton(progressIndicatorFrame);
// set default behaviour for transferring excess sequence data to the
// dataset
- trimDsSeqs = Cache.getDefault("TRIM_FETCHED_DATASET_SEQS", true);
+ trimDsSeqs = Cache.getDefault(TRIM_RETRIEVED_SEQUENCES, true);
if (sources == null)
{
setDatabaseSources(featureSettings, isNucleotide);
{
// af.featureSettings_actionPerformed(null);
String[] defdb = null;
- List<DbSourceProxy> selsources = new ArrayList<DbSourceProxy>();
- Vector<jalviewSourceI> dasselsrc = (featureSettings != null)
- ? featureSettings.getSelectedSources()
- : new DasSourceBrowser().getSelectedSources();
-
- for (jalviewSourceI src : dasselsrc)
- {
- List<DbSourceProxy> sp = src.getSequenceSourceProxies();
- if (sp != null)
- {
- selsources.addAll(sp);
- if (sp.size() > 1)
- {
- Cache.log.debug("Added many Db Sources for :" + src.getTitle());
- }
- }
- }
+ List<DbSourceProxy> selsources = new ArrayList<>();
// select appropriate databases based on alignFrame context.
if (forNucleotide)
{
{
defdb = DBRefSource.PROTEINDBS;
}
- List<DbSourceProxy> srces = new ArrayList<DbSourceProxy>();
+ List<DbSourceProxy> srces = new ArrayList<>();
for (String ddb : defdb)
{
List<DbSourceProxy> srcesfordb = sfetcher.getSourceProxy(ddb);
}
/**
- * retrieve all the das sequence sources and add them to the list of db
- * sources to retrieve from
- */
- public void appendAllDasSources()
- {
- if (dbSources == null)
- {
- dbSources = new DbSourceProxy[0];
- }
- // append additional sources
- DbSourceProxy[] otherdb = sfetcher
- .getDbSourceProxyInstances(DasSequenceSource.class);
- if (otherdb != null && otherdb.length > 0)
- {
- DbSourceProxy[] newsrc = new DbSourceProxy[dbSources.length
- + otherdb.length];
- System.arraycopy(dbSources, 0, newsrc, 0, dbSources.length);
- System.arraycopy(otherdb, 0, newsrc, dbSources.length,
- otherdb.length);
- dbSources = newsrc;
- }
- }
-
- /**
* start the fetcher thread
*
* @param waitTillFinished
}
else if (seqs == null)
{
- seqs = new Vector<SequenceI>();
+ seqs = new Vector<>();
seqs.addElement(seq);
}
}
else
{
- seqs = new Vector<SequenceI>();
+ seqs = new Vector<>();
seqs.addElement(seq);
}
e.printStackTrace();
}
- Vector<SequenceI> sdataset = new Vector<SequenceI>(
+ Vector<SequenceI> sdataset = new Vector<>(
Arrays.asList(dataset));
- List<String> warningMessages = new ArrayList<String>();
+ List<String> warningMessages = new ArrayList<>();
int db = 0;
while (sdataset.size() > 0 && db < dbSources.length)
SequenceI[] currSeqs = new SequenceI[sdataset.size()];
sdataset.copyInto(currSeqs);// seqs that are to be validated against
// dbSources[db]
- Vector<String> queries = new Vector<String>(); // generated queries curSeq
- seqRefs = new Hashtable<String, Vector<SequenceI>>();
+ Vector<String> queries = new Vector<>(); // generated queries curSeq
+ seqRefs = new Hashtable<>();
int seqIndex = 0;
{
// Work out which sequences this sequence matches,
// taking into account all accessionIds and names in the file
- Vector<SequenceI> sequenceMatches = new Vector<SequenceI>();
+ Vector<SequenceI> sequenceMatches = new Vector<>();
// look for corresponding accession ids
DBRefEntry[] entryRefs = DBRefUtils
.selectRefs(retrievedSeq.getDBRefs(), new String[]
int startShift = absStart - sequenceStart + 1;
if (startShift != 0)
{
- modified |= sequence.getFeatures().shiftFeatures(startShift);
+ modified |= sequence.getFeatures().shiftFeatures(1,
+ startShift);
}
}
}
*/
private SequenceI[] recoverDbSequences(SequenceI[] sequencesArray)
{
- Vector<SequenceI> nseq = new Vector<SequenceI>();
+ Vector<SequenceI> nseq = new Vector<>();
for (int i = 0; sequencesArray != null
&& i < sequencesArray.length; i++)
{
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ws;
-
-import jalview.bin.Cache;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.DBRefSource;
-import jalview.datamodel.SequenceFeature;
-import jalview.datamodel.SequenceI;
-import jalview.gui.AlignFrame;
-import jalview.gui.Desktop;
-import jalview.gui.FeatureSettings;
-import jalview.gui.JvOptionPane;
-import jalview.util.DBRefUtils;
-import jalview.util.MessageManager;
-import jalview.util.UrlLink;
-import jalview.ws.dbsources.das.api.DasSourceRegistryI;
-import jalview.ws.dbsources.das.api.jalviewSourceI;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import org.biodas.jdas.client.FeaturesClient;
-import org.biodas.jdas.client.adapters.features.DasGFFAdapter;
-import org.biodas.jdas.client.adapters.features.DasGFFAdapter.GFFAdapter;
-import org.biodas.jdas.client.threads.FeaturesClientMultipleSources;
-import org.biodas.jdas.schema.features.ERRORSEGMENT;
-import org.biodas.jdas.schema.features.FEATURE;
-import org.biodas.jdas.schema.features.LINK;
-import org.biodas.jdas.schema.features.SEGMENT;
-import org.biodas.jdas.schema.features.TYPE;
-import org.biodas.jdas.schema.features.UNKNOWNFEATURE;
-import org.biodas.jdas.schema.features.UNKNOWNSEGMENT;
-import org.biodas.jdas.schema.sources.COORDINATES;
-
-/**
- * DOCUMENT ME!
- *
- * @author $author$
- * @version $Revision$
- */
-public class DasSequenceFeatureFetcher
-{
- SequenceI[] sequences;
-
- AlignFrame af;
-
- FeatureSettings fsettings;
-
- StringBuffer sbuffer = new StringBuffer();
-
- List<jalviewSourceI> selectedSources;
-
- boolean cancelled = false;
-
- private void debug(String mesg)
- {
- debug(mesg, null);
- }
-
- private void debug(String mesg, Exception e)
- {
- if (Cache.log != null)
- {
- Cache.log.debug(mesg, e);
- }
- else
- {
- System.err.println(mesg);
- if (e != null)
- {
- e.printStackTrace();
- }
- }
- }
-
- long startTime;
-
- private DasSourceRegistryI sourceRegistry;
-
- private boolean useJDASMultiThread = true;
-
- /**
- * Creates a new SequenceFeatureFetcher object. Uses default
- *
- * @param align
- * DOCUMENT ME!
- * @param ap
- * DOCUMENT ME!
- */
- public DasSequenceFeatureFetcher(SequenceI[] sequences,
- FeatureSettings fsettings, Vector selectedSources)
- {
- this(sequences, fsettings, selectedSources, true, true, true);
- }
-
- public DasSequenceFeatureFetcher(SequenceI[] oursequences,
- FeatureSettings fsettings, List<jalviewSourceI> selectedSources2,
- boolean checkDbrefs, boolean promptFetchDbrefs)
- {
- this(oursequences, fsettings, selectedSources2, checkDbrefs,
- promptFetchDbrefs, true);
- }
-
- public DasSequenceFeatureFetcher(SequenceI[] oursequences,
- FeatureSettings fsettings, List<jalviewSourceI> selectedSources2,
- boolean checkDbrefs, boolean promptFetchDbrefs,
- boolean useJDasMultiThread)
- {
- this.useJDASMultiThread = useJDasMultiThread;
- this.selectedSources = new ArrayList<>();
- // filter both sequences and sources to eliminate duplicates
- for (jalviewSourceI src : selectedSources2)
- {
- if (!selectedSources.contains(src))
- {
- selectedSources.add(src);
- }
- ;
- }
- Vector sqs = new Vector();
- for (int i = 0; i < oursequences.length; i++)
- {
- if (!sqs.contains(oursequences[i]))
- {
- sqs.addElement(oursequences[i]);
- }
- }
- sequences = new SequenceI[sqs.size()];
- for (int i = 0; i < sequences.length; i++)
- {
- sequences[i] = (SequenceI) sqs.elementAt(i);
- }
- if (fsettings != null)
- {
- this.fsettings = fsettings;
- this.af = fsettings.af;
- af.setShowSeqFeatures(true);
- }
- int uniprotCount = 0;
- for (jalviewSourceI source : selectedSources)
- {
- for (COORDINATES coords : source.getVersion().getCOORDINATES())
- {
- // TODO: match UniProt coord system canonically (?) - does
- // UniProt==uniprot==UNIPROT ?
- if (coords.getAuthority().toLowerCase().equals("uniprot"))
- {
- uniprotCount++;
- break;
- }
- }
- }
-
- int refCount = 0;
- for (int i = 0; i < sequences.length; i++)
- {
- DBRefEntry[] dbref = sequences[i].getDBRefs();
- if (dbref != null)
- {
- for (int j = 0; j < dbref.length; j++)
- {
- if (dbref[j].getSource().equals(DBRefSource.UNIPROT))
- {
- refCount++;
- break;
- }
- }
- }
- }
-
- if (checkDbrefs && refCount < sequences.length && uniprotCount > 0)
- {
-
- int reply = JvOptionPane.YES_OPTION;
- if (promptFetchDbrefs)
- {
- reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
- MessageManager.getString(
- "info.you_want_jalview_to_find_uniprot_accessions"),
- MessageManager
- .getString("label.find_uniprot_accession_ids"),
- JvOptionPane.YES_NO_OPTION, JvOptionPane.QUESTION_MESSAGE);
- }
-
- if (reply == JvOptionPane.YES_OPTION)
- {
- Thread thread = new Thread(new FetchDBRefs());
- thread.start();
- }
- else
- {
- _startFetching();
- }
- }
- else
- {
- _startFetching();
- }
-
- }
-
- private void _startFetching()
- {
- running = true;
- new Thread(new FetchSeqFeatures()).start();
- }
-
- class FetchSeqFeatures implements Runnable
- {
- @Override
- public void run()
- {
- startFetching();
- setGuiFetchComplete();
- }
- }
-
- class FetchDBRefs implements Runnable
- {
- @Override
- public void run()
- {
- running = true;
- boolean isNucleotide = af.getViewport().getAlignment().isNucleotide();
- new DBRefFetcher(sequences, af, null, af.featureSettings,
- isNucleotide).fetchDBRefs(true);
-
- startFetching();
- setGuiFetchComplete();
- }
- }
-
- /**
- * Spawns Fetcher threads to add features to sequences in the dataset
- */
- void startFetching()
- {
- running = true;
- cancelled = false;
- startTime = System.currentTimeMillis();
- if (af != null)
- {
- af.setProgressBar(MessageManager.getString(
- "status.fetching_das_sequence_features"), startTime);
- }
- if (sourceRegistry == null)
- {
- sourceRegistry = Cache.getDasSourceRegistry();
- }
- if (selectedSources == null || selectedSources.size() == 0)
- {
- try
- {
- jalviewSourceI[] sources = sourceRegistry.getSources()
- .toArray(new jalviewSourceI[0]);
- String active = Cache.getDefault("DAS_ACTIVE_SOURCE", "uniprot");
- StringTokenizer st = new StringTokenizer(active, "\t");
- selectedSources = new Vector();
- String token;
- while (st.hasMoreTokens())
- {
- token = st.nextToken();
- for (int i = 0; i < sources.length; i++)
- {
- if (sources[i].getTitle().equals(token))
- {
- selectedSources.add(sources[i]);
- break;
- }
- }
- }
- } catch (Exception ex)
- {
- debug("Exception whilst setting default feature sources from registry and local preferences.",
- ex);
- }
- }
-
- if (selectedSources == null || selectedSources.size() == 0)
- {
- System.out.println("No DAS Sources active");
- cancelled = true;
- setGuiNoDassourceActive();
- return;
- }
-
- sourcesRemaining = selectedSources.size();
- FeaturesClientMultipleSources fc = new FeaturesClientMultipleSources();
- fc.setConnProps(sourceRegistry.getSessionHandler());
- // Now sending requests one at a time to each server
- 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<>();
- List<DBRefEntry> idob = new ArrayList<>();
- List<String> qset = new ArrayList<>();
-
- for (SequenceI seq : sequences)
- {
- Object[] idset = nextSequence(_sr, seq);
- if (idset != null)
- {
- List<DBRefEntry> _idob = (List<DBRefEntry>) idset[0];
- List<String> _qset = (List<String>) idset[1];
- if (_idob.size() > 0)
- {
- // add sequence's ref for each id derived from it
- // (space inefficient, but most unambiguous)
- // could replace with hash with _qset values as keys.
- Iterator<DBRefEntry> dbobj = _idob.iterator();
- for (String q : _qset)
- {
- SequenceI osq = slist.get(q);
- DBRefEntry dr = dbobj.next();
- if (osq != null && osq != seq)
- {
- // skip - non-canonical query
- }
- else
- {
- idob.add(dr);
- qset.add(q);
- slist.put(q, seq);
- }
- }
- }
- }
- }
- if (idob.size() > 0)
- {
- srcobj.add(_sr);
- src.add(_sr.getSourceURL());
- ids.add(qset);
- idobj.add(idob);
- sqset.add(slist);
- }
- }
- 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();
- // iterate over each query for each source and do each one individually
- for (List<String> idl : ids)
- {
- String source = sources.next();
- FeaturesClient featuresc = new FeaturesClient(
- sourceRegistry.getSessionHandler()
- .getConnectionPropertyProviderFor(source));
- for (String id : idl)
- {
- List<String> qid = Arrays.asList(new String[] { id });
- try
- {
- DasGFFAdapter dga = featuresc.fetchData(source, qid);
- Map<List<String>, DasGFFAdapter> ers = results.get(source);
- if (ers == null)
- {
- results.put(source,
- ers = new HashMap<>());
- }
- ers.put(qid, dga);
- } catch (Exception ex)
- {
- Map<List<String>, Exception> ers = errors.get(source);
- if (ers == null)
- {
- errors.put(source,
- ers = new HashMap<>());
- }
- ers.put(qid, ex);
- }
- }
- }
- }
- else
- {
- // pass them all at once
- fc.fetchData(src, ids, false, results, errors);
- fc.shutDown();
- while (!fc.isTerminated())
- {
- try
- {
- Thread.sleep(200);
- } catch (InterruptedException x)
- {
-
- }
- }
- }
- Iterator<List<String>> idset = ids.iterator();
- Iterator<List<DBRefEntry>> idobjset = idobj.iterator();
- Iterator<Map<String, SequenceI>> seqset = sqset.iterator();
- for (jalviewSourceI source : srcobj)
- {
- processResponse(seqset.next(), source, idset.next(), idobjset.next(),
- results.get(source.getSourceURL()),
- errors.get(source.getSourceURL()));
- }
- }
-
- private void processResponse(Map<String, SequenceI> sequencemap,
- jalviewSourceI jvsource, List<String> ids, List<DBRefEntry> idobj,
- Map<List<String>, DasGFFAdapter> results,
- Map<List<String>, Exception> errors)
- {
- Set<SequenceI> sequences = new HashSet<>();
- String source = jvsource.getSourceURL();
- // process features
- DasGFFAdapter result = (results == null) ? null : results.get(ids);
- Exception error = (errors == null) ? null : errors.get(ids);
- if (result == null)
- {
- debug("das source " + source + " could not be contacted. "
- + (error == null ? "" : error.toString()));
- }
- else
- {
-
- GFFAdapter gff = result.getGFF();
- List<SEGMENT> segments = gff.getSegments();
- List<ERRORSEGMENT> errorsegs = gff.getErrorSegments();
- List<UNKNOWNFEATURE> unkfeats = gff.getUnknownFeatures();
- List<UNKNOWNSEGMENT> unksegs = gff.getUnknownSegments();
- debug("das source " + source + " returned " + gff.getTotal()
- + " responses. " + (errorsegs != null ? errorsegs.size() : 0)
- + " were incorrect segment queries, "
- + (unkfeats != null ? unkfeats.size() : 0)
- + " were unknown features "
- + (unksegs != null ? unksegs.size() : 0)
- + " were unknown segments and "
- + (segments != null ? segments.size() : 0)
- + " were segment responses.");
- Iterator<DBRefEntry> dbr = idobj.iterator();
- if (segments != null)
- {
- for (SEGMENT seg : segments)
- {
- String id = seg.getId();
- if (ids.indexOf(id) == -1)
- {
- id = id.toUpperCase();
- }
- DBRefEntry dbref = idobj.get(ids.indexOf(id));
- SequenceI sequence = sequencemap.get(id);
- boolean added = false;
- sequences.add(sequence);
-
- for (FEATURE feat : seg.getFEATURE())
- {
- // standard DAS feature-> jalview sequence feature transformation
- SequenceFeature f = newSequenceFeature(feat,
- jvsource.getTitle());
- if (!parseSeqFeature(sequence, f, feat, jvsource))
- {
- if (dbref.getMap() != null && f.getBegin() > 0
- && f.getEnd() > 0)
- {
- debug("mapping from " + f.getBegin() + " - " + f.getEnd());
- SequenceFeature vf[] = null;
-
- try
- {
- vf = dbref.getMap().locateFeature(f);
- } catch (Exception ex)
- {
- Cache.log.warn(
- "Error in 'experimental' mapping of features. Please try to reproduce and then report info to jalview-discuss@jalview.org.");
- Cache.log.warn("Mapping feature from " + f.getBegin()
- + " to " + f.getEnd() + " in dbref "
- + dbref.getAccessionId() + " in "
- + dbref.getSource());
- Cache.log.warn("using das Source " + source);
- Cache.log.warn("Exception", ex);
- }
-
- if (vf != null)
- {
- for (int v = 0; v < vf.length; v++)
- {
- debug("mapping to " + v + ": " + vf[v].getBegin()
- + " - " + vf[v].getEnd());
- sequence.addSequenceFeature(vf[v]);
- }
- }
- }
- else
- {
- sequence.addSequenceFeature(f);
- }
- }
- }
- }
- featuresAdded(sequences);
- }
- else
- {
- // System.out.println("No features found for " + seq.getName()
- // + " from: " + e.getDasSource().getNickname());
- }
- }
- }
-
- private void setGuiNoDassourceActive()
- {
-
- if (af != null)
- {
- af.setProgressBar(
- MessageManager.getString("status.no_das_sources_active"),
- startTime);
- }
- if (getFeatSettings() != null)
- {
- fsettings.noDasSourceActive();
- }
- }
-
- /**
- * Update our fsettings dialog reference if we didn't have one when we were
- * first initialised.
- *
- * @return fsettings
- */
- private FeatureSettings getFeatSettings()
- {
- if (fsettings == null)
- {
- if (af != null)
- {
- fsettings = af.featureSettings;
- }
- }
- return fsettings;
- }
-
- public void cancel()
- {
- if (af != null)
- {
- af.setProgressBar(MessageManager.getString(
- "status.das_feature_fetching_cancelled"), startTime);
- }
- cancelled = true;
- }
-
- int sourcesRemaining = 0;
-
- private boolean running = false;
-
- private void setGuiFetchComplete()
- {
- running = false;
- if (!cancelled && af != null)
- {
- // only update the progress bar if we've completed the fetch normally
- af.setProgressBar(MessageManager.getString(
- "status.das_feature_fetching_complete"), startTime);
- }
-
- if (af != null && af.featureSettings != null)
- {
- af.featureSettings.discoverAllFeatureData();
- }
-
- if (getFeatSettings() != null)
- {
- fsettings.complete();
- }
- }
-
- void featuresAdded(Set<SequenceI> seqs)
- {
- if (af == null)
- {
- // no gui to update with features.
- return;
- }
- af.getFeatureRenderer().featuresAdded();
-
- int start = af.getViewport().getRanges().getStartSeq();
- int end = af.getViewport().getRanges().getEndSeq();
- int index;
- for (index = start; index < end; index++)
- {
- for (SequenceI seq : seqs)
- {
- if (seq == af.getViewport().getAlignment().getSequenceAt(index)
- .getDatasetSequence())
- {
- af.alignPanel.paintAlignment(true, true);
- index = end;
- break;
- }
- }
- }
- }
-
- Object[] nextSequence(jalviewSourceI dasSource, SequenceI seq)
- {
- if (cancelled)
- {
- return null;
- }
- DBRefEntry[] uprefs = DBRefUtils.selectRefs(seq.getDBRefs(),
- new String[]
- {
- // jalview.datamodel.DBRefSource.PDB,
- DBRefSource.UNIPROT,
- // jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord
- // sys sources
- });
- // TODO: minimal list of DAS queries to make by querying with untyped ID if
- // distinct from any typed IDs
-
- List<DBRefEntry> ids = new ArrayList<>();
- List<String> qstring = new ArrayList<>();
- boolean dasCoordSysFound = false;
-
- if (uprefs != null)
- {
- // do any of these ids match the source's coordinate system ?
- for (int j = 0; !dasCoordSysFound && j < uprefs.length; j++)
- {
-
- for (COORDINATES csys : dasSource.getVersion().getCOORDINATES())
- {
- if (DBRefUtils.isDasCoordinateSystem(csys.getAuthority(),
- uprefs[j]))
- {
- debug("Launched fetcher for coordinate system "
- + csys.getAuthority());
- // Will have to pass any mapping information to the fetcher
- // - the start/end for the DBRefEntry may not be the same as the
- // sequence's start/end
-
- System.out.println(
- seq.getName() + " " + (seq.getDatasetSequence() == null)
- + " " + csys.getUri());
-
- dasCoordSysFound = true; // break's out of the loop
- ids.add(uprefs[j]);
- qstring.add(uprefs[j].getAccessionId());
- }
- else
- {
- System.out.println("IGNORE " + csys.getAuthority());
- }
- }
- }
- }
-
- if (!dasCoordSysFound)
- {
- String id = null;
- // try and use the name as the sequence id
- if (seq.getName().indexOf("|") > -1)
- {
- id = seq.getName().substring(seq.getName().lastIndexOf("|") + 1);
- if (id.trim().length() < 4)
- {
- // hack - we regard a significant ID as being at least 4
- // non-whitespace characters
- id = seq.getName().substring(0, seq.getName().lastIndexOf("|"));
- if (id.indexOf("|") > -1)
- {
- id = id.substring(id.lastIndexOf("|") + 1);
- }
- }
- }
- else
- {
- id = seq.getName();
- }
- if (id != null)
- {
- DBRefEntry dbre = new DBRefEntry();
- dbre.setAccessionId(id);
- // Should try to call a general feature fetcher that
- // queries many sources with name to discover applicable ID references
- ids.add(dbre);
- qstring.add(dbre.getAccessionId());
- }
- }
-
- return new Object[] { ids, qstring };
- }
-
- /**
- * examine the given sequence feature to determine if it should actually be
- * turned into sequence annotation or database cross references rather than a
- * simple sequence feature.
- *
- * @param seq
- * the sequence to annotate
- * @param f
- * the jalview sequence feature generated from the DAS feature
- * @param map
- * the sequence feature attributes
- * @param source
- * the source that emitted the feature
- * @return true if feature was consumed as another kind of annotation.
- */
- protected boolean parseSeqFeature(SequenceI seq, SequenceFeature f,
- FEATURE feature, jalviewSourceI source)
- {
- SequenceI mseq = seq;
- while (seq.getDatasetSequence() != null)
- {
- seq = seq.getDatasetSequence();
- }
- if (f.getType() != null)
- {
- String type = f.getType();
- if (type.equalsIgnoreCase("protein_name"))
- {
- // parse name onto the alignment sequence or the dataset sequence.
- if (seq.getDescription() == null
- || seq.getDescription().trim().length() == 0)
- {
- // could look at the note series to pick out the first long name, for
- // the moment just use the whole description string
- seq.setDescription(f.getDescription());
- }
- if (mseq.getDescription() == null
- || mseq.getDescription().trim().length() == 0)
- {
- // could look at the note series to pick out the first long name, for
- // the moment just use the whole description string
- mseq.setDescription(f.getDescription());
- }
- return true;
- }
- // check if source has biosapiens or other sequence ontology label
- if (type.equalsIgnoreCase("DBXREF") || type.equalsIgnoreCase("DBREF"))
- {
- // try to parse the accession out
-
- DBRefEntry dbr = new DBRefEntry();
- dbr.setVersion(source.getTitle());
- StringTokenizer st = new StringTokenizer(f.getDescription(), ":");
- if (st.hasMoreTokens())
- {
- dbr.setSource(st.nextToken());
- }
- if (st.hasMoreTokens())
- {
- dbr.setAccessionId(st.nextToken());
- }
- seq.addDBRef(dbr);
-
- if (f.links != null && f.links.size() > 0)
- {
- // feature is also appended to enable links to be seen.
- // TODO: consider extending dbrefs to have their own links ?
- // TODO: new feature: extract dbref links from DAS servers and add the
- // URL pattern to the list of DB name associated links in the user's
- // preferences ?
- // for the moment - just fix up the existing feature so it displays
- // correctly.
- // f.setType(dbr.getSource());
- // f.setDescription();
- f.setValue("linkonly", Boolean.TRUE);
- // f.setDescription("");
- Vector newlinks = new Vector();
- Enumeration it = f.links.elements();
- while (it.hasMoreElements())
- {
- String elm;
- UrlLink urllink = new UrlLink(elm = (String) it.nextElement());
- if (urllink.isValid())
- {
- urllink.setLabel(f.getDescription());
- newlinks.addElement(urllink.toString());
- }
- else
- {
- // couldn't parse the link properly. Keep it anyway - just in
- // case.
- debug("couldn't parse link string - " + elm);
- newlinks.addElement(elm);
- }
- }
- f.links = newlinks;
- seq.addSequenceFeature(f);
- }
- return true;
- }
- }
- return false;
- }
-
- /**
- * creates a jalview sequence feature from a das feature document
- *
- * @param feat
- * @return sequence feature object created using dasfeature information
- */
- SequenceFeature newSequenceFeature(FEATURE feat, String nickname)
- {
- if (feat == null)
- {
- return null;
- }
- try
- {
- /**
- * Different qNames for a DAS Feature - are string keys to the HashMaps in
- * features "METHOD") || qName.equals("TYPE") || qName.equals("START") ||
- * qName.equals("END") || qName.equals("NOTE") || qName.equals("LINK") ||
- * qName.equals("SCORE")
- */
- String desc = new String();
- if (feat.getNOTE() != null)
- {
- for (String note : feat.getNOTE())
- {
- desc += note;
- }
- }
-
- int start = 0, end = 0;
- float score = 0f;
-
- try
- {
- start = Integer.parseInt(feat.getSTART().toString());
- } catch (Exception ex)
- {
- }
- try
- {
- end = Integer.parseInt(feat.getEND().toString());
- } catch (Exception ex)
- {
- }
- try
- {
- Object scr = feat.getSCORE();
- if (scr != null)
- {
- score = (float) Double.parseDouble(scr.toString());
-
- }
- } catch (Exception ex)
- {
- }
-
- SequenceFeature f = new SequenceFeature(getTypeString(feat.getTYPE()),
- desc, start, end, score, nickname);
-
- if (feat.getLINK() != null)
- {
- for (LINK link : feat.getLINK())
- {
- // Do not put feature extent in link text for non-positional features
- if (f.begin == 0 && f.end == 0)
- {
- f.addLink(f.getType() + " " + link.getContent() + "|"
- + link.getHref());
- }
- else
- {
- f.addLink(f.getType() + " " + f.begin + "_" + f.end + " "
- + link.getContent() + "|" + link.getHref());
- }
- }
- }
-
- return f;
- } catch (Exception e)
- {
- System.out.println("ERRR " + e);
- e.printStackTrace();
- System.out.println("############");
- debug("Failed to parse " + feat.toString(), e);
- return null;
- }
- }
-
- private String getTypeString(TYPE type)
- {
- return type.getContent();
- }
-
- public boolean isRunning()
- {
- return running;
- }
-
-}
import jalview.ws.dbsources.PfamSeed;
import jalview.ws.dbsources.RfamSeed;
import jalview.ws.dbsources.Uniprot;
-import jalview.ws.dbsources.das.api.jalviewSourceI;
import jalview.ws.seqfetcher.ASequenceFetcher;
import jalview.ws.seqfetcher.DbSourceProxy;
import java.util.ArrayList;
-import java.util.List;
/**
* This implements the run-time discovery of sequence database clients.
*/
public SequenceFetcher()
{
- this(true);
- }
-
- public SequenceFetcher(boolean addDas)
- {
addDBRefSourceImpl(EnsemblGene.class);
addDBRefSourceImpl(EnsemblGenomes.class);
addDBRefSourceImpl(EmblSource.class);
addDBRefSourceImpl(PfamFull.class);
addDBRefSourceImpl(PfamSeed.class);
addDBRefSourceImpl(RfamSeed.class);
-
- if (addDas)
- {
- registerDasSequenceSources();
- }
}
/**
- * return an ordered list of database sources where non-das database classes
- * appear before das database classes
+ * return an ordered list of database sources excluding alignment only databases
*/
public String[] getOrderedSupportedSources()
{
String[] srcs = this.getSupportedDb();
- ArrayList<String> dassrc = new ArrayList<String>(),
- nondas = new ArrayList<String>();
+ ArrayList<String> src = new ArrayList<>();
+
for (int i = 0; i < srcs.length; i++)
{
- boolean das = false, skip = false;
- String nm;
+ boolean skip = false;
for (DbSourceProxy dbs : getSourceProxy(srcs[i]))
{
// Skip the alignment databases for the moment - they're not useful for
{
skip = true;
}
- else
- {
- nm = dbs.getDbName();
- if (getSourceProxy(
- srcs[i]) instanceof jalview.ws.dbsources.das.datamodel.DasSequenceSource)
- {
- if (nm.startsWith("das:"))
- {
- nm = nm.substring(4);
- das = true;
- }
- break;
- }
- }
}
if (skip)
{
continue;
}
- if (das)
{
- dassrc.add(srcs[i]);
- }
- else
- {
- nondas.add(srcs[i]);
+ src.add(srcs[i]);
}
}
- String[] tosort = nondas.toArray(new String[0]),
- sorted = nondas.toArray(new String[0]);
+ String[] tosort = src.toArray(new String[0]),
+ sorted = src.toArray(new String[0]);
for (int j = 0, jSize = sorted.length; j < jSize; j++)
{
tosort[j] = tosort[j].toLowerCase();
}
jalview.util.QuickSort.sort(tosort, sorted);
// construct array with all sources listed
-
- srcs = new String[sorted.length + dassrc.size()];
int i = 0;
for (int j = sorted.length - 1; j >= 0; j--, i++)
{
srcs[i] = sorted[j];
- sorted[j] = null;
- }
-
- sorted = dassrc.toArray(new String[0]);
- tosort = dassrc.toArray(new String[0]);
- for (int j = 0, jSize = sorted.length; j < jSize; j++)
- {
- tosort[j] = tosort[j].toLowerCase();
- }
- jalview.util.QuickSort.sort(tosort, sorted);
- for (int j = sorted.length - 1; j >= 0; j--, i++)
- {
- srcs[i] = sorted[j];
}
return srcs;
}
-
- /**
- * query the currently defined DAS source registry for sequence sources and
- * add a DasSequenceSource instance for each source to the SequenceFetcher
- * source list.
- */
- public void registerDasSequenceSources()
- {
- // TODO: define a context as a registry provider (either desktop,
- // jalview.bin.cache, or something else).
- for (jalviewSourceI source : jalview.bin.Cache.getDasSourceRegistry()
- .getSources())
- {
- if (source.isSequenceSource())
- {
- List<DbSourceProxy> dassources = source.getSequenceSourceProxies();
- for (DbSourceProxy seqsrc : dassources)
- {
- addDbRefSourceImpl(seqsrc);
- }
- }
- }
- }
-
}
*/
package jalview.ws.dbsources;
+import jalview.bin.Cache;
import jalview.datamodel.DBRefSource;
import com.stevesoft.pat.Regex;
*/
abstract public class Pfam extends Xfam
{
+ static final String PFAM_BASEURL_KEY = "PFAM_BASEURL";
+
+ private static final String DEFAULT_PFAM_BASEURL = "https://pfam.xfam.org";
public Pfam()
{
@Override
public String getAccessionSeparator()
{
- // TODO Auto-generated method stub
return null;
}
@Override
public Regex getAccessionValidator()
{
- // TODO Auto-generated method stub
return null;
}
@Override
public String getDbVersion()
{
- // TODO Auto-generated method stub
return null;
}
- /**
- * Returns base URL for selected Pfam alignment type
- *
- * @return PFAM URL stub for this DbSource
- */
@Override
- protected abstract String getXFAMURL();
+ protected String getURLPrefix()
+ {
+ return Cache.getDefault(PFAM_BASEURL_KEY, DEFAULT_PFAM_BASEURL);
+ }
/*
* (non-Javadoc)
super();
}
- /*
- * (non-Javadoc)
- *
- * @see jalview.ws.dbsources.Pfam#getPFAMURL()
- */
- @Override
- protected String getXFAMURL()
- {
- return "http://pfam.xfam.org/family/";
-
- }
-
@Override
- public String getXFAMURLSUFFIX()
+ public String getURLSuffix()
{
return "/alignment/full";
}
super();
}
- /*
- * (non-Javadoc)
- *
- * @see jalview.ws.dbsources.Pfam#getPFAMURL()
- */
- @Override
- protected String getXFAMURL()
- {
- return "http://pfam.xfam.org/family/";
- }
-
@Override
- public String getXFAMURLSUFFIX()
+ public String getURLSuffix()
{
return "/alignment/seed";
}
*/
package jalview.ws.dbsources;
+import jalview.bin.Cache;
import jalview.datamodel.DBRefSource;
import com.stevesoft.pat.Regex;
*/
abstract public class Rfam extends Xfam
{
+ static final String RFAM_BASEURL_KEY = "RFAM_BASEURL";
+
+ private static final String DEFAULT_RFAM_BASEURL = "https://rfam.xfam.org";
+
+ @Override
+ protected String getURLPrefix()
+ {
+ return Cache.getDefault(RFAM_BASEURL_KEY, DEFAULT_RFAM_BASEURL);
+ }
public Rfam()
{
@Override
public String getAccessionSeparator()
{
- // TODO Auto-generated method stub
return null;
}
@Override
public Regex getAccessionValidator()
{
- // TODO Auto-generated method stub
return null;
}
@Override
public String getDbVersion()
{
- // TODO Auto-generated method stub
return null;
}
- /**
- * Returns base URL for selected Rfam alignment type
- *
- * @return RFAM URL stub for this DbSource
- */
- @Override
- protected abstract String getXFAMURL();
-
/*
* (non-Javadoc)
*
super();
}
- /*
- * (non-Javadoc)
- *
- * @see jalview.ws.dbsources.Rfam#getXFAMURL()
- */
- @Override
- protected String getXFAMURL()
- {
- return "http://rfam.xfam.org/family/";
-
- }
-
@Override
- public String getXFAMURLSUFFIX()
+ public String getURLSuffix()
{
return "/alignment/full";
}
super();
}
- /*
- * (non-Javadoc)
- *
- * @see jalview.ws.dbsources.Rfam#getRFAMURL()
- */
- @Override
- protected String getXFAMURL()
- {
- return "http://rfam.xfam.org/family/";
- }
-
@Override
- public String getXFAMURLSUFFIX()
+ public String getURLSuffix()
{
// to download gzipped file add '?gzip=1'
return "/alignment/stockholm";
*/
package jalview.ws.dbsources;
+import jalview.bin.Cache;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.xdb.uniprot.UniprotEntry;
import jalview.datamodel.xdb.uniprot.UniprotFeature;
import jalview.datamodel.xdb.uniprot.UniprotFile;
+import jalview.schemes.ResidueProperties;
+import jalview.util.StringUtils;
import jalview.ws.seqfetcher.DbSourceProxyImpl;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
+import java.util.List;
import java.util.Vector;
import org.exolab.castor.mapping.Mapping;
*/
public class Uniprot extends DbSourceProxyImpl
{
+ private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org";
+
private static final String BAR_DELIMITER = "|";
/*
super();
}
+ private String getDomain()
+ {
+ return Cache.getDefault("UNIPROT_DOMAIN", DEFAULT_UNIPROT_DOMAIN);
+ }
+
/*
* (non-Javadoc)
*
"(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
AlignmentI al = null;
- String downloadstring = "http://www.uniprot.org/uniprot/" + queries
+ String downloadstring = getDomain() + "/uniprot/" + queries
+ ".xml";
URL url = null;
URLConnection urlconn = null;
for (UniprotFeature uf : entry.getFeature())
{
SequenceFeature copy = new SequenceFeature(uf.getType(),
- uf.getDescription(), uf.getBegin(), uf.getEnd(), "Uniprot");
+ getDescription(uf), uf.getBegin(), uf.getEnd(), "Uniprot");
copy.setStatus(uf.getStatus());
sequence.addSequenceFeature(copy);
}
}
/**
+ * Constructs a feature description from the description and (optionally)
+ * original and variant fields of the Uniprot XML feature
+ *
+ * @param uf
+ * @return
+ */
+ protected static String getDescription(UniprotFeature uf)
+ {
+ String orig = uf.getOriginal();
+ List<String> variants = uf.getVariation();
+ StringBuilder sb = new StringBuilder();
+
+ /*
+ * append variant in standard format if present
+ * e.g. p.Arg59Lys
+ * multiple variants are split over lines using <br>
+ */
+ boolean asHtml = false;
+ if (orig != null && !orig.isEmpty() && variants != null
+ && !variants.isEmpty())
+ {
+ int p = 0;
+ for (String var : variants)
+ {
+ // TODO proper HGVS nomenclature for delins structural variations
+ // http://varnomen.hgvs.org/recommendations/protein/variant/delins/
+ // for now we are pragmatic - any orig/variant sequence longer than
+ // three characters is shown with single-character notation rather than
+ // three-letter notation
+ sb.append("p.");
+ if (orig.length() < 4)
+ {
+ for (int c = 0, clen = orig.length(); c < clen; c++)
+ {
+ char origchar = orig.charAt(c);
+ String orig3 = ResidueProperties.aa2Triplet.get("" + origchar);
+ sb.append(orig3 == null ? origchar
+ : StringUtils.toSentenceCase(orig3));
+ }
+ }
+ else
+ {
+ sb.append(orig);
+ }
+
+ sb.append(Integer.toString(uf.getPosition()));
+
+ if (var.length() < 4)
+ {
+ for (int c = 0, clen = var.length(); c < clen; c++)
+ {
+ char varchar = var.charAt(c);
+ String var3 = ResidueProperties.aa2Triplet.get("" + varchar);
+
+ sb.append(var3 != null ? StringUtils.toSentenceCase(var3)
+ : "" + varchar);
+ }
+ }
+ else
+ {
+ sb.append(var);
+ }
+ if (++p != variants.size())
+ {
+ sb.append("<br/> ");
+ asHtml = true;
+ }
+ else
+ {
+ sb.append(" ");
+ }
+ }
+ }
+ String description = uf.getDescription();
+ if (description != null)
+ {
+ sb.append(description);
+ }
+ if (asHtml)
+ {
+ sb.insert(0, "<html>");
+ sb.append("</html>");
+ }
+
+ return sb.toString();
+ }
+
+ /**
*
* @param entry
* UniportEntry
super();
}
- protected abstract String getXFAMURL();
+ /**
+ * the base URL for this Xfam-like service
+ *
+ * @return
+ */
+ protected abstract String getURLPrefix();
@Override
public abstract String getDbVersion();
// retrieved.
startQuery();
// TODO: trap HTTP 404 exceptions and return null
- String xfamUrl = getXFAMURL() + queries.trim().toUpperCase()
- + getXFAMURLSUFFIX();
+ String xfamUrl = getURL(queries);
if (Cache.log != null)
{
return rcds;
}
+ String getURL(String queries)
+ {
+ return getURLPrefix() + "/family/" + queries.trim().toUpperCase()
+ + getURLSuffix();
+ }
+
/**
* Pfam and Rfam provide alignments
*/
*
* @return "" for most Xfam sources
*/
- public String getXFAMURLSUFFIX()
+ public String getURLSuffix()
{
return "";
}
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ws.dbsources.das.api;
-
-import java.util.List;
-
-import org.biodas.jdas.client.threads.MultipleConnectionPropertyProviderI;
-
-/**
- * API for a registry that provides datasources that jalview can access
- *
- * @author jprocter
- *
- */
-public interface DasSourceRegistryI
-{
-
- List<jalviewSourceI> getSources();
-
- String getDasRegistryURL();
-
- jalviewSourceI getSource(String nickname);
-
- // TODO: re JAL-424 - introduce form where local source is queried for
- // metadata, rather than have it all provided by caller.
- jalviewSourceI createLocalSource(String uri, String name,
- boolean sequence, boolean features);
-
- boolean removeLocalSource(jalviewSourceI source);
-
- void refreshSources();
-
- String getLocalSourceString();
-
- List<jalviewSourceI> resolveSourceNicknames(List<String> sources);
-
- // TODO: refactor to jDAS specific interface
- MultipleConnectionPropertyProviderI getSessionHandler();
-}
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ws.dbsources.das.api;
-
-import jalview.ws.seqfetcher.DbSourceProxy;
-
-import java.util.List;
-
-import org.biodas.jdas.schema.sources.MAINTAINER;
-import org.biodas.jdas.schema.sources.VERSION;
-
-public interface jalviewSourceI
-{
-
- String getTitle();
-
- VERSION getVersion();
-
- String getDocHref();
-
- String getDescription();
-
- String getUri();
-
- MAINTAINER getMAINTAINER();
-
- String getEmail();
-
- boolean isLocal();
-
- boolean isSequenceSource();
-
- String[] getCapabilityList(VERSION v);
-
- String[] getLabelsFor(VERSION v);
-
- /**
- *
- * @return null if not a sequence source, otherwise a series of database
- * sources that can be used to retrieve sequence data for particular
- * database coordinate systems
- */
- List<DbSourceProxy> getSequenceSourceProxies();
-
- boolean isFeatureSource();
-
- /**
- * returns the base URL for the latest version of a source's DAS endpoint set
- *
- * @return
- */
- String getSourceURL();
-
- /**
- * test to see if this source's latest version is older than the given source
- *
- * @param jalviewSourceI
- * @return true if newer than given source
- */
- boolean isNewerThan(jalviewSourceI jalviewSourceI);
-
- /**
- * test if the source is a reference source for the authority
- *
- * @return
- */
- boolean isReferenceSource();
-
-}
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ws.dbsources.das.datamodel;
-
-import jalview.bin.Cache;
-import jalview.datamodel.Alignment;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.Sequence;
-import jalview.datamodel.SequenceI;
-import jalview.util.MessageManager;
-import jalview.ws.dbsources.das.api.jalviewSourceI;
-import jalview.ws.seqfetcher.DbSourceProxy;
-import jalview.ws.seqfetcher.DbSourceProxyImpl;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import org.biodas.jdas.client.SequenceClient;
-import org.biodas.jdas.client.adapters.sequence.DasSequenceAdapter;
-import org.biodas.jdas.client.threads.MultipleConnectionPropertyProviderI;
-import org.biodas.jdas.client.threads.SequenceClientMultipleSources;
-import org.biodas.jdas.schema.sequence.SEQUENCE;
-import org.biodas.jdas.schema.sources.COORDINATES;
-import org.biodas.jdas.schema.sources.SOURCE;
-import org.biodas.jdas.schema.sources.VERSION;
-
-import com.stevesoft.pat.Regex;
-
-/**
- * an instance of this class is created for each unique DAS Sequence source (ie
- * one capable of handling the 'sequence' for a particular MapMaster)
- *
- * @author JimP
- *
- */
-public class DasSequenceSource extends DbSourceProxyImpl
- implements DbSourceProxy
-{
- private jalviewSourceI jsrc;
-
- protected SOURCE source = null;
-
- protected VERSION version = null;
-
- protected COORDINATES coordsys = null;
-
- protected String dbname = "DASCS";
-
- protected String dbrefname = "das:source";
-
- protected MultipleConnectionPropertyProviderI connprops = null;
-
- /**
- * DAS sources are tier 1 - if we have a direct DB connection then we should
- * prefer it
- */
- private int tier = 1;
-
- /**
- * create a new DbSource proxy for a DAS 1 source
- *
- * @param dbnbame
- * Human Readable Name to use when fetching from this source
- * @param dbrefname
- * DbRefName for DbRefs attached to sequences retrieved from this
- * source
- * @param source
- * Das1Source
- * @param coordsys
- * specific coordinate system to use for this source
- * @throws Exception
- * if source is not capable of the 'sequence' command
- */
- public DasSequenceSource(String dbname, String dbrefname, SOURCE source,
- VERSION version, COORDINATES coordsys,
- MultipleConnectionPropertyProviderI connprops) throws Exception
- {
- if (!(jsrc = new JalviewSource(source, connprops, false))
- .isSequenceSource())
- {
- throw new Exception(MessageManager.formatMessage(
- "exception.das_source_doesnt_support_sequence_command",
- new String[]
- { source.getTitle() }));
- }
- this.tier = 1 + ((jsrc.isLocal() || jsrc.isReferenceSource()) ? 0 : 1);
- this.source = source;
- this.dbname = dbname;
- this.dbrefname = dbrefname.toUpperCase();
- if (coordsys != null)
- {
- this.coordsys = coordsys;
- }
- this.connprops = connprops;
- }
-
- public String getAccessionSeparator()
- {
- return "\t";
- }
-
- public Regex getAccessionValidator()
- {
- /** ? * */
- return Regex.perlCode("m/([^:]+)(:\\d+,\\d+)?/");
- }
-
- public String getDbName()
- {
- // TODO: map to
- return dbname + " (DAS)";
- }
-
- public String getDbSource()
- {
- return dbrefname;
- }
-
- public String getDbVersion()
- {
- return coordsys != null ? coordsys.getVersion() : "";
- }
-
- public AlignmentI getSequenceRecords(String queries) throws Exception
- {
- StringTokenizer st = new StringTokenizer(queries, "\t");
- List<String> toks = new ArrayList<String>(),
- src = new ArrayList<String>(), acIds = new ArrayList<String>();
- while (st.hasMoreTokens())
- {
- String t;
- toks.add(t = st.nextToken());
- acIds.add(t.replaceAll(":[0-9,]+", ""));
- }
- src.add(jsrc.getSourceURL());
- Map<String, Map<List<String>, DasSequenceAdapter>> resultset = new HashMap<String, Map<List<String>, DasSequenceAdapter>>();
- Map<String, Map<List<String>, Exception>> errors = new HashMap<String, Map<List<String>, Exception>>();
-
- // First try multiple sources
- boolean multiple = true, retry = false;
- do
- {
- if (!multiple)
- {
- retry = false;
- // slow, fetch one at a time.
- for (String sr : src)
- {
- System.err.println(
- "Retrieving IDs individually from das source: " + sr);
- org.biodas.jdas.client.SequenceClient sq = new SequenceClient(
- connprops.getConnectionPropertyProviderFor(sr));
- for (String q : toks)
- {
- List<String> qset = Arrays.asList(new String[] { q });
- try
- {
- DasSequenceAdapter s = sq.fetchData(sr, qset);
- Map<List<String>, DasSequenceAdapter> dss = resultset.get(sr);
- if (dss == null)
- {
- resultset.put(sr,
- dss = new HashMap<List<String>, DasSequenceAdapter>());
- }
- dss.put(qset, s);
- } catch (Exception x)
- {
- Map<List<String>, Exception> ers = errors.get(sr);
- if (ers == null)
- {
- errors.put(sr,
- ers = new HashMap<List<String>, Exception>());
- }
- ers.put(qset, x);
- }
- }
- }
- }
- else
- {
- SequenceClientMultipleSources sclient;
- sclient = new SequenceClientMultipleSources();
- sclient.fetchData(src, toks, resultset, errors);
- sclient.shutDown();
- while (!sclient.isTerminated())
- {
- try
- {
- Thread.sleep(200);
-
- } catch (InterruptedException x)
- {
- }
- }
- if (resultset.isEmpty() && !errors.isEmpty())
- {
- retry = true;
- multiple = false;
- }
- }
- } while (retry);
-
- if (resultset.isEmpty())
- {
- System.err.println("Sequence Query to " + jsrc.getTitle() + " with '"
- + queries + "' returned no sequences.");
- return null;
- }
- else
- {
- Vector<SequenceI> seqs = null;
- for (Map.Entry<String, Map<List<String>, DasSequenceAdapter>> resset : resultset
- .entrySet())
- {
- for (Map.Entry<List<String>, DasSequenceAdapter> result : resset
- .getValue().entrySet())
- {
- DasSequenceAdapter dasseqresp = result.getValue();
- List<String> accessions = result.getKey();
- for (SEQUENCE e : dasseqresp.getSequence())
- {
- String lbl = e.getId();
-
- if (acIds.indexOf(lbl) == -1)
- {
- System.err.println(
- "Warning - received sequence event for strange accession code ("
- + lbl + ")");
- }
- else
- {
- if (seqs == null)
- {
- if (e.getContent().length() == 0)
- {
- System.err.println(
- "Empty sequence returned for accession code ("
- + lbl + ") from " + resset.getKey()
- + " (source is " + getDbName());
- continue;
- }
- }
- seqs = new java.util.Vector<SequenceI>();
- // JDAS returns a sequence complete with any newlines and spaces
- // in the XML
- Sequence sq = new Sequence(lbl,
- e.getContent().replaceAll("\\s+", ""));
- sq.setStart(e.getStart().intValue());
- sq.addDBRef(new DBRefEntry(getDbSource(),
- getDbVersion() + ":" + e.getVersion(), lbl));
- seqs.addElement(sq);
- }
- }
- }
- }
-
- if (seqs == null || seqs.size() == 0)
- return null;
- SequenceI[] sqs = new SequenceI[seqs.size()];
- for (int i = 0, iSize = seqs.size(); i < iSize; i++)
- {
- sqs[i] = (SequenceI) seqs.elementAt(i);
- }
- Alignment al = new Alignment(sqs);
- if (jsrc.isFeatureSource())
- {
- java.util.Vector<jalviewSourceI> srcs = new java.util.Vector<jalviewSourceI>();
- srcs.addElement(jsrc);
- try
- {
- jalview.ws.DasSequenceFeatureFetcher dssf = new jalview.ws.DasSequenceFeatureFetcher(
- sqs, null, srcs, false, false, multiple);
- while (dssf.isRunning())
- {
- try
- {
- Thread.sleep(200);
- } catch (InterruptedException x)
- {
-
- }
- }
-
- } catch (Exception x)
- {
- Cache.log.error(
- "Couldn't retrieve features for sequence from its source.",
- x);
- }
- }
-
- return al;
- }
- }
-
- public String getTestQuery()
- {
- return coordsys == null ? "" : coordsys.getTestRange();
- }
-
- public boolean isValidReference(String accession)
- {
- // TODO try to validate an accession against source
- // We don't really know how to do this without querying source
-
- return true;
- }
-
- /**
- * @return the source
- */
- public SOURCE getSource()
- {
- return source;
- }
-
- /**
- * @return the coordsys
- */
- public COORDINATES getCoordsys()
- {
- return coordsys;
- }
-
- @Override
- public int getTier()
- {
- return tier;
- }
-}
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ws.dbsources.das.datamodel;
-
-import jalview.bin.Cache;
-import jalview.ws.dbsources.das.api.DasSourceRegistryI;
-import jalview.ws.dbsources.das.api.jalviewSourceI;
-
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.StringTokenizer;
-
-import org.biodas.jdas.client.ConnectionPropertyProviderI;
-import org.biodas.jdas.client.SourcesClient;
-import org.biodas.jdas.client.threads.MultipleConnectionPropertyProviderI;
-import org.biodas.jdas.dassources.Capabilities;
-import org.biodas.jdas.schema.sources.CAPABILITY;
-import org.biodas.jdas.schema.sources.SOURCE;
-import org.biodas.jdas.schema.sources.SOURCES;
-import org.biodas.jdas.schema.sources.VERSION;
-
-/**
- *
- */
-public class DasSourceRegistry
- implements DasSourceRegistryI, MultipleConnectionPropertyProviderI
-{
- // private org.biodas.jdas.schema.sources.SOURCE[] dasSources = null;
- private List<jalviewSourceI> dasSources = null;
-
- private Hashtable<String, jalviewSourceI> sourceNames = null;
-
- private Hashtable<String, jalviewSourceI> localSources = null;
-
- // public static String DEFAULT_REGISTRY = "http://www.dasregistry.org/das/";
- public static String DEFAULT_REGISTRY = "http://www.ebi.ac.uk/das-srv/registry/das/";
-
- /**
- * true if thread is running and we are talking to DAS registry service
- */
- private boolean loadingDasSources = false;
-
- public boolean isLoadingDasSources()
- {
- return loadingDasSources;
- }
-
- @Override
- public String getDasRegistryURL()
- {
- String registry = jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",
- DEFAULT_REGISTRY);
-
- if (registry.indexOf("/registry/das1/sources/") > -1)
- {
- jalview.bin.Cache.setProperty(jalview.bin.Cache.DAS_REGISTRY_URL,
- DEFAULT_REGISTRY);
- registry = DEFAULT_REGISTRY;
- }
- if (registry.lastIndexOf("sources.xml") == registry.length() - 11)
- {
- // no trailing sources.xml document for registry in JDAS
- jalview.bin.Cache.setProperty(jalview.bin.Cache.DAS_REGISTRY_URL,
- registry = registry.substring(0,
- registry.lastIndexOf("sources.xml")));
- }
- return registry;
- }
-
- /**
- * query the default DAS Source Registry for sources. Uses value of jalview
- * property DAS_REGISTRY_URL and the DasSourceBrowser.DEFAULT_REGISTRY if that
- * doesn't exist.
- *
- * @return list of sources
- */
- private List<jalviewSourceI> getDASSources()
- {
-
- return getDASSources(getDasRegistryURL(), this);
- }
-
- /**
- * query the given URL for DasSources.
- *
- * @param registryURL
- * return sources from registryURL
- */
- private static List<jalviewSourceI> getDASSources(String registryURL,
- MultipleConnectionPropertyProviderI registry)
- {
- try
- {
- URL url = new URL(registryURL);
- org.biodas.jdas.client.SourcesClientInterface client = new SourcesClient();
-
- SOURCES sources = client.fetchDataRegistry(registryURL, null, null,
- null, null, null, null);
-
- List<SOURCE> dassources = sources.getSOURCE();
- ArrayList<jalviewSourceI> dsrc = new ArrayList<jalviewSourceI>();
- HashMap<String, Integer> latests = new HashMap<String, Integer>();
- Integer latest;
- for (SOURCE src : dassources)
- {
- JalviewSource jsrc = new JalviewSource(src, registry, false);
- latest = latests.get(jsrc.getSourceURL());
- if (latest != null)
- {
- if (jsrc.isNewerThan(dsrc.get(latest.intValue())))
- {
- dsrc.set(latest.intValue(), jsrc);
- }
- else
- {
- System.out.println(
- "Debug: Ignored older source " + jsrc.getTitle());
- }
- }
- else
- {
- latests.put(jsrc.getSourceURL(), Integer.valueOf(dsrc.size()));
- dsrc.add(jsrc);
- }
- }
- return dsrc;
- } catch (Exception ex)
- {
- System.out.println(
- "DAS1 registry at " + registryURL + " no longer exists");
- return new ArrayList<jalviewSourceI>();
- }
- }
-
- public void run()
- {
- getSources();
- }
-
- @Override
- public List<jalviewSourceI> getSources()
- {
- if (dasSources == null)
- {
- dasSources = getDASSources();
- }
- return appendLocalSources();
- }
-
- /**
- * generate Sources from the local das source list
- *
- */
- private void addLocalDasSources()
- {
- if (localSources == null)
- {
- // get local sources from properties and initialise the local source list
- String local = jalview.bin.Cache.getProperty("DAS_LOCAL_SOURCE");
-
- if (local != null)
- {
- int n = 1;
- StringTokenizer st = new StringTokenizer(local, "\t");
- while (st.hasMoreTokens())
- {
- String token = st.nextToken();
- int bar = token.indexOf("|");
- if (bar == -1)
- {
- System.err.println(
- "Warning: DAS user local source appears to have no nickname (expected a '|' followed by nickname)\nOffending definition: '"
- + token + "'");
- }
- String url = token.substring(bar + 1);
- boolean features = true, sequence = false;
- if (url.startsWith("sequence:"))
- {
- url = url.substring(9);
- // this source also serves sequences as well as features
- sequence = true;
- }
- try
- {
- if (bar > -1)
- {
- createLocalSource(url, token.substring(0, bar), sequence,
- features);
- }
- else
- {
- createLocalSource(url, "User Source" + n, sequence, features);
- }
- } catch (Exception q)
- {
- System.err.println(
- "Unexpected exception when creating local source from '"
- + token + "'");
- q.printStackTrace();
- }
- n++;
- }
- }
- }
- }
-
- private List<jalviewSourceI> appendLocalSources()
- {
- List<jalviewSourceI> srclist = new ArrayList<jalviewSourceI>();
- addLocalDasSources();
- sourceNames = new Hashtable<String, jalviewSourceI>();
- if (dasSources != null)
- {
- for (jalviewSourceI src : dasSources)
- {
- sourceNames.put(src.getTitle(), src);
- srclist.add(src);
- }
- }
-
- if (localSources == null)
- {
- return srclist;
- }
- Enumeration en = localSources.keys();
- while (en.hasMoreElements())
- {
- String key = en.nextElement().toString();
- jalviewSourceI jvsrc = localSources.get(key);
- sourceNames.put(key, jvsrc);
- srclist.add(jvsrc);
- }
- return srclist;
- }
-
- /*
- *
- */
-
- @Override
- public jalviewSourceI createLocalSource(String url, String name,
- boolean sequence, boolean features)
- {
- SOURCE local = _createLocalSource(url, name, sequence, features);
-
- if (localSources == null)
- {
- localSources = new Hashtable<String, jalviewSourceI>();
- }
- jalviewSourceI src = new JalviewSource(local, this, true);
- localSources.put(local.getTitle(), src);
- return src;
- }
-
- private SOURCE _createLocalSource(String url, String name,
- boolean sequence, boolean features)
- {
- SOURCE local = new SOURCE();
-
- local.setUri(url);
- local.setTitle(name);
- local.setVERSION(new ArrayList<VERSION>());
- VERSION v = new VERSION();
- List<CAPABILITY> cp = new ArrayList<CAPABILITY>();
- if (sequence)
- {
- /*
- * Could try and synthesize a coordinate system for the source if needbe
- * COORDINATES coord = new COORDINATES(); coord.setAuthority("NCBI");
- * coord.setSource("Chromosome"); coord.setTaxid("9606");
- * coord.setVersion("35"); version.getCOORDINATES().add(coord);
- */
- CAPABILITY cap = new CAPABILITY();
- cap.setType("das1:" + Capabilities.SEQUENCE.getName());
- cap.setQueryUri(url + "/sequence");
- cp.add(cap);
- }
- if (features)
- {
- CAPABILITY cap = new CAPABILITY();
- cap.setType("das1:" + Capabilities.FEATURES.getName());
- cap.setQueryUri(url + "/features");
- cp.add(cap);
- }
-
- v.getCAPABILITY().addAll(cp);
- local.getVERSION().add(v);
-
- return local;
- }
-
- @Override
- public jalviewSourceI getSource(String nickname)
- {
- return sourceNames.get(nickname);
- }
-
- @Override
- public boolean removeLocalSource(jalviewSourceI source)
- {
- if (localSources.containsValue(source))
- {
- localSources.remove(source.getTitle());
- sourceNames.remove(source.getTitle());
- dasSources.remove(source);
- jalview.bin.Cache.setProperty("DAS_LOCAL_SOURCE",
- getLocalSourceString());
-
- return true;
- }
- return false;
- }
-
- @Override
- public void refreshSources()
- {
- dasSources = null;
- sourceNames = null;
- run();
- }
-
- @Override
- public List<jalviewSourceI> resolveSourceNicknames(List<String> sources)
- {
- ArrayList<jalviewSourceI> resolved = new ArrayList<jalviewSourceI>();
- if (sourceNames != null)
- {
- for (String src : sources)
- {
- jalviewSourceI dsrc = sourceNames.get(src);
- if (dsrc != null)
- {
- resolved.add(dsrc);
- }
- }
- }
- return resolved;
- }
-
- @Override
- public String getLocalSourceString()
- {
- if (localSources != null)
- {
- StringBuffer sb = new StringBuffer();
- Enumeration en = localSources.keys();
- while (en.hasMoreElements())
- {
- String token = en.nextElement().toString();
- jalviewSourceI srco = localSources.get(token);
- sb.append(token + "|" + (srco.isSequenceSource() ? "sequence:" : "")
- + srco.getUri() + "\t");
- }
- return sb.toString();
- }
- return "";
- }
-
- private static final Hashtable<URL, String> authStash;
- static
- {
- authStash = new Hashtable<URL, String>();
-
- try
- {
- // TODO: allow same credentials for https and http
- authStash.put(
- new URL("http://www.compbio.dundee.ac.uk/geneweb/das/myseq/"),
- "Basic SmltOm1pSg==");
- } catch (MalformedURLException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- @Override
- public MultipleConnectionPropertyProviderI getSessionHandler()
- {
- return this;
- }
-
- @Override
- public ConnectionPropertyProviderI getConnectionPropertyProviderFor(
- String arg0)
- {
-
- final ConnectionPropertyProviderI conprov = new ConnectionPropertyProviderI()
- {
- boolean authed = false;
-
- @Override
- public void setConnectionProperties(HttpURLConnection connection)
- {
- String auth = authStash.get(connection.getURL());
- if (auth != null && auth.length() > 0)
- {
- connection.setRequestProperty("Authorisation", auth);
- authed = true;
- }
- else
- {
- authed = false;
- }
- }
-
- @Override
- public boolean getResponseProperties(HttpURLConnection connection)
- {
- String auth = authStash.get(connection.getURL());
- if (auth != null && auth.length() == 0)
- {
- // don't attempt to check if we authed or not - user entered empty
- // password
- return false;
- }
- if (!authed)
- {
- if (auth != null)
- {
- // try and pass credentials.
- return true;
- }
- // see if we should try and create a new auth record.
- String ameth = connection.getHeaderField("X-DAS-AuthMethods");
- Cache.log.debug("Could authenticate to " + connection.getURL()
- + " with : " + ameth);
- // TODO: search auth string and raise login box - return if auth was
- // provided
- return false;
- }
- else
- {
- // check to see if auth was successful
- String asuc = connection
- .getHeaderField("X-DAS_AuthenticatedUser");
- if (asuc != null && asuc.trim().length() > 0)
- {
- // authentication was successful
- Cache.log.debug("Authenticated successfully to "
- + connection.getURL().toString());
- return false;
- }
- // it wasn't - so we should tell the user it failed and ask if they
- // want to attempt authentication again.
- authStash.remove(connection.getURL());
- // open a new login/password dialog with cancel button
- // set new authStash content with password and return true
- return true; //
- // User cancelled auth - so put empty string in stash to indicate we
- // don't want to auth with this server.
- // authStash.put(connection.getURL(), "");
- // return false;
- }
- }
- };
- return conprov;
- }
-
-}
+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ws.dbsources.das.datamodel;
-
-import jalview.util.MessageManager;
-import jalview.ws.dbsources.das.api.jalviewSourceI;
-import jalview.ws.seqfetcher.DbSourceProxy;
-
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-
-import org.biodas.jdas.client.threads.MultipleConnectionPropertyProviderI;
-import org.biodas.jdas.dassources.Capabilities;
-import org.biodas.jdas.dassources.utils.DasTimeFormat;
-import org.biodas.jdas.schema.sources.CAPABILITY;
-import org.biodas.jdas.schema.sources.COORDINATES;
-import org.biodas.jdas.schema.sources.MAINTAINER;
-import org.biodas.jdas.schema.sources.PROP;
-import org.biodas.jdas.schema.sources.SOURCE;
-import org.biodas.jdas.schema.sources.VERSION;
-
-public class JalviewSource implements jalviewSourceI
-{
- SOURCE source;
-
- MultipleConnectionPropertyProviderI connprov;
-
- public JalviewSource(SOURCE local2,
- MultipleConnectionPropertyProviderI connprov, boolean local)
- {
- this.connprov = connprov;
- this.local = local;
- source = local2;
- }
-
- @Override
- public String getTitle()
- {
- return source.getTitle();
- }
-
- @Override
- public VERSION getVersion()
- {
-
- return getVersionFor(source);
- }
-
- @Override
- public String getDocHref()
- {
- return source.getDocHref();
- }
-
- @Override
- public String getDescription()
- {
- return source.getDescription();
- }
-
- @Override
- public String getUri()
- {
- return source.getUri();
- }
-
- @Override
- public MAINTAINER getMAINTAINER()
- {
- return source.getMAINTAINER();
- }
-
- @Override
- public String getEmail()
- {
- return (local) ? null : source.getMAINTAINER().getEmail();
- }
-
- boolean local = false;
-
- @Override
- public boolean isLocal()
- {
- return local;
- }
-
- @Override
- public boolean isSequenceSource()
- {
- String seqcap = "das1:" + Capabilities.SEQUENCE.getName();
- for (String cp : getCapabilityList(getVersionFor(source)))
- {
- if (cp.equals(seqcap))
- {
- return true;
-
- }
- }
- return false;
- }
-
- @Override
- public boolean isFeatureSource()
- {
- String seqcap = "das1:" + Capabilities.FEATURES.getName();
- for (String cp : getCapabilityList(getVersionFor(source)))
- {
- if (cp.equals(seqcap))
- {
- return true;
-
- }
- }
- return false;
- }
-
- private VERSION getVersionFor(SOURCE ds)
- {
- VERSION latest = null;
- for (VERSION v : ds.getVERSION())
- {
- if (latest == null
- || isLaterThan(latest.getCreated(), v.getCreated()))
- {
- // TODO: das 1.6 - should just get the first version - ignore other
- // versions since not specified how to construct URL from version's URI
- // + source URI
- latest = v;
- }
- }
- return latest;
- }
-
- /**
- * compare date strings. null or unparseable dates are assumed to be oldest
- *
- * @param ref
- * @param newer
- * @return true iff ref comes before newer
- */
- private boolean isLaterThan(String ref, String newer)
- {
- Date refdate = null, newdate = null;
- if (ref != null && ref.trim().length() > 0)
- {
- try
- {
- refdate = DasTimeFormat.fromDASString(ref.trim());
-
- } catch (ParseException x)
- {
- }
- }
- if (newer != null && newer.trim().length() > 0)
- {
- try
- {
- newdate = DasTimeFormat.fromDASString(newer);
- } catch (ParseException e)
- {
- }
- }
- if (refdate != null)
- {
- if (newdate != null)
- {
- return refdate.before(newdate);
- }
- return false;
- }
- if (newdate != null)
- {
- return true;
- }
- // assume first instance of source is newest in list. - TODO: check if
- // natural ordering of source versions is newest first or oldest first
- return false;
- }
-
- public String[] getLabelsFor(VERSION v)
- {
- ArrayList<String> labels = new ArrayList<String>();
- for (PROP p : v.getPROP())
- {
- if (p.getName().equalsIgnoreCase("LABEL"))
- {
- labels.add(p.getValue());
- }
- }
- return labels.toArray(new String[0]);
- }
-
- private CAPABILITY getCapability(Capabilities capability)
- {
- for (CAPABILITY p : getVersion().getCAPABILITY())
- {
- if (p.getType().equalsIgnoreCase(capability.getName()) || p.getType()
- .equalsIgnoreCase("das1:" + capability.getName()))
- {
- return p;
- }
- }
- return null;
- }
-
- public String[] getCapabilityList(VERSION v)
- {
-
- ArrayList<String> labels = new ArrayList<String>();
- for (CAPABILITY p : v.getCAPABILITY())
- {
- // TODO: work out what to do with namespace prefix
- // does SEQUENCE == das1:SEQUENCE and das2:SEQUENCE ?
- // for moment, just show all capabilities...
- if (p.getType().startsWith("das1:"))
- {
- labels.add(p.getType());
- }
- }
- return labels.toArray(new String[0]);
- }
-
- @Override
- public List<DbSourceProxy> getSequenceSourceProxies()
- {
- if (!isSequenceSource())
- {
- return null;
- }
- ArrayList<DbSourceProxy> seqsources = new ArrayList<DbSourceProxy>();
- if (!local)
- {
- VERSION v = getVersion();
- Map<String, COORDINATES> latestc = new Hashtable<String, COORDINATES>();
- for (COORDINATES cs : v.getCOORDINATES())
- {
- COORDINATES ltst = latestc.get(cs.getUri());
- if (ltst == null || ltst.getVersion() == null
- || (ltst.getVersion() != null && cs.getVersion() != null
- && isLaterThan(ltst.getVersion(), cs.getVersion())))
- {
- latestc.put(cs.getUri(), cs);
- }
- }
- for (COORDINATES cs : latestc.values())
- {
- DasSequenceSource ds;
- /*
- * if (css == null || css.length == 0) { // TODO: query das source
- * directly to identify coordinate system... or // have to make up a
- * coordinate system css = new DasCoordinateSystem[] { new
- * DasCoordinateSystem() }; css[0].setName(d1s.getNickname());
- * css[0].setUniqueId(d1s.getNickname()); } for (int c = 0; c <
- * css.length; c++) {
- */
- try
- {
- seqsources.add(ds = new DasSequenceSource(
- getTitle() + " (" + cs.getAuthority() + " "
- + cs.getSource()
- + (cs.getVersion() != null ? " " + cs.getVersion()
- : "")
- + ")",
- cs.getAuthority(), source, v, cs, connprov));
- if (seqsources.size() > 1)
- {
- System.err.println("Added another sequence DB source for "
- + getTitle() + " (" + ds.getDbName() + ")");
- }
- } catch (Exception e)
- {
- System.err.println("Ignoring sequence coord system " + cs + " ("
- + cs.getContent() + ") for source " + getTitle()
- + "- threw exception when constructing fetcher.\n");
- e.printStackTrace();
- }
- }
- }
- else
- {
- try
- {
- seqsources.add(new DasSequenceSource(getTitle(), getTitle(), source,
- getVersion(), null, connprov));
- } catch (Exception e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- }
- if (seqsources.size() > 1)
- {
- // sort by name
- DbSourceProxy[] tsort = seqsources.toArray(new DasSequenceSource[0]);
- String[] nm = new String[tsort.length];
- for (int i = 0; i < nm.length; i++)
- {
- nm[i] = tsort[i].getDbName().toLowerCase();
- }
- jalview.util.QuickSort.sort(nm, tsort);
- seqsources.clear();
- for (DbSourceProxy ssrc : tsort)
- {
- seqsources.add(ssrc);
- }
- }
- return seqsources;
- }
-
- @Override
- public String getSourceURL()
- {
- try
- {
- // kind of dumb, since
- // org.biodas.jdas.dassources.utils.VersionAdapter.getSourceUriFromQueryUri()
- // does this,
- // but this way, we can access non DAS 1.6 compliant sources (which have
- // to have a URL like <sourcename>/das/ and cause a validation exception)
-
- for (CAPABILITY cap : getVersion().getCAPABILITY())
- {
- String capname = cap.getType()
- .substring(cap.getType().indexOf(":") + 1);
- int p = cap.getQueryUri().lastIndexOf(capname);
- if (p < -1)
- {
- throw new Exception(MessageManager.formatMessage(
- "exception.invalid_das_source", new String[]
- { source.getUri() }));
- }
- if (cap.getQueryUri().charAt(p) == '/')
- {
- p--;
- }
- return cap.getQueryUri().substring(0, p);
- }
- } catch (Exception x)
- {
- System.err.println("Serious: Couldn't get the URL for source "
- + source.getTitle());
- x.printStackTrace();
- }
- return null;
- }
-
- @Override
- public boolean isNewerThan(jalviewSourceI other)
- {
- return isLaterThan(getVersion().getCreated(),
- other.getVersion().getCreated());
- }
-
- @Override
- public boolean isReferenceSource()
- {
- // TODO check source object for indication that we are the primary for a DAS
- // coordinate system
- return false;
- }
-}
{
// Adjust input view for gaps
// propagate insertions into profile
- alhidden = HiddenColumns.propagateInsertions(profileseq, al,
- input);
+ alhidden = al.propagateInsertions(profileseq, input);
}
}
}
private CoordinateSys seqCoordSys = CoordinateSys.UNIPROT;
+ /**
+ * PDB sequence position to sequence coordinate mapping as derived from SIFTS
+ * record for the identified SeqCoordSys Used for lift-over from sequence
+ * derived from PDB (with first extracted PDBRESNUM as 'start' to the sequence
+ * being annotated with PDB data
+ */
+ private jalview.datamodel.Mapping seqFromPdbMapping;
+
private static final int BUFFER_SIZE = 4096;
- public static final int UNASSIGNED = -1;
+ public static final int UNASSIGNED = Integer.MIN_VALUE;
private static final int PDB_RES_POS = 0;
private static final int PDB_ATOM_POS = 1;
+ private static final int PDBE_POS = 2;
+
private static final String NOT_OBSERVED = "Not_Observed";
private static final String SIFTS_FTP_BASE_URL = "http://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/";
public StructureMapping getSiftsStructureMapping(SequenceI seq,
String pdbFile, String chain) throws SiftsException
{
+ SequenceI aseq = seq;
+ while (seq.getDatasetSequence() != null)
+ {
+ seq = seq.getDatasetSequence();
+ }
structId = (chain == null) ? pdbId : pdbId + "|" + chain;
System.out.println("Getting SIFTS mapping for " + structId + ": seq "
+ seq.getName());
HashMap<Integer, int[]> mapping = getGreedyMapping(chain, seq, ps);
String mappingOutput = mappingDetails.toString();
- StructureMapping siftsMapping = new StructureMapping(seq, pdbFile,
- pdbId, chain, mapping, mappingOutput);
+ StructureMapping siftsMapping = new StructureMapping(aseq, pdbFile,
+ pdbId, chain, mapping, mappingOutput, seqFromPdbMapping);
+
return siftsMapping;
}
public HashMap<Integer, int[]> getGreedyMapping(String entityId,
SequenceI seq, java.io.PrintStream os) throws SiftsException
{
- List<Integer> omitNonObserved = new ArrayList<Integer>();
- int nonObservedShiftIndex = 0;
+ List<Integer> omitNonObserved = new ArrayList<>();
+ int nonObservedShiftIndex = 0,pdbeNonObserved=0;
// System.out.println("Generating mappings for : " + entityId);
Entity entity = null;
entity = getEntityById(entityId);
TreeMap<Integer, String> resNumMap = new TreeMap<Integer, String>();
List<Segment> segments = entity.getSegment();
SegmentHelperPojo shp = new SegmentHelperPojo(seq, mapping, resNumMap,
- omitNonObserved, nonObservedShiftIndex);
+ omitNonObserved, nonObservedShiftIndex,pdbeNonObserved);
processSegments(segments, shp);
try
{
{
throw new SiftsException("SIFTS mapping failed");
}
+ // also construct a mapping object between the seq-coord sys and the PDB seq's coord sys
Integer[] keys = mapping.keySet().toArray(new Integer[0]);
Arrays.sort(keys);
seqStart = keys[0];
seqEnd = keys[keys.length - 1];
-
+ List<int[]> from=new ArrayList<>(),to=new ArrayList<>();
+ int[]_cfrom=null,_cto=null;
String matchedSeq = originalSeq;
- if (seqStart != UNASSIGNED)
+ if (seqStart != UNASSIGNED) // fixme! seqStart can map to -1 for a pdb sequence that starts <-1
{
+ for (int seqps:keys)
+ {
+ int pdbpos = mapping.get(seqps)[PDBE_POS];
+ if (pdbpos == UNASSIGNED)
+ {
+ // not correct - pdbpos might be -1, but leave it for now
+ continue;
+ }
+ if (_cfrom==null || seqps!=_cfrom[1]+1)
+ {
+ _cfrom = new int[] { seqps,seqps};
+ from.add(_cfrom);
+ _cto = null; // discontinuity
+ } else {
+ _cfrom[1]= seqps;
+ }
+ if (_cto==null || pdbpos!=1+_cto[1])
+ {
+ _cto = new int[] { pdbpos,pdbpos};
+ to.add(_cto);
+ } else {
+ _cto[1] = pdbpos;
+ }
+ }
+ _cfrom = new int[from.size() * 2];
+ _cto = new int[to.size() * 2];
+ int p = 0;
+ for (int[] range : from)
+ {
+ _cfrom[p++] = range[0];
+ _cfrom[p++] = range[1];
+ }
+ ;
+ p = 0;
+ for (int[] range : to)
+ {
+ _cto[p++] = range[0];
+ _cto[p++] = range[1];
+ }
+ ;
+
+ seqFromPdbMapping = new jalview.datamodel.Mapping(null, _cto, _cfrom,
+ 1,
+ 1);
pdbStart = mapping.get(seqStart)[PDB_RES_POS];
pdbEnd = mapping.get(seqEnd)[PDB_RES_POS];
int orignalSeqStart = seq.getStart();
TreeMap<Integer, String> resNumMap = shp.getResNumMap();
List<Integer> omitNonObserved = shp.getOmitNonObserved();
int nonObservedShiftIndex = shp.getNonObservedShiftIndex();
+ int pdbeNonObservedCount = shp.getPdbeNonObserved();
+ int firstPDBResNum = UNASSIGNED;
for (Segment segment : segments)
{
// System.out.println("Mapping segments : " + segment.getSegId() + "\\"s
List<Residue> residues = segment.getListResidue().getResidue();
for (Residue residue : residues)
{
+ boolean isObserved = isResidueObserved(residue);
+ int pdbeIndex = getLeadingIntegerValue(residue.getDbResNum(),
+ UNASSIGNED);
int currSeqIndex = UNASSIGNED;
List<CrossRefDb> cRefDbs = residue.getCrossRefDb();
CrossRefDb pdbRefDb = null;
if (cRefDb.getDbSource().equalsIgnoreCase(DBRefSource.PDB))
{
pdbRefDb = cRefDb;
+ if (firstPDBResNum == UNASSIGNED)
+ {
+ firstPDBResNum = getLeadingIntegerValue(cRefDb.getDbResNum(),
+ UNASSIGNED);
+ }
+ else
+ {
+ if (isObserved)
+ {
+ // after we find the first observed residue we just increment
+ firstPDBResNum++;
+ }
+ }
}
if (cRefDb.getDbCoordSys().equalsIgnoreCase(seqCoordSys.getName())
&& isAccessionMatched(cRefDb.getDbAccessionId()))
}
}
}
+ if (!isObserved)
+ {
+ ++pdbeNonObservedCount;
+ }
+ if (seqCoordSys == seqCoordSys.PDB) // FIXME: is seqCoordSys ever PDBe
+ // ???
+ {
+ // if the sequence has a primary reference to the PDB, then we are
+ // dealing with a sequence extracted directly from the PDB. In that
+ // case, numbering is PDBe - non-observed residues
+ currSeqIndex = seq.getStart() - 1 + pdbeIndex;
+ }
+ if (!isObserved)
+ {
+ if (seqCoordSys != CoordinateSys.UNIPROT) // FIXME: PDB or PDBe only
+ // here
+ {
+ // mapping to PDB or PDBe so we need to bookkeep for the
+ // non-observed
+ // SEQRES positions
+ omitNonObserved.add(currSeqIndex);
+ ++nonObservedShiftIndex;
+ }
+ }
if (currSeqIndex == UNASSIGNED)
{
+ // change in logic - unobserved residues with no currSeqIndex
+ // corresponding are still counted in both nonObservedShiftIndex and
+ // pdbeIndex...
continue;
}
- if (currSeqIndex >= seq.getStart() && currSeqIndex <= seq.getEnd())
+ // if (currSeqIndex >= seq.getStart() && currSeqIndex <= seqlength) //
+ // true
+ // numbering
+ // is
+ // not
+ // up
+ // to
+ // seq.getEnd()
{
int resNum = (pdbRefDb == null)
: getLeadingIntegerValue(pdbRefDb.getDbResNum(),
UNASSIGNED);
- if (isResidueObserved(residue)
- || seqCoordSys == CoordinateSys.UNIPROT)
+ if (isObserved)
{
char resCharCode = ResidueProperties
.getSingleCharacterCode(ResidueProperties
.getCanonicalAminoAcid(residue.getDbResName()));
resNumMap.put(currSeqIndex, String.valueOf(resCharCode));
+
+ int[] mappingcols = new int[] { Integer.valueOf(resNum),
+ UNASSIGNED, isObserved ? firstPDBResNum : UNASSIGNED };
+
+ mapping.put(currSeqIndex - nonObservedShiftIndex, mappingcols);
}
- else
- {
- omitNonObserved.add(currSeqIndex);
- ++nonObservedShiftIndex;
- }
- mapping.put(currSeqIndex - nonObservedShiftIndex,
- new int[]
- { Integer.valueOf(resNum), UNASSIGNED });
}
}
}
private int nonObservedShiftIndex;
+ /**
+ * count of number of 'not observed' positions in the PDB record's SEQRES
+ * (total number of residues with coordinates == length(SEQRES) -
+ * pdbeNonObserved
+ */
+ private int pdbeNonObserved;
+
public SegmentHelperPojo(SequenceI seq, HashMap<Integer, int[]> mapping,
TreeMap<Integer, String> resNumMap,
- List<Integer> omitNonObserved, int nonObservedShiftIndex)
+ List<Integer> omitNonObserved, int nonObservedShiftIndex,
+ int pdbeNonObserved)
{
setSeq(seq);
setMapping(mapping);
setResNumMap(resNumMap);
setOmitNonObserved(omitNonObserved);
setNonObservedShiftIndex(nonObservedShiftIndex);
+ setPdbeNonObserved(pdbeNonObserved);
+
}
+ public void setPdbeNonObserved(int pdbeNonObserved2)
+ {
+ this.pdbeNonObserved = pdbeNonObserved2;
+ }
+
+ public int getPdbeNonObserved()
+ {
+ return pdbeNonObserved;
+ }
public SequenceI getSeq()
{
return seq;
{
this.nonObservedShiftIndex = nonObservedShiftIndex;
}
+
}
@Override
--- /dev/null
+package org.stackoverflowusers.file;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.ParseException;
+
+/**
+ * Represents a Windows shortcut (typically visible to Java only as a '.lnk' file).
+ *
+ * Retrieved 2011-09-23 from http://stackoverflow.com/questions/309495/windows-shortcut-lnk-parser-in-java/672775#672775
+ * Originally called LnkParser
+ *
+ * Written by: (the stack overflow users, obviously!)
+ * Apache Commons VFS dependency removed by crysxd (why were we using that!?) https://github.com/crysxd
+ * Headerified, refactored and commented by Code Bling http://stackoverflow.com/users/675721/code-bling
+ * Network file support added by Stefan Cordes http://stackoverflow.com/users/81330/stefan-cordes
+ * Adapted by Sam Brightman http://stackoverflow.com/users/2492/sam-brightman
+ * Based on information in 'The Windows Shortcut File Format' by Jesse Hager <jessehager@iname.com>
+ * And somewhat based on code from the book 'Swing Hacks: Tips and Tools for Killer GUIs'
+ * by Joshua Marinacci and Chris Adamson
+ * ISBN: 0-596-00907-0
+ * http://www.oreilly.com/catalog/swinghks/
+ */
+public class WindowsShortcut
+{
+ private boolean isDirectory;
+ private boolean isLocal;
+ private String real_file;
+
+ /**
+ * Provides a quick test to see if this could be a valid link !
+ * If you try to instantiate a new WindowShortcut and the link is not valid,
+ * Exceptions may be thrown and Exceptions are extremely slow to generate,
+ * therefore any code needing to loop through several files should first check this.
+ *
+ * @param file the potential link
+ * @return true if may be a link, false otherwise
+ * @throws IOException if an IOException is thrown while reading from the file
+ */
+ public static boolean isPotentialValidLink(File file) throws IOException {
+ final int minimum_length = 0x64;
+ InputStream fis = new FileInputStream(file);
+ boolean isPotentiallyValid = false;
+ try {
+ isPotentiallyValid = file.isFile()
+ && file.getName().toLowerCase().endsWith(".lnk")
+ && fis.available() >= minimum_length
+ && isMagicPresent(getBytes(fis, 32));
+ } finally {
+ fis.close();
+ }
+ return isPotentiallyValid;
+ }
+
+ public WindowsShortcut(File file) throws IOException, ParseException {
+ InputStream in = new FileInputStream(file);
+ try {
+ parseLink(getBytes(in));
+ } finally {
+ in.close();
+ }
+ }
+
+ /**
+ * @return the name of the filesystem object pointed to by this shortcut
+ */
+ public String getRealFilename() {
+ return real_file;
+ }
+
+ /**
+ * Tests if the shortcut points to a local resource.
+ * @return true if the 'local' bit is set in this shortcut, false otherwise
+ */
+ public boolean isLocal() {
+ return isLocal;
+ }
+
+ /**
+ * Tests if the shortcut points to a directory.
+ * @return true if the 'directory' bit is set in this shortcut, false otherwise
+ */
+ public boolean isDirectory() {
+ return isDirectory;
+ }
+
+ /**
+ * Gets all the bytes from an InputStream
+ * @param in the InputStream from which to read bytes
+ * @return array of all the bytes contained in 'in'
+ * @throws IOException if an IOException is encountered while reading the data from the InputStream
+ */
+ private static byte[] getBytes(InputStream in) throws IOException {
+ return getBytes(in, null);
+ }
+
+ /**
+ * Gets up to max bytes from an InputStream
+ * @param in the InputStream from which to read bytes
+ * @param max maximum number of bytes to read
+ * @return array of all the bytes contained in 'in'
+ * @throws IOException if an IOException is encountered while reading the data from the InputStream
+ */
+ private static byte[] getBytes(InputStream in, Integer max) throws IOException {
+ // read the entire file into a byte buffer
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ byte[] buff = new byte[256];
+ while (max == null || max > 0) {
+ int n = in.read(buff);
+ if (n == -1) {
+ break;
+ }
+ bout.write(buff, 0, n);
+ if (max != null)
+ max -= n;
+ }
+ in.close();
+ return bout.toByteArray();
+ }
+
+ private static boolean isMagicPresent(byte[] link) {
+ final int magic = 0x0000004C;
+ final int magic_offset = 0x00;
+ return link.length >= 32 && bytesToDword(link, magic_offset) == magic;
+ }
+
+ /**
+ * Gobbles up link data by parsing it and storing info in member fields
+ * @param link all the bytes from the .lnk file
+ */
+ private void parseLink(byte[] link) throws ParseException {
+ try {
+ if (!isMagicPresent(link))
+ throw new ParseException("Invalid shortcut; magic is missing", 0);
+
+ // get the flags byte
+ byte flags = link[0x14];
+
+ // get the file attributes byte
+ final int file_atts_offset = 0x18;
+ byte file_atts = link[file_atts_offset];
+ byte is_dir_mask = (byte)0x10;
+ if ((file_atts & is_dir_mask) > 0) {
+ isDirectory = true;
+ } else {
+ isDirectory = false;
+ }
+
+ // if the shell settings are present, skip them
+ final int shell_offset = 0x4c;
+ final byte has_shell_mask = (byte)0x01;
+ int shell_len = 0;
+ if ((flags & has_shell_mask) > 0) {
+ // the plus 2 accounts for the length marker itself
+ shell_len = bytesToWord(link, shell_offset) + 2;
+ }
+
+ // get to the file settings
+ int file_start = 0x4c + shell_len;
+
+ final int file_location_info_flag_offset_offset = 0x08;
+ int file_location_info_flag = link[file_start + file_location_info_flag_offset_offset];
+ isLocal = (file_location_info_flag & 2) == 0;
+ // get the local volume and local system values
+ //final int localVolumeTable_offset_offset = 0x0C;
+ final int basename_offset_offset = 0x10;
+ final int networkVolumeTable_offset_offset = 0x14;
+ final int finalname_offset_offset = 0x18;
+ int finalname_offset = link[file_start + finalname_offset_offset] + file_start;
+ String finalname = getNullDelimitedString(link, finalname_offset);
+ if (isLocal) {
+ int basename_offset = link[file_start + basename_offset_offset] + file_start;
+ String basename = getNullDelimitedString(link, basename_offset);
+ real_file = basename + finalname;
+ } else {
+ int networkVolumeTable_offset = link[file_start + networkVolumeTable_offset_offset] + file_start;
+ int shareName_offset_offset = 0x08;
+ int shareName_offset = link[networkVolumeTable_offset + shareName_offset_offset]
+ + networkVolumeTable_offset;
+ String shareName = getNullDelimitedString(link, shareName_offset);
+ real_file = shareName + "\\" + finalname;
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new ParseException("Could not be parsed, probably not a valid WindowsShortcut", 0);
+ }
+ }
+
+ private static String getNullDelimitedString(byte[] bytes, int off) {
+ int len = 0;
+ // count bytes until the null character (0)
+ while (true) {
+ if (bytes[off + len] == 0) {
+ break;
+ }
+ len++;
+ }
+ return new String(bytes, off, len);
+ }
+
+ /*
+ * convert two bytes into a short note, this is little endian because it's
+ * for an Intel only OS.
+ */
+ private static int bytesToWord(byte[] bytes, int off) {
+ return ((bytes[off + 1] & 0xff) << 8) | (bytes[off] & 0xff);
+ }
+
+ private static int bytesToDword(byte[] bytes, int off) {
+ return (bytesToWord(bytes, off + 2) << 16) | bytesToWord(bytes, off);
+ }
+
+}
a3.resName = "ASP";
a3.resNumber = 41;
- Vector<Bond> v = new Vector<Bond>();
+ Vector<Bond> v = new Vector<>();
v.add(new Bond(a1, a2));
v.add(new Bond(a2, a3));
v.add(new Bond(a3, a1));
@Test(groups = { "Functional" })
public void testMakeResidueList_noAnnotation()
{
- Vector<Atom> atoms = new Vector<Atom>();
+ Vector<Atom> atoms = new Vector<>();
c.atoms = atoms;
c.isNa = true;
atoms.add(makeAtom(4, "N", "MET"));
@Test(groups = { "Functional" })
public void testMakeResidueList_withTempFactor()
{
- Vector<Atom> atoms = new Vector<Atom>();
+ Vector<Atom> atoms = new Vector<>();
c.atoms = atoms;
atoms.add(makeAtom(4, "N", "MET"));
atoms.get(atoms.size() - 1).tfactor = 1f;
atoms.add(makeAtom(5, "CA", "LYS"));
atoms.get(atoms.size() - 1).tfactor = 9f;
atoms.add(makeAtom(6, "O", "LEU"));
- atoms.get(atoms.size() - 1).tfactor = 4f;
+ atoms.get(atoms.size() - 1).tfactor = -4f;
atoms.add(makeAtom(6, "N", "LEU"));
atoms.get(atoms.size() - 1).tfactor = 5f;
atoms.add(makeAtom(6, "CA", "LEU"));
/*
* Verify annotations; note the tempFactor is read from the first atom in
- * each residue i.e. we expect values 1, 7, 4 for the residues
+ * each residue i.e. we expect values 1, 7, -4 for the residues
*/
AlignmentAnnotation[] ann = c.sequence.getAnnotation();
assertEquals(1, ann.length);
assertEquals("Temperature Factor for 1gaqA", ann[0].description);
assertSame(c.sequence, ann[0].sequenceRef);
assertEquals(AlignmentAnnotation.LINE_GRAPH, ann[0].graph);
- assertEquals(0f, ann[0].graphMin, 0.001f);
+ assertEquals(-4f, ann[0].graphMin, 0.001f);
assertEquals(7f, ann[0].graphMax, 0.001f);
assertEquals(3, ann[0].annotations.length);
assertEquals(1f, ann[0].annotations[0].value, 0.001f);
assertEquals(7f, ann[0].annotations[1].value, 0.001f);
- assertEquals(4f, ann[0].annotations[2].value, 0.001f);
+ assertEquals(-4f, ann[0].annotations[2].value, 0.001f);
}
/**
public void testMakeCaBondList()
{
c.isNa = true;
- Vector<Atom> atoms = new Vector<Atom>();
+ Vector<Atom> atoms = new Vector<>();
c.atoms = atoms;
atoms.add(makeAtom(4, "N", "MET"));
atoms.add(makeAtom(4, "CA", "MET"));
public void testMakeCaBondList_nucleotide()
{
c.isNa = false;
- Vector<Atom> atoms = new Vector<Atom>();
+ Vector<Atom> atoms = new Vector<>();
c.atoms = atoms;
atoms.add(makeAtom(4, "N", "G"));
atoms.add(makeAtom(4, "P", "G"));
@Test(groups = { "Functional" })
public void testMakeExactMapping()
{
- Vector<Atom> atoms = new Vector<Atom>();
+ Vector<Atom> atoms = new Vector<>();
c.atoms = atoms;
atoms.add(makeAtom(4, "N", "MET"));
atoms.add(makeAtom(4, "CA", "MET"));
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.GeneLociI;
import jalview.datamodel.Mapping;
import jalview.datamodel.SearchResultMatchI;
import jalview.datamodel.SearchResultsI;
import jalview.io.FileFormat;
import jalview.io.FileFormatI;
import jalview.io.FormatAdapter;
+import jalview.io.gff.SequenceOntologyI;
import jalview.util.MapList;
import jalview.util.MappingUtils;
public class AlignmentUtilsTests
{
+ private static Sequence ts = new Sequence("short",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm");
@BeforeClass(alwaysRun = true)
public void setUpJvOptionPane()
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- public static Sequence ts = new Sequence("short",
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm");
-
@Test(groups = { "Functional" })
public void testExpandContext()
{
@Test(groups = { "Functional" })
public void testMapProteinAlignmentToCdna_noXrefs() throws IOException
{
- List<SequenceI> protseqs = new ArrayList<SequenceI>();
+ List<SequenceI> protseqs = new ArrayList<>();
protseqs.add(new Sequence("UNIPROT|V12345", "EIQ"));
protseqs.add(new Sequence("UNIPROT|V12346", "EIQ"));
protseqs.add(new Sequence("UNIPROT|V12347", "SAR"));
AlignmentI protein = new Alignment(protseqs.toArray(new SequenceI[3]));
protein.setDataset(null);
- List<SequenceI> dnaseqs = new ArrayList<SequenceI>();
+ List<SequenceI> dnaseqs = new ArrayList<>();
dnaseqs.add(new Sequence("EMBL|A11111", "TCAGCACGC")); // = SAR
dnaseqs.add(new Sequence("EMBL|A22222", "GAGATACAA")); // = EIQ
dnaseqs.add(new Sequence("EMBL|A33333", "GAAATCCAG")); // = EIQ
acf.addMap(dna1.getDatasetSequence(), prot1.getDatasetSequence(), map);
acf.addMap(dna2.getDatasetSequence(), prot2.getDatasetSequence(), map);
acf.addMap(dna3.getDatasetSequence(), prot3.getDatasetSequence(), map);
- ArrayList<AlignedCodonFrame> acfs = new ArrayList<AlignedCodonFrame>();
+ ArrayList<AlignedCodonFrame> acfs = new ArrayList<>();
acfs.add(acf);
protein.setCodonFrames(acfs);
public void testMapProteinAlignmentToCdna_withStartAndStopCodons()
throws IOException
{
- List<SequenceI> protseqs = new ArrayList<SequenceI>();
+ List<SequenceI> protseqs = new ArrayList<>();
protseqs.add(new Sequence("UNIPROT|V12345", "EIQ"));
protseqs.add(new Sequence("UNIPROT|V12346", "EIQ"));
protseqs.add(new Sequence("UNIPROT|V12347", "SAR"));
AlignmentI protein = new Alignment(protseqs.toArray(new SequenceI[3]));
protein.setDataset(null);
- List<SequenceI> dnaseqs = new ArrayList<SequenceI>();
+ List<SequenceI> dnaseqs = new ArrayList<>();
// start + SAR:
dnaseqs.add(new Sequence("EMBL|A11111", "ATGTCAGCACGC"));
// = EIQ + stop
@Test(groups = { "Functional" })
public void testMapProteinAlignmentToCdna_withXrefs() throws IOException
{
- List<SequenceI> protseqs = new ArrayList<SequenceI>();
+ List<SequenceI> protseqs = new ArrayList<>();
protseqs.add(new Sequence("UNIPROT|V12345", "EIQ"));
protseqs.add(new Sequence("UNIPROT|V12346", "EIQ"));
protseqs.add(new Sequence("UNIPROT|V12347", "SAR"));
AlignmentI protein = new Alignment(protseqs.toArray(new SequenceI[3]));
protein.setDataset(null);
- List<SequenceI> dnaseqs = new ArrayList<SequenceI>();
+ List<SequenceI> dnaseqs = new ArrayList<>();
dnaseqs.add(new Sequence("EMBL|A11111", "TCAGCACGC")); // = SAR
dnaseqs.add(new Sequence("EMBL|A22222", "ATGGAGATACAA")); // = start + EIQ
dnaseqs.add(new Sequence("EMBL|A33333", "GAAATCCAG")); // = EIQ
public void testMapProteinAlignmentToCdna_prioritiseXrefs()
throws IOException
{
- List<SequenceI> protseqs = new ArrayList<SequenceI>();
+ List<SequenceI> protseqs = new ArrayList<>();
protseqs.add(new Sequence("UNIPROT|V12345", "EIQ"));
protseqs.add(new Sequence("UNIPROT|V12346", "EIQ"));
AlignmentI protein = new Alignment(
protseqs.toArray(new SequenceI[protseqs.size()]));
protein.setDataset(null);
- List<SequenceI> dnaseqs = new ArrayList<SequenceI>();
+ List<SequenceI> dnaseqs = new ArrayList<>();
dnaseqs.add(new Sequence("EMBL|A11111", "GAAATCCAG")); // = EIQ
dnaseqs.add(new Sequence("EMBL|A22222", "GAAATTCAG")); // = EIQ
AlignmentI cdna = new Alignment(dnaseqs.toArray(new SequenceI[dnaseqs
al.addAnnotation(ann4); // Temp for seq1
al.addAnnotation(ann5); // Temp for seq2
al.addAnnotation(ann6); // Temp for no sequence
- List<String> types = new ArrayList<String>();
- List<SequenceI> scope = new ArrayList<SequenceI>();
+ List<String> types = new ArrayList<>();
+ List<SequenceI> scope = new ArrayList<>();
/*
* Set all sequence related Structure to hidden (ann1, ann2)
dna.addCodonFrame(acf);
/*
- * In this case, mappings originally came from matching Uniprot accessions - so need an xref on dna involving those regions. These are normally constructed from CDS annotation
+ * In this case, mappings originally came from matching Uniprot accessions
+ * - so need an xref on dna involving those regions.
+ * These are normally constructed from CDS annotation
*/
DBRefEntry dna1xref = new DBRefEntry("UNIPROT", "ENSEMBL", "pep1",
new Mapping(mapfordna1));
- dna1.getDatasetSequence().addDBRef(dna1xref);
+ dna1.addDBRef(dna1xref);
+ assertEquals(2, dna1.getDBRefs().length); // to self and to pep1
DBRefEntry dna2xref = new DBRefEntry("UNIPROT", "ENSEMBL", "pep2",
new Mapping(mapfordna2));
- dna2.getDatasetSequence().addDBRef(dna2xref);
+ dna2.addDBRef(dna2xref);
+ assertEquals(2, dna2.getDBRefs().length); // to self and to pep2
/*
* execute method under test:
assertEquals(cdsMapping.getInverse(), dbref.getMap().getMap());
/*
+ * verify cDNA has added a dbref with mapping to CDS
+ */
+ assertEquals(3, dna1.getDBRefs().length);
+ DBRefEntry dbRefEntry = dna1.getDBRefs()[2];
+ assertSame(cds1Dss, dbRefEntry.getMap().getTo());
+ MapList dnaToCdsMapping = new MapList(new int[] { 4, 6, 10, 12 },
+ new int[] { 1, 6 }, 1, 1);
+ assertEquals(dnaToCdsMapping, dbRefEntry.getMap().getMap());
+ assertEquals(3, dna2.getDBRefs().length);
+ dbRefEntry = dna2.getDBRefs()[2];
+ assertSame(cds2Dss, dbRefEntry.getMap().getTo());
+ dnaToCdsMapping = new MapList(new int[] { 1, 3, 7, 9, 13, 15 },
+ new int[] { 1, 9 }, 1, 1);
+ assertEquals(dnaToCdsMapping, dbRefEntry.getMap().getMap());
+
+ /*
+ * verify CDS has added a dbref with mapping to cDNA
+ */
+ assertEquals(2, cds1Dss.getDBRefs().length);
+ dbRefEntry = cds1Dss.getDBRefs()[1];
+ assertSame(dna1.getDatasetSequence(), dbRefEntry.getMap().getTo());
+ MapList cdsToDnaMapping = new MapList(new int[] { 1, 6 }, new int[] {
+ 4, 6, 10, 12 }, 1, 1);
+ assertEquals(cdsToDnaMapping, dbRefEntry.getMap().getMap());
+ assertEquals(2, cds2Dss.getDBRefs().length);
+ dbRefEntry = cds2Dss.getDBRefs()[1];
+ assertSame(dna2.getDatasetSequence(), dbRefEntry.getMap().getTo());
+ cdsToDnaMapping = new MapList(new int[] { 1, 9 }, new int[] { 1, 3, 7,
+ 9, 13, 15 }, 1, 1);
+ assertEquals(cdsToDnaMapping, dbRefEntry.getMap().getMap());
+
+ /*
* Verify mappings from CDS to peptide, cDNA to CDS, and cDNA to peptide
* the mappings are on the shared alignment dataset
* 6 mappings, 2*(DNA->CDS), 2*(DNA->Pep), 2*(CDS->Pep)
map = new MapList(new int[] { 9, 11 }, new int[] { 2, 2 }, 3, 1);
acf.addMap(dna3.getDatasetSequence(), prot3.getDatasetSequence(), map);
- ArrayList<AlignedCodonFrame> acfs = new ArrayList<AlignedCodonFrame>();
+ ArrayList<AlignedCodonFrame> acfs = new ArrayList<>();
acfs.add(acf);
protein.setCodonFrames(acfs);
sf6.setValue("alleles", "g, a"); // should force to upper-case
sf6.setValue("ID", "sequence_variant:rs758803216");
dna.addSequenceFeature(sf6);
+
SequenceFeature sf7 = new SequenceFeature("sequence_variant", "", 15,
15, 0f, null);
sf7.setValue("alleles", "A, T");
* variants:
* GAA -> E source: Ensembl
* CAA -> Q source: dbSNP
+ * TAA -> STOP source: dnSNP
* AAG synonymous source: COSMIC
* AAT -> N source: Ensembl
* ...TTC synonymous source: dbSNP
String ensembl = "Ensembl";
String dbSnp = "dbSNP";
String cosmic = "COSMIC";
+
SequenceFeature sf1 = new SequenceFeature("sequence_variant", "", 1, 1,
0f, ensembl);
- sf1.setValue("alleles", "A,G"); // GAA -> E
+ sf1.setValue("alleles", "A,G"); // AAA -> GAA -> K/E
sf1.setValue("ID", "var1.125A>G");
+
SequenceFeature sf2 = new SequenceFeature("sequence_variant", "", 1, 1,
0f, dbSnp);
- sf2.setValue("alleles", "A,C"); // CAA -> Q
+ sf2.setValue("alleles", "A,C"); // AAA -> CAA -> K/Q
sf2.setValue("ID", "var2");
sf2.setValue("clinical_significance", "Dodgy");
- SequenceFeature sf3 = new SequenceFeature("sequence_variant", "", 3, 3,
- 0f, cosmic);
- sf3.setValue("alleles", "A,G"); // synonymous
+
+ SequenceFeature sf3 = new SequenceFeature("sequence_variant", "", 1, 1,
+ 0f, dbSnp);
+ sf3.setValue("alleles", "A,T"); // AAA -> TAA -> stop codon
sf3.setValue("ID", "var3");
- sf3.setValue("clinical_significance", "None");
+ sf3.setValue("clinical_significance", "Bad");
+
SequenceFeature sf4 = new SequenceFeature("sequence_variant", "", 3, 3,
+ 0f, cosmic);
+ sf4.setValue("alleles", "A,G"); // AAA -> AAG synonymous
+ sf4.setValue("ID", "var4");
+ sf4.setValue("clinical_significance", "None");
+
+ SequenceFeature sf5 = new SequenceFeature("sequence_variant", "", 3, 3,
0f, ensembl);
- sf4.setValue("alleles", "A,T"); // AAT -> N
- sf4.setValue("ID", "sequence_variant:var4"); // prefix gets stripped off
- sf4.setValue("clinical_significance", "Benign");
- SequenceFeature sf5 = new SequenceFeature("sequence_variant", "", 6, 6,
+ sf5.setValue("alleles", "A,T"); // AAA -> AAT -> K/N
+ sf5.setValue("ID", "sequence_variant:var5"); // prefix gets stripped off
+ sf5.setValue("clinical_significance", "Benign");
+
+ SequenceFeature sf6 = new SequenceFeature("sequence_variant", "", 6, 6,
0f, dbSnp);
- sf5.setValue("alleles", "T,C"); // synonymous
- sf5.setValue("ID", "var5");
- sf5.setValue("clinical_significance", "Bad");
- SequenceFeature sf6 = new SequenceFeature("sequence_variant", "", 8, 8,
- 0f, cosmic);
- sf6.setValue("alleles", "C,A,G"); // CAC,CGC -> H,R
+ sf6.setValue("alleles", "T,C"); // TTT -> TTC synonymous
sf6.setValue("ID", "var6");
- sf6.setValue("clinical_significance", "Good");
- List<DnaVariant> codon1Variants = new ArrayList<DnaVariant>();
- List<DnaVariant> codon2Variants = new ArrayList<DnaVariant>();
- List<DnaVariant> codon3Variants = new ArrayList<DnaVariant>();
+ SequenceFeature sf7 = new SequenceFeature("sequence_variant", "", 8, 8,
+ 0f, cosmic);
+ sf7.setValue("alleles", "C,A,G"); // CCC -> CAC,CGC -> P/H/R
+ sf7.setValue("ID", "var7");
+ sf7.setValue("clinical_significance", "Good");
+
+ List<DnaVariant> codon1Variants = new ArrayList<>();
+ List<DnaVariant> codon2Variants = new ArrayList<>();
+ List<DnaVariant> codon3Variants = new ArrayList<>();
+
List<DnaVariant> codonVariants[] = new ArrayList[3];
codonVariants[0] = codon1Variants;
codonVariants[1] = codon2Variants;
*/
codon1Variants.add(new DnaVariant("A", sf1));
codon1Variants.add(new DnaVariant("A", sf2));
+ codon1Variants.add(new DnaVariant("A", sf3));
codon2Variants.add(new DnaVariant("A"));
- codon2Variants.add(new DnaVariant("A"));
- codon3Variants.add(new DnaVariant("A", sf3));
+ // codon2Variants.add(new DnaVariant("A"));
codon3Variants.add(new DnaVariant("A", sf4));
+ codon3Variants.add(new DnaVariant("A", sf5));
AlignmentUtils.computePeptideVariants(peptide, 1, codonVariants);
/*
codon3Variants.clear();
codon1Variants.add(new DnaVariant("T"));
codon2Variants.add(new DnaVariant("T"));
- codon3Variants.add(new DnaVariant("T", sf5));
+ codon3Variants.add(new DnaVariant("T", sf6));
AlignmentUtils.computePeptideVariants(peptide, 2, codonVariants);
/*
codon2Variants.clear();
codon3Variants.clear();
codon1Variants.add(new DnaVariant("C"));
- codon2Variants.add(new DnaVariant("C", sf6));
+ codon2Variants.add(new DnaVariant("C", sf7));
codon3Variants.add(new DnaVariant("C"));
AlignmentUtils.computePeptideVariants(peptide, 3, codonVariants);
* verify added sequence features for
* var1 K -> E Ensembl
* var2 K -> Q dbSNP
- * var4 K -> N Ensembl
- * var6 P -> H COSMIC
- * var6 P -> R COSMIC
+ * var3 K -> stop
+ * var4 synonymous
+ * var5 K -> N Ensembl
+ * var6 synonymous
+ * var7 P -> H COSMIC
+ * var8 P -> R COSMIC
*/
List<SequenceFeature> sfs = peptide.getSequenceFeatures();
SequenceFeatures.sortFeatures(sfs, true);
- assertEquals(5, sfs.size());
+ assertEquals(8, sfs.size());
/*
* features are sorted by start position ascending, but in no
* particular order where start positions match; asserts here
* simply match the data returned (the order is not important)
*/
+ // AAA -> AAT -> K/N
SequenceFeature sf = sfs.get(0);
assertEquals(1, sf.getBegin());
assertEquals(1, sf.getEnd());
+ assertEquals("nonsynonymous_variant", sf.getType());
assertEquals("p.Lys1Asn", sf.getDescription());
- assertEquals("var4", sf.getValue("ID"));
+ assertEquals("var5", sf.getValue("ID"));
assertEquals("Benign", sf.getValue("clinical_significance"));
- assertEquals("ID=var4;clinical_significance=Benign", sf.getAttributes());
+ assertEquals("ID=var5;clinical_significance=Benign",
+ sf.getAttributes());
assertEquals(1, sf.links.size());
assertEquals(
- "p.Lys1Asn var4|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var4",
+ "p.Lys1Asn var5|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var5",
sf.links.get(0));
assertEquals(ensembl, sf.getFeatureGroup());
+ // AAA -> CAA -> K/Q
sf = sfs.get(1);
assertEquals(1, sf.getBegin());
assertEquals(1, sf.getEnd());
+ assertEquals("nonsynonymous_variant", sf.getType());
assertEquals("p.Lys1Gln", sf.getDescription());
assertEquals("var2", sf.getValue("ID"));
assertEquals("Dodgy", sf.getValue("clinical_significance"));
sf.links.get(0));
assertEquals(dbSnp, sf.getFeatureGroup());
+ // AAA -> GAA -> K/E
sf = sfs.get(2);
assertEquals(1, sf.getBegin());
assertEquals(1, sf.getEnd());
+ assertEquals("nonsynonymous_variant", sf.getType());
assertEquals("p.Lys1Glu", sf.getDescription());
assertEquals("var1.125A>G", sf.getValue("ID"));
assertNull(sf.getValue("clinical_significance"));
sf.links.get(0));
assertEquals(ensembl, sf.getFeatureGroup());
+ // AAA -> TAA -> stop codon
sf = sfs.get(3);
+ assertEquals(1, sf.getBegin());
+ assertEquals(1, sf.getEnd());
+ assertEquals("stop_gained", sf.getType());
+ assertEquals("Aaa/Taa", sf.getDescription());
+ assertEquals("var3", sf.getValue("ID"));
+ assertEquals("Bad", sf.getValue("clinical_significance"));
+ assertEquals("ID=var3;clinical_significance=Bad", sf.getAttributes());
+ assertEquals(1, sf.links.size());
+ assertEquals(
+ "Aaa/Taa var3|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var3",
+ sf.links.get(0));
+ assertEquals(dbSnp, sf.getFeatureGroup());
+
+ // AAA -> AAG synonymous
+ sf = sfs.get(4);
+ assertEquals(1, sf.getBegin());
+ assertEquals(1, sf.getEnd());
+ assertEquals("synonymous_variant", sf.getType());
+ assertEquals("aaA/aaG", sf.getDescription());
+ assertEquals("var4", sf.getValue("ID"));
+ assertEquals("None", sf.getValue("clinical_significance"));
+ assertEquals("ID=var4;clinical_significance=None", sf.getAttributes());
+ assertEquals(1, sf.links.size());
+ assertEquals(
+ "aaA/aaG var4|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var4",
+ sf.links.get(0));
+ assertEquals(cosmic, sf.getFeatureGroup());
+
+ // TTT -> TTC synonymous
+ sf = sfs.get(5);
+ assertEquals(2, sf.getBegin());
+ assertEquals(2, sf.getEnd());
+ assertEquals("synonymous_variant", sf.getType());
+ assertEquals("ttT/ttC", sf.getDescription());
+ assertEquals("var6", sf.getValue("ID"));
+ assertNull(sf.getValue("clinical_significance"));
+ assertEquals("ID=var6", sf.getAttributes());
+ assertEquals(1, sf.links.size());
+ assertEquals(
+ "ttT/ttC var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
+ sf.links.get(0));
+ assertEquals(dbSnp, sf.getFeatureGroup());
+
+ // var7 generates two distinct protein variant features (two alleles)
+ // CCC -> CGC -> P/R
+ sf = sfs.get(6);
assertEquals(3, sf.getBegin());
assertEquals(3, sf.getEnd());
+ assertEquals("nonsynonymous_variant", sf.getType());
assertEquals("p.Pro3Arg", sf.getDescription());
- assertEquals("var6", sf.getValue("ID"));
+ assertEquals("var7", sf.getValue("ID"));
assertEquals("Good", sf.getValue("clinical_significance"));
- assertEquals("ID=var6;clinical_significance=Good", sf.getAttributes());
+ assertEquals("ID=var7;clinical_significance=Good", sf.getAttributes());
assertEquals(1, sf.links.size());
assertEquals(
- "p.Pro3Arg var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
+ "p.Pro3Arg var7|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var7",
sf.links.get(0));
assertEquals(cosmic, sf.getFeatureGroup());
- // var5 generates two distinct protein variant features
- sf = sfs.get(4);
+ // CCC -> CAC -> P/H
+ sf = sfs.get(7);
assertEquals(3, sf.getBegin());
assertEquals(3, sf.getEnd());
+ assertEquals("nonsynonymous_variant", sf.getType());
assertEquals("p.Pro3His", sf.getDescription());
- assertEquals("var6", sf.getValue("ID"));
+ assertEquals("var7", sf.getValue("ID"));
assertEquals("Good", sf.getValue("clinical_significance"));
- assertEquals("ID=var6;clinical_significance=Good", sf.getAttributes());
+ assertEquals("ID=var7;clinical_significance=Good", sf.getAttributes());
assertEquals(1, sf.links.size());
assertEquals(
- "p.Pro3His var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
+ "p.Pro3His var7|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var7",
sf.links.get(0));
assertEquals(cosmic, sf.getFeatureGroup());
}
seq1.createDatasetSequence();
Mapping mapping = new Mapping(seq1, new MapList(
new int[] { 3, 6, 9, 10 }, new int[] { 1, 6 }, 1, 1));
- Map<Integer, Map<SequenceI, Character>> map = new TreeMap<Integer, Map<SequenceI, Character>>();
+ Map<Integer, Map<SequenceI, Character>> map = new TreeMap<>();
AlignmentUtils.addMappedPositions(seq1, from, mapping, map);
/*
seq1.createDatasetSequence();
Mapping mapping = new Mapping(seq1, new MapList(
new int[] { 3, 6, 9, 10 }, new int[] { 1, 6 }, 1, 1));
- Map<Integer, Map<SequenceI, Character>> map = new TreeMap<Integer, Map<SequenceI, Character>>();
+ Map<Integer, Map<SequenceI, Character>> map = new TreeMap<>();
AlignmentUtils.addMappedPositions(seq1, from, mapping, map);
/*
assertEquals(s_as3, uas3.getSequenceAsString());
}
+ @Test(groups = { "Functional" })
+ public void testTransferGeneLoci()
+ {
+ SequenceI from = new Sequence("transcript",
+ "aaacccgggTTTAAACCCGGGtttaaacccgggttt");
+ SequenceI to = new Sequence("CDS", "TTTAAACCCGGG");
+ MapList map = new MapList(new int[] { 1, 12 }, new int[] { 10, 21 }, 1,
+ 1);
+
+ /*
+ * first with nothing to transfer
+ */
+ AlignmentUtils.transferGeneLoci(from, map, to);
+ assertNull(to.getGeneLoci());
+
+ /*
+ * next with gene loci set on 'from' sequence
+ */
+ int[] exons = new int[] { 100, 105, 155, 164, 210, 229 };
+ MapList geneMap = new MapList(new int[] { 1, 36 }, exons, 1, 1);
+ from.setGeneLoci("human", "GRCh38", "7", geneMap);
+ AlignmentUtils.transferGeneLoci(from, map, to);
+
+ GeneLociI toLoci = to.getGeneLoci();
+ assertNotNull(toLoci);
+ // DBRefEntry constructor upper-cases 'source'
+ assertEquals("HUMAN", toLoci.getSpeciesId());
+ assertEquals("GRCh38", toLoci.getAssemblyId());
+ assertEquals("7", toLoci.getChromosomeId());
+
+ /*
+ * transcript 'exons' are 1-6, 7-16, 17-36
+ * CDS 1:12 is transcript 10-21
+ * transcript 'CDS' is 10-16, 17-21
+ * which is 'gene' 158-164, 210-214
+ */
+ MapList toMap = toLoci.getMap();
+ assertEquals(1, toMap.getFromRanges().size());
+ assertEquals(2, toMap.getFromRanges().get(0).length);
+ assertEquals(1, toMap.getFromRanges().get(0)[0]);
+ assertEquals(12, toMap.getFromRanges().get(0)[1]);
+ assertEquals(2, toMap.getToRanges().size());
+ assertEquals(2, toMap.getToRanges().get(0).length);
+ assertEquals(158, toMap.getToRanges().get(0)[0]);
+ assertEquals(164, toMap.getToRanges().get(0)[1]);
+ assertEquals(210, toMap.getToRanges().get(1)[0]);
+ assertEquals(214, toMap.getToRanges().get(1)[1]);
+ // or summarised as (but toString might change in future):
+ assertEquals("[ [1, 12] ] 1:1 to [ [158, 164] [210, 214] ]",
+ toMap.toString());
+
+ /*
+ * an existing value is not overridden
+ */
+ geneMap = new MapList(new int[] { 1, 36 }, new int[] { 36, 1 }, 1, 1);
+ from.setGeneLoci("inhuman", "GRCh37", "6", geneMap);
+ AlignmentUtils.transferGeneLoci(from, map, to);
+ assertEquals("GRCh38", toLoci.getAssemblyId());
+ assertEquals("7", toLoci.getChromosomeId());
+ toMap = toLoci.getMap();
+ assertEquals("[ [1, 12] ] 1:1 to [ [158, 164] [210, 214] ]",
+ toMap.toString());
+ }
+
/**
* Tests for the method that maps nucleotide to protein based on CDS features
*/
* Case 2: CDS 3 times length of peptide + stop codon
* (note code does not currently check trailing codon is a stop codon)
*/
- dna = new Sequence("dna", "AACGacgtCTCCTTGA");
+ dna = new Sequence("dna", "AACGacgtCTCCTCCC");
dna.createDatasetSequence();
dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null));
dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 16, null));
Arrays.deepToString(ml.getFromRanges().toArray()));
/*
- * Case 3: CDS not 3 times length of peptide - no mapping is made
+ * Case 3: CDS longer than 3 * peptide + stop codon - no mapping is made
+ */
+ dna = new Sequence("dna", "AACGacgtCTCCTTGATCA");
+ dna.createDatasetSequence();
+ dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null));
+ dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 19, null));
+ ml = AlignmentUtils.mapCdsToProtein(dna, peptide);
+ assertNull(ml);
+
+ /*
+ * Case 4: CDS shorter than 3 * peptide - no mapping is made
+ */
+ dna = new Sequence("dna", "AACGacgtCTCC");
+ dna.createDatasetSequence();
+ dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null));
+ dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 12, null));
+ ml = AlignmentUtils.mapCdsToProtein(dna, peptide);
+ assertNull(ml);
+
+ /*
+ * Case 5: CDS 3 times length of peptide + part codon - mapping is truncated
*/
dna = new Sequence("dna", "AACGacgtCTCCTTG");
dna.createDatasetSequence();
dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null));
dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 15, null));
ml = AlignmentUtils.mapCdsToProtein(dna, peptide);
- assertNull(ml);
+ assertEquals(3, ml.getFromRatio());
+ assertEquals(1, ml.getToRatio());
+ assertEquals("[[1, 3]]",
+ Arrays.deepToString(ml.getToRanges().toArray()));
+ assertEquals("[[1, 4], [9, 13]]",
+ Arrays.deepToString(ml.getFromRanges().toArray()));
/*
- * Case 4: incomplete start codon corresponding to X in peptide
+ * Case 6: incomplete start codon corresponding to X in peptide
*/
dna = new Sequence("dna", "ACGacgtCTCCTTGG");
dna.createDatasetSequence();
Arrays.deepToString(ml.getFromRanges().toArray()));
}
+ /**
+ * Tests for the method that locates the CDS sequence that has a mapping to
+ * the given protein. That is, given a transcript-to-peptide mapping, find the
+ * cds-to-peptide mapping that relates to both, and return the CDS sequence.
+ */
+ @Test
+ public void testFindCdsForProtein()
+ {
+ List<AlignedCodonFrame> mappings = new ArrayList<>();
+ AlignedCodonFrame acf1 = new AlignedCodonFrame();
+ mappings.add(acf1);
+
+ SequenceI dna1 = new Sequence("dna1", "cgatATcgGCTATCTATGacg");
+ dna1.createDatasetSequence();
+
+ // NB we currently exclude STOP codon from CDS sequences
+ // the test would need to change if this changes in future
+ SequenceI cds1 = new Sequence("cds1", "ATGCTATCT");
+ cds1.createDatasetSequence();
+
+ SequenceI pep1 = new Sequence("pep1", "MLS");
+ pep1.createDatasetSequence();
+ List<AlignedCodonFrame> seqMappings = new ArrayList<>();
+ MapList mapList = new MapList(
+ new int[]
+ { 5, 6, 9, 15 }, new int[] { 1, 3 }, 3, 1);
+ Mapping dnaToPeptide = new Mapping(pep1.getDatasetSequence(), mapList);
+
+ // add dna to peptide mapping
+ seqMappings.add(acf1);
+ acf1.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(),
+ mapList);
+
+ /*
+ * first case - no dna-to-CDS mapping exists - search fails
+ */
+ SequenceI seq = AlignmentUtils.findCdsForProtein(mappings, dna1,
+ seqMappings, dnaToPeptide);
+ assertNull(seq);
+
+ /*
+ * second case - CDS-to-peptide mapping exists but no dna-to-CDS
+ * - search fails
+ */
+ // todo this test fails if the mapping is added to acf1, not acf2
+ // need to tidy up use of lists of mappings in AlignedCodonFrame
+ AlignedCodonFrame acf2 = new AlignedCodonFrame();
+ mappings.add(acf2);
+ MapList cdsToPeptideMapping = new MapList(new int[]
+ { 1, 9 }, new int[] { 1, 3 }, 3, 1);
+ acf2.addMap(cds1.getDatasetSequence(), pep1.getDatasetSequence(),
+ cdsToPeptideMapping);
+ assertNull(AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings,
+ dnaToPeptide));
+
+ /*
+ * third case - add dna-to-CDS mapping - CDS is now found!
+ */
+ MapList dnaToCdsMapping = new MapList(new int[] { 5, 6, 9, 15 },
+ new int[]
+ { 1, 9 }, 1, 1);
+ acf1.addMap(dna1.getDatasetSequence(), cds1.getDatasetSequence(),
+ dnaToCdsMapping);
+ seq = AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings,
+ dnaToPeptide);
+ assertSame(seq, cds1.getDatasetSequence());
+ }
+
+ /**
+ * Tests for the method that locates the CDS sequence that has a mapping to
+ * the given protein. That is, given a transcript-to-peptide mapping, find the
+ * cds-to-peptide mapping that relates to both, and return the CDS sequence.
+ * This test is for the case where transcript and CDS are the same length.
+ */
+ @Test
+ public void testFindCdsForProtein_noUTR()
+ {
+ List<AlignedCodonFrame> mappings = new ArrayList<>();
+ AlignedCodonFrame acf1 = new AlignedCodonFrame();
+ mappings.add(acf1);
+
+ SequenceI dna1 = new Sequence("dna1", "ATGCTATCTTAA");
+ dna1.createDatasetSequence();
+
+ // NB we currently exclude STOP codon from CDS sequences
+ // the test would need to change if this changes in future
+ SequenceI cds1 = new Sequence("cds1", "ATGCTATCT");
+ cds1.createDatasetSequence();
+
+ SequenceI pep1 = new Sequence("pep1", "MLS");
+ pep1.createDatasetSequence();
+ List<AlignedCodonFrame> seqMappings = new ArrayList<>();
+ MapList mapList = new MapList(
+ new int[]
+ { 1, 9 }, new int[] { 1, 3 }, 3, 1);
+ Mapping dnaToPeptide = new Mapping(pep1.getDatasetSequence(), mapList);
+
+ // add dna to peptide mapping
+ seqMappings.add(acf1);
+ acf1.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(),
+ mapList);
+
+ /*
+ * first case - transcript lacks CDS features - it appears to be
+ * the CDS sequence and is returned
+ */
+ SequenceI seq = AlignmentUtils.findCdsForProtein(mappings, dna1,
+ seqMappings, dnaToPeptide);
+ assertSame(seq, dna1.getDatasetSequence());
+
+ /*
+ * second case - transcript has CDS feature - this means it is
+ * not returned as a match for CDS (CDS sequences don't have CDS features)
+ */
+ dna1.addSequenceFeature(
+ new SequenceFeature(SequenceOntologyI.CDS, "cds", 1, 12, null));
+ seq = AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings,
+ dnaToPeptide);
+ assertNull(seq);
+
+ /*
+ * third case - CDS-to-peptide mapping exists but no dna-to-CDS
+ * - search fails
+ */
+ // todo this test fails if the mapping is added to acf1, not acf2
+ // need to tidy up use of lists of mappings in AlignedCodonFrame
+ AlignedCodonFrame acf2 = new AlignedCodonFrame();
+ mappings.add(acf2);
+ MapList cdsToPeptideMapping = new MapList(new int[]
+ { 1, 9 }, new int[] { 1, 3 }, 3, 1);
+ acf2.addMap(cds1.getDatasetSequence(), pep1.getDatasetSequence(),
+ cdsToPeptideMapping);
+ assertNull(AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings,
+ dnaToPeptide));
+
+ /*
+ * fourth case - add dna-to-CDS mapping - CDS is now found!
+ */
+ MapList dnaToCdsMapping = new MapList(new int[] { 1, 9 },
+ new int[]
+ { 1, 9 }, 1, 1);
+ acf1.addMap(dna1.getDatasetSequence(), cds1.getDatasetSequence(),
+ dnaToCdsMapping);
+ seq = AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings,
+ dnaToPeptide);
+ assertSame(seq, cds1.getDatasetSequence());
+ }
}
public void testFindXrefSourcesForSequence_proteinToDna()
{
SequenceI seq = new Sequence("Seq1", "MGKYQARLSS");
- List<String> sources = new ArrayList<String>();
+ List<String> sources = new ArrayList<>();
AlignmentI al = new Alignment(new SequenceI[] {});
/*
sources = new CrossRef(new SequenceI[] { seq }, al)
.findXrefSourcesForSequences(false);
// method is patched to remove EMBL from the sources to match
- assertEquals(3, sources.size());
- assertEquals("[EMBLCDS, GENEDB, ENSEMBL]", sources.toString());
+ assertEquals(4, sources.size());
+ assertEquals("[EMBLCDS, GENEDB, ENSEMBL, ENSEMBLGENOMES]",
+ sources.toString());
/*
* add a sequence to the alignment which has a dbref to UNIPROT|A1234
pep1.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2"));
AlignmentI al = new Alignment(new SequenceI[] { dna1, pep1 });
- List<SequenceI> result = new ArrayList<SequenceI>();
+ List<SequenceI> result = new ArrayList<>();
/*
* first search for a dbref nowhere on the alignment:
* argument false suppresses adding DAS sources
* todo: define an interface type SequenceFetcherI and mock that
*/
- SequenceFetcher mockFetcher = new SequenceFetcher(false)
+ SequenceFetcher mockFetcher = new SequenceFetcher()
{
@Override
public boolean isFetchable(String source)
* argument false suppresses adding DAS sources
* todo: define an interface type SequenceFetcherI and mock that
*/
- SequenceFetcher mockFetcher = new SequenceFetcher(false)
+ SequenceFetcher mockFetcher = new SequenceFetcher()
{
@Override
public boolean isFetchable(String source)
* passed in calls to getSequences() - important to verify that
* duplicate sequence fetches are not requested
*/
- SequenceFetcher mockFetcher = new SequenceFetcher(false)
+ SequenceFetcher mockFetcher = new SequenceFetcher()
{
int call = 0;
import jalview.io.FormatAdapter;
import java.io.IOException;
+import java.util.Iterator;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
FileFormat.Fasta);
HiddenColumns cs = new HiddenColumns();
AlignViewportI av = new AlignViewport(alf, cs);
- Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 });
+ Iterator<int[]> contigs = cs.getVisContigsIterator(0, alf.getWidth(),
+ false);
+ Dna dna = new Dna(av, contigs);
AlignmentI translated = dna.translateCdna();
assertNotNull("Couldn't do a full width translation of test data.",
translated);
cs.hideColumns(0, ipos - 1);
}
cs.hideColumns(ipos + vwidth, alf.getWidth());
- int[] vcontigs = cs.getVisibleContigs(0, alf.getWidth());
+ Iterator<int[]> vcontigs = cs.getVisContigsIterator(0,
+ alf.getWidth(), false);
AlignViewportI av = new AlignViewport(alf, cs);
Dna dna = new Dna(av, vcontigs);
AlignmentI transAlf = dna.translateCdna();
DataSourceType.PASTE, FileFormat.Fasta);
HiddenColumns cs = new HiddenColumns();
AlignViewportI av = new AlignViewport(alf, cs);
- Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 });
+ Iterator<int[]> contigs = cs.getVisContigsIterator(0, alf.getWidth(),
+ false);
+ Dna dna = new Dna(av, contigs);
AlignmentI translated = dna.translateCdna();
String aa = translated.getSequenceAt(0).getSequenceAsString();
assertEquals(
cs.hideColumns(24, 35); // hide codons 9-12
cs.hideColumns(177, 191); // hide codons 60-64
AlignViewportI av = new AlignViewport(alf, cs);
- Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 });
+ Iterator<int[]> contigs = cs.getVisContigsIterator(0, alf.getWidth(),
+ false);
+ Dna dna = new Dna(av, contigs);
AlignmentI translated = dna.translateCdna();
String aa = translated.getSequenceAt(0).getSequenceAsString();
assertEquals("AACDDGGGGHHIIIKKLLLLLLMNNPPPPQQRRRRRRSSSSSSTTTTVVVVW", aa);
.generate(12, 8, 97, 5, 5);
HiddenColumns cs = new HiddenColumns();
AlignViewportI av = new AlignViewport(cdna, cs);
- Dna dna = new Dna(av, new int[] { 0, cdna.getWidth() - 1 });
+ Iterator<int[]> contigs = cs.getVisContigsIterator(0, cdna.getWidth(),
+ false);
+ Dna dna = new Dna(av, contigs);
AlignmentI translated = dna.translateCdna();
/*
}
AlignmentI cdnaReordered = new Alignment(sorted);
av = new AlignViewport(cdnaReordered, cs);
- dna = new Dna(av, new int[] { 0, cdna.getWidth() - 1 });
+ contigs = cs.getVisContigsIterator(0, cdna.getWidth(), false);
+ dna = new Dna(av, contigs);
AlignmentI translated2 = dna.translateCdna();
/*
HiddenColumns cs = new HiddenColumns();
AlignViewportI av = new AlignViewport(al, cs);
- Dna testee = new Dna(av, new int[] { 0, al.getWidth() - 1 });
+ Iterator<int[]> contigs = cs.getVisContigsIterator(0, al.getWidth(),
+ false);
+ Dna testee = new Dna(av, contigs);
AlignmentI reversed = testee.reverseCdna(false);
assertEquals(1, reversed.getHeight());
assertEquals(seqRev, reversed.getSequenceAt(0).getSequenceAsString());
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ScanResult;
+
public class CommandLineOperations
{
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- private static final int TEST_TIMEOUT = 4500; // Note longer timeout needed on
+ private static final int TEST_TIMEOUT = 9000; // Note longer timeout needed on
// full test run than on
// individual tests
private static final int MINFILESIZE_BIG = 4096;
- private ArrayList<String> successfulCMDs = new ArrayList<String>();
+ private ArrayList<String> successfulCMDs = new ArrayList<>();
/***
* from
}
}
+ private static ClassGraph scanner = null;
+
+ private static String classpath = null;
+
+ public synchronized static String getClassPath()
+ {
+ if (scanner == null)
+ {
+ scanner = new ClassGraph();
+ ScanResult scan = scanner.scan();
+ classpath = scan.getClasspath();
+ }
+ while (classpath == null)
+ {
+ try
+ {
+ Thread.sleep(10);
+ } catch (InterruptedException x)
+ {
+
+ }
+ }
+ return classpath;
+ }
private Worker jalviewDesktopRunner(boolean withAwt, String cmd,
int timeout)
{
+ // Note: JAL-3065 - don't include quotes for lib/* because the arguments are
+ // not expanded by the shell
+ String classpath = getClassPath();
String _cmd = "java "
+ (withAwt ? "-Djava.awt.headless=true" : "")
- + " -Djava.ext.dirs=./lib -classpath ./classes jalview.bin.Jalview ";
- System.out.println("CMD [" + cmd + "]");
+ + " -classpath " + classpath + " jalview.bin.Jalview ";
Process ls2_proc = null;
Worker worker = null;
try
package jalview.commands;
import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
import jalview.commands.EditCommand.Action;
import jalview.commands.EditCommand.Edit;
import jalview.datamodel.features.SequenceFeatures;
import jalview.gui.JvOptionPane;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
*/
public class EditCommandTest
{
+ private static Comparator<SequenceFeature> BY_DESCRIPTION = new Comparator<SequenceFeature>()
+ {
+
+ @Override
+ public int compare(SequenceFeature o1, SequenceFeature o2)
+ {
+ return o1.getDescription().compareTo(o2.getDescription());
+ }
+ };
+
+ private EditCommand testee;
+
+ private SequenceI[] seqs;
+
+ private Alignment al;
+
/*
* compute n(n+1)/2 e.g.
* func(5) = 5 + 4 + 3 + 2 + 1 = 15
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- private EditCommand testee;
-
- private SequenceI[] seqs;
-
- private Alignment al;
-
@BeforeMethod(alwaysRun = true)
public void setUp()
{
}
/**
- * Test a Paste action, where this adds sequences to an alignment.
+ * Test a Paste action, followed by Undo and Redo
*/
@Test(groups = { "Functional" }, enabled = false)
- // TODO fix so it works
- public void testPaste_addToAlignment()
+ public void testPaste_undo_redo()
{
+ // TODO code this test properly, bearing in mind that:
+ // Paste action requires something on the clipboard (Cut/Copy)
+ // - EditCommand.paste doesn't add sequences to the alignment
+ // ... that is done in AlignFrame.paste()
+ // ... unless as a Redo
+ // ...
+
SequenceI[] newSeqs = new SequenceI[2];
newSeqs[0] = new Sequence("newseq0", "ACEFKL");
newSeqs[1] = new Sequence("newseq1", "JWMPDH");
- Edit ec = testee.new Edit(Action.PASTE, newSeqs, 0, al.getWidth(), al);
- EditCommand.paste(ec, new AlignmentI[] { al });
+ new EditCommand("Paste", Action.PASTE, newSeqs, 0, al.getWidth(), al);
assertEquals(6, al.getSequences().size());
assertEquals("1234567890", seqs[3].getSequenceAsString());
assertEquals("ACEFKL", seqs[4].getSequenceAsString());
{
// seem to need a dataset sequence on the edited sequence here
seqs[1].createDatasetSequence();
- new EditCommand("", Action.REPLACE, "ZXY", new SequenceI[] { seqs[1] },
+ assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
+ // NB command.number holds end position for a Replace command
+ new EditCommand("", Action.REPLACE, "Z-xY", new SequenceI[] { seqs[1] },
4, 8, al);
assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
+ assertEquals("fghjZ-xYopq", seqs[1].getSequenceAsString());
+ assertEquals("fghjZxYopq",
+ seqs[1].getDatasetSequence().getSequenceAsString());
assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
assertEquals("1234567890", seqs[3].getSequenceAsString());
- seqs[1] = new Sequence("seq1", "fghjZXYnopq");
+ }
+
+ /**
+ * Test the replace command (used to manually edit a sequence)
+ */
+ @Test(groups = { "Functional" })
+ public void testReplace_withGaps()
+ {
+ SequenceI seq = new Sequence("seq", "ABC--DEF");
+ seq.createDatasetSequence();
+ assertEquals("ABCDEF", seq.getDatasetSequence().getSequenceAsString());
+ assertEquals(1, seq.getStart());
+ assertEquals(6, seq.getEnd());
+
+ /*
+ * replace C- with XYZ
+ * NB arg4 = start column of selection for edit (base 0)
+ * arg5 = column after end of selection for edit
+ */
+ EditCommand edit = new EditCommand("", Action.REPLACE, "xyZ",
+ new SequenceI[]
+ { seq }, 2,
+ 4, al);
+ assertEquals("ABxyZ-DEF", seq.getSequenceAsString());
+ assertEquals(1, seq.getStart());
+ assertEquals(8, seq.getEnd());
+ assertEquals("ABxyZDEF",
+ seq.getDatasetSequence().getSequenceAsString());
+ assertEquals(8, seq.getDatasetSequence().getEnd());
+
+ /*
+ * undo the edit
+ */
+ AlignmentI[] views = new AlignmentI[]
+ { new Alignment(new SequenceI[] { seq }) };
+ edit.undoCommand(views);
+
+ assertEquals("ABC--DEF", seq.getSequenceAsString());
+ assertEquals("ABCDEF", seq.getDatasetSequence().getSequenceAsString());
+ assertEquals(1, seq.getStart());
+ assertEquals(6, seq.getEnd());
+ assertEquals(6, seq.getDatasetSequence().getEnd());
+
+ /*
+ * redo the edit
+ */
+ edit.doCommand(views);
+
+ assertEquals("ABxyZ-DEF", seq.getSequenceAsString());
+ assertEquals(1, seq.getStart());
+ assertEquals(8, seq.getEnd());
+ assertEquals("ABxyZDEF",
+ seq.getDatasetSequence().getSequenceAsString());
+ assertEquals(8, seq.getDatasetSequence().getEnd());
+
+ }
+
+ /**
+ * Test replace command when it doesn't cause a sequence edit (see comment in
+ */
+ @Test(groups = { "Functional" })
+ public void testReplaceFirstResiduesWithGaps()
+ {
+ // test replace when gaps are inserted at start. Start/end should change
+ // w.r.t. original edited sequence.
+ SequenceI dsseq = seqs[1].getDatasetSequence();
+ EditCommand edit = new EditCommand("", Action.REPLACE, "----",
+ new SequenceI[]
+ { seqs[1] }, 0, 4, al);
+
+ // trimmed start
+ assertEquals("----klmnopq", seqs[1].getSequenceAsString());
+ // and ds is preserved
+ assertTrue(dsseq == seqs[1].getDatasetSequence());
+ // and it is unchanged
+ assertEquals("fghjklmnopq", dsseq.getSequenceAsString());
+ // and that alignment sequence start has been adjusted
+ assertEquals(5, seqs[1].getStart());
+ assertEquals(11, seqs[1].getEnd());
+
+ AlignmentI[] views = new AlignmentI[] { new Alignment(seqs) };
+ // and undo
+ edit.undoCommand(views);
+
+ // dataset sequence unchanged
+ assertTrue(dsseq == seqs[1].getDatasetSequence());
+ // restore sequence
+ assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
+ // and start/end numbering also restored
+ assertEquals(1, seqs[1].getStart());
+ assertEquals(11, seqs[1].getEnd());
+
+ // now redo
+ edit.undoCommand(views);
+
+ // and repeat asserts for the original edit
+
+ // trimmed start
+ assertEquals("----klmnopq", seqs[1].getSequenceAsString());
+ // and ds is preserved
+ assertTrue(dsseq == seqs[1].getDatasetSequence());
+ // and it is unchanged
+ assertEquals("fghjklmnopq", dsseq.getSequenceAsString());
+ // and that alignment sequence start has been adjusted
+ assertEquals(5, seqs[1].getStart());
+ assertEquals(11, seqs[1].getEnd());
+
}
/**
* create sequence features before, after and overlapping
* a cut of columns/residues 4-7
*/
- SequenceI seq0 = seqs[0];
+ SequenceI seq0 = seqs[0]; // abcdefghjk/1-10
seq0.addSequenceFeature(new SequenceFeature("before", "", 1, 3, 0f,
null));
seq0.addSequenceFeature(new SequenceFeature("overlap left", "", 2, 6,
seq0.addSequenceFeature(new SequenceFeature("after", "", 8, 10, 0f,
null));
+ /*
+ * add some contact features
+ */
+ SequenceFeature internalContact = new SequenceFeature("disulphide bond", "", 5,
+ 6, 0f, null);
+ seq0.addSequenceFeature(internalContact); // should get deleted
+ SequenceFeature overlapLeftContact = new SequenceFeature(
+ "disulphide bond", "", 2, 6, 0f, null);
+ seq0.addSequenceFeature(overlapLeftContact); // should get deleted
+ SequenceFeature overlapRightContact = new SequenceFeature(
+ "disulphide bond", "", 5, 8, 0f, null);
+ seq0.addSequenceFeature(overlapRightContact); // should get deleted
+ SequenceFeature spanningContact = new SequenceFeature(
+ "disulphide bond", "", 2, 9, 0f, null);
+ seq0.addSequenceFeature(spanningContact); // should get shortened 3'
+
+ /*
+ * cut columns 3-6 (base 0), residues d-g 4-7
+ */
Edit ec = testee.new Edit(Action.CUT, seqs, 3, 4, al); // cols 3-6 base 0
EditCommand.cut(ec, new AlignmentI[] { al });
List<SequenceFeature> sfs = seq0.getSequenceFeatures();
SequenceFeatures.sortFeatures(sfs, true);
- assertEquals(4, sfs.size()); // feature internal to cut has been deleted
+ assertEquals(5, sfs.size()); // features internal to cut were deleted
SequenceFeature sf = sfs.get(0);
assertEquals("before", sf.getType());
assertEquals(1, sf.getBegin());
assertEquals(3, sf.getEnd());
sf = sfs.get(1);
+ assertEquals("disulphide bond", sf.getType());
+ assertEquals(2, sf.getBegin());
+ assertEquals(5, sf.getEnd()); // truncated by cut
+ sf = sfs.get(2);
assertEquals("overlap left", sf.getType());
assertEquals(2, sf.getBegin());
assertEquals(3, sf.getEnd()); // truncated by cut
- sf = sfs.get(2);
- assertEquals("overlap right", sf.getType());
- assertEquals(4, sf.getBegin()); // shifted left by cut
- assertEquals(5, sf.getEnd()); // truncated by cut
sf = sfs.get(3);
assertEquals("after", sf.getType());
assertEquals(4, sf.getBegin()); // shifted left by cut
assertEquals(6, sf.getEnd()); // shifted left by cut
+ sf = sfs.get(4);
+ assertEquals("overlap right", sf.getType());
+ assertEquals(4, sf.getBegin()); // shifted left by cut
+ assertEquals(4, sf.getEnd()); // truncated by cut
}
/**
* create a sequence features on each subrange of 1-5
*/
SequenceI seq0 = new Sequence("seq", "ABCDE");
+ int start = 8;
+ int end = 12;
+ seq0.setStart(start);
+ seq0.setEnd(end);
AlignmentI alignment = new Alignment(new SequenceI[] { seq0 });
alignment.setDataset(null);
- for (int from = 1; from <= seq0.getLength(); from++)
+
+ /*
+ * create a new alignment with shared dataset sequence
+ */
+ AlignmentI copy = new Alignment(
+ new SequenceI[]
+ { alignment.getDataset().getSequenceAt(0).deriveSequence() });
+ SequenceI copySeq0 = copy.getSequenceAt(0);
+
+ for (int from = start; from <= end; from++)
{
- for (int to = from; to <= seq0.getLength(); to++)
+ for (int to = from; to <= end; to++)
{
String desc = String.format("%d-%d", from, to);
SequenceFeature sf = new SequenceFeature("test", desc, from, to,
- 0f,
- null);
+ 0f, null);
sf.setValue("from", Integer.valueOf(from));
sf.setValue("to", Integer.valueOf(to));
seq0.addSequenceFeature(sf);
// sanity check
List<SequenceFeature> sfs = seq0.getSequenceFeatures();
assertEquals(func(5), sfs.size());
+ assertEquals(sfs, copySeq0.getSequenceFeatures());
+ String copySequenceFeatures = copySeq0.getSequenceFeatures().toString();
/*
- * now perform all possible cuts of subranges of 1-5 (followed by Undo)
+ * now perform all possible cuts of subranges of columns 1-5
* and validate the resulting remaining sequence features!
*/
SequenceI[] sqs = new SequenceI[] { seq0 };
- // goal is to have this passing for all from/to values!!
- // for (int from = 0; from < seq0.getLength(); from++)
- // {
- // for (int to = from; to < seq0.getLength(); to++)
- for (int from = 1; from < 3; from++)
+ for (int from = 0; from < seq0.getLength(); from++)
{
- for (int to = 2; to < 3; to++)
+ for (int to = from; to < seq0.getLength(); to++)
{
- testee.appendEdit(Action.CUT, sqs, from, (to - from + 1),
- alignment, true);
+ EditCommand ec = new EditCommand("Cut", Action.CUT, sqs, from, (to
+ - from + 1), alignment);
+ final String msg = String.format("Cut %d-%d ", from + 1, to + 1);
+ boolean newDatasetSequence = copySeq0.getDatasetSequence() != seq0
+ .getDatasetSequence();
+
+ verifyCut(seq0, from, to, msg, start);
+
+ /*
+ * verify copy alignment dataset sequence unaffected
+ */
+ assertEquals("Original dataset sequence was modified",
+ copySequenceFeatures,
+ copySeq0.getSequenceFeatures().toString());
+ /*
+ * verify any new dataset sequence was added to the
+ * alignment dataset
+ */
+ assertEquals("Wrong Dataset size after " + msg,
+ newDatasetSequence ? 2 : 1,
+ alignment.getDataset().getHeight());
+
+ /*
+ * undo and verify all restored
+ */
+ AlignmentI[] views = new AlignmentI[] { alignment };
+ ec.undoCommand(views);
sfs = seq0.getSequenceFeatures();
+ assertEquals("After undo of " + msg, func(5), sfs.size());
+ verifyUndo(from, to, sfs);
+
+ /*
+ * verify copy alignment dataset sequence still unaffected
+ * and alignment dataset has shrunk (if it was added to)
+ */
+ assertEquals("Original dataset sequence was modified",
+ copySequenceFeatures,
+ copySeq0.getSequenceFeatures().toString());
+ assertEquals("Wrong Dataset size after Undo of " + msg, 1,
+ alignment.getDataset().getHeight());
/*
- * confirm the number of features has reduced by the
- * number of features within the cut region i.e. by
- * func(length of cut)
+ * redo and verify
*/
- String msg = String.format("Cut %d-%d ", from, to);
- if (to - from == 4)
- {
- // all columns cut
- assertNull(sfs);
- }
- else
- {
- assertEquals(msg + "wrong number of features left", func(5)
- - func(to - from + 1), sfs.size());
- }
+ ec.doCommand(views);
+ verifyCut(seq0, from, to, msg, start);
/*
- * inspect individual features
+ * verify copy alignment dataset sequence unaffected
+ * and any new dataset sequence readded to alignment dataset
*/
- if (sfs != null)
- {
- for (SequenceFeature sf : sfs)
- {
- checkFeatureRelocation(sf, from + 1, to + 1);
- }
- }
+ assertEquals("Original dataset sequence was modified",
+ copySequenceFeatures,
+ copySeq0.getSequenceFeatures().toString());
+ assertEquals("Wrong Dataset size after Redo of " + msg,
+ newDatasetSequence ? 2 : 1,
+ alignment.getDataset().getHeight());
+
/*
* undo ready for next cut
*/
- testee.undoCommand(new AlignmentI[] { alignment });
- assertEquals(func(5), seq0.getSequenceFeatures().size());
+ ec.undoCommand(views);
+
+ /*
+ * final verify that copy alignment dataset sequence is still unaffected
+ * and that alignment dataset has shrunk
+ */
+ assertEquals("Original dataset sequence was modified",
+ copySequenceFeatures,
+ copySeq0.getSequenceFeatures().toString());
+ assertEquals("Wrong Dataset size after final Undo of " + msg, 1,
+ alignment.getDataset().getHeight());
}
}
}
/**
+ * Verify by inspection that the sequence features left on the sequence after
+ * a cut match the expected results. The trick to this is that we can parse
+ * each feature's original start-end positions from its description.
+ *
+ * @param seq0
+ * @param from
+ * @param to
+ * @param msg
+ * @param seqStart
+ */
+ protected void verifyCut(SequenceI seq0, int from, int to,
+ final String msg, int seqStart)
+ {
+ List<SequenceFeature> sfs;
+ sfs = seq0.getSequenceFeatures();
+
+ Collections.sort(sfs, BY_DESCRIPTION);
+
+ /*
+ * confirm the number of features has reduced by the
+ * number of features within the cut region i.e. by
+ * func(length of cut); exception is a cut at start or end of sequence,
+ * which retains the original coordinates, dataset sequence
+ * and all its features
+ */
+ boolean datasetRetained = from == 0 || to == 4;
+ if (datasetRetained)
+ {
+ // dataset and all features retained
+ assertEquals(msg, func(5), sfs.size());
+ }
+ else if (to - from == 4)
+ {
+ // all columns were cut
+ assertTrue(sfs.isEmpty());
+ }
+ else
+ {
+ // failure in checkFeatureRelocation is more informative!
+ assertEquals(msg + "wrong number of features left", func(5)
+ - func(to - from + 1), sfs.size());
+ }
+
+ /*
+ * inspect individual features
+ */
+ for (SequenceFeature sf : sfs)
+ {
+ verifyFeatureRelocation(sf, from + 1, to + 1, !datasetRetained,
+ seqStart);
+ }
+ }
+
+ /**
+ * Check that after Undo, every feature has start/end that match its original
+ * "start" and "end" properties
+ *
+ * @param from
+ * @param to
+ * @param sfs
+ */
+ protected void verifyUndo(int from, int to, List<SequenceFeature> sfs)
+ {
+ for (SequenceFeature sf : sfs)
+ {
+ final int oldFrom = ((Integer) sf.getValue("from")).intValue();
+ final int oldTo = ((Integer) sf.getValue("to")).intValue();
+ String msg = String.format(
+ "Undo cut of [%d-%d], feature at [%d-%d] ", from + 1, to + 1,
+ oldFrom, oldTo);
+ assertEquals(msg + "start", oldFrom, sf.getBegin());
+ assertEquals(msg + "end", oldTo, sf.getEnd());
+ }
+ }
+
+ /**
* Helper method to check a feature has been correctly relocated after a cut
*
* @param sf
* @param from
- * start of cut (first residue cut)
+ * start of cut (first residue cut 1..)
* @param to
- * end of cut (last residue cut)
+ * end of cut (last residue cut 1..)
+ * @param newDataset
+ * @param seqStart
*/
- private void checkFeatureRelocation(SequenceFeature sf, int from, int to)
+ private void verifyFeatureRelocation(SequenceFeature sf, int from, int to,
+ boolean newDataset, int seqStart)
{
// TODO handle the gapped sequence case as well
int cutSize = to - from + 1;
- int oldFrom = ((Integer) sf.getValue("from")).intValue();
- int oldTo = ((Integer) sf.getValue("to")).intValue();
+ final int oldFrom = ((Integer) sf.getValue("from")).intValue();
+ final int oldTo = ((Integer) sf.getValue("to")).intValue();
+ final int oldFromPosition = oldFrom - seqStart + 1; // 1..
+ final int oldToPosition = oldTo - seqStart + 1; // 1..
String msg = String.format(
"Feature %s relocated to %d-%d after cut of %d-%d",
sf.getDescription(), sf.getBegin(), sf.getEnd(), from, to);
- if (oldTo < from)
+ if (!newDataset)
+ {
+ // dataset retained with all features unchanged
+ assertEquals("0: " + msg, oldFrom, sf.getBegin());
+ assertEquals("0: " + msg, oldTo, sf.getEnd());
+ }
+ else if (oldToPosition < from)
{
// before cut region so unchanged
assertEquals("1: " + msg, oldFrom, sf.getBegin());
assertEquals("2: " + msg, oldTo, sf.getEnd());
}
- else if (oldFrom > to)
+ else if (oldFromPosition > to)
{
// follows cut region - shift by size of cut
- assertEquals("3: " + msg, oldFrom - cutSize, sf.getBegin());
- assertEquals("4: " + msg, oldTo - cutSize, sf.getEnd());
+ assertEquals("3: " + msg, newDataset ? oldFrom - cutSize : oldFrom,
+ sf.getBegin());
+ assertEquals("4: " + msg, newDataset ? oldTo - cutSize : oldTo,
+ sf.getEnd());
}
- else if (oldFrom < from && oldTo > to)
+ else if (oldFromPosition < from && oldToPosition > to)
{
// feature encloses cut region - shrink it right
assertEquals("5: " + msg, oldFrom, sf.getBegin());
assertEquals("6: " + msg, oldTo - cutSize, sf.getEnd());
}
- else if (oldFrom < from)
+ else if (oldFromPosition < from)
{
// feature overlaps left side of cut region - truncated right
- assertEquals("7: " + msg, from - 1, sf.getEnd());
+ assertEquals("7: " + msg, from - 1 + seqStart - 1, sf.getEnd());
}
- else if (oldTo > to)
+ else if (oldToPosition > to)
{
// feature overlaps right side of cut region - truncated left
- assertEquals("8: " + msg, from, sf.getBegin());
- assertEquals("9: " + msg, from + oldTo - to - 1, sf.getEnd());
+ assertEquals("8: " + msg, newDataset ? from + seqStart - 1 : to + 1,
+ sf.getBegin());
+ assertEquals("9: " + msg, newDataset ? from + oldTo - to - 1 : oldTo,
+ sf.getEnd());
}
else
{
* Test a cut action's relocation of sequence features
*/
@Test(groups = { "Functional" })
- public void testCut_gappedWithFeatures()
+ public void testCut_withFeatures5prime()
{
+ SequenceI seq0 = new Sequence("seq/8-11", "A-BCC");
+ seq0.createDatasetSequence();
+ assertEquals(8, seq0.getStart());
+ seq0.addSequenceFeature(new SequenceFeature("", "", 10, 11, 0f,
+ null));
+ SequenceI[] seqsArray = new SequenceI[] { seq0 };
+ AlignmentI alignment = new Alignment(seqsArray);
+
/*
- * create sequence features before, after and overlapping
- * a cut of columns/residues 4-7
+ * cut columns of A-B; same dataset sequence is retained, aligned sequence
+ * start becomes 10
*/
- SequenceI seq0 = new Sequence("seq", "A-BCC");
- seq0.addSequenceFeature(new SequenceFeature("", "", 3, 4, 0f,
- null));
- AlignmentI alignment = new Alignment(new SequenceI[] { seq0 });
- // cut columns of A-B
- Edit ec = testee.new Edit(Action.CUT, seqs, 0, 3, alignment); // cols 0-3
- // base 0
+ Edit ec = testee.new Edit(Action.CUT, seqsArray, 0, 3, alignment);
EditCommand.cut(ec, new AlignmentI[] { alignment });
/*
- * feature on CC(3-4) should now be on CC(1-2)
+ * feature on CC(10-11) should still be on CC(10-11)
*/
+ assertSame(seq0, alignment.getSequenceAt(0));
+ assertEquals(10, seq0.getStart());
List<SequenceFeature> sfs = seq0.getSequenceFeatures();
assertEquals(1, sfs.size());
SequenceFeature sf = sfs.get(0);
- assertEquals(1, sf.getBegin());
- assertEquals(2, sf.getEnd());
-
- // TODO add further cases including Undo - see JAL-2541
+ assertEquals(10, sf.getBegin());
+ assertEquals(11, sf.getEnd());
}
}
import jalview.analysis.Finder;
import jalview.api.AlignViewControllerI;
+import jalview.api.FeatureColourI;
+import jalview.datamodel.Alignment;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.Sequence;
import jalview.gui.JvOptionPane;
import jalview.io.DataSourceType;
import jalview.io.FileLoader;
+import jalview.schemes.FeatureColour;
+import java.awt.Color;
import java.util.Arrays;
import java.util.BitSet;
null));
seq1.addSequenceFeature(new SequenceFeature("Helix", "desc", 1, 15, 0f,
null));
- seq2.addSequenceFeature(new SequenceFeature("Metal", "desc", 4, 10, 0f,
+ seq2.addSequenceFeature(new SequenceFeature("Metal", "desc", 4, 10,
+ 10f,
null));
seq3.addSequenceFeature(new SequenceFeature("Metal", "desc", 11, 15,
- 0f, null));
+ 10f, null));
// disulfide bond is a 'contact feature' - only select its 'start' and 'end'
- seq3.addSequenceFeature(new SequenceFeature("disulfide bond", "desc", 8, 12,
- 0f, null));
+ seq3.addSequenceFeature(new SequenceFeature("disulfide bond", "desc",
+ 8, 12, 0f, null));
/*
* select the first five columns --> Metal in seq1 cols 4-5
sg.addSequence(seq3, false);
sg.addSequence(seq4, false);
+ /*
+ * set features visible on a viewport as only visible features are selected
+ */
+ AlignFrame af = new AlignFrame(new Alignment(new SequenceI[] { seq1,
+ seq2, seq3, seq4 }), 100, 100);
+ af.getFeatureRenderer().findAllFeatures(true);
+
+ AlignViewController avc = new AlignViewController(af, af.getViewport(),
+ af.alignPanel);
+
BitSet bs = new BitSet();
- int seqCount = AlignViewController.findColumnsWithFeature("Metal", sg,
- bs);
+ int seqCount = avc.findColumnsWithFeature("Metal", sg, bs);
assertEquals(1, seqCount);
assertEquals(2, bs.cardinality());
assertTrue(bs.get(3)); // base 0
*/
sg.setEndRes(6);
bs.clear();
- seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
+ seqCount = avc.findColumnsWithFeature("Metal", sg, bs);
assertEquals(2, seqCount);
assertEquals(4, bs.cardinality());
assertTrue(bs.get(3));
sg.setStartRes(13);
sg.setEndRes(13);
bs.clear();
- seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
+ seqCount = avc.findColumnsWithFeature("Metal", sg, bs);
assertEquals(1, seqCount);
assertEquals(1, bs.cardinality());
assertTrue(bs.get(13));
sg.setStartRes(17);
sg.setEndRes(19);
bs.clear();
- seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
+ seqCount = avc.findColumnsWithFeature("Metal", sg, bs);
assertEquals(0, seqCount);
assertEquals(0, bs.cardinality());
/*
+ * threshold Metal to hide where score < 5
+ * seq1 feature in columns 4-6 is hidden
+ * seq2 feature in columns 6-7 is shown
+ */
+ FeatureColourI fc = new FeatureColour(Color.red, Color.blue, 0f, 10f);
+ fc.setAboveThreshold(true);
+ fc.setThreshold(5f);
+ af.getFeatureRenderer().setColour("Metal", fc);
+ sg.setStartRes(0);
+ sg.setEndRes(6);
+ bs.clear();
+ seqCount = avc.findColumnsWithFeature("Metal", sg, bs);
+ assertEquals(1, seqCount);
+ assertEquals(2, bs.cardinality());
+ assertTrue(bs.get(5));
+ assertTrue(bs.get(6));
+
+ /*
* columns 11-13 should not match disulfide bond at 8/12
*/
sg.setStartRes(10);
sg.setEndRes(12);
bs.clear();
- seqCount = AlignViewController.findColumnsWithFeature("disulfide bond",
- sg, bs);
+ seqCount = avc.findColumnsWithFeature("disulfide bond", sg, bs);
assertEquals(0, seqCount);
assertEquals(0, bs.cardinality());
sg.setStartRes(5);
sg.setEndRes(17);
bs.clear();
- seqCount = AlignViewController.findColumnsWithFeature("disulfide bond",
- sg, bs);
+ seqCount = avc.findColumnsWithFeature("disulfide bond", sg, bs);
assertEquals(1, seqCount);
assertEquals(2, bs.cardinality());
assertTrue(bs.get(8));
sg.setStartRes(0);
sg.setEndRes(19);
bs.clear();
- seqCount = AlignViewController.findColumnsWithFeature("Pfam", sg, bs);
+ seqCount = avc.findColumnsWithFeature("Pfam", sg, bs);
assertEquals(0, seqCount);
assertEquals(0, bs.cardinality());
}
*/
package jalview.datamodel;
+import static org.testng.Assert.assertNull;
import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertNull;
import jalview.analysis.AlignSeq;
import jalview.gui.JvOptionPane;
Assert.assertTrue(ann.isQuantitative(),
"Mixed 'E' annotation set should be quantitative.");
}
+
+ @Test(groups = "Functional")
+ public void testMakeVisibleAnnotation()
+ {
+ HiddenColumns h = new HiddenColumns();
+ Annotation[] anns = new Annotation[] { null, null, new Annotation(1),
+ new Annotation(2), new Annotation(3), null, null, new Annotation(4),
+ new Annotation(5), new Annotation(6), new Annotation(7),
+ new Annotation(8) };
+ AlignmentAnnotation ann = new AlignmentAnnotation("an", "some an",
+ anns);
+
+ // null annotations
+ AlignmentAnnotation emptyann = new AlignmentAnnotation("an", "some ann",
+ null);
+ emptyann.makeVisibleAnnotation(h);
+ assertNull(emptyann.annotations);
+
+ emptyann.makeVisibleAnnotation(3, 4, h);
+ assertNull(emptyann.annotations);
+
+ // without bounds, does everything
+ ann.makeVisibleAnnotation(h);
+ assertEquals(12, ann.annotations.length);
+ assertNull(ann.annotations[0]);
+ assertNull(ann.annotations[1]);
+ assertEquals(1.0f, ann.annotations[2].value);
+ assertEquals(2.0f, ann.annotations[3].value);
+ assertEquals(3.0f, ann.annotations[4].value);
+ assertNull(ann.annotations[5]);
+ assertNull(ann.annotations[6]);
+ assertEquals(4.0f, ann.annotations[7].value);
+ assertEquals(5.0f, ann.annotations[8].value);
+ assertEquals(6.0f, ann.annotations[9].value);
+ assertEquals(7.0f, ann.annotations[10].value);
+ assertEquals(8.0f, ann.annotations[11].value);
+
+ // without hidden cols, just truncates
+ ann.makeVisibleAnnotation(3, 5, h);
+ assertEquals(3, ann.annotations.length);
+ assertEquals(2.0f, ann.annotations[0].value);
+ assertEquals(3.0f, ann.annotations[1].value);
+ assertNull(ann.annotations[2]);
+
+ anns = new Annotation[] { null, null, new Annotation(1),
+ new Annotation(2), new Annotation(3), null, null, new Annotation(4),
+ new Annotation(5), new Annotation(6), new Annotation(7),
+ new Annotation(8) };
+ ann = new AlignmentAnnotation("an", "some an", anns);
+ h.hideColumns(4, 7);
+ ann.makeVisibleAnnotation(1, 9, h);
+ assertEquals(5, ann.annotations.length);
+ assertNull(ann.annotations[0]);
+ assertEquals(1.0f, ann.annotations[1].value);
+ assertEquals(2.0f, ann.annotations[2].value);
+ assertEquals(5.0f, ann.annotations[3].value);
+ assertEquals(6.0f, ann.annotations[4].value);
+
+ anns = new Annotation[] { null, null, new Annotation(1),
+ new Annotation(2), new Annotation(3), null, null, new Annotation(4),
+ new Annotation(5), new Annotation(6), new Annotation(7),
+ new Annotation(8) };
+ ann = new AlignmentAnnotation("an", "some an", anns);
+ h.hideColumns(1, 2);
+ ann.makeVisibleAnnotation(1, 9, h);
+ assertEquals(3, ann.annotations.length);
+ assertEquals(2.0f, ann.annotations[0].value);
+ assertEquals(5.0f, ann.annotations[1].value);
+ assertEquals(6.0f, ann.annotations[2].value);
+
+ anns = new Annotation[] { null, null, new Annotation(1),
+ new Annotation(2), new Annotation(3), null, null, new Annotation(4),
+ new Annotation(5), new Annotation(6), new Annotation(7),
+ new Annotation(8), new Annotation(9), new Annotation(10),
+ new Annotation(11), new Annotation(12), new Annotation(13),
+ new Annotation(14), new Annotation(15) };
+ ann = new AlignmentAnnotation("an", "some an", anns);
+ h = new HiddenColumns();
+ h.hideColumns(5, 18);
+ h.hideColumns(20, 21);
+ ann.makeVisibleAnnotation(1, 21, h);
+ assertEquals(5, ann.annotations.length);
+ assertEquals(1.0f, ann.annotations[1].value);
+ assertEquals(2.0f, ann.annotations[2].value);
+ assertEquals(3.0f, ann.annotations[3].value);
+ assertNull(ann.annotations[0]);
+ assertNull(ann.annotations[4]);
+ }
}
import jalview.io.FileFormat;
import jalview.io.FileFormatI;
import jalview.io.FormatAdapter;
+import jalview.util.Comparison;
import jalview.util.MapList;
import java.io.IOException;
if (raiseAssert)
{
Assert.fail(message
- + " DBRefEntry for sequence in alignment had map to sequence not in dataset");
+ + " DBRefEntry " + dbr + " for sequence "
+ + seqds
+ + " in alignment has map to sequence not in dataset");
}
return false;
}
// third found.. so
assertFalse(iter.hasNext());
+ // search for annotation on one sequence with a particular label - expect
+ // one
+ SequenceI sqfound;
+ anns = al.findAnnotations(sqfound = al.getSequenceAt(1), null,
+ "Secondary Structure");
+ iter = anns.iterator();
+ assertTrue(iter.hasNext());
+ // expect reference to sequence 1 in the alignment
+ assertTrue(sqfound == iter.next().sequenceRef);
+ assertFalse(iter.hasNext());
+
// null on all parameters == find all annotations
anns = al.findAnnotations(null, null, null);
iter = anns.iterator();
// todo test coverage for annotations, mappings, groups,
// hidden sequences, properties
}
+
+ /**
+ * test that calcId == null on findOrCreate doesn't raise an NPE, and yields
+ * an annotation with a null calcId
+ *
+ */
+ @Test(groups = "Functional")
+ public void testFindOrCreateForNullCalcId()
+ {
+ SequenceI seq = new Sequence("seq1", "FRMLPSRT-A--L-");
+ AlignmentI alignment = new Alignment(new SequenceI[] { seq });
+
+ AlignmentAnnotation ala = alignment.findOrCreateAnnotation(
+ "Temperature Factor", null, false, seq, null);
+ assertNotNull(ala);
+ assertEquals(seq, ala.sequenceRef);
+ assertEquals("", ala.calcId);
+ }
+
+ @Test(groups = "Functional")
+ public void testPropagateInsertions()
+ {
+ // create an alignment with no gaps - this will be the profile seq and other
+ // JPRED seqs
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI al = gen.generate(25, 10, 1234, 0, 0);
+
+ // get the profileseq
+ SequenceI profileseq = al.getSequenceAt(0);
+ SequenceI gappedseq = new Sequence(profileseq);
+ gappedseq.insertCharAt(5, al.getGapCharacter());
+ gappedseq.insertCharAt(6, al.getGapCharacter());
+ gappedseq.insertCharAt(7, al.getGapCharacter());
+ gappedseq.insertCharAt(8, al.getGapCharacter());
+
+ // force different kinds of padding
+ al.getSequenceAt(3).deleteChars(2, 23);
+ al.getSequenceAt(4).deleteChars(2, 27);
+ al.getSequenceAt(5).deleteChars(10, 27);
+
+ // create an alignment view with the gapped sequence
+ SequenceI[] seqs = new SequenceI[1];
+ seqs[0] = gappedseq;
+ AlignmentI newal = new Alignment(seqs);
+ HiddenColumns hidden = new HiddenColumns();
+ hidden.hideColumns(15, 17);
+
+ AlignmentView view = new AlignmentView(newal, hidden, null, true, false,
+ false);
+
+ // confirm that original contigs are as expected
+ Iterator<int[]> visible = hidden.getVisContigsIterator(0, 25, false);
+ int[] region = visible.next();
+ assertEquals("[0, 14]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[18, 24]", Arrays.toString(region));
+
+ // propagate insertions
+ HiddenColumns result = al.propagateInsertions(profileseq, view);
+
+ // confirm that the contigs have changed to account for the gaps
+ visible = result.getVisContigsIterator(0, 25, false);
+ region = visible.next();
+ assertEquals("[0, 10]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[14, 24]", Arrays.toString(region));
+
+ // confirm the alignment has been changed so that the other sequences have
+ // gaps inserted where the columns are hidden
+ assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[10]));
+ assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[11]));
+ assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[12]));
+ assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[13]));
+ assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[14]));
+
+ }
+
+ @Test(groups = "Functional")
+ public void testPropagateInsertionsOverlap()
+ {
+ // test propagateInsertions where gaps and hiddenColumns overlap
+
+ // create an alignment with no gaps - this will be the profile seq and other
+ // JPRED seqs
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI al = gen.generate(20, 10, 1234, 0, 0);
+
+ // get the profileseq
+ SequenceI profileseq = al.getSequenceAt(0);
+ SequenceI gappedseq = new Sequence(profileseq);
+ gappedseq.insertCharAt(5, al.getGapCharacter());
+ gappedseq.insertCharAt(6, al.getGapCharacter());
+ gappedseq.insertCharAt(7, al.getGapCharacter());
+ gappedseq.insertCharAt(8, al.getGapCharacter());
+
+ // create an alignment view with the gapped sequence
+ SequenceI[] seqs = new SequenceI[1];
+ seqs[0] = gappedseq;
+ AlignmentI newal = new Alignment(seqs);
+
+ // hide columns so that some overlap with the gaps
+ HiddenColumns hidden = new HiddenColumns();
+ hidden.hideColumns(7, 10);
+
+ AlignmentView view = new AlignmentView(newal, hidden, null, true, false,
+ false);
+
+ // confirm that original contigs are as expected
+ Iterator<int[]> visible = hidden.getVisContigsIterator(0, 20, false);
+ int[] region = visible.next();
+ assertEquals("[0, 6]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[11, 19]", Arrays.toString(region));
+ assertFalse(visible.hasNext());
+
+ // propagate insertions
+ HiddenColumns result = al.propagateInsertions(profileseq, view);
+
+ // confirm that the contigs have changed to account for the gaps
+ visible = result.getVisContigsIterator(0, 20, false);
+ region = visible.next();
+ assertEquals("[0, 4]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[7, 19]", Arrays.toString(region));
+ assertFalse(visible.hasNext());
+
+ // confirm the alignment has been changed so that the other sequences have
+ // gaps inserted where the columns are hidden
+ assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[4]));
+ assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[5]));
+ assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[6]));
+ assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[7]));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testPadGaps()
+ {
+ SequenceI seq1 = new Sequence("seq1", "ABCDEF--");
+ SequenceI seq2 = new Sequence("seq2", "-JKLMNO--");
+ SequenceI seq3 = new Sequence("seq2", "-PQR");
+ AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 });
+ a.setGapCharacter('.'); // this replaces existing gaps
+ assertEquals("ABCDEF..", seq1.getSequenceAsString());
+ a.padGaps();
+ // trailing gaps are pruned, short sequences padded with gap character
+ assertEquals("ABCDEF.", seq1.getSequenceAsString());
+ assertEquals(".JKLMNO", seq2.getSequenceAsString());
+ assertEquals(".PQR...", seq3.getSequenceAsString());
+ }
}
import java.util.BitSet;
import java.util.Collections;
import java.util.ConcurrentModificationException;
+import java.util.Iterator;
import java.util.List;
import org.testng.annotations.BeforeClass;
// hide column 5 (and adjacent):
cs.hideSelectedColumns(5, al.getHiddenColumns());
// 4,5,6 now hidden:
- List<int[]> hidden = al.getHiddenColumns().getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
+ Iterator<int[]> regions = al.getHiddenColumns().iterator();
+ assertEquals(1, al.getHiddenColumns().getNumberOfRegions());
+ assertEquals("[4, 6]", Arrays.toString(regions.next()));
// none now selected:
assertTrue(cs.getSelected().isEmpty());
cs.addElement(5);
cs.addElement(6);
cs.hideSelectedColumns(4, al.getHiddenColumns());
- hidden = al.getHiddenColumns().getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
+ regions = al.getHiddenColumns().iterator();
+ assertEquals(1, al.getHiddenColumns().getNumberOfRegions());
+ assertEquals("[4, 6]", Arrays.toString(regions.next()));
assertTrue(cs.getSelected().isEmpty());
// repeat, hiding column (4, 5 and) 6
cs.addElement(5);
cs.addElement(6);
cs.hideSelectedColumns(6, al.getHiddenColumns());
- hidden = al.getHiddenColumns().getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
+ regions = al.getHiddenColumns().iterator();
+ assertEquals(1, al.getHiddenColumns().getNumberOfRegions());
+ assertEquals("[4, 6]", Arrays.toString(regions.next()));
assertTrue(cs.getSelected().isEmpty());
// repeat, with _only_ adjacent columns selected
cs.addElement(4);
cs.addElement(6);
cs.hideSelectedColumns(5, al.getHiddenColumns());
- hidden = al.getHiddenColumns().getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
+ regions = al.getHiddenColumns().iterator();
+ assertEquals(1, al.getHiddenColumns().getNumberOfRegions());
+ assertEquals("[4, 6]", Arrays.toString(regions.next()));
assertTrue(cs.getSelected().isEmpty());
}
cs.hideSelectedColumns(al);
assertTrue(cs.getSelected().isEmpty());
- List<int[]> hidden = cols.getHiddenColumnsCopy();
- assertEquals(4, hidden.size());
- assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
- assertEquals("[7, 9]", Arrays.toString(hidden.get(1)));
- assertEquals("[15, 18]", Arrays.toString(hidden.get(2)));
- assertEquals("[20, 22]", Arrays.toString(hidden.get(3)));
+ Iterator<int[]> regions = cols.iterator();
+ assertEquals(4, cols.getNumberOfRegions());
+ assertEquals("[2, 4]", Arrays.toString(regions.next()));
+ assertEquals("[7, 9]", Arrays.toString(regions.next()));
+ assertEquals("[15, 18]", Arrays.toString(regions.next()));
+ assertEquals("[20, 22]", Arrays.toString(regions.next()));
}
/**
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import static org.testng.Assert.assertNull;
+import static org.testng.AssertJUnit.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class HiddenColumnsCursorTest
+{
+
+ @Test(groups = { "Functional" })
+ public void testConstructor()
+ {
+ HiddenColumnsCursor cursor = new HiddenColumnsCursor();
+ assertNull(cursor.findRegionForColumn(0, false));
+
+ List<int[]> hlist = new ArrayList<>();
+ cursor = new HiddenColumnsCursor(hlist);
+ assertNull(cursor.findRegionForColumn(0, false));
+
+ cursor = new HiddenColumnsCursor(hlist, 3, 12);
+ assertNull(cursor.findRegionForColumn(0, false));
+
+ hlist.add(new int[] { 3, 7 });
+ hlist.add(new int[] { 15, 25 });
+ cursor = new HiddenColumnsCursor(hlist);
+ HiddenCursorPosition p = cursor.findRegionForColumn(8, false);
+ assertEquals(1, p.getRegionIndex());
+
+ cursor = new HiddenColumnsCursor(hlist, 1, 5);
+ p = cursor.findRegionForColumn(8, false);
+ assertEquals(1, p.getRegionIndex());
+ }
+
+ /**
+ * Test the method which finds the corresponding region given a column
+ */
+ @Test(groups = { "Functional" })
+ public void testFindRegionForColumn()
+ {
+ HiddenColumnsCursor cursor = new HiddenColumnsCursor();
+
+ HiddenCursorPosition pos = cursor.findRegionForColumn(20, false);
+ assertNull(pos);
+
+ List<int[]> hidden = new ArrayList<>();
+ hidden.add(new int[] { 53, 76 });
+ hidden.add(new int[] { 104, 125 });
+
+ cursor = new HiddenColumnsCursor(hidden);
+
+ int regionIndex = cursor.findRegionForColumn(126, false).getRegionIndex();
+ assertEquals(2, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(125, false).getRegionIndex();
+ assertEquals(1, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(108, false).getRegionIndex();
+ assertEquals(1, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(104, false).getRegionIndex();
+ assertEquals(1, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(103, false).getRegionIndex();
+ assertEquals(1, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(77, false).getRegionIndex();
+ assertEquals(1, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(76, false).getRegionIndex();
+ assertEquals(0, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(53, false).getRegionIndex();
+ assertEquals(0, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(52, false).getRegionIndex();
+ assertEquals(0, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(0, false).getRegionIndex();
+ assertEquals(0, regionIndex);
+
+ hidden.add(new int[] { 138, 155 });
+
+ cursor = new HiddenColumnsCursor(hidden);
+
+ regionIndex = cursor.findRegionForColumn(160, false).getRegionIndex();
+ assertEquals(3, regionIndex);
+
+ regionIndex = cursor.findRegionForColumn(100, false).getRegionIndex();
+ assertEquals(1, regionIndex);
+ }
+
+ /**
+ * Test the method which counts the number of hidden columns before a column
+ */
+ @Test(groups = { "Functional" })
+ public void testFindRegionForColumn_Visible()
+ {
+ HiddenColumnsCursor cursor = new HiddenColumnsCursor();
+
+ HiddenCursorPosition pos = cursor.findRegionForColumn(20, true);
+ assertNull(pos);
+
+ List<int[]> hidden = new ArrayList<>();
+ hidden.add(new int[] { 53, 76 });
+ hidden.add(new int[] { 104, 125 });
+
+ cursor = new HiddenColumnsCursor(hidden);
+
+ int offset = cursor.findRegionForColumn(80, true).getHiddenSoFar();
+ assertEquals(46, offset);
+
+ offset = cursor.findRegionForColumn(79, true).getHiddenSoFar();
+ assertEquals(24, offset);
+
+ offset = cursor.findRegionForColumn(53, true).getHiddenSoFar();
+ assertEquals(24, offset);
+
+ offset = cursor.findRegionForColumn(52, true).getHiddenSoFar();
+ assertEquals(0, offset);
+
+ offset = cursor.findRegionForColumn(10, true).getHiddenSoFar();
+ assertEquals(0, offset);
+
+ offset = cursor.findRegionForColumn(0, true).getHiddenSoFar();
+ assertEquals(0, offset);
+
+ offset = cursor.findRegionForColumn(79, true).getHiddenSoFar();
+ assertEquals(24, offset);
+
+ offset = cursor.findRegionForColumn(80, true).getHiddenSoFar();
+ assertEquals(46, offset);
+ }
+}
import static org.testng.AssertJUnit.assertTrue;
import jalview.analysis.AlignmentGenerator;
-import jalview.gui.JvOptionPane;
import java.util.Arrays;
import java.util.BitSet;
-import java.util.List;
-import java.util.Random;
+import java.util.Iterator;
-import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class HiddenColumnsTest
{
-
- @BeforeClass(alwaysRun = true)
- public void setUpJvOptionPane()
- {
- JvOptionPane.setInteractiveMode(false);
- JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
- }
-
/**
* Test the method which counts the number of hidden columns
*/
public void testFindColumnPosition()
{
HiddenColumns cs = new HiddenColumns();
- assertEquals(5, cs.findColumnPosition(5));
+ assertEquals(5, cs.absoluteToVisibleColumn(5));
// hiding column 6 makes no difference
cs.hideColumns(6, 6);
- assertEquals(5, cs.findColumnPosition(5));
+ assertEquals(5, cs.absoluteToVisibleColumn(5));
// hiding column 4 moves column 5 to column 4
cs.hideColumns(4, 4);
- assertEquals(4, cs.findColumnPosition(5));
+ assertEquals(4, cs.absoluteToVisibleColumn(5));
// hiding column 4 moves column 4 to position 3
- assertEquals(3, cs.findColumnPosition(4));
+ assertEquals(3, cs.absoluteToVisibleColumn(4));
// hiding columns 1 and 2 moves column 5 to column 2
cs.hideColumns(1, 2);
- assertEquals(2, cs.findColumnPosition(5));
+ assertEquals(2, cs.absoluteToVisibleColumn(5));
// check with > 1 hidden column regions
// where some columns are in the hidden regions
cs2.hideColumns(40, 44);
// hiding columns 5-10 and 20-27 moves column 8 to column 4
- assertEquals(4, cs2.findColumnPosition(8));
+ assertEquals(4, cs2.absoluteToVisibleColumn(8));
// and moves column 24 to 13
- assertEquals(13, cs2.findColumnPosition(24));
+ assertEquals(13, cs2.absoluteToVisibleColumn(24));
// and moves column 28 to 14
- assertEquals(14, cs2.findColumnPosition(28));
+ assertEquals(14, cs2.absoluteToVisibleColumn(28));
// and moves column 40 to 25
- assertEquals(25, cs2.findColumnPosition(40));
+ assertEquals(25, cs2.absoluteToVisibleColumn(40));
// check when hidden columns start at 0 that the visible column
// is returned as 0
HiddenColumns cs3 = new HiddenColumns();
cs3.hideColumns(0, 4);
- assertEquals(0, cs3.findColumnPosition(2));
+ assertEquals(0, cs3.absoluteToVisibleColumn(2));
+ // check that column after the last hidden region doesn't crash
+ assertEquals(46, cs2.absoluteToVisibleColumn(65));
}
- /**
- * Test the method that finds the visible column position a given distance
- * before another column
- */
@Test(groups = { "Functional" })
- public void testFindColumnNToLeft()
+ public void testVisibleContigsIterator()
{
HiddenColumns cs = new HiddenColumns();
- // test that without hidden columns, findColumnNToLeft returns
- // position n to left of provided position
- int pos = cs.subtractVisibleColumns(3, 10);
- assertEquals(7, pos);
-
- // 0 returns same position
- pos = cs.subtractVisibleColumns(0, 10);
- assertEquals(10, pos);
-
- // overflow to left returns negative number
- pos = cs.subtractVisibleColumns(3, 0);
- assertEquals(-3, pos);
-
- // test that with hidden columns to left of result column
- // behaviour is the same as above
- cs.hideColumns(1, 3);
-
- // position n to left of provided position
- pos = cs.subtractVisibleColumns(3, 10);
- assertEquals(7, pos);
-
- // 0 returns same position
- pos = cs.subtractVisibleColumns(0, 10);
- assertEquals(10, pos);
-
- // test with one set of hidden columns between start and required position
- cs.hideColumns(12, 15);
- pos = cs.subtractVisibleColumns(8, 17);
- assertEquals(5, pos);
-
- // test with two sets of hidden columns between start and required position
- cs.hideColumns(20, 21);
- pos = cs.subtractVisibleColumns(8, 23);
- assertEquals(9, pos);
-
- // repeat last 2 tests with no hidden columns to left of required position
- ColumnSelection colsel = new ColumnSelection();
- cs.revealAllHiddenColumns(colsel);
-
- // test with one set of hidden columns between start and required position
- cs.hideColumns(12, 15);
- pos = cs.subtractVisibleColumns(8, 17);
- assertEquals(5, pos);
-
- // test with two sets of hidden columns between start and required position
- cs.hideColumns(20, 21);
- pos = cs.subtractVisibleColumns(8, 23);
- assertEquals(9, pos);
-
- }
+ Iterator<int[]> visible = cs.getVisContigsIterator(3, 10, false);
+ int[] region = visible.next();
+ assertEquals("[3, 9]", Arrays.toString(region));
+ assertFalse(visible.hasNext());
- @Test(groups = { "Functional" })
- public void testGetVisibleContigs()
- {
- HiddenColumns cs = new HiddenColumns();
cs.hideColumns(3, 6);
cs.hideColumns(8, 9);
cs.hideColumns(12, 12);
- // start position is inclusive, end position exclusive:
- int[] visible = cs.getVisibleContigs(1, 13);
- assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible));
-
- visible = cs.getVisibleContigs(4, 14);
- assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible));
-
- visible = cs.getVisibleContigs(3, 10);
- assertEquals("[7, 7]", Arrays.toString(visible));
-
- visible = cs.getVisibleContigs(4, 6);
- assertEquals("[]", Arrays.toString(visible));
+ // Test both ends visible region
+
+ // start position is inclusive, end position exclusive
+ visible = cs.getVisContigsIterator(1, 13, false);
+ region = visible.next();
+ assertEquals("[1, 2]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[7, 7]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[10, 11]", Arrays.toString(region));
+ assertFalse(visible.hasNext());
+
+ // Test start hidden, end visible
+ visible = cs.getVisContigsIterator(4, 14, false);
+ region = visible.next();
+ assertEquals("[7, 7]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[10, 11]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[13, 13]", Arrays.toString(region));
+ assertFalse(visible.hasNext());
+
+ // Test start hidden, end hidden
+ visible = cs.getVisContigsIterator(3, 10, false);
+ region = visible.next();
+ assertEquals("[7, 7]", Arrays.toString(region));
+ assertFalse(visible.hasNext());
+
+ // Test start visible, end hidden
+ visible = cs.getVisContigsIterator(0, 13, false);
+ region = visible.next();
+ assertEquals("[0, 2]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[7, 7]", Arrays.toString(region));
+ region = visible.next();
+ assertEquals("[10, 11]", Arrays.toString(region));
+ assertFalse(visible.hasNext());
+
+ // Test empty result
+ visible = cs.getVisContigsIterator(4, 6, false);
+ assertFalse(visible.hasNext());
}
@Test(groups = { "Functional" })
assertFalse(cs.equals(cs2));
assertFalse(cs2.equals(cs));
+ // with the wrong kind of object
+ assertFalse(cs.equals(new HiddenColumnsCursor()));
+
+ // with a different hiddenColumns object - by size
+ HiddenColumns cs3 = new HiddenColumns();
+ cs3.hideColumns(2, 3);
+ assertFalse(cs.equals(cs3));
+
// with hidden columns added in a different order
cs2.hideColumns(6, 9);
+ assertFalse(cs.equals(cs2));
+ assertFalse(cs2.equals(cs));
+
cs2.hideColumns(5, 8);
assertTrue(cs.equals(cs2));
assertTrue(cs.equals(cs));
assertTrue(cs2.equals(cs));
assertTrue(cs2.equals(cs2));
+
+ // different ranges, same size
+ cs.hideColumns(10, 12);
+ cs2.hideColumns(10, 15);
+ assertFalse(cs.equals(cs2));
+
}
@Test(groups = "Functional")
HiddenColumns cs = new HiddenColumns();
cs.hideColumns(10, 11);
cs.hideColumns(5, 7);
+ Iterator<int[]> regions = cs.iterator();
assertEquals("[5, 7]",
- Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
+ Arrays.toString(regions.next()));
HiddenColumns cs2 = new HiddenColumns(cs);
+ regions = cs2.iterator();
assertTrue(cs2.hasHiddenColumns());
- assertEquals(2, cs2.getHiddenColumnsCopy().size());
+ assertEquals(2, cs2.getNumberOfRegions());
// hidden columns are held in column order
assertEquals("[5, 7]",
- Arrays.toString(cs2.getHiddenColumnsCopy().get(0)));
+ Arrays.toString(regions.next()));
assertEquals("[10, 11]",
- Arrays.toString(cs2.getHiddenColumnsCopy().get(1)));
+ Arrays.toString(regions.next()));
}
- /**
- * Test the code used to locate the reference sequence ruler origin
- */
- @Test(groups = { "Functional" })
- public void testLocateVisibleBoundsofSequence()
+ @Test(groups = "Functional")
+ public void testCopyConstructor2()
{
- // create random alignment
- AlignmentGenerator gen = new AlignmentGenerator(false);
- AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+ HiddenColumns cs = new HiddenColumns();
+ cs.hideColumns(10, 11);
+ cs.hideColumns(5, 7);
- HiddenColumns cs = al.getHiddenColumns();
- ColumnSelection colsel = new ColumnSelection();
+ HiddenColumns cs2 = new HiddenColumns(cs, 3, 9, 1);
+ assertTrue(cs2.hasHiddenColumns());
+ Iterator<int[]> regions = cs2.iterator();
- SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
- assertEquals(2, seq.findIndex(seq.getStart()));
-
- // no hidden columns
- assertEquals(
- Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
- seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
- // hidden column on gap after end of sequence - should not affect bounds
- colsel.hideSelectedColumns(13, al.getHiddenColumns());
- assertEquals(
- Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
- seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+ // only [5,7] returned, offset by 1
+ assertEquals("[4, 6]",
+ Arrays.toString(regions.next()));
+ assertEquals(3, cs2.getSize());
- cs.revealAllHiddenColumns(colsel);
- // hidden column on gap before beginning of sequence - should vis bounds by
- // one
- colsel.hideSelectedColumns(0, al.getHiddenColumns());
- assertEquals(
- Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
- seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
- seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
- cs.revealAllHiddenColumns(colsel);
- // hide columns around most of sequence - leave one residue remaining
- cs.hideColumns(1, 3);
- cs.hideColumns(6, 11);
- assertEquals("-D",
- cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
- assertEquals(
- Arrays.toString(new int[] { 1, 1, 3, 3,
- seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
- cs.revealAllHiddenColumns(colsel);
+ cs2 = new HiddenColumns(cs, 8, 15, 4);
+ regions = cs2.iterator();
+ assertTrue(cs2.hasHiddenColumns());
- // hide whole sequence - should just get location of hidden region
- // containing sequence
- cs.hideColumns(1, 11);
- assertEquals(
- Arrays.toString(new int[] { 0, 1, 0, 0,
- seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+ // only [10,11] returned, offset by 4
+ assertEquals("[6, 7]",
+ Arrays.toString(regions.next()));
+ assertEquals(2, cs2.getSize());
+ cs2 = new HiddenColumns(cs, 6, 10, 4);
+ assertFalse(cs2.hasHiddenColumns());
}
- @Test(groups = { "Functional" })
- public void testLocateVisibleBoundsPathologicals()
- {
- // test some pathological cases we missed
- AlignmentI al = new Alignment(new SequenceI[] { new Sequence(
- "refseqGaptest", "KTDVTI----------NFI-----G----L") });
- HiddenColumns cs = new HiddenColumns();
- cs.hideInsertionsFor(al.getSequenceAt(0));
- assertEquals(
- "G",
- ""
- + al.getSequenceAt(0).getCharAt(
- cs.adjustForHiddenColumns(9)));
-
- }
@Test(groups = { "Functional" })
public void testHideColumns()
ColumnSelection colsel = new ColumnSelection();
HiddenColumns cs = al.getHiddenColumns();
colsel.hideSelectedColumns(5, al.getHiddenColumns());
- List<int[]> hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[5, 5]", Arrays.toString(hidden.get(0)));
+ Iterator<int[]> regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals("[5, 5]", Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 1);
colsel.hideSelectedColumns(3, al.getHiddenColumns());
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(2, hidden.size());
+ regions = cs.iterator();
+ assertEquals(2, cs.getNumberOfRegions());
// two hidden ranges, in order:
- assertEquals(hidden.size(), cs.getHiddenColumnsCopy().size());
- assertEquals("[3, 3]", Arrays.toString(hidden.get(0)));
- assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
+ assertEquals("[3, 3]", Arrays.toString(regions.next()));
+ assertEquals("[5, 5]", Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 2);
// hiding column 4 expands [3, 3] to [3, 4]
// and merges to [5, 5] to make [3, 5]
colsel.hideSelectedColumns(4, al.getHiddenColumns());
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[3, 5]", Arrays.toString(hidden.get(0)));
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals("[3, 5]", Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 3);
// clear hidden columns (note they are added to selected)
cs.revealAllHiddenColumns(colsel);
// it is now actually null but getter returns an empty list
- assertTrue(cs.getHiddenColumnsCopy().isEmpty());
+ assertEquals(0, cs.getNumberOfRegions());
+ assertEquals(cs.getSize(), 0);
cs.hideColumns(3, 6);
- hidden = cs.getHiddenColumnsCopy();
- int[] firstHiddenRange = hidden.get(0);
+ regions = cs.iterator();
+ int[] firstHiddenRange = regions.next();
assertEquals("[3, 6]", Arrays.toString(firstHiddenRange));
+ assertEquals(cs.getSize(), 4);
// adding a subrange of already hidden should do nothing
cs.hideColumns(4, 5);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
assertEquals("[3, 6]",
- Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
+ Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 4);
cs.hideColumns(3, 5);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
assertEquals("[3, 6]",
- Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
+ Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 4);
cs.hideColumns(4, 6);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
assertEquals("[3, 6]",
- Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
+ Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 4);
cs.hideColumns(3, 6);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
assertEquals("[3, 6]",
- Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
+ Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 4);
cs.revealAllHiddenColumns(colsel);
cs.hideColumns(2, 4);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals("[2, 4]", Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 3);
// extend contiguous with 2 positions overlap
cs.hideColumns(3, 5);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[2, 5]", Arrays.toString(hidden.get(0)));
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals("[2, 5]", Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 4);
// extend contiguous with 1 position overlap
cs.hideColumns(5, 6);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[2, 6]", Arrays.toString(hidden.get(0)));
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals("[2, 6]", Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 5);
// extend contiguous with overlap both ends:
cs.hideColumns(1, 7);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[1, 7]", Arrays.toString(hidden.get(0)));
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals("[1, 7]", Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 7);
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(15, 18);
+ cs.hideColumns(2, 4);
+ cs.hideColumns(7, 9);
+ regions = cs.iterator();
+ assertEquals(3, cs.getNumberOfRegions());
+ assertEquals("[2, 4]", Arrays.toString(regions.next()));
+ assertEquals("[7, 9]", Arrays.toString(regions.next()));
+ assertEquals("[15, 18]", Arrays.toString(regions.next()));
+ assertEquals(cs.getSize(), 10);
}
/**
{
ColumnSelection colsel = new ColumnSelection();
HiddenColumns cs = new HiddenColumns();
+
+ // test with null hidden columns
+ cs.revealHiddenColumns(5, colsel);
+ assertTrue(colsel.getSelected().isEmpty());
+
cs.hideColumns(5, 8);
colsel.addElement(10);
cs.revealHiddenColumns(5, colsel);
- // hidden columns list now null but getter returns empty list:
- assertTrue(cs.getHiddenColumnsCopy().isEmpty());
+
+ // hiddenColumns now empty
+ assertEquals(0, cs.getSize());
+
// revealed columns are marked as selected (added to selection):
assertEquals("[10, 5, 6, 7, 8]", colsel.getSelected().toString());
colsel = new ColumnSelection();
cs = new HiddenColumns();
cs.hideColumns(5, 8);
- List<int[]> hidden = cs.getHiddenColumnsCopy();
+
+ int prevSize = cs.getSize();
cs.revealHiddenColumns(6, colsel);
- assertEquals(hidden.size(), cs.getHiddenColumnsCopy().size());
+ assertEquals(prevSize, cs.getSize());
+ assertTrue(colsel.getSelected().isEmpty());
+
+ // reveal hidden columns when there is more than one region
+ cs.hideColumns(20, 23);
+ // now there are 2 hidden regions
+ assertEquals(2, cs.getNumberOfRegions());
+
+ cs.revealHiddenColumns(20, colsel);
+
+ // hiddenColumns now has one region
+ assertEquals(1, cs.getNumberOfRegions());
+
+ // revealed columns are marked as selected (added to selection):
+ assertEquals("[20, 21, 22, 23]", colsel.getSelected().toString());
+
+ // call with a column past the end of the hidden column ranges
+ colsel.clear();
+ cs.revealHiddenColumns(20, colsel);
+ // hiddenColumns still has 1 region
+ assertEquals(1, cs.getNumberOfRegions());
assertTrue(colsel.getSelected().isEmpty());
}
@Test(groups = { "Functional" })
public void testRevealAllHiddenColumns()
{
- HiddenColumns cs = new HiddenColumns();
+ HiddenColumns hidden = new HiddenColumns();
ColumnSelection colsel = new ColumnSelection();
- cs.hideColumns(5, 8);
- cs.hideColumns(2, 3);
+
+ // test with null hidden columns
+ hidden.revealAllHiddenColumns(colsel);
+ assertTrue(colsel.getSelected().isEmpty());
+
+ hidden.hideColumns(5, 8);
+ hidden.hideColumns(2, 3);
colsel.addElement(11);
colsel.addElement(1);
- cs.revealAllHiddenColumns(colsel);
+ hidden.revealAllHiddenColumns(colsel);
/*
* revealing hidden columns adds them (in order) to the (unordered)
* selection list
*/
- assertTrue(cs.getHiddenColumnsCopy().isEmpty());
- assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", colsel.getSelected()
- .toString());
+
+ // hiddenColumns now empty
+ assertEquals(0, hidden.getSize());
+
+ assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]",
+ colsel.getSelected().toString());
}
@Test(groups = { "Functional" })
public void testIsVisible()
{
HiddenColumns cs = new HiddenColumns();
+ assertTrue(cs.isVisible(5));
+
cs.hideColumns(2, 4);
cs.hideColumns(6, 7);
assertTrue(cs.isVisible(0));
assertTrue(cs.isVisible(5));
assertFalse(cs.isVisible(6));
assertFalse(cs.isVisible(7));
+ assertTrue(cs.isVisible(8));
}
/**
HiddenColumns cs = new HiddenColumns();
cs.hideColumns(49, 59);
cs.hideColumns(69, 79);
- List<int[]> hidden = cs.getHiddenColumnsCopy();
- assertEquals(2, hidden.size());
- assertEquals("[49, 59]", Arrays.toString(hidden.get(0)));
- assertEquals("[69, 79]", Arrays.toString(hidden.get(1)));
+ Iterator<int[]> regions = cs.iterator();
+ assertEquals(2, cs.getNumberOfRegions());
+ assertEquals("[49, 59]", Arrays.toString(regions.next()));
+ assertEquals("[69, 79]", Arrays.toString(regions.next()));
+ assertEquals(22, cs.getSize());
cs.hideColumns(48, 80);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[48, 80]", Arrays.toString(hidden.get(0)));
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals("[48, 80]", Arrays.toString(regions.next()));
+ assertEquals(33, cs.getSize());
/*
* another...joining hidden ranges
cs.hideColumns(50, 60);
// hiding 21-49 should merge to one range
cs.hideColumns(21, 49);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[10, 60]", Arrays.toString(hidden.get(0)));
+ regions = cs.iterator();
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals("[10, 60]", Arrays.toString(regions.next()));
+ assertEquals(51, cs.getSize());
/*
* another...left overlap, subsumption, right overlap,
cs.hideColumns(60, 70);
cs.hideColumns(15, 45);
- hidden = cs.getHiddenColumnsCopy();
- assertEquals(2, hidden.size());
- assertEquals("[10, 50]", Arrays.toString(hidden.get(0)));
- assertEquals("[60, 70]", Arrays.toString(hidden.get(1)));
+ regions = cs.iterator();
+ assertEquals(2, cs.getNumberOfRegions());
+ assertEquals("[10, 50]", Arrays.toString(regions.next()));
+ assertEquals("[60, 70]", Arrays.toString(regions.next()));
+ assertEquals(52, cs.getSize());
}
@Test(groups = { "Functional" })
- public void testHideBitset()
+ public void testHideColumns_BitSet()
{
HiddenColumns cs;
// one hidden range
one.set(1);
cs = new HiddenColumns();
- cs.hideMarkedBits(one);
- assertEquals(1, cs.getHiddenColumnsCopy().size());
+ cs.hideColumns(one);
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals(1, cs.getSize());
one.set(2);
cs = new HiddenColumns();
- cs.hideMarkedBits(one);
- assertEquals(1, cs.getHiddenColumnsCopy().size());
+ cs.hideColumns(one);
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals(2, cs.getSize());
one.set(3);
cs = new HiddenColumns();
- cs.hideMarkedBits(one);
- assertEquals(1, cs.getHiddenColumnsCopy().size());
+ cs.hideColumns(one);
+ assertEquals(1, cs.getNumberOfRegions());
+ assertEquals(3, cs.getSize());
// split
one.clear(2);
cs = new HiddenColumns();
- cs.hideMarkedBits(one);
- assertEquals(2, cs.getHiddenColumnsCopy().size());
+ cs.hideColumns(one);
+ assertEquals(2, cs.getNumberOfRegions());
+ assertEquals(2, cs.getSize());
- assertEquals(0, cs.adjustForHiddenColumns(0));
- assertEquals(2, cs.adjustForHiddenColumns(1));
- assertEquals(4, cs.adjustForHiddenColumns(2));
+ assertEquals(0, cs.visibleToAbsoluteColumn(0));
+ assertEquals(2, cs.visibleToAbsoluteColumn(1));
+ assertEquals(4, cs.visibleToAbsoluteColumn(2));
// one again
one.clear(1);
cs = new HiddenColumns();
- cs.hideMarkedBits(one);
+ cs.hideColumns(one);
+ assertEquals(1, cs.getSize());
- assertEquals(1, cs.getHiddenColumnsCopy().size());
+ assertEquals(1, cs.getNumberOfRegions());
- assertEquals(0, cs.adjustForHiddenColumns(0));
- assertEquals(1, cs.adjustForHiddenColumns(1));
- assertEquals(2, cs.adjustForHiddenColumns(2));
- assertEquals(4, cs.adjustForHiddenColumns(3));
- }
-
- @Test(groups = { "Functional" })
- public void testGetBitset()
- {
- BitSet toMark, fromMark;
- long seed = -3241532;
- Random number = new Random(seed);
- for (int n = 0; n < 1000; n++)
- {
- // create a random bitfield
- toMark = BitSet.valueOf(new long[] { number.nextLong(),
- number.nextLong(), number.nextLong() });
- toMark.set(n * number.nextInt(10), n * (25 + number.nextInt(25)));
- HiddenColumns hc = new HiddenColumns();
- hc.hideMarkedBits(toMark);
-
- // see if we can recover bitfield
- hc.markHiddenRegions(fromMark = new BitSet());
- assertEquals(toMark, fromMark);
- }
- }
-
- @Test(groups = { "Functional" })
- public void testFindHiddenRegionPositions()
- {
- HiddenColumns hc = new HiddenColumns();
-
- List<Integer> positions = hc.findHiddenRegionPositions();
- assertTrue(positions.isEmpty());
-
- hc.hideColumns(3, 7);
- hc.hideColumns(10, 10);
- hc.hideColumns(14, 15);
-
- positions = hc.findHiddenRegionPositions();
- assertEquals(3, positions.size());
- assertEquals(3, positions.get(0).intValue());
- assertEquals(5, positions.get(1).intValue());
- assertEquals(8, positions.get(2).intValue());
+ assertEquals(0, cs.visibleToAbsoluteColumn(0));
+ assertEquals(1, cs.visibleToAbsoluteColumn(1));
+ assertEquals(2, cs.visibleToAbsoluteColumn(2));
+ assertEquals(4, cs.visibleToAbsoluteColumn(3));
}
@Test(groups = { "Functional" })
}
@Test(groups = "Functional")
- public void getVisibleStartAndEndIndexTest()
+ public void testGetVisibleStartAndEndIndex()
{
Sequence seq = new Sequence("testSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
AlignmentI align = new Alignment(new SequenceI[] { seq });
System.out.println(startEnd[0] + " : " + startEnd[1]);
assertEquals(1, startEnd[0]);
assertEquals(23, startEnd[1]);
+
+ // force lowest range to start of alignment
+ hc = new HiddenColumns();
+ hc.hideColumns(3, 4);
+ startEnd = hc.getVisibleStartAndEndIndex(align.getWidth());
+ assertEquals(0, startEnd[0]);
+ assertEquals(25, startEnd[1]);
}
@Test(groups = "Functional")
hc.hideColumns(10, 10);
hc.hideColumns(14, 15);
- result = hc.getRegionWithEdgeAtRes(3);
+ result = hc.getRegionWithEdgeAtRes(2);
assertEquals(3, result[0]);
assertEquals(7, result[1]);
+ result = hc.getRegionWithEdgeAtRes(4);
+ assertEquals(10, result[0]);
+ assertEquals(10, result[1]);
+
result = hc.getRegionWithEdgeAtRes(5);
assertEquals(10, result[0]);
assertEquals(10, result[1]);
result = hc.getRegionWithEdgeAtRes(6);
assertNull(result);
+
+ result = hc.getRegionWithEdgeAtRes(0);
+ assertNull(result);
+
+ result = hc.getRegionWithEdgeAtRes(7);
+ assertEquals(14, result[0]);
+ assertEquals(15, result[1]);
+
+ result = hc.getRegionWithEdgeAtRes(8);
+ assertEquals(14, result[0]);
+ assertEquals(15, result[1]);
+
+ result = hc.getRegionWithEdgeAtRes(16);
+ assertNull(result);
}
@Test(groups = "Functional")
- public void testPropagateInsertions()
+ public void testHasHiddenColumns()
{
- // create an alignment with no gaps - this will be the profile seq and other
- // JPRED seqs
- AlignmentGenerator gen = new AlignmentGenerator(false);
- AlignmentI al = gen.generate(20, 10, 1234, 0, 0);
-
- // get the profileseq
- SequenceI profileseq = al.getSequenceAt(0);
- SequenceI gappedseq = new Sequence(profileseq);
- gappedseq.insertCharAt(5, al.getGapCharacter());
- gappedseq.insertCharAt(6, al.getGapCharacter());
- gappedseq.insertCharAt(7, al.getGapCharacter());
- gappedseq.insertCharAt(8, al.getGapCharacter());
-
- // create an alignment view with the gapped sequence
- SequenceI[] seqs = new SequenceI[1];
- seqs[0] = gappedseq;
- AlignmentI newal = new Alignment(seqs);
- HiddenColumns hidden = new HiddenColumns();
- hidden.hideColumns(15, 17);
-
- AlignmentView view = new AlignmentView(newal, hidden, null, true, false,
- false);
-
- // confirm that original contigs are as expected
- int[] oldcontigs = hidden.getVisibleContigs(0, 20);
- int[] testcontigs = { 0, 14, 18, 19 };
- assertTrue(Arrays.equals(oldcontigs, testcontigs));
-
- // propagate insertions
- HiddenColumns result = HiddenColumns.propagateInsertions(profileseq, al,
- view);
-
- // confirm that the contigs have changed to account for the gaps
- int[] newcontigs = result.getVisibleContigs(0, 20);
- testcontigs[1] = 10;
- testcontigs[2] = 14;
- assertTrue(Arrays.equals(newcontigs, testcontigs));
-
+ HiddenColumns h = new HiddenColumns();
+
+ // new HiddenColumns2 has no hidden cols
+ assertFalse(h.hasHiddenColumns());
+
+ // some columns hidden, returns true
+ h.hideColumns(5, 10);
+ assertTrue(h.hasHiddenColumns());
+
+ // reveal columns, no hidden cols again
+ ColumnSelection sel = new ColumnSelection();
+ h.revealAllHiddenColumns(sel);
+ assertFalse(h.hasHiddenColumns());
+ }
+
+ @Test(groups = "Functional")
+ public void testHasManyHiddenColumns()
+ {
+ HiddenColumns h = new HiddenColumns();
+
+ // h has no hidden cols
+ assertFalse(h.hasMultiHiddenColumnRegions());
+
+ // one set of columns hidden, returns false
+ h.hideColumns(5, 10);
+ assertFalse(h.hasMultiHiddenColumnRegions());
+
+ // two sets hidden, returns true
+ h.hideColumns(15, 17);
+ assertTrue(h.hasMultiHiddenColumnRegions());
+
+ // back to one block, asserts false
+ h.hideColumns(11, 14);
+ assertFalse(h.hasMultiHiddenColumnRegions());
+ }
+
+ @Test(groups = "Functional")
+ public void testAdjustForHiddenColumns()
+ {
+ HiddenColumns h = new HiddenColumns();
+ // returns input value when there are no hidden columns
+ assertEquals(10, h.visibleToAbsoluteColumn(10));
+
+ h.hideColumns(20, 30);
+ assertEquals(10, h.visibleToAbsoluteColumn(10));
+ assertEquals(20 + 11, h.visibleToAbsoluteColumn(20));
+ assertEquals(35 + 11, h.visibleToAbsoluteColumn(35));
+
+ h.hideColumns(5, 7);
+ assertEquals(10 + 3, h.visibleToAbsoluteColumn(10));
+ assertEquals(20 + 14, h.visibleToAbsoluteColumn(20));
+ assertEquals(35 + 14, h.visibleToAbsoluteColumn(35));
+
+ ColumnSelection sel = new ColumnSelection();
+ h.revealAllHiddenColumns(sel);
+ h.hideColumns(0, 1);
+ assertEquals(4, h.visibleToAbsoluteColumn(2));
+ }
+
+ @Test(groups = "Functional")
+ public void testGetNextHiddenBoundary_Left()
+ {
+ HiddenColumns h = new HiddenColumns();
+
+ // returns same value if no hidden cols
+ assertEquals(3, h.getNextHiddenBoundary(true, 3));
+
+ h.hideColumns(5, 10);
+ assertEquals(10, h.getNextHiddenBoundary(true, 15));
+ assertEquals(3, h.getNextHiddenBoundary(true, 3));
+ assertEquals(7, h.getNextHiddenBoundary(true, 7));
+
+ h.hideColumns(15, 20);
+ assertEquals(10, h.getNextHiddenBoundary(true, 15));
+ assertEquals(20, h.getNextHiddenBoundary(true, 21));
+ }
+
+ @Test(groups = "Functional")
+ public void testGetNextHiddenBoundary_Right()
+ {
+ HiddenColumns h = new HiddenColumns();
+
+ // returns same value if no hidden cols
+ assertEquals(3, h.getNextHiddenBoundary(false, 3));
+
+ h.hideColumns(5, 10);
+ assertEquals(5, h.getNextHiddenBoundary(false, 3));
+ assertEquals(15, h.getNextHiddenBoundary(false, 15));
+ assertEquals(7, h.getNextHiddenBoundary(false, 7));
+
+ h.hideColumns(15, 20);
+ assertEquals(15, h.getNextHiddenBoundary(false, 7));
+ assertEquals(15, h.getNextHiddenBoundary(false, 14));
+
+ // returns same value if there is no next hidden column
+ assertEquals(22, h.getNextHiddenBoundary(false, 22));
+ }
+
+ @Test(groups = "Functional")
+ public void testIterator()
+ {
+ HiddenColumns h = new HiddenColumns();
+ Iterator<int[]> result = h.iterator();
+ assertFalse(result.hasNext());
+
+ h.hideColumns(5, 10);
+ result = h.iterator();
+ int[] next = result.next();
+ assertEquals(5, next[0]);
+ assertEquals(10, next[1]);
+ assertFalse(result.hasNext());
+
+ h.hideColumns(22, 23);
+ result = h.iterator();
+ next = result.next();
+ assertEquals(5, next[0]);
+ assertEquals(10, next[1]);
+ next = result.next();
+ assertEquals(22, next[0]);
+ assertEquals(23, next[1]);
+ assertFalse(result.hasNext());
+
+ // test for only one hidden region at start of alignment
+ ColumnSelection sel = new ColumnSelection();
+ h.revealAllHiddenColumns(sel);
+ h.hideColumns(0, 1);
+ result = h.iterator();
+ next = result.next();
+ assertEquals(0, next[0]);
+ assertEquals(1, next[1]);
+ assertFalse(result.hasNext());
+ }
+
+ /* @Test(groups = "Functional")
+ public void testGetVisibleSequenceStrings()
+ {
+ HiddenColumns h = new HiddenColumns();
+ SequenceI seq1 = new Sequence("TEST1", "GALMFWKQESPVICYHRNDT");
+ SequenceI seq2 = new Sequence("TEST2", "VICYHRNDTGA");
+ SequenceI[] seqs = new SequenceI[2];
+ seqs[0] = seq1;
+ seqs[1] = seq2;
+ String[] result = h.getVisibleSequenceStrings(5, 10, seqs);
+ assertEquals(2, result.length);
+ assertEquals("WKQES", result[0]);
+ assertEquals("RNDTG", result[1]);
+
+ h.hideColumns(6, 8);
+ result = h.getVisibleSequenceStrings(5, 10, seqs);
+ assertEquals(2, result.length);
+ assertEquals("WS", result[0]);
+ assertEquals("RG", result[1]);
+
+ SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
+ ColumnSelection sel = new ColumnSelection();
+ h.revealAllHiddenColumns(sel);
+ h.hideColumns(1, 3);
+ h.hideColumns(6, 11);
+ assertEquals("-D",
+ h.getVisibleSequenceStrings(0, 5, new SequenceI[]
+ { seq })[0]);
+ }*/
+
+ @Test(groups = "Functional")
+ public void testHideInsertionsFor()
+ {
+ HiddenColumns h = new HiddenColumns();
+ HiddenColumns h2 = new HiddenColumns();
+ SequenceI seq1 = new Sequence("TEST1", "GAL---MFW-KQESPVICY--HRNDT");
+ SequenceI seq2 = new Sequence("TEST1", "GALMFWKQESPVICYHRNDT");
+
+ h.hideList(seq2.getInsertions());
+ assertTrue(h.equals(h2));
+ assertEquals(0, h.getSize());
+
+ h.hideList(seq1.getInsertions());
+ h2.hideColumns(3, 5);
+ h2.hideColumns(9, 9);
+ h2.hideColumns(19, 20);
+ assertTrue(h.equals(h2));
+ assertEquals(6, h.getSize());
+ }
+
+ @Test(groups = "Functional")
+ public void testHideColumns_BitSet_range()
+ {
+ HiddenColumns h = new HiddenColumns();
+ HiddenColumns h2 = new HiddenColumns();
+
+ BitSet tohide = new BitSet(25);
+ h.hideColumns(tohide);
+ assertTrue(h.equals(h2));
+
+ // when setting bitset, first param is inclusive, second exclusive
+ tohide.set(3, 6);
+ tohide.set(9);
+ tohide.set(15, 21);
+ h.clearAndHideColumns(tohide, 5, 23);
+
+ h2.hideColumns(5, 5);
+ h2.hideColumns(9, 9);
+ h2.hideColumns(15, 20);
+ assertTrue(h.equals(h2));
+ assertEquals(h.getSize(), h2.getSize());
+
+ tohide.clear();
+ tohide.set(41);
+ h.clearAndHideColumns(tohide, 23, 30);
+ assertTrue(h.equals(h2));
+ assertEquals(h.getSize(), h2.getSize());
+
+ tohide.set(41);
+ h.clearAndHideColumns(tohide, 30, 45);
+ h2.hideColumns(41, 41);
+ assertTrue(h.equals(h2));
+ assertEquals(h.getSize(), h2.getSize());
+
+ tohide.clear();
+ tohide.set(25, 28);
+ h.clearAndHideColumns(tohide, 17, 50);
+ h2 = new HiddenColumns();
+ h2.hideColumns(5, 5);
+ h2.hideColumns(9, 9);
+ h2.hideColumns(15, 16);
+ h2.hideColumns(25, 27);
+ assertTrue(h.equals(h2));
+ assertEquals(h.getSize(), h2.getSize());
+
+ HiddenColumns hc = new HiddenColumns();
+ hc.hideColumns(3, 5);
+ hc.hideColumns(15, 20);
+ hc.hideColumns(45, 60);
+
+ tohide = new BitSet();
+
+ // all unhidden if tohide is empty and range covers hidden
+ hc.clearAndHideColumns(tohide, 1, 70);
+ assertTrue(!hc.hasHiddenColumns());
+ assertEquals(0, hc.getSize());
+
+ hc.hideColumns(3, 5);
+ hc.hideColumns(15, 20);
+ hc.hideColumns(45, 60);
+ assertEquals(25, hc.getSize());
+
+ // but not if range does not cover hidden
+ hc.clearAndHideColumns(tohide, 23, 40);
+ assertTrue(hc.hasHiddenColumns());
+ assertEquals(25, hc.getSize());
+
+ // and partial unhide if range partially covers
+ hc.clearAndHideColumns(tohide, 1, 17);
+ Iterator<int[]> it = hc.iterator();
+ assertTrue(it.hasNext());
+ int[] region = it.next();
+
+ assertEquals(18, region[0]);
+ assertEquals(20, region[1]);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+
+ assertEquals(45, region[0]);
+ assertEquals(60, region[1]);
+
+ assertFalse(it.hasNext());
+ assertEquals(19, hc.getSize());
+ }
+
+ @Test(groups = "Functional")
+ public void testOffsetByVisibleColumns()
+ {
+ HiddenColumns h = new HiddenColumns();
+ int result = h.offsetByVisibleColumns(-1, 10);
+ assertEquals(9, result);
+
+ h.hideColumns(7, 9);
+ result = h.offsetByVisibleColumns(-4, 10);
+ assertEquals(3, result);
+
+ h.hideColumns(14, 15);
+ result = h.offsetByVisibleColumns(-4, 10);
+ assertEquals(3, result);
+
+ result = h.offsetByVisibleColumns(-10, 17);
+ assertEquals(2, result);
+
+ result = h.offsetByVisibleColumns(-1, 7);
+ assertEquals(5, result);
+
+ result = h.offsetByVisibleColumns(-1, 8);
+ assertEquals(5, result);
+
+ result = h.offsetByVisibleColumns(-3, 15);
+ assertEquals(10, result);
+
+ ColumnSelection sel = new ColumnSelection();
+ h.revealAllHiddenColumns(sel);
+ h.hideColumns(0, 30);
+ result = h.offsetByVisibleColumns(-31, 0);
+ assertEquals(-31, result);
+
+ HiddenColumns cs = new HiddenColumns();
+
+ // test that without hidden columns, offsetByVisibleColumns returns
+ // position n to left of provided position
+ long pos = cs.offsetByVisibleColumns(-3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = cs.offsetByVisibleColumns(0, 10);
+ assertEquals(10, pos);
+
+ // overflow to left returns negative number
+ pos = cs.offsetByVisibleColumns(-3, 0);
+ assertEquals(-3, pos);
+
+ // test that with hidden columns to left of result column
+ // behaviour is the same as above
+ cs.hideColumns(1, 3);
+
+ // position n to left of provided position
+ pos = cs.offsetByVisibleColumns(-3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = cs.offsetByVisibleColumns(0, 10);
+ assertEquals(10, pos);
+
+ // test with one set of hidden columns between start and required position
+ cs.hideColumns(12, 15);
+ pos = cs.offsetByVisibleColumns(-8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden columns between start and required position
+ cs.hideColumns(20, 21);
+ pos = cs.offsetByVisibleColumns(-8, 23);
+ assertEquals(9, pos);
+
+ // repeat last 2 tests with no hidden columns to left of required position
+ ColumnSelection colsel = new ColumnSelection();
+ cs.revealAllHiddenColumns(colsel);
+
+ // test with one set of hidden columns between start and required position
+ cs.hideColumns(12, 15);
+ pos = cs.offsetByVisibleColumns(-8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden columns between start and required position
+ cs.hideColumns(20, 21);
+ pos = cs.offsetByVisibleColumns(-8, 23);
+ assertEquals(9, pos);
+
+ // test with right (positive) offsets
+
+ // test that without hidden columns, offsetByVisibleColumns returns
+ // position n to right of provided position
+ pos = cs.offsetByVisibleColumns(3, 7);
+ assertEquals(10, pos);
+
+ // test that with hidden columns to left of result column
+ // behaviour is the same as above
+ cs.hideColumns(1, 3);
+
+ // test with one set of hidden columns between start and required position
+ cs.hideColumns(12, 15);
+ pos = cs.offsetByVisibleColumns(8, 5);
+ assertEquals(17, pos);
+
+ // test with two sets of hidden columns between start and required position
+ cs.hideColumns(20, 21);
+ pos = cs.offsetByVisibleColumns(8, 9);
+ assertEquals(23, pos);
+
+ // repeat last 2 tests with no hidden columns to left of required position
+ colsel = new ColumnSelection();
+ cs.revealAllHiddenColumns(colsel);
+
+ // test with one set of hidden columns between start and required position
+ cs.hideColumns(12, 15);
+ pos = cs.offsetByVisibleColumns(8, 5);
+ assertEquals(17, pos);
+
+ // test with two sets of hidden columns between start and required position
+ cs.hideColumns(20, 21);
+ pos = cs.offsetByVisibleColumns(8, 9);
+ assertEquals(23, pos);
+ }
+
+ @Test(groups = "Functional")
+ public void testBoundedIterator()
+ {
+ HiddenColumns h = new HiddenColumns();
+ Iterator<int[]> it = h.getBoundedIterator(0, 10);
+
+ // no hidden columns = nothing to iterate over
+ assertFalse(it.hasNext());
+
+ // [start,end] contains all hidden columns
+ // all regions are returned
+ h.hideColumns(3, 10);
+ h.hideColumns(14, 16);
+ it = h.getBoundedIterator(0, 20);
+ assertTrue(it.hasNext());
+ int[] next = it.next();
+ assertEquals(3, next[0]);
+ assertEquals(10, next[1]);
+ next = it.next();
+ assertEquals(14, next[0]);
+ assertEquals(16, next[1]);
+ assertFalse(it.hasNext());
+
+ // [start,end] overlaps a region
+ // 1 region returned
+ it = h.getBoundedIterator(5, 7);
+ assertTrue(it.hasNext());
+ next = it.next();
+ assertEquals(3, next[0]);
+ assertEquals(10, next[1]);
+ assertFalse(it.hasNext());
+
+ // [start,end] fully contains 1 region and start of last
+ // - 2 regions returned
+ it = h.getBoundedIterator(3, 15);
+ assertTrue(it.hasNext());
+ next = it.next();
+ assertEquals(3, next[0]);
+ assertEquals(10, next[1]);
+ next = it.next();
+ assertEquals(14, next[0]);
+ assertEquals(16, next[1]);
+ assertFalse(it.hasNext());
+
+ // [start,end] contains end of first region and whole of last region
+ // - 2 regions returned
+ it = h.getBoundedIterator(4, 20);
+ assertTrue(it.hasNext());
+ next = it.next();
+ assertEquals(3, next[0]);
+ assertEquals(10, next[1]);
+ next = it.next();
+ assertEquals(14, next[0]);
+ assertEquals(16, next[1]);
+ assertFalse(it.hasNext());
+ }
+
+ @Test(groups = "Functional")
+ public void testBoundedStartIterator()
+ {
+ HiddenColumns h = new HiddenColumns();
+ Iterator<Integer> it = h.getStartRegionIterator(0, 10);
+
+ // no hidden columns = nothing to iterate over
+ assertFalse(it.hasNext());
+
+ // [start,end] contains all hidden columns
+ // all regions are returned
+ h.hideColumns(3, 10);
+ h.hideColumns(14, 16);
+ it = h.getStartRegionIterator(0, 20);
+ assertTrue(it.hasNext());
+ int next = it.next();
+ assertEquals(3, next);
+ next = it.next();
+ assertEquals(6, next);
+ assertFalse(it.hasNext());
+
+ // [start,end] does not contain a start of a region
+ // no regions to iterate over
+ it = h.getStartRegionIterator(4, 5);
+ assertFalse(it.hasNext());
+
+ // [start,end] fully contains 1 region and start of last
+ // - 2 regions returned
+ it = h.getStartRegionIterator(3, 7);
+ assertTrue(it.hasNext());
+ next = it.next();
+ assertEquals(3, next);
+ next = it.next();
+ assertEquals(6, next);
+ assertFalse(it.hasNext());
+
+ // [start,end] contains whole of last region
+ // - 1 region returned
+ it = h.getStartRegionIterator(4, 20);
+ assertTrue(it.hasNext());
+ next = it.next();
+ assertEquals(6, next);
+ assertFalse(it.hasNext());
+ }
+
+ @Test(groups = "Functional")
+ public void testVisibleBlocksVisBoundsIterator()
+ {
+ HiddenColumns h = new HiddenColumns();
+ Iterator<int[]> regions = h.getVisContigsIterator(0, 31, true);
+
+ // only 1 visible region spanning 0-30 if nothing is hidden
+ assertTrue(regions.hasNext());
+ int[] region = regions.next();
+ assertEquals(0, region[0]);
+ assertEquals(30, region[1]);
+ assertFalse(regions.hasNext());
+
+ // hide 1 region in middle
+ // 2 regions one on either side
+ // second region boundary accounts for hidden columns
+ h.hideColumns(10, 15);
+ regions = h.getVisContigsIterator(0, 31, true);
+
+ assertTrue(regions.hasNext());
+ region = regions.next();
+ assertEquals(0, region[0]);
+ assertEquals(9, region[1]);
+ region = regions.next();
+ assertEquals(16, region[0]);
+ assertEquals(36, region[1]);
+ assertFalse(regions.hasNext());
+
+ // single hidden region at left
+ h = new HiddenColumns();
+ h.hideColumns(0, 5);
+ regions = h.getVisContigsIterator(0, 31, true);
+
+ assertTrue(regions.hasNext());
+ region = regions.next();
+ assertEquals(6, region[0]);
+ assertEquals(36, region[1]);
+ assertFalse(regions.hasNext());
+
+ // single hidden region at right
+ h = new HiddenColumns();
+ h.hideColumns(27, 30);
+ regions = h.getVisContigsIterator(0, 31, true);
+
+ assertTrue(regions.hasNext());
+ region = regions.next();
+ assertEquals(0, region[0]);
+ assertEquals(26, region[1]);
+ region = regions.next();
+ assertEquals(31, region[0]);
+ assertEquals(34, region[1]);
+ assertFalse(regions.hasNext());
+
+ // hidden region at left + hidden region in middle
+ h = new HiddenColumns();
+ h.hideColumns(0, 5);
+ h.hideColumns(23, 25);
+ regions = h.getVisContigsIterator(0, 31, true);
+
+ assertTrue(regions.hasNext());
+ region = regions.next();
+ assertEquals(6, region[0]);
+ assertEquals(22, region[1]);
+ region = regions.next();
+ assertEquals(26, region[0]);
+ assertEquals(39, region[1]);
+ assertFalse(regions.hasNext());
+
+ // hidden region at right + hidden region in middle
+ h = new HiddenColumns();
+ h.hideColumns(27, 30);
+ h.hideColumns(11, 14);
+ regions = h.getVisContigsIterator(0, 31, true);
+
+ assertTrue(regions.hasNext());
+ region = regions.next();
+ assertEquals(0, region[0]);
+ assertEquals(10, region[1]);
+ region = regions.next();
+ assertEquals(15, region[0]);
+ assertEquals(26, region[1]);
+ region = regions.next();
+ assertEquals(31, region[0]);
+ assertEquals(38, region[1]);
+ assertFalse(regions.hasNext());
+
+ // hidden region at left and right
+ h = new HiddenColumns();
+ h.hideColumns(27, 35);
+ h.hideColumns(0, 4);
+ regions = h.getVisContigsIterator(0, 31, true);
+
+ assertTrue(regions.hasNext());
+ region = regions.next();
+ assertEquals(5, region[0]);
+ assertEquals(26, region[1]);
+ region = regions.next();
+ assertEquals(36, region[0]);
+ assertEquals(44, region[1]);
+ assertFalse(regions.hasNext());
+
+ // multiple hidden regions
+ h = new HiddenColumns();
+ h.hideColumns(1, 1);
+ h.hideColumns(3, 5);
+ h.hideColumns(9, 11);
+ h.hideColumns(22, 26);
+
+ regions = h.getVisContigsIterator(0, 31, true);
+
+ assertTrue(regions.hasNext());
+ region = regions.next();
+ assertEquals(0, region[0]);
+ assertEquals(0, region[1]);
+ region = regions.next();
+ assertEquals(2, region[0]);
+ assertEquals(2, region[1]);
+ region = regions.next();
+ assertEquals(6, region[0]);
+ assertEquals(8, region[1]);
+ region = regions.next();
+ assertEquals(12, region[0]);
+ assertEquals(21, region[1]);
+ region = regions.next();
+ assertEquals(27, region[0]);
+ assertEquals(42, region[1]);
+ assertFalse(regions.hasNext());
+ }
+
+ /*
+ * the VisibleColsIterator is tested elsewhere, this just tests that
+ * it can be retrieved from HiddenColumns
+ */
+ @Test(groups = "Functional")
+ public void testGetVisibleColsIterator()
+ {
+ HiddenColumns h = new HiddenColumns();
+ Iterator<Integer> it = h.getVisibleColsIterator(0, 10);
+
+ assertTrue(it instanceof RangeElementsIterator);
+ }
+
+ @Test(groups = "Functional")
+ public void testHashCode()
+ {
+ HiddenColumns h = new HiddenColumns();
+ h.hideColumns(0, 25);
+
+ int result = h.hashCode();
+ assertTrue(result > 0);
+
+ h.hideColumns(30, 50);
+ assertTrue(h.hashCode() > 0);
+ assertTrue(result != h.hashCode());
}
}
import static org.testng.Assert.assertTrue;
+import java.util.Iterator;
import java.util.NoSuchElementException;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-public class VisibleColsIteratorTest
+public class RangeElementsIteratorTest
{
HiddenColumns hiddenCols;
@Test(groups = { "Functional" })
public void testHasNextAndNextWithHidden()
{
- VisibleColsIterator it = new VisibleColsIterator(0, 6, hiddenCols);
+ Iterator<Integer> it = hiddenCols.getVisibleColsIterator(0, 6);
int count = 0;
while (it.hasNext())
{
- it.next();
+ int result = it.next();
+ System.out.println(result);
count++;
}
assertTrue(count == 4, "hasNext() is false after 4 iterations");
@Test(groups = { "Functional" })
public void testHasNextAndNextNoHidden()
{
- VisibleColsIterator it2 = new VisibleColsIterator(0, 3,
- new HiddenColumns());
+ HiddenColumns test = new HiddenColumns();
+ Iterator<Integer> it2 = test.getVisibleColsIterator(0, 3);
int count = 0;
while (it2.hasNext())
{
@Test(groups = { "Functional" })
public void testHasNextAndNextStartHidden()
{
- VisibleColsIterator it3 = new VisibleColsIterator(0, 6,
- hiddenColsAtStart);
+ Iterator<Integer> it3 = hiddenColsAtStart.getVisibleColsIterator(0, 6);
int count = 0;
while (it3.hasNext())
{
@Test(groups = { "Functional" })
public void testHasNextAndNextEndHidden()
{
- VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols);
+ Iterator<Integer> it4 = hiddenCols.getVisibleColsIterator(0, 4);
int count = 0;
while (it4.hasNext())
{
expectedExceptions = { NoSuchElementException.class })
public void testLastNextWithHidden() throws NoSuchElementException
{
- VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols);
+ Iterator<Integer> it = hiddenCols.getVisibleColsIterator(0, 3);
while (it.hasNext())
{
it.next();
expectedExceptions = { NoSuchElementException.class })
public void testLastNextNoHidden() throws NoSuchElementException
{
- VisibleColsIterator it2 = new VisibleColsIterator(0, 3,
- new HiddenColumns());
+ HiddenColumns test = new HiddenColumns();
+ Iterator<Integer> it2 = test.getVisibleColsIterator(0, 3);
while (it2.hasNext())
{
it2.next();
expectedExceptions = { NoSuchElementException.class })
public void testLastNextStartHidden() throws NoSuchElementException
{
- VisibleColsIterator it3 = new VisibleColsIterator(0, 6,
- hiddenColsAtStart);
+ Iterator<Integer> it3 = hiddenColsAtStart.getVisibleColsIterator(0, 6);
while (it3.hasNext())
{
it3.next();
expectedExceptions = { NoSuchElementException.class })
public void testLastNextEndHidden() throws NoSuchElementException
{
- VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols);
+ Iterator<Integer> it4 = hiddenCols.getVisibleColsIterator(0, 4);
while (it4.hasNext())
{
it4.next();
expectedExceptions = { UnsupportedOperationException.class })
public void testRemove() throws UnsupportedOperationException
{
- VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols);
+ Iterator<Integer> it = hiddenCols.getVisibleColsIterator(0, 3);
it.remove();
}
}
"group");
assertTrue(sf.isContactFeature());
}
+
+ @Test(groups = { "Functional" })
+ public void testGetDetailsReport()
+ {
+ // single locus, no group, no score
+ SequenceFeature sf = new SequenceFeature("variant", "G,C", 22, 22, null);
+ String expected = "<br><table><tr><td>Type</td><td>variant</td><td></td></tr>"
+ + "<tr><td>Start/end</td><td>22</td><td></td></tr>"
+ + "<tr><td>Description</td><td>G,C</td><td></td></tr></table>";
+ assertEquals(expected, sf.getDetailsReport());
+
+ // contact feature
+ sf = new SequenceFeature("Disulphide Bond", "a description", 28, 31,
+ null);
+ expected = "<br><table><tr><td>Type</td><td>Disulphide Bond</td><td></td></tr>"
+ + "<tr><td>Start/end</td><td>28:31</td><td></td></tr>"
+ + "<tr><td>Description</td><td>a description</td><td></td></tr></table>";
+ assertEquals(expected, sf.getDetailsReport());
+
+ sf = new SequenceFeature("variant", "G,C", 22, 33,
+ 12.5f, "group");
+ sf.setValue("Parent", "ENSG001");
+ sf.setValue("Child", "ENSP002");
+ expected = "<br><table><tr><td>Type</td><td>variant</td><td></td></tr>"
+ + "<tr><td>Start/end</td><td>22-33</td><td></td></tr>"
+ + "<tr><td>Description</td><td>G,C</td><td></td></tr>"
+ + "<tr><td>Score</td><td>12.5</td><td></td></tr>"
+ + "<tr><td>Group</td><td>group</td><td></td></tr>"
+ + "<tr><td>Child</td><td></td><td>ENSP002</td></tr>"
+ + "<tr><td>Parent</td><td></td><td>ENSG001</td></tr></table>";
+ assertEquals(expected, sf.getDetailsReport());
+
+ /*
+ * feature with embedded html link in description
+ */
+ String desc = "<html>Fer2 Status: True Positive <a href=\"http://pfam.xfam.org/family/PF00111\">Pfam 8_8</a></html>";
+ sf = new SequenceFeature("Pfam", desc, 8, 83, "Uniprot");
+ expected = "<br><table><tr><td>Type</td><td>Pfam</td><td></td></tr>"
+ + "<tr><td>Start/end</td><td>8-83</td><td></td></tr>"
+ + "<tr><td>Description</td><td>Fer2 Status: True Positive <a href=\"http://pfam.xfam.org/family/PF00111\">Pfam 8_8</a></td><td></td></tr>"
+ + "<tr><td>Group</td><td>Uniprot</td><td></td></tr></table>";
+ assertEquals(expected, sf.getDetailsReport());
+ }
}
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
+import jalview.analysis.AlignmentGenerator;
import jalview.commands.EditCommand;
import jalview.commands.EditCommand.Action;
import jalview.datamodel.PDBEntry.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Vector;
-import junit.extensions.PA;
-
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
public class SequenceTest
{
sq.sequenceChanged();
assertEquals(6, sq.findIndex(9));
- sq = new Sequence("test/8-13", "-A--B-C-D-E-F--");
+ final String aligned = "-A--B-C-D-E-F--";
+ assertEquals(15, aligned.length());
+ sq = new Sequence("test/8-13", aligned);
assertEquals(2, sq.findIndex(8));
sq.sequenceChanged();
assertEquals(5, sq.findIndex(9));
// beyond end returns last residue column
sq.sequenceChanged();
assertEquals(13, sq.findIndex(99));
+
+ /*
+ * residue before sequence 'end' but beyond end of sequence returns
+ * length of sequence (last column) (rightly or wrongly!)
+ */
+ sq = new Sequence("test/8-15", "A-B-C-"); // trailing gap case
+ assertEquals(6, sq.getLength());
+ sq.sequenceChanged();
+ assertEquals(sq.getLength(), sq.findIndex(14));
+ sq = new Sequence("test/8-99", "-A--B-C-D"); // trailing residue case
+ sq.sequenceChanged();
+ assertEquals(sq.getLength(), sq.findIndex(65));
+
+ /*
+ * residue after sequence 'start' but before first residue returns
+ * zero (before first column) (rightly or wrongly!)
+ */
+ sq = new Sequence("test/8-15", "-A-B-C-"); // leading gap case
+ sq.sequenceChanged();
+ assertEquals(0, sq.findIndex(3));
+ sq = new Sequence("test/8-15", "A-B-C-"); // leading residue case
+ sq.sequenceChanged();
+ assertEquals(0, sq.findIndex(2));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testFindPositions()
+ {
+ SequenceI sq = new Sequence("test/8-13", "-ABC---DE-F--");
+
+ /*
+ * invalid inputs
+ */
+ assertNull(sq.findPositions(6, 5));
+ assertNull(sq.findPositions(0, 5));
+ assertNull(sq.findPositions(-1, 5));
+
+ /*
+ * all gapped ranges
+ */
+ assertNull(sq.findPositions(1, 1)); // 1-based columns
+ assertNull(sq.findPositions(5, 5));
+ assertNull(sq.findPositions(5, 6));
+ assertNull(sq.findPositions(5, 7));
+
+ /*
+ * all ungapped ranges
+ */
+ assertEquals(new Range(8, 8), sq.findPositions(2, 2)); // A
+ assertEquals(new Range(8, 9), sq.findPositions(2, 3)); // AB
+ assertEquals(new Range(8, 10), sq.findPositions(2, 4)); // ABC
+ assertEquals(new Range(9, 10), sq.findPositions(3, 4)); // BC
+
+ /*
+ * gap to ungapped range
+ */
+ assertEquals(new Range(8, 10), sq.findPositions(1, 4)); // ABC
+ assertEquals(new Range(11, 12), sq.findPositions(6, 9)); // DE
+
+ /*
+ * ungapped to gapped range
+ */
+ assertEquals(new Range(10, 10), sq.findPositions(4, 5)); // C
+ assertEquals(new Range(9, 13), sq.findPositions(3, 11)); // BCDEF
+
+ /*
+ * ungapped to ungapped enclosing gaps
+ */
+ assertEquals(new Range(10, 11), sq.findPositions(4, 8)); // CD
+ assertEquals(new Range(8, 13), sq.findPositions(2, 11)); // ABCDEF
+
+ /*
+ * gapped to gapped enclosing ungapped
+ */
+ assertEquals(new Range(8, 10), sq.findPositions(1, 5)); // ABC
+ assertEquals(new Range(11, 12), sq.findPositions(5, 10)); // DE
+ assertEquals(new Range(8, 13), sq.findPositions(1, 13)); // the lot
+ assertEquals(new Range(8, 13), sq.findPositions(1, 99));
}
/**
assertEquals("test:Pos13:Col10:startCol3:endCol10:tok0",
PA.getValue(sq, "cursor").toString());
sq.sequenceChanged();
- assertEquals(12, sq.findPosition(8));
- cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertEquals(12, sq.findPosition(8)); // E12
// sequenceChanged() invalidates cursor.lastResidueColumn
cursor = (SequenceCursor) PA.getValue(sq, "cursor");
assertEquals("test:Pos12:Col9:startCol3:endCol0:tok1",
assertEquals(6, sq.getEnd());
assertNull(PA.getValue(sq, "datasetSequence"));
+ sq = new Sequence("test", "ABCDE");
+ sq.deleteChars(0, 3);
+ assertEquals("DE", sq.getSequenceAsString());
+ assertEquals(4, sq.getStart());
+ assertEquals(5, sq.getEnd());
+ assertNull(PA.getValue(sq, "datasetSequence"));
+
/*
* delete at end
*/
assertEquals(1, sq.getStart());
assertEquals(4, sq.getEnd());
assertNull(PA.getValue(sq, "datasetSequence"));
+
+ /*
+ * delete more positions than there are
+ */
+ sq = new Sequence("test/8-11", "ABCD");
+ sq.deleteChars(0, 99);
+ assertEquals("", sq.getSequenceAsString());
+ assertEquals(12, sq.getStart()); // = findPosition(99) ?!?
+ assertEquals(11, sq.getEnd());
+
+ sq = new Sequence("test/8-11", "----");
+ sq.deleteChars(0, 99); // ArrayIndexOutOfBoundsException <= 2.10.2
+ assertEquals("", sq.getSequenceAsString());
+ assertEquals(8, sq.getStart());
+ assertEquals(11, sq.getEnd());
}
@Test(groups = { "Functional" })
Assert.assertEquals(pdbe1a,
sq.getDatasetSequence().getPDBEntry("1PDB"),
"PDB Entry '1PDB' not found on dataset sequence via getPDBEntry.");
- ArrayList<Annotation> annotsList = new ArrayList<Annotation>();
+ ArrayList<Annotation> annotsList = new ArrayList<>();
System.out.println(">>>>>> " + sq.getSequenceAsString().length());
annotsList.add(new Annotation("A", "A", 'X', 0.1f));
annotsList.add(new Annotation("A", "A", 'X', 0.1f));
{
Sequence sq = new Sequence("test/8-13", "-A--BCD-EF--");
- // find F given A
+ // find F given A, check cursor is now at the found position
assertEquals(10, sq.findIndex(13, new SequenceCursor(sq, 8, 2, 0)));
+ SequenceCursor cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertEquals(13, cursor.residuePosition);
+ assertEquals(10, cursor.columnPosition);
// find A given F
assertEquals(2, sq.findIndex(8, new SequenceCursor(sq, 13, 10, 0)));
+ cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertEquals(8, cursor.residuePosition);
+ assertEquals(2, cursor.columnPosition);
- // find C given C
+ // find C given C (no cursor update is done for this case)
assertEquals(6, sq.findIndex(10, new SequenceCursor(sq, 10, 6, 0)));
+ SequenceCursor cursor2 = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertSame(cursor2, cursor);
+
+ /*
+ * sequence 'end' beyond end of sequence returns length of sequence
+ * (for compatibility with pre-cursor code)
+ * - also verify the cursor is left in a valid state
+ */
+ sq = new Sequence("test/8-99", "-A--B-C-D-E-F--"); // trailing gap case
+ assertEquals(7, sq.findIndex(10)); // establishes a cursor
+ cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertEquals(10, cursor.residuePosition);
+ assertEquals(7, cursor.columnPosition);
+ assertEquals(sq.getLength(), sq.findIndex(65));
+ cursor2 = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertSame(cursor, cursor2); // not updated for this case!
+
+ sq = new Sequence("test/8-99", "-A--B-C-D-E-F"); // trailing residue case
+ sq.findIndex(10); // establishes a cursor
+ cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertEquals(sq.getLength(), sq.findIndex(65));
+ cursor2 = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertSame(cursor, cursor2); // not updated for this case!
+
+ /*
+ * residue after sequence 'start' but before first residue should return
+ * zero (for compatibility with pre-cursor code)
+ */
+ sq = new Sequence("test/8-15", "-A-B-C-"); // leading gap case
+ sq.findIndex(10); // establishes a cursor
+ cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertEquals(0, sq.findIndex(3));
+ cursor2 = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertSame(cursor, cursor2); // not updated for this case!
+
+ sq = new Sequence("test/8-15", "A-B-C-"); // leading residue case
+ sq.findIndex(10); // establishes a cursor
+ cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertEquals(0, sq.findIndex(2));
+ cursor2 = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertSame(cursor, cursor2); // not updated for this case!
}
@Test(groups = { "Functional" })
// cursor should now be at [D 6]
cursor = (SequenceCursor) PA.getValue(sq, "cursor");
assertEquals(new SequenceCursor(sq, 11, 6, ++token), cursor);
+ assertEquals(0, cursor.lastColumnPosition); // not yet found
+ assertEquals(13, sq.findPosition(8)); // E13
+ cursor = (SequenceCursor) PA.getValue(sq, "cursor");
+ assertEquals(9, cursor.lastColumnPosition); // found
/*
* deleteChars should invalidate the cached cursor
}
@Test(groups = { "Functional" })
- public void testFindPositions()
+ public void testGapBitset()
{
SequenceI sq = new Sequence("test/8-13", "-ABC---DE-F--");
+ BitSet bs = sq.gapBitset();
+ BitSet expected = new BitSet();
+ expected.set(0);
+ expected.set(4, 7);
+ expected.set(9);
+ expected.set(11, 13);
- /*
- * invalid inputs
- */
- assertNull(sq.findPositions(6, 5));
- assertNull(sq.findPositions(0, 5));
- assertNull(sq.findPositions(-1, 5));
-
- /*
- * all gapped ranges
- */
- assertNull(sq.findPositions(1, 1)); // 1-based columns
- assertNull(sq.findPositions(5, 5));
- assertNull(sq.findPositions(5, 6));
- assertNull(sq.findPositions(5, 7));
-
- /*
- * all ungapped ranges
- */
- assertEquals(new Range(8, 8), sq.findPositions(2, 2)); // A
- assertEquals(new Range(8, 9), sq.findPositions(2, 3)); // AB
- assertEquals(new Range(8, 10), sq.findPositions(2, 4)); // ABC
- assertEquals(new Range(9, 10), sq.findPositions(3, 4)); // BC
-
- /*
- * gap to ungapped range
- */
- assertEquals(new Range(8, 10), sq.findPositions(1, 4)); // ABC
- assertEquals(new Range(11, 12), sq.findPositions(6, 9)); // DE
+ assertTrue(bs.equals(expected));
- /*
- * ungapped to gapped range
- */
- assertEquals(new Range(10, 10), sq.findPositions(4, 5)); // C
- assertEquals(new Range(9, 13), sq.findPositions(3, 11)); // BCDEF
-
- /*
- * ungapped to ungapped enclosing gaps
- */
- assertEquals(new Range(10, 11), sq.findPositions(4, 8)); // CD
- assertEquals(new Range(8, 13), sq.findPositions(2, 11)); // ABCDEF
-
- /*
- * gapped to gapped enclosing ungapped
- */
- assertEquals(new Range(8, 10), sq.findPositions(1, 5)); // ABC
- assertEquals(new Range(11, 12), sq.findPositions(5, 10)); // DE
- assertEquals(new Range(8, 13), sq.findPositions(1, 13)); // the lot
- assertEquals(new Range(8, 13), sq.findPositions(1, 99));
}
- @Test(groups = { "Functional" })
public void testFindFeatures_largeEndPos()
{
/*
assertEquals(8, sq.getDatasetSequence().getStart());
assertEquals(9, sq.getDatasetSequence().getEnd());
}
+
+ /**
+ * Test the code used to locate the reference sequence ruler origin
+ */
+ @Test(groups = { "Functional" })
+ public void testLocateVisibleStartofSequence()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
+ HiddenColumns cs = al.getHiddenColumns();
+ ColumnSelection colsel = new ColumnSelection();
+
+ SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
+ assertEquals(2, seq.findIndex(seq.getStart()));
+
+ // no hidden columns
+ assertEquals(seq.findIndex(seq.getStart()) - 1,
+ seq.firstResidueOutsideIterator(cs.iterator()));
+
+ // hidden column on gap after end of sequence - should not affect bounds
+ colsel.hideSelectedColumns(13, al.getHiddenColumns());
+ assertEquals(seq.findIndex(seq.getStart()) - 1,
+ seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ // hidden column on gap before beginning of sequence - should vis bounds by
+ // one
+ colsel.hideSelectedColumns(0, al.getHiddenColumns());
+ assertEquals(seq.findIndex(seq.getStart()) - 2,
+ cs.absoluteToVisibleColumn(
+ seq.firstResidueOutsideIterator(cs.iterator())));
+
+ cs.revealAllHiddenColumns(colsel);
+ // hide columns around most of sequence - leave one residue remaining
+ cs.hideColumns(1, 3);
+ cs.hideColumns(6, 11);
+
+ Iterator<int[]> it = cs.getVisContigsIterator(0, 6, false);
+
+ assertEquals("-D", seq.getSequenceStringFromIterator(it));
+ // cs.getVisibleSequenceStrings(0, 5, new SequenceI[]
+ // { seq })[0]);
+
+ assertEquals(4, seq.firstResidueOutsideIterator(cs.iterator()));
+ cs.revealAllHiddenColumns(colsel);
+
+ // hide whole sequence - should just get location of hidden region
+ // containing sequence
+ cs.hideColumns(1, 11);
+ assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 15);
+ assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ SequenceI seq2 = new Sequence("RefSeq2", "-------A-SD-ASD--E---");
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(7, 17);
+ assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(3, 17);
+ assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(3, 19);
+ assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 0);
+ assertEquals(1, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 1);
+ assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 2);
+ assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(1, 1);
+ assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(1, 2);
+ assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(1, 3);
+ assertEquals(4, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 2);
+ cs.hideColumns(5, 6);
+ assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 2);
+ cs.hideColumns(5, 6);
+ cs.hideColumns(9, 10);
+ assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 2);
+ cs.hideColumns(7, 11);
+ assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(2, 4);
+ cs.hideColumns(7, 11);
+ assertEquals(1, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(2, 4);
+ cs.hideColumns(7, 12);
+ assertEquals(1, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(1, 11);
+ assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 12);
+ assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 4);
+ cs.hideColumns(6, 12);
+ assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 1);
+ cs.hideColumns(3, 12);
+ assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(3, 14);
+ cs.hideColumns(17, 19);
+ assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(3, 7);
+ cs.hideColumns(9, 14);
+ cs.hideColumns(17, 19);
+ assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator()));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(0, 1);
+ cs.hideColumns(3, 4);
+ cs.hideColumns(6, 8);
+ cs.hideColumns(10, 12);
+ assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator()));
+
+ }
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class StartRegionIteratorTest
+{
+ /**
+ * Test the start region iterator
+ */
+ @Test(groups = { "Functional" })
+ public void testBasicBoundsIterator()
+ {
+ List<int[]> hiddenColumns = null;
+
+ // null hidden columns
+ Iterator<Integer> it = new StartRegionIterator(3, 10,
+ hiddenColumns);
+ assertFalse(it.hasNext());
+
+ hiddenColumns = new ArrayList<>();
+
+ // no hidden columns
+ it = new StartRegionIterator(3, 10, hiddenColumns);
+ assertFalse(it.hasNext());
+
+ // add some hidden columns
+ hiddenColumns.add(new int[] { 5, 10 });
+ hiddenColumns.add(new int[] { 25, 40 });
+
+ it = new StartRegionIterator(3, 10, hiddenColumns);
+ assertTrue(it.hasNext());
+ Integer result = it.next();
+ assertEquals(5, (int) result);
+ assertFalse(it.hasNext());
+
+ it = new StartRegionIterator(3, 15, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(5, (int) result);
+ assertFalse(it.hasNext());
+
+ it = new StartRegionIterator(3, 18, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(5, (int) result);
+ assertFalse(it.hasNext());
+
+ it = new StartRegionIterator(3, 19, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(5, (int) result);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(19, (int) result);
+ assertFalse(it.hasNext());
+
+ hiddenColumns.add(new int[] { 47, 50 });
+
+ it = new StartRegionIterator(15, 60, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(19, (int) result);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(25, (int) result);
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * Test the start region iterator with null cursor
+ */
+ @Test(groups = { "Functional" })
+ public void testBoundsIteratorUsingNullCursor()
+ {
+ List<int[]> hiddenColumns = null;
+ HiddenCursorPosition pos = null;
+
+ // null hidden columns
+ Iterator<Integer> it = new StartRegionIterator(pos, 3, 10,
+ hiddenColumns);
+ assertFalse(it.hasNext());
+
+ hiddenColumns = new ArrayList<>();
+
+ // no hidden columns
+ it = new StartRegionIterator(pos, 3, 10, hiddenColumns);
+ assertFalse(it.hasNext());
+
+ // add some hidden columns
+ hiddenColumns.add(new int[] { 5, 10 });
+ hiddenColumns.add(new int[] { 25, 40 });
+
+ it = new StartRegionIterator(pos, 3, 10, hiddenColumns);
+ assertTrue(it.hasNext());
+ Integer result = it.next();
+ assertEquals(5, (int) result);
+ assertFalse(it.hasNext());
+
+ it = new StartRegionIterator(pos, 3, 15, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(5, (int) result);
+ assertFalse(it.hasNext());
+
+ it = new StartRegionIterator(pos, 3, 18, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(5, (int) result);
+ assertFalse(it.hasNext());
+
+ it = new StartRegionIterator(pos, 3, 19, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(5, (int) result);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(19, (int) result);
+ assertFalse(it.hasNext());
+
+ hiddenColumns.add(new int[] { 47, 50 });
+
+ it = new StartRegionIterator(pos, 15, 60, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(19, (int) result);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(25, (int) result);
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * Test the start region iterator with nonnull cursor
+ */
+ @Test(groups = { "Functional" })
+ public void testBoundsIteratorUsingCursor()
+ {
+ List<int[]> hiddenColumns = new ArrayList<>();
+
+ // add some hidden columns
+ hiddenColumns.add(new int[] { 5, 10 });
+ hiddenColumns.add(new int[] { 25, 40 });
+
+ HiddenCursorPosition pos = new HiddenCursorPosition(0, 0);
+
+ Iterator<Integer> it = new StartRegionIterator(pos, 3, 10,
+ hiddenColumns);
+ assertTrue(it.hasNext());
+ Integer result = it.next();
+ assertEquals(5, (int) result);
+ assertFalse(it.hasNext());
+
+ it = new StartRegionIterator(pos, 3, 15, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(5, (int) result);
+ assertFalse(it.hasNext());
+
+ it = new StartRegionIterator(pos, 3, 18, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(5, (int) result);
+ assertFalse(it.hasNext());
+
+ it = new StartRegionIterator(pos, 3, 19, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(5, (int) result);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(19, (int) result);
+ assertFalse(it.hasNext());
+
+ pos = new HiddenCursorPosition(1, 6);
+ hiddenColumns.add(new int[] { 47, 50 });
+
+ it = new StartRegionIterator(pos, 15, 60, hiddenColumns);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(19, (int) result);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(25, (int) result);
+ assertFalse(it.hasNext());
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class VisibleContigsIteratorTest
+{
+ /**
+ * Test the iterator with single visible regions
+ */
+ @Test(groups = { "Functional" })
+ public void testSimpleVisibleRegions()
+ {
+ List<int[]> hiddenColumns = null;
+
+ // null hidden columns
+ VisibleContigsIterator it = new VisibleContigsIterator(3, 10,
+ hiddenColumns);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ int[] result = it.next();
+ assertEquals(3, result[0]);
+ assertEquals(9, result[1]);
+ assertFalse(it.hasNext());
+ assertFalse(it.endsAtHidden());
+
+ hiddenColumns = new ArrayList<>();
+
+ // no hidden columns
+ it = new VisibleContigsIterator(3, 10,
+ hiddenColumns);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(3, result[0]);
+ assertEquals(9, result[1]);
+ assertFalse(it.hasNext());
+ assertFalse(it.endsAtHidden());
+
+ // hidden columns, but not where we are looking
+ hiddenColumns.add(new int[] { 5, 10 });
+ hiddenColumns.add(new int[] { 25, 40 });
+
+ it = new VisibleContigsIterator(2, 3, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(2, result[0]);
+ assertEquals(2, result[1]);
+ assertFalse(it.hasNext());
+ assertFalse(it.endsAtHidden());
+
+ it = new VisibleContigsIterator(5, 7, hiddenColumns);
+ assertFalse(it.hasNext());
+ assertFalse(it.endsAtHidden());
+
+ it = new VisibleContigsIterator(11, 15, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(11, result[0]);
+ assertEquals(14, result[1]);
+ assertFalse(it.hasNext());
+ assertFalse(it.endsAtHidden());
+
+ it = new VisibleContigsIterator(50, 60, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(50, result[0]);
+ assertEquals(59, result[1]);
+ assertFalse(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ }
+
+ /**
+ * Test the iterator with multiple visible regions
+ */
+ @Test(groups = { "Functional" })
+ public void testMultipleVisibleRegions()
+ {
+ List<int[]> hiddenColumns = new ArrayList<>();
+ hiddenColumns.add(new int[] { 5, 10 });
+ hiddenColumns.add(new int[] { 25, 40 });
+
+ // all hidden columns covered
+ VisibleContigsIterator it = new VisibleContigsIterator(3, 50,
+ hiddenColumns);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ int[] result = it.next();
+ assertEquals(3, result[0]);
+ assertEquals(4, result[1]);
+
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(11, result[0]);
+ assertEquals(24, result[1]);
+
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(41, result[0]);
+ assertEquals(49, result[1]);
+
+ assertFalse(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ }
+
+ /**
+ * Test the iterator with regions which start/end at hidden region edges
+ */
+ @Test(groups = { "Functional" })
+ public void testVisibleRegionsAtHiddenEdges()
+ {
+ List<int[]> hiddenColumns = new ArrayList<>();
+ hiddenColumns.add(new int[] { 5, 10 });
+ hiddenColumns.add(new int[] { 25, 40 });
+
+ VisibleContigsIterator it = new VisibleContigsIterator(0, 10,
+ hiddenColumns);
+ assertTrue(it.hasNext());
+ assertTrue(it.endsAtHidden());
+ int[] result = it.next();
+ assertEquals(0, result[0]);
+ assertEquals(4, result[1]);
+ assertFalse(it.hasNext());
+ assertTrue(it.endsAtHidden());
+
+ it = new VisibleContigsIterator(2, 11, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertTrue(it.endsAtHidden());
+ result = it.next();
+ assertEquals(2, result[0]);
+ assertEquals(4, result[1]);
+ assertFalse(it.hasNext());
+ assertTrue(it.endsAtHidden());
+
+ it = new VisibleContigsIterator(2, 12, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(2, result[0]);
+ assertEquals(4, result[1]);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(11, result[0]);
+ assertEquals(11, result[1]);
+ assertFalse(it.hasNext());
+ assertFalse(it.endsAtHidden());
+
+ it = new VisibleContigsIterator(13, 25, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(13, result[0]);
+ assertEquals(24, result[1]);
+ assertFalse(it.hasNext());
+
+ it = new VisibleContigsIterator(13, 26, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertTrue(it.endsAtHidden());
+ result = it.next();
+ assertEquals(13, result[0]);
+ assertEquals(24, result[1]);
+ assertFalse(it.hasNext());
+
+ it = new VisibleContigsIterator(13, 27, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertTrue(it.endsAtHidden());
+ result = it.next();
+ assertEquals(13, result[0]);
+ assertEquals(24, result[1]);
+ assertFalse(it.hasNext());
+
+ it = new VisibleContigsIterator(13, 41, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertTrue(it.endsAtHidden());
+ result = it.next();
+ assertEquals(13, result[0]);
+ assertEquals(24, result[1]);
+ assertFalse(it.hasNext());
+
+ it = new VisibleContigsIterator(13, 42, hiddenColumns);
+ assertTrue(it.hasNext());
+ assertFalse(it.endsAtHidden());
+ result = it.next();
+ assertEquals(13, result[0]);
+ assertEquals(24, result[1]);
+ assertTrue(it.hasNext());
+ result = it.next();
+ assertEquals(41, result[0]);
+ assertEquals(41, result[1]);
+ }
+}
--- /dev/null
+package jalview.datamodel.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.features.FeatureAttributes.Datatype;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import junit.extensions.PA;
+
+public class FeatureAttributesTest
+{
+
+ /**
+ * clear down attributes map before tests
+ */
+ @BeforeClass(alwaysRun = true)
+ public void setUp()
+ {
+ FeatureAttributes fa = FeatureAttributes.getInstance();
+ ((Map<?, ?>) PA.getValue(fa, "attributes")).clear();
+ }
+
+ /**
+ * clear down attributes map after tests
+ */
+ @AfterMethod(alwaysRun = true)
+ public void tearDown()
+ {
+ FeatureAttributes fa = FeatureAttributes.getInstance();
+ ((Map<?, ?>) PA.getValue(fa, "attributes")).clear();
+ }
+
+ /**
+ * Test the method that keeps attribute names in non-case-sensitive order,
+ * including handling of 'compound' names
+ */
+ @Test(groups="Functional")
+ public void testAttributeNameComparator()
+ {
+ FeatureAttributes fa = FeatureAttributes.getInstance();
+ Comparator<String[]> comp = (Comparator<String[]>) PA.getValue(fa,
+ "comparator");
+
+ assertEquals(
+ comp.compare(new String[] { "CSQ" }, new String[] { "csq" }), 0);
+
+ assertTrue(comp.compare(new String[] { "CSQ", "a" },
+ new String[] { "csq" }) > 0);
+
+ assertTrue(comp.compare(new String[] { "CSQ" }, new String[] { "csq",
+ "b" }) < 0);
+
+ assertTrue(comp.compare(new String[] { "CSQ", "AF" }, new String[] {
+ "csq", "ac" }) > 0);
+
+ assertTrue(comp.compare(new String[] { "CSQ", "ac" }, new String[] {
+ "csq", "AF" }) < 0);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetMinMax()
+ {
+ SequenceFeature sf = new SequenceFeature("Pfam", "desc", 10, 20,
+ "group");
+ FeatureAttributes fa = FeatureAttributes.getInstance();
+ assertNull(fa.getMinMax("Pfam", "kd"));
+ sf.setValue("domain", "xyz");
+ assertNull(fa.getMinMax("Pfam", "kd"));
+ sf.setValue("kd", "1.3");
+ assertEquals(fa.getMinMax("Pfam", "kd"), new float[] { 1.3f, 1.3f });
+ sf.setValue("kd", "-2.6");
+ assertEquals(fa.getMinMax("Pfam", "kd"), new float[] { -2.6f, 1.3f });
+ // setting 'mixed' character and numeric values wipes the min/max value
+ sf.setValue("kd", "some text");
+ assertNull(fa.getMinMax("Pfam", "kd"));
+
+ Map<String, String> csq = new HashMap<>();
+ csq.put("AF", "-3");
+ sf.setValue("CSQ", csq);
+ assertEquals(fa.getMinMax("Pfam", "CSQ", "AF"),
+ new float[]
+ { -3f, -3f });
+ csq.put("AF", "4");
+ sf.setValue("CSQ", csq);
+ assertEquals(fa.getMinMax("Pfam", "CSQ", "AF"),
+ new float[]
+ { -3f, 4f });
+ }
+
+ /**
+ * Test the method that returns an attribute description, provided it is
+ * recorded and unique
+ */
+ @Test(groups = "Functional")
+ public void testGetDescription()
+ {
+ FeatureAttributes fa = FeatureAttributes.getInstance();
+ // with no description returns null
+ assertNull(fa.getDescription("Pfam", "kd"));
+ // with a unique description, returns that value
+ fa.addDescription("Pfam", "desc1", "kd");
+ assertEquals(fa.getDescription("Pfam", "kd"), "desc1");
+ // with ambiguous description, returns null
+ fa.addDescription("Pfam", "desc2", "kd");
+ assertNull(fa.getDescription("Pfam", "kd"));
+ }
+
+ @Test(groups = "Functional")
+ public void testDatatype()
+ {
+ FeatureAttributes fa = FeatureAttributes.getInstance();
+ assertNull(fa.getDatatype("Pfam", "kd"));
+ SequenceFeature sf = new SequenceFeature("Pfam", "desc", 10, 20,
+ "group");
+ sf.setValue("kd", "-1");
+ sf.setValue("domain", "Metal");
+ sf.setValue("phase", "1");
+ sf.setValue("phase", "reverse");
+ assertEquals(fa.getDatatype("Pfam", "kd"), Datatype.Number);
+ assertEquals(fa.getDatatype("Pfam", "domain"), Datatype.Character);
+ assertEquals(fa.getDatatype("Pfam", "phase"), Datatype.Mixed);
+ }
+}
--- /dev/null
+package jalview.datamodel.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import jalview.datamodel.SequenceFeature;
+import jalview.util.matcher.Condition;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+public class FeatureMatcherSetTest
+{
+ @Test(groups = "Functional")
+ public void testMatches_byAttribute()
+ {
+ /*
+ * a numeric matcher - MatcherTest covers more conditions
+ */
+ FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
+ "AF");
+ FeatureMatcherSetI fms = new FeatureMatcherSet();
+ fms.and(fm);
+ SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
+ assertFalse(fms.matches(sf));
+ sf.setValue("AF", "foobar");
+ assertFalse(fms.matches(sf));
+ sf.setValue("AF", "-2");
+ assertTrue(fms.matches(sf));
+ sf.setValue("AF", "-1");
+ assertTrue(fms.matches(sf));
+ sf.setValue("AF", "-3");
+ assertFalse(fms.matches(sf));
+ sf.setValue("AF", "");
+ assertFalse(fms.matches(sf));
+
+ /*
+ * a string pattern matcher
+ */
+ fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "AF");
+ fms = new FeatureMatcherSet();
+ fms.and(fm);
+ assertFalse(fms.matches(sf));
+ sf.setValue("AF", "raining cats and dogs");
+ assertTrue(fms.matches(sf));
+ }
+
+ @Test(groups = "Functional")
+ public void testAnd()
+ {
+ // condition1: AF value contains "dog" (matches)
+ FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains,
+ "dog", "AF");
+ // condition 2: CSQ value does not contain "how" (does not match)
+ FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
+ "how", "CSQ");
+
+ SequenceFeature sf = new SequenceFeature("Cath", "helix domain", 11, 12,
+ 6.2f, "grp");
+ sf.setValue("AF", "raining cats and dogs");
+ sf.setValue("CSQ", "showers");
+
+ assertTrue(fm1.matches(sf));
+ assertFalse(fm2.matches(sf));
+
+ FeatureMatcherSetI fms = new FeatureMatcherSet();
+ assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass
+ fms.and(fm1);
+ assertTrue(fms.matches(sf));
+ fms.and(fm2);
+ assertFalse(fms.matches(sf));
+
+ /*
+ * OR a failed attribute condition with a matched label condition
+ */
+ fms = new FeatureMatcherSet();
+ fms.and(fm2);
+ assertFalse(fms.matches(sf));
+ FeatureMatcher byLabelPass = FeatureMatcher.byLabel(Condition.Contains,
+ "Helix");
+ fms.or(byLabelPass);
+ assertTrue(fms.matches(sf));
+
+ /*
+ * OR a failed attribute condition with a failed score condition
+ */
+ fms = new FeatureMatcherSet();
+ fms.and(fm2);
+ assertFalse(fms.matches(sf));
+ FeatureMatcher byScoreFail = FeatureMatcher.byScore(Condition.LT,
+ "5.9");
+ fms.or(byScoreFail);
+ assertFalse(fms.matches(sf));
+
+ /*
+ * OR failed attribute and score conditions with matched label condition
+ */
+ fms = new FeatureMatcherSet();
+ fms.or(fm2);
+ fms.or(byScoreFail);
+ assertFalse(fms.matches(sf));
+ fms.or(byLabelPass);
+ assertTrue(fms.matches(sf));
+ }
+
+ @Test(groups = "Functional")
+ public void testToString()
+ {
+ Locale.setDefault(Locale.ENGLISH);
+ FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
+ "AF");
+ assertEquals(fm1.toString(), "AF < 1.2");
+
+ FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
+ "path", "CLIN_SIG");
+ assertEquals(fm2.toString(), "CLIN_SIG does not contain 'path'");
+
+ /*
+ * AND them
+ */
+ FeatureMatcherSetI fms = new FeatureMatcherSet();
+ assertEquals(fms.toString(), "");
+ fms.and(fm1);
+ assertEquals(fms.toString(), "AF < 1.2");
+ fms.and(fm2);
+ assertEquals(fms.toString(),
+ "(AF < 1.2) and (CLIN_SIG does not contain 'path')");
+
+ /*
+ * OR them
+ */
+ fms = new FeatureMatcherSet();
+ assertEquals(fms.toString(), "");
+ fms.or(fm1);
+ assertEquals(fms.toString(), "AF < 1.2");
+ fms.or(fm2);
+ assertEquals(fms.toString(),
+ "(AF < 1.2) or (CLIN_SIG does not contain 'path')");
+
+ try
+ {
+ fms.and(fm1);
+ fail("Expected exception");
+ } catch (IllegalStateException e)
+ {
+ // expected
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testOr()
+ {
+ // condition1: AF value contains "dog" (matches)
+ FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains,
+ "dog", "AF");
+ // condition 2: CSQ value does not contain "how" (does not match)
+ FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
+ "how", "CSQ");
+
+ SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
+ sf.setValue("AF", "raining cats and dogs");
+ sf.setValue("CSQ", "showers");
+
+ assertTrue(fm1.matches(sf));
+ assertFalse(fm2.matches(sf));
+
+ FeatureMatcherSetI fms = new FeatureMatcherSet();
+ assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass
+ fms.or(fm1);
+ assertTrue(fms.matches(sf));
+ fms.or(fm2);
+ assertTrue(fms.matches(sf)); // true or false makes true
+
+ fms = new FeatureMatcherSet();
+ fms.or(fm2);
+ assertFalse(fms.matches(sf));
+ fms.or(fm1);
+ assertTrue(fms.matches(sf)); // false or true makes true
+
+ try
+ {
+ fms.and(fm2);
+ fail("Expected exception");
+ } catch (IllegalStateException e)
+ {
+ // expected
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testIsEmpty()
+ {
+ FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2.0",
+ "AF");
+ FeatureMatcherSetI fms = new FeatureMatcherSet();
+ assertTrue(fms.isEmpty());
+ fms.and(fm);
+ assertFalse(fms.isEmpty());
+ }
+
+ @Test(groups = "Functional")
+ public void testGetMatchers()
+ {
+ FeatureMatcherSetI fms = new FeatureMatcherSet();
+
+ /*
+ * empty iterable:
+ */
+ Iterator<FeatureMatcherI> iterator = fms.getMatchers().iterator();
+ assertFalse(iterator.hasNext());
+
+ /*
+ * one matcher:
+ */
+ FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.GE, "-2",
+ "AF");
+ fms.and(fm1);
+ iterator = fms.getMatchers().iterator();
+ assertSame(fm1, iterator.next());
+ assertFalse(iterator.hasNext());
+
+ /*
+ * two matchers:
+ */
+ FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.LT, "8f",
+ "AF");
+ fms.and(fm2);
+ iterator = fms.getMatchers().iterator();
+ assertSame(fm1, iterator.next());
+ assertSame(fm2, iterator.next());
+ assertFalse(iterator.hasNext());
+ }
+
+ /**
+ * Tests for the 'compound attribute' key i.e. where first key's value is a map
+ * from which we take the value for the second key, e.g. CSQ : Consequence
+ */
+ @Test(groups = "Functional")
+ public void testMatches_compoundKey()
+ {
+ /*
+ * a numeric matcher - MatcherTest covers more conditions
+ */
+ FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
+ "CSQ", "Consequence");
+ SequenceFeature sf = new SequenceFeature("Cath", "desc", 2, 10, "grp");
+ FeatureMatcherSetI fms = new FeatureMatcherSet();
+ fms.and(fm);
+ assertFalse(fms.matches(sf));
+ Map<String, String> csq = new HashMap<>();
+ sf.setValue("CSQ", csq);
+ assertFalse(fms.matches(sf));
+ csq.put("Consequence", "-2");
+ assertTrue(fms.matches(sf));
+ csq.put("Consequence", "-1");
+ assertTrue(fms.matches(sf));
+ csq.put("Consequence", "-3");
+ assertFalse(fms.matches(sf));
+ csq.put("Consequence", "");
+ assertFalse(fms.matches(sf));
+ csq.put("Consequence", "junk");
+ assertFalse(fms.matches(sf));
+
+ /*
+ * a string pattern matcher
+ */
+ fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "CSQ",
+ "Consequence");
+ fms = new FeatureMatcherSet();
+ fms.and(fm);
+ assertFalse(fms.matches(sf));
+ csq.put("PolyPhen", "damaging");
+ assertFalse(fms.matches(sf));
+ csq.put("Consequence", "damaging");
+ assertFalse(fms.matches(sf));
+ csq.put("Consequence", "Catastrophic");
+ assertTrue(fms.matches(sf));
+ }
+
+ /**
+ * Tests for toStableString which (unlike toString) does not i18n the
+ * conditions
+ *
+ * @see FeatureMatcherTest#testToStableString()
+ */
+ @Test(groups = "Functional")
+ public void testToStableString()
+ {
+ FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
+ "AF");
+ assertEquals(fm1.toStableString(), "AF LT 1.2");
+
+ FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
+ "path", "CLIN_SIG");
+ assertEquals(fm2.toStableString(), "CLIN_SIG NotContains path");
+
+ /*
+ * AND them
+ */
+ FeatureMatcherSetI fms = new FeatureMatcherSet();
+ assertEquals(fms.toStableString(), "");
+ fms.and(fm1);
+ // no brackets needed if a single condition
+ assertEquals(fms.toStableString(), "AF LT 1.2");
+ // brackets if more than one condition
+ fms.and(fm2);
+ assertEquals(fms.toStableString(),
+ "(AF LT 1.2) AND (CLIN_SIG NotContains path)");
+
+ /*
+ * OR them
+ */
+ fms = new FeatureMatcherSet();
+ assertEquals(fms.toStableString(), "");
+ fms.or(fm1);
+ assertEquals(fms.toStableString(), "AF LT 1.2");
+ fms.or(fm2);
+ assertEquals(fms.toStableString(),
+ "(AF LT 1.2) OR (CLIN_SIG NotContains path)");
+
+ /*
+ * attribute or value including space is quoted
+ */
+ FeatureMatcher fm3 = FeatureMatcher.byAttribute(Condition.NotMatches,
+ "foo bar", "CSQ", "Poly Phen");
+ assertEquals(fm3.toStableString(),
+ "'CSQ:Poly Phen' NotMatches 'foo bar'");
+ fms.or(fm3);
+ assertEquals(fms.toStableString(),
+ "(AF LT 1.2) OR (CLIN_SIG NotContains path) OR ('CSQ:Poly Phen' NotMatches 'foo bar')");
+
+ try
+ {
+ fms.and(fm1);
+ fail("Expected exception");
+ } catch (IllegalStateException e)
+ {
+ // expected
+ }
+ }
+
+ /**
+ * Tests for parsing a string representation of a FeatureMatcherSet
+ *
+ * @see FeatureMatcherSetTest#testToStableString()
+ */
+ @Test(groups = "Functional")
+ public void testFromString()
+ {
+ String descriptor = "AF LT 1.2";
+ FeatureMatcherSetI fms = FeatureMatcherSet.fromString(descriptor);
+
+ /*
+ * shortcut asserts by verifying a 'roundtrip',
+ * which we trust if other tests pass :-)
+ */
+ assertEquals(fms.toStableString(), descriptor);
+
+ // brackets optional, quotes optional, condition case insensitive
+ fms = FeatureMatcherSet.fromString("('AF' lt '1.2')");
+ assertEquals(fms.toStableString(), descriptor);
+
+ descriptor = "(AF LT 1.2) AND (CLIN_SIG NotContains path)";
+ fms = FeatureMatcherSet.fromString(descriptor);
+ assertEquals(fms.toStableString(), descriptor);
+
+ // AND is not case-sensitive
+ fms = FeatureMatcherSet
+ .fromString("(AF LT 1.2) and (CLIN_SIG NotContains path)");
+ assertEquals(fms.toStableString(), descriptor);
+
+ descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path)";
+ fms = FeatureMatcherSet.fromString(descriptor);
+ assertEquals(fms.toStableString(), descriptor);
+
+ // OR is not case-sensitive
+ fms = FeatureMatcherSet
+ .fromString("(AF LT 1.2) or (CLIN_SIG NotContains path)");
+ assertEquals(fms.toStableString(), descriptor);
+
+ // can get away without brackets on last match condition
+ fms = FeatureMatcherSet
+ .fromString("(AF LT 1.2) or CLIN_SIG NotContains path");
+ assertEquals(fms.toStableString(), descriptor);
+
+ descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path) OR ('CSQ:Poly Phen' NotMatches 'foo bar')";
+ fms = FeatureMatcherSet.fromString(descriptor);
+ assertEquals(fms.toStableString(), descriptor);
+
+ // can't mix OR and AND
+ descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path) AND ('CSQ:Poly Phen' NotMatches 'foo bar')";
+ assertNull(FeatureMatcherSet.fromString(descriptor));
+
+ // can't mix AND and OR
+ descriptor = "(AF LT 1.2) and (CLIN_SIG NotContains path) or ('CSQ:Poly Phen' NotMatches 'foo bar')";
+ assertNull(FeatureMatcherSet.fromString(descriptor));
+
+ // brackets missing
+ assertNull(FeatureMatcherSet
+ .fromString("AF LT 1.2 or CLIN_SIG NotContains path"));
+
+ // invalid conjunction
+ assertNull(FeatureMatcherSet.fromString("(AF LT 1.2) but (AF GT -2)"));
+
+ // unbalanced quote (1)
+ assertNull(FeatureMatcherSet.fromString("('AF lt '1.2')"));
+
+ // unbalanced quote (2)
+ assertNull(FeatureMatcherSet.fromString("('AF' lt '1.2)"));
+ }
+}
--- /dev/null
+package jalview.datamodel.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.SequenceFeature;
+import jalview.util.MessageManager;
+import jalview.util.matcher.Condition;
+
+import java.util.Locale;
+
+import org.testng.annotations.Test;
+
+public class FeatureMatcherTest
+{
+ @Test(groups = "Functional")
+ public void testMatches_byLabel()
+ {
+ SequenceFeature sf = new SequenceFeature("Cath", "this is my label", 11,
+ 12, "grp");
+
+ /*
+ * contains - not case sensitive
+ */
+ assertTrue(
+ FeatureMatcher.byLabel(Condition.Contains, "IS").matches(sf));
+ assertTrue(FeatureMatcher.byLabel(Condition.Contains, "").matches(sf));
+ assertFalse(
+ FeatureMatcher.byLabel(Condition.Contains, "ISNT").matches(sf));
+
+ /*
+ * does not contain
+ */
+ assertTrue(FeatureMatcher.byLabel(Condition.NotContains, "isnt")
+ .matches(sf));
+ assertFalse(FeatureMatcher.byLabel(Condition.NotContains, "is")
+ .matches(sf));
+
+ /*
+ * matches
+ */
+ assertTrue(FeatureMatcher.byLabel(Condition.Matches, "THIS is MY label")
+ .matches(sf));
+ assertFalse(FeatureMatcher.byLabel(Condition.Matches, "THIS is MY")
+ .matches(sf));
+
+ /*
+ * does not match
+ */
+ assertFalse(FeatureMatcher
+ .byLabel(Condition.NotMatches, "THIS is MY label").matches(sf));
+ assertTrue(FeatureMatcher.byLabel(Condition.NotMatches, "THIS is MY")
+ .matches(sf));
+
+ /*
+ * is present / not present
+ */
+ assertTrue(FeatureMatcher.byLabel(Condition.Present, "").matches(sf));
+ assertFalse(
+ FeatureMatcher.byLabel(Condition.NotPresent, "").matches(sf));
+ }
+
+ @Test(groups = "Functional")
+ public void testMatches_byScore()
+ {
+ SequenceFeature sf = new SequenceFeature("Cath", "this is my label", 11,
+ 12, 3.2f, "grp");
+
+ assertTrue(FeatureMatcher.byScore(Condition.LT, "3.3").matches(sf));
+ assertFalse(FeatureMatcher.byScore(Condition.LT, "3.2").matches(sf));
+ assertFalse(FeatureMatcher.byScore(Condition.LT, "2.2").matches(sf));
+
+ assertTrue(FeatureMatcher.byScore(Condition.LE, "3.3").matches(sf));
+ assertTrue(FeatureMatcher.byScore(Condition.LE, "3.2").matches(sf));
+ assertFalse(FeatureMatcher.byScore(Condition.LE, "2.2").matches(sf));
+
+ assertFalse(FeatureMatcher.byScore(Condition.EQ, "3.3").matches(sf));
+ assertTrue(FeatureMatcher.byScore(Condition.EQ, "3.2").matches(sf));
+
+ assertFalse(FeatureMatcher.byScore(Condition.GE, "3.3").matches(sf));
+ assertTrue(FeatureMatcher.byScore(Condition.GE, "3.2").matches(sf));
+ assertTrue(FeatureMatcher.byScore(Condition.GE, "2.2").matches(sf));
+
+ assertFalse(FeatureMatcher.byScore(Condition.GT, "3.3").matches(sf));
+ assertFalse(FeatureMatcher.byScore(Condition.GT, "3.2").matches(sf));
+ assertTrue(FeatureMatcher.byScore(Condition.GT, "2.2").matches(sf));
+ }
+
+ @Test(groups = "Functional")
+ public void testMatches_byAttribute()
+ {
+ /*
+ * a numeric matcher - MatcherTest covers more conditions
+ */
+ FeatureMatcherI fm = FeatureMatcher
+ .byAttribute(Condition.GE, "-2", "AF");
+ SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
+ assertFalse(fm.matches(sf));
+ sf.setValue("AF", "foobar");
+ assertFalse(fm.matches(sf));
+ sf.setValue("AF", "-2");
+ assertTrue(fm.matches(sf));
+ sf.setValue("AF", "-1");
+ assertTrue(fm.matches(sf));
+ sf.setValue("AF", "-3");
+ assertFalse(fm.matches(sf));
+ sf.setValue("AF", "");
+ assertFalse(fm.matches(sf));
+
+ /*
+ * a string pattern matcher
+ */
+ fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "AF");
+ assertFalse(fm.matches(sf));
+ sf.setValue("AF", "raining cats and dogs");
+ assertTrue(fm.matches(sf));
+
+ fm = FeatureMatcher.byAttribute(Condition.Present, "", "AC");
+ assertFalse(fm.matches(sf));
+ sf.setValue("AC", "21");
+ assertTrue(fm.matches(sf));
+
+ fm = FeatureMatcher.byAttribute(Condition.NotPresent, "", "AC_Females");
+ assertTrue(fm.matches(sf));
+ sf.setValue("AC_Females", "21");
+ assertFalse(fm.matches(sf));
+ }
+
+ @Test(groups = "Functional")
+ public void testToString()
+ {
+ Locale.setDefault(Locale.ENGLISH);
+
+ /*
+ * toString uses the i18n translation of the enum conditions
+ */
+ FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.LT, "1.2",
+ "AF");
+ assertEquals(fm.toString(), "AF < 1.2");
+
+ /*
+ * Present / NotPresent omit the value pattern
+ */
+ fm = FeatureMatcher.byAttribute(Condition.Present, "", "AF");
+ assertEquals(fm.toString(), "AF is present");
+ fm = FeatureMatcher.byAttribute(Condition.NotPresent, "", "AF");
+ assertEquals(fm.toString(), "AF is not present");
+
+ /*
+ * by Label
+ */
+ fm = FeatureMatcher.byLabel(Condition.Matches, "foobar");
+ assertEquals(fm.toString(),
+ MessageManager.getString("label.label") + " matches 'foobar'");
+
+ /*
+ * by Score
+ */
+ fm = FeatureMatcher.byScore(Condition.GE, "12.2");
+ assertEquals(fm.toString(),
+ MessageManager.getString("label.score") + " >= 12.2");
+ }
+
+ @Test(groups = "Functional")
+ public void testGetAttribute()
+ {
+ FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
+ "AF");
+ assertEquals(fm.getAttribute(), new String[] { "AF" });
+
+ /*
+ * compound key (attribute / subattribute)
+ */
+ fm = FeatureMatcher.byAttribute(Condition.GE, "-2F", "CSQ",
+ "Consequence");
+ assertEquals(fm.getAttribute(), new String[] { "CSQ", "Consequence" });
+
+ /*
+ * answers null if match is by Label or by Score
+ */
+ assertNull(FeatureMatcher.byLabel(Condition.NotContains, "foo")
+ .getAttribute());
+ assertNull(FeatureMatcher.byScore(Condition.LE, "-1").getAttribute());
+ }
+
+ @Test(groups = "Functional")
+ public void testIsByAttribute()
+ {
+ assertFalse(FeatureMatcher.byLabel(Condition.NotContains, "foo")
+ .isByAttribute());
+ assertFalse(FeatureMatcher.byScore(Condition.LE, "-1").isByAttribute());
+ assertTrue(FeatureMatcher.byAttribute(Condition.LE, "-1", "AC")
+ .isByAttribute());
+ }
+
+ @Test(groups = "Functional")
+ public void testIsByLabel()
+ {
+ assertTrue(FeatureMatcher.byLabel(Condition.NotContains, "foo")
+ .isByLabel());
+ assertFalse(FeatureMatcher.byScore(Condition.LE, "-1").isByLabel());
+ assertFalse(FeatureMatcher.byAttribute(Condition.LE, "-1", "AC")
+ .isByLabel());
+ }
+
+ @Test(groups = "Functional")
+ public void testIsByScore()
+ {
+ assertFalse(FeatureMatcher.byLabel(Condition.NotContains, "foo")
+ .isByScore());
+ assertTrue(FeatureMatcher.byScore(Condition.LE, "-1").isByScore());
+ assertFalse(FeatureMatcher.byAttribute(Condition.LE, "-1", "AC")
+ .isByScore());
+ }
+
+ @Test(groups = "Functional")
+ public void testGetMatcher()
+ {
+ FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2f",
+ "AF");
+ assertEquals(fm.getMatcher().getCondition(), Condition.GE);
+ assertEquals(fm.getMatcher().getFloatValue(), -2F);
+ assertEquals(fm.getMatcher().getPattern(), "-2.0");
+ }
+
+ @Test(groups = "Functional")
+ public void testFromString()
+ {
+ FeatureMatcherI fm = FeatureMatcher.fromString("'AF' LT 1.2");
+ assertFalse(fm.isByLabel());
+ assertFalse(fm.isByScore());
+ assertEquals(fm.getAttribute(), new String[] { "AF" });
+ assertSame(Condition.LT, fm.getMatcher().getCondition());
+ assertEquals(fm.getMatcher().getFloatValue(), 1.2f);
+ assertEquals(fm.getMatcher().getPattern(), "1.2");
+
+ // quotes are optional, condition is not case sensitive
+ fm = FeatureMatcher.fromString("AF lt '1.2'");
+ assertFalse(fm.isByLabel());
+ assertFalse(fm.isByScore());
+ assertEquals(fm.getAttribute(), new String[] { "AF" });
+ assertSame(Condition.LT, fm.getMatcher().getCondition());
+ assertEquals(fm.getMatcher().getFloatValue(), 1.2f);
+ assertEquals(fm.getMatcher().getPattern(), "1.2");
+
+ fm = FeatureMatcher.fromString("'AF' Present");
+ assertFalse(fm.isByLabel());
+ assertFalse(fm.isByScore());
+ assertEquals(fm.getAttribute(), new String[] { "AF" });
+ assertSame(Condition.Present, fm.getMatcher().getCondition());
+
+ fm = FeatureMatcher.fromString("CSQ:Consequence contains damaging");
+ assertFalse(fm.isByLabel());
+ assertFalse(fm.isByScore());
+ assertEquals(fm.getAttribute(), new String[] { "CSQ", "Consequence" });
+ assertSame(Condition.Contains, fm.getMatcher().getCondition());
+ assertEquals(fm.getMatcher().getPattern(), "damaging");
+
+ // keyword Label is not case sensitive
+ fm = FeatureMatcher.fromString("LABEL Matches 'foobar'");
+ assertTrue(fm.isByLabel());
+ assertFalse(fm.isByScore());
+ assertNull(fm.getAttribute());
+ assertSame(Condition.Matches, fm.getMatcher().getCondition());
+ assertEquals(fm.getMatcher().getPattern(), "foobar");
+
+ fm = FeatureMatcher.fromString("'Label' matches 'foo bar'");
+ assertTrue(fm.isByLabel());
+ assertFalse(fm.isByScore());
+ assertNull(fm.getAttribute());
+ assertSame(Condition.Matches, fm.getMatcher().getCondition());
+ assertEquals(fm.getMatcher().getPattern(), "foo bar");
+
+ // quotes optional on pattern
+ fm = FeatureMatcher.fromString("'Label' matches foo bar");
+ assertTrue(fm.isByLabel());
+ assertFalse(fm.isByScore());
+ assertNull(fm.getAttribute());
+ assertSame(Condition.Matches, fm.getMatcher().getCondition());
+ assertEquals(fm.getMatcher().getPattern(), "foo bar");
+
+ fm = FeatureMatcher.fromString("Score GE 12.2");
+ assertFalse(fm.isByLabel());
+ assertTrue(fm.isByScore());
+ assertNull(fm.getAttribute());
+ assertSame(Condition.GE, fm.getMatcher().getCondition());
+ assertEquals(fm.getMatcher().getPattern(), "12.2");
+ assertEquals(fm.getMatcher().getFloatValue(), 12.2f);
+
+ // keyword Score is not case sensitive
+ fm = FeatureMatcher.fromString("'SCORE' ge '12.2'");
+ assertFalse(fm.isByLabel());
+ assertTrue(fm.isByScore());
+ assertNull(fm.getAttribute());
+ assertSame(Condition.GE, fm.getMatcher().getCondition());
+ assertEquals(fm.getMatcher().getPattern(), "12.2");
+ assertEquals(fm.getMatcher().getFloatValue(), 12.2f);
+
+ // invalid numeric pattern
+ assertNull(FeatureMatcher.fromString("Score eq twelve"));
+ // unbalanced opening quote
+ assertNull(FeatureMatcher.fromString("'Score ge 12.2"));
+ // unbalanced pattern quote
+ assertNull(FeatureMatcher.fromString("'Score' ge '12.2"));
+ // pattern missing
+ assertNull(FeatureMatcher.fromString("Score ge"));
+ // condition and pattern missing
+ assertNull(FeatureMatcher.fromString("Score"));
+ // everything missing
+ assertNull(FeatureMatcher.fromString(""));
+ }
+
+ /**
+ * Tests for toStableString which (unlike toString) does not i18n the
+ * conditions
+ */
+ @Test(groups = "Functional")
+ public void testToStableString()
+ {
+ // attribute name not quoted unless it contains space
+ FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.LT, "1.2",
+ "AF");
+ assertEquals(fm.toStableString(), "AF LT 1.2");
+
+ /*
+ * Present / NotPresent omit the value pattern
+ */
+ fm = FeatureMatcher.byAttribute(Condition.Present, "", "AF");
+ assertEquals(fm.toStableString(), "AF Present");
+ fm = FeatureMatcher.byAttribute(Condition.NotPresent, "", "AF");
+ assertEquals(fm.toStableString(), "AF NotPresent");
+
+ /*
+ * by Label
+ * pattern not quoted unless it contains space
+ */
+ fm = FeatureMatcher.byLabel(Condition.Matches, "foobar");
+ assertEquals(fm.toStableString(), "Label Matches foobar");
+
+ fm = FeatureMatcher.byLabel(Condition.Matches, "foo bar");
+ assertEquals(fm.toStableString(), "Label Matches 'foo bar'");
+
+ /*
+ * by Score
+ */
+ fm = FeatureMatcher.byScore(Condition.GE, "12.2");
+ assertEquals(fm.toStableString(), "Score GE 12.2");
+ }
+}
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
import jalview.datamodel.SequenceFeature;
public void testShiftFeatures()
{
FeatureStore fs = new FeatureStore();
- assertFalse(fs.shiftFeatures(1));
+ assertFalse(fs.shiftFeatures(0, 1)); // nothing to do
SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
fs.addFeature(sf1);
fs.addFeature(sf4);
/*
- * shift features right by 5
+ * shift all features right by 5
*/
- assertTrue(fs.shiftFeatures(5));
+ assertTrue(fs.shiftFeatures(0, 5));
// non-positional features untouched:
List<SequenceFeature> nonPos = fs.getNonPositionalFeatures();
* feature at [7-10] should be removed
* feature at [13-19] should become [1-4]
*/
- assertTrue(fs.shiftFeatures(-15));
+ assertTrue(fs.shiftFeatures(0, -15));
pos = fs.getPositionalFeatures();
assertEquals(pos.size(), 2);
SequenceFeatures.sortFeatures(pos, true);
assertEquals(pos.get(0).getEnd(), 4);
assertEquals(pos.get(1).getBegin(), 13);
assertEquals(pos.get(1).getEnd(), 22);
+
+ /*
+ * shift right by 4 from position 2 onwards
+ * feature at [1-4] unchanged, feature at [13-22] shifts
+ */
+ assertTrue(fs.shiftFeatures(2, 4));
+ pos = fs.getPositionalFeatures();
+ assertEquals(pos.size(), 2);
+ SequenceFeatures.sortFeatures(pos, true);
+ assertEquals(pos.get(0).getBegin(), 1);
+ assertEquals(pos.get(0).getEnd(), 4);
+ assertEquals(pos.get(1).getBegin(), 17);
+ assertEquals(pos.get(1).getEnd(), 26);
+
+ /*
+ * shift right by 4 from position 18 onwards
+ * should be no change
+ */
+ SequenceFeature f1 = pos.get(0);
+ SequenceFeature f2 = pos.get(1);
+ assertFalse(fs.shiftFeatures(18, 4)); // no update
+ pos = fs.getPositionalFeatures();
+ assertEquals(pos.size(), 2);
+ SequenceFeatures.sortFeatures(pos, true);
+ assertSame(pos.get(0), f1);
+ assertSame(pos.get(1), f2);
}
@Test(groups = "Functional")
import java.util.Map;
import java.util.Set;
-import junit.extensions.PA;
-
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
public class SequenceFeaturesTest
{
@Test(groups = "Functional")
assertTrue(store.getFeaturesByOntology(new String[] {}).isEmpty());
assertTrue(store.getFeaturesByOntology((String[]) null).isEmpty());
- SequenceFeature sf1 = new SequenceFeature("transcript", "desc", 10, 20,
+ SequenceFeature transcriptFeature = new SequenceFeature("transcript", "desc", 10, 20,
Float.NaN, null);
- store.add(sf1);
+ store.add(transcriptFeature);
- // mRNA isA transcript; added here 'as if' non-positional
- // just to show that non-positional features are included in results
- SequenceFeature sf2 = new SequenceFeature("mRNA", "desc", 0, 0,
+ /*
+ * mRNA is a sub-type of transcript; added here 'as if' non-positional
+ * just to show that non-positional features are included in results
+ */
+ SequenceFeature mrnaFeature = new SequenceFeature("mRNA", "desc", 0, 0,
Float.NaN, null);
- store.add(sf2);
+ store.add(mrnaFeature);
- SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 30, 40,
+ SequenceFeature pfamFeature = new SequenceFeature("Pfam", "desc", 30, 40,
Float.NaN, null);
- store.add(sf3);
+ store.add(pfamFeature);
+ /*
+ * "transcript" matches both itself and the sub-term "mRNA"
+ */
features = store.getFeaturesByOntology("transcript");
assertEquals(features.size(), 2);
- assertTrue(features.contains(sf1));
- assertTrue(features.contains(sf2));
+ assertTrue(features.contains(transcriptFeature));
+ assertTrue(features.contains(mrnaFeature));
+ /*
+ * "mRNA" matches itself but not parent term "transcript"
+ */
features = store.getFeaturesByOntology("mRNA");
assertEquals(features.size(), 1);
- assertTrue(features.contains(sf2));
+ assertTrue(features.contains(mrnaFeature));
+ /*
+ * "pfam" is not an SO term but is included as an exact match
+ */
features = store.getFeaturesByOntology("mRNA", "Pfam");
assertEquals(features.size(), 2);
- assertTrue(features.contains(sf2));
- assertTrue(features.contains(sf3));
+ assertTrue(features.contains(mrnaFeature));
+ assertTrue(features.contains(pfamFeature));
features = store.getFeaturesByOntology("sequence_variant");
assertTrue(features.isEmpty());
@Test(groups = "Functional")
public void testSortFeatures()
{
- List<SequenceFeature> sfs = new ArrayList<SequenceFeature>();
+ List<SequenceFeature> sfs = new ArrayList<>();
SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 30, 80,
Float.NaN, null);
sfs.add(sf1);
public void testShiftFeatures()
{
SequenceFeatures store = new SequenceFeatures();
- assertFalse(store.shiftFeatures(1));
+ assertFalse(store.shiftFeatures(0, 1));
SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
store.add(sf1);
/*
* shift features right by 5
*/
- assertTrue(store.shiftFeatures(5));
+ assertTrue(store.shiftFeatures(0, 5));
// non-positional features untouched:
List<SequenceFeature> nonPos = store.getNonPositionalFeatures();
* feature at [7-10] should be removed
* feature at [13-19] should become [1-4]
*/
- assertTrue(store.shiftFeatures(-15));
+ assertTrue(store.shiftFeatures(0, -15));
pos = store.getPositionalFeatures();
assertEquals(pos.size(), 2);
SequenceFeatures.sortFeatures(pos, true);
assertEquals(pos.get(1).getBegin(), 13);
assertEquals(pos.get(1).getEnd(), 22);
assertEquals(pos.get(1).getType(), "Disulfide bond");
+
+ /*
+ * shift right by 4 from column 2
+ * feature at [1-4] should be unchanged
+ * feature at [13-22] should become [17-26]
+ */
+ assertTrue(store.shiftFeatures(2, 4));
+ pos = store.getPositionalFeatures();
+ assertEquals(pos.size(), 2);
+ SequenceFeatures.sortFeatures(pos, true);
+ assertEquals(pos.get(0).getBegin(), 1);
+ assertEquals(pos.get(0).getEnd(), 4);
+ assertEquals(pos.get(0).getType(), "Metal");
+ assertEquals(pos.get(1).getBegin(), 17);
+ assertEquals(pos.get(1).getEnd(), 26);
+ assertEquals(pos.get(1).getType(), "Disulfide bond");
+
+ /*
+ * shift right from column 18
+ * should be no updates
+ */
+ SequenceFeature f1 = pos.get(0);
+ SequenceFeature f2 = pos.get(1);
+ assertFalse(store.shiftFeatures(18, 6));
+ pos = store.getPositionalFeatures();
+ assertEquals(pos.size(), 2);
+ SequenceFeatures.sortFeatures(pos, true);
+ assertSame(pos.get(0), f1);
+ assertSame(pos.get(1), f2);
}
@Test(groups = "Functional")
assertTrue(store.isOntologyTerm("junk", new String[] {}));
assertTrue(store.isOntologyTerm("junk", (String[]) null));
}
+
+ @Test(groups = "Functional")
+ public void testDeleteAll()
+ {
+ SequenceFeaturesI store = new SequenceFeatures();
+ assertFalse(store.hasFeatures());
+ store.deleteAll();
+ assertFalse(store.hasFeatures());
+ store.add(new SequenceFeature("Cath", "Desc", 12, 20, 0f, "Group"));
+ store.add(new SequenceFeature("Pfam", "Desc", 6, 12, 2f, "Group2"));
+ assertTrue(store.hasFeatures());
+ store.deleteAll();
+ assertFalse(store.hasFeatures());
+ }
}
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertTrue;
+import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceDummy;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
sf.setValue("Parent", "transcript:" + accId);
assertTrue(testee.retainFeature(sf, accId));
+ // test is not case-sensitive
+ assertTrue(testee.retainFeature(sf, accId.toLowerCase()));
+
// feature with wrong parent is not retained
sf.setValue("Parent", "transcript:XYZ");
assertFalse(testee.retainFeature(sf, accId));
* accession id as parent
*/
@Test(groups = "Functional")
- public void testIdentifiesSequence()
+ public void testGetIdentifyingFeatures()
{
String accId = "ABC123";
- EnsemblCdna testee = new EnsemblCdna();
+ SequenceI seq = new Sequence(accId, "MKLNFRQIE");
- // exon with no parent not valid
- SequenceFeature sf = new SequenceFeature("exon", "", 1, 2, 0f, null);
- assertFalse(testee.identifiesSequence(sf, accId));
+ // exon with no parent: not valid
+ SequenceFeature sf1 = new SequenceFeature("exon", "", 1, 2, 0f, null);
+ seq.addSequenceFeature(sf1);
- // exon with wrong parent not valid
- sf.setValue("Parent", "transcript:XYZ");
- assertFalse(testee.identifiesSequence(sf, accId));
+ // exon with wrong parent: not valid
+ SequenceFeature sf2 = new SequenceFeature("exon", "", 1, 2, 0f, null);
+ sf2.setValue("Parent", "transcript:XYZ");
+ seq.addSequenceFeature(sf2);
// exon with right parent is valid
- sf.setValue("Parent", "transcript:" + accId);
- assertTrue(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf3 = new SequenceFeature("exon", "", 1, 2, 0f, null);
+ sf3.setValue("Parent", "transcript:" + accId);
+ seq.addSequenceFeature(sf3);
// exon sub-type with right parent is valid
- sf = new SequenceFeature("coding_exon", "", 1, 2, 0f, null);
- sf.setValue("Parent", "transcript:" + accId);
- assertTrue(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf4 = new SequenceFeature("coding_exon", "", 1, 2, 0f,
+ null);
+ sf4.setValue("Parent", "transcript:" + accId);
+ seq.addSequenceFeature(sf4);
// transcript not valid:
- sf = new SequenceFeature("transcript", "", 1, 2, 0f, null);
- sf.setValue("Parent", "transcript:" + accId);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf5 = new SequenceFeature("transcript", "", 1, 2, 0f,
+ null);
+ sf5.setValue("Parent", "transcript:" + accId);
+ seq.addSequenceFeature(sf5);
// CDS not valid:
- sf = new SequenceFeature("CDS", "", 1, 2, 0f, null);
- sf.setValue("Parent", "transcript:" + accId);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf6 = new SequenceFeature("transcript", "", 1, 2, 0f,
+ null);
+ sf6.setValue("Parent", "transcript:" + accId);
+ seq.addSequenceFeature(sf6);
+
+ List<SequenceFeature> sfs = new EnsemblCdna()
+ .getIdentifyingFeatures(seq, accId);
+ assertFalse(sfs.contains(sf1));
+ assertFalse(sfs.contains(sf2));
+ assertTrue(sfs.contains(sf3));
+ assertTrue(sfs.contains(sf4));
+ assertFalse(sfs.contains(sf5));
+ assertFalse(sfs.contains(sf6));
}
@Test(groups = "Functional")
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
+import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceDummy;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
* accession id as parent
*/
@Test(groups = "Functional")
- public void testIdentifiesSequence()
+ public void testGetIdentifyingFeatures()
{
String accId = "ABC123";
- EnsemblCds testee = new EnsemblCds();
+ SequenceI seq = new Sequence(accId, "MKDONS");
// cds with no parent not valid
- SequenceFeature sf = new SequenceFeature("CDS", "", 1, 2, 0f, null);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf1 = new SequenceFeature("CDS", "", 1, 2, 0f, null);
+ seq.addSequenceFeature(sf1);
// cds with wrong parent not valid
- sf.setValue("Parent", "transcript:XYZ");
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf2 = new SequenceFeature("CDS", "", 1, 2, 0f, null);
+ sf2.setValue("Parent", "transcript:XYZ");
+ seq.addSequenceFeature(sf2);
// cds with right parent is valid
- sf.setValue("Parent", "transcript:" + accId);
- assertTrue(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf3 = new SequenceFeature("CDS", "", 1, 2, 0f, null);
+ sf3.setValue("Parent", "transcript:" + accId);
+ seq.addSequenceFeature(sf3);
// cds sub-type with right parent is valid
- sf = new SequenceFeature("CDS_predicted", "", 1, 2, 0f, null);
- sf.setValue("Parent", "transcript:" + accId);
- assertTrue(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf4 = new SequenceFeature("CDS_predicted", "", 1, 2, 0f,
+ null);
+ sf4.setValue("Parent", "transcript:" + accId);
+ seq.addSequenceFeature(sf4);
// transcript not valid:
- sf = new SequenceFeature("transcript", "", 1, 2, 0f, null);
- sf.setValue("Parent", "transcript:" + accId);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf5 = new SequenceFeature("transcript", "", 1, 2, 0f,
+ null);
+ sf5.setValue("Parent", "transcript:" + accId);
+ seq.addSequenceFeature(sf5);
// exon not valid:
- sf = new SequenceFeature("exon", "", 1, 2, 0f, null);
- sf.setValue("Parent", "transcript:" + accId);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf6 = new SequenceFeature("exon", "", 1, 2, 0f, null);
+ sf6.setValue("Parent", "transcript:" + accId);
+ seq.addSequenceFeature(sf6);
+
+ List<SequenceFeature> sfs = new EnsemblCds().getIdentifyingFeatures(seq,
+ accId);
+ assertFalse(sfs.contains(sf1));
+ assertFalse(sfs.contains(sf2));
+ assertTrue(sfs.contains(sf3));
+ assertTrue(sfs.contains(sf4));
+ assertFalse(sfs.contains(sf5));
+ assertFalse(sfs.contains(sf6));
}
@Test(groups = "Functional")
import static org.testng.AssertJUnit.assertTrue;
import jalview.api.FeatureSettingsModelI;
+import jalview.bin.Cache;
+import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceDummy;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
@BeforeClass(alwaysRun = true)
public void setUp()
{
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
}
genomic.setEnd(50000);
String geneId = "ABC123";
- // gene at (start+20000) length 501
- // should be ignored - the first 'gene' found defines the whole range
- // (note features are found in position order, not addition order)
- SequenceFeature sf = new SequenceFeature("gene", "", 20000, 20500, 0f,
- null);
- sf.setValue("ID", "gene:" + geneId);
- sf.setStrand("+");
- genomic.addSequenceFeature(sf);
-
// gene at (start + 10500) length 101
- sf = new SequenceFeature("gene", "", 10500, 10600, 0f, null);
+ SequenceFeature sf = new SequenceFeature("gene", "", 10500, 10600, 0f,
+ null);
sf.setValue("ID", "gene:" + geneId);
sf.setStrand("+");
genomic.addSequenceFeature(sf);
genomic.setEnd(50000);
String geneId = "ABC123";
- // gene at (start+20000) length 501
- // should be ignored - the first 'gene' found defines the whole range
- // (real data would only have one such feature)
- SequenceFeature sf = new SequenceFeature("ncRNA_gene", "", 20000,
- 20500, 0f, null);
- sf.setValue("ID", "gene:" + geneId);
- sf.setStrand("-");
- genomic.addSequenceFeature(sf);
-
// gene at (start + 10500) length 101
- sf = new SequenceFeature("gene", "", 10500, 10600, 0f, null);
+ SequenceFeature sf = new SequenceFeature("gene", "", 10500, 10600, 0f,
+ null);
sf.setValue("ID", "gene:" + geneId);
sf.setStrand("+");
genomic.addSequenceFeature(sf);
// NMD_transcript_variant treated like transcript in Ensembl
SequenceFeature sf3 = new SequenceFeature("NMD_transcript_variant", "",
22000, 22500, 0f, null);
- sf3.setValue("Parent", "gene:" + geneId);
+ // id matching should not be case-sensitive
+ sf3.setValue("Parent", "gene:" + geneId.toLowerCase());
sf3.setValue("transcript_id", "transcript3");
genomic.addSequenceFeature(sf3);
* accession id as ID
*/
@Test(groups = "Functional")
- public void testIdentifiesSequence()
+ public void testGetIdentifyingFeatures()
{
String accId = "ABC123";
- EnsemblGene testee = new EnsemblGene();
+ SequenceI seq = new Sequence(accId, "HIBEES");
// gene with no ID not valid
- SequenceFeature sf = new SequenceFeature("gene", "", 1, 2, 0f, null);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf1 = new SequenceFeature("gene", "", 1, 2, 0f, null);
+ seq.addSequenceFeature(sf1);
// gene with wrong ID not valid
- sf.setValue("ID", "gene:XYZ");
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf2 = new SequenceFeature("gene", "", 1, 2, 0f, null);
+ sf2.setValue("ID", "gene:XYZ");
+ seq.addSequenceFeature(sf2);
// gene with right ID is valid
- sf.setValue("ID", "gene:" + accId);
- assertTrue(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf3 = new SequenceFeature("gene", "", 1, 2, 0f, null);
+ sf3.setValue("ID", "gene:" + accId);
+ seq.addSequenceFeature(sf3);
// gene sub-type with right ID is valid
- sf = new SequenceFeature("snRNA_gene", "", 1, 2, 0f, null);
- sf.setValue("ID", "gene:" + accId);
- assertTrue(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf4 = new SequenceFeature("snRNA_gene", "", 1, 2, 0f, null);
+ sf4.setValue("ID", "gene:" + accId);
+ seq.addSequenceFeature(sf4);
// transcript not valid:
- sf = new SequenceFeature("transcript", "", 1, 2, 0f, null);
- sf.setValue("ID", "gene:" + accId);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf5 = new SequenceFeature("transcript", "", 1, 2, 0f, null);
+ sf5.setValue("ID", "gene:" + accId);
+ seq.addSequenceFeature(sf5);
// exon not valid:
- sf = new SequenceFeature("exon", "", 1, 2, 0f, null);
- sf.setValue("ID", "gene:" + accId);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf6 = new SequenceFeature("exon", "", 1, 2, 0f, null);
+ sf6.setValue("ID", "gene:" + accId);
+ seq.addSequenceFeature(sf6);
+
+ List<SequenceFeature> sfs = new EnsemblGene()
+ .getIdentifyingFeatures(seq, accId);
+ assertFalse(sfs.contains(sf1));
+ assertFalse(sfs.contains(sf2));
+ assertTrue(sfs.contains(sf3));
+ assertTrue(sfs.contains(sf4));
+ assertFalse(sfs.contains(sf5));
+ assertFalse(sfs.contains(sf6));
}
/**
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
+import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceDummy;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
* accession id as ID
*/
@Test(groups = "Functional")
- public void testIdentifiesSequence()
+ public void testGetIdentifyingFeatures()
{
String accId = "ABC123";
- EnsemblGenome testee = new EnsemblGenome();
+ SequenceI seq = new Sequence(accId, "HEARTS");
// transcript with no ID not valid
- SequenceFeature sf = new SequenceFeature("transcript", "", 1, 2, 0f,
+ SequenceFeature sf1 = new SequenceFeature("transcript", "", 1, 2, 0f,
null);
- assertFalse(testee.identifiesSequence(sf, accId));
+ seq.addSequenceFeature(sf1);
// transcript with wrong ID not valid
- sf.setValue("ID", "transcript");
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf2 = new SequenceFeature("transcript", "", 1, 2, 0f,
+ null);
+ sf2.setValue("ID", "transcript");
+ seq.addSequenceFeature(sf2);
// transcript with right ID is valid
- sf.setValue("ID", "transcript:" + accId);
- assertTrue(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf3 = new SequenceFeature("transcript", "", 1, 2, 0f,
+ null);
+ sf3.setValue("ID", "transcript:" + accId);
+ seq.addSequenceFeature(sf3);
// transcript sub-type with right ID is valid
- sf = new SequenceFeature("ncRNA", "", 1, 2, 0f, null);
- sf.setValue("ID", "transcript:" + accId);
- assertTrue(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf4 = new SequenceFeature("ncRNA", "", 1, 2, 0f, null);
+ sf4.setValue("ID", "transcript:" + accId);
+ seq.addSequenceFeature(sf4);
// Ensembl treats NMD_transcript_variant as if a transcript
- sf = new SequenceFeature("NMD_transcript_variant", "", 1, 2, 0f, null);
- sf.setValue("ID", "transcript:" + accId);
- assertTrue(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf5 = new SequenceFeature("NMD_transcript_variant", "",
+ 1, 2, 0f, null);
+ sf5.setValue("ID", "transcript:" + accId);
+ seq.addSequenceFeature(sf5);
// gene not valid:
- sf = new SequenceFeature("gene", "", 1, 2, 0f, null);
- sf.setValue("ID", "transcript:" + accId);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf6 = new SequenceFeature("gene", "", 1, 2, 0f, null);
+ sf6.setValue("ID", "transcript:" + accId);
+ seq.addSequenceFeature(sf6);
// exon not valid:
- sf = new SequenceFeature("exon", "", 1, 2, 0f, null);
- sf.setValue("ID", "transcript:" + accId);
- assertFalse(testee.identifiesSequence(sf, accId));
+ SequenceFeature sf7 = new SequenceFeature("exon", "", 1, 2, 0f, null);
+ sf7.setValue("ID", "transcript:" + accId);
+ seq.addSequenceFeature(sf7);
+
+ List<SequenceFeature> sfs = new EnsemblGenome()
+ .getIdentifyingFeatures(seq, accId);
+ assertFalse(sfs.contains(sf1));
+ assertFalse(sfs.contains(sf2));
+ assertTrue(sfs.contains(sf3));
+ assertTrue(sfs.contains(sf4));
+ assertTrue(sfs.contains(sf5));
+ assertFalse(sfs.contains(sf6));
+ assertFalse(sfs.contains(sf7));
}
}
{
return false;
}
-
- @Override
- protected String getRequestMimeType(boolean b)
- {
- return null;
- }
-
- @Override
- protected String getResponseMimeType()
- {
- return null;
- }
-
};
}
package jalview.ext.ensembl;
import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* A convenience class to simplify writing unit tests (pending Mockito or
}
@Override
- protected boolean identifiesSequence(SequenceFeature sf, String accId)
+ protected List<SequenceFeature> getIdentifyingFeatures(SequenceI seq,
+ String accId)
{
- return false;
+ return new ArrayList<>();
}
}
package jalview.ext.ensembl;
import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertSame;
-import static org.testng.AssertJUnit.assertTrue;
-import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.datamodel.features.SequenceFeatures;
import jalview.gui.JvOptionPane;
import jalview.io.DataSourceType;
import jalview.io.FastaFile;
-import jalview.io.FileParse;
import jalview.io.gff.SequenceOntologyFactory;
import jalview.io.gff.SequenceOntologyLite;
+ "LKKALMMRGLIPECCAVYRIQDGEKKPIGWDTDISWLTGEELHVEVLENVPLTTHNFVRK\n"
+ "TFFTLAFCDFCRKLLFQGFRCQTCGYKFHQRCSTEVPLMCVNYDQLDLLFVSKFFEHHPI\n"
+ "PQEEASLAETALTSGSSPSAPASDSIGPQILTSPSPSKSIPIPQPFRPADEDHRNQFGQR\n"
- + "DRSSSAPNVHINTIEPVNIDDLIRDQGFRGDGGSTTGLSATPPASLPGSLTNVKALQKSP\n"
+ + "DRSSSAPNVHINTIEPVNIDDLIRDQGFRGDG\n"
+ // ? insertion added in ENSP00000288602.11, not in P15056
+ + "APLNQLMRCLRKYQSRTPSPLLHSVPSEIVFDFEPGPVFR\n"
+ // end insertion
+ + "GSTTGLSATPPASLPGSLTNVKALQKSP\n"
+ "GPQRERKSSSSSEDRNRMKTLGRRDSSDDWEIPDGQITVGQRIGSGSFGTVYKGKWHGDV\n"
+ "AVKMLNVTAPTPQQLQAFKNEVGVLRKTRHVNILLFMGYSTKPQLAIVTQWCEGSSLYHH\n"
+ "LHIIETKFEMIKLIDIARQTAQGMDYLHAKSIIHRDLKSNNIFLHEDLTVKIGDFGLATV\n"
}
@Test(dataProvider = "ens_seqs", suiteName = "live")
- public void testGetOneSeqs(EnsemblRestClient proxy, String sq,
+ public void testGetSequenceRecords(EnsemblSeqProxy proxy, String sq,
String fastasq) throws Exception
{
- FileParse fp = proxy.getSequenceReader(Arrays
- .asList(new String[] { sq }));
- SequenceI[] sqs = new FastaFile(fp).getSeqsAsArray();
FastaFile trueRes = new FastaFile(fastasq, DataSourceType.PASTE);
- SequenceI[] trueSqs = trueRes.getSeqsAsArray();
- Assert.assertEquals(sqs.length, trueSqs.length,
+ SequenceI[] expected = trueRes.getSeqsAsArray();
+ AlignmentI retrieved = proxy.getSequenceRecords(sq);
+
+ Assert.assertEquals(retrieved.getHeight(), expected.length,
"Different number of sequences retrieved for query " + sq);
- Alignment ral = new Alignment(sqs);
- for (SequenceI tr : trueSqs)
+
+ for (SequenceI tr : expected)
{
SequenceI[] rseq;
Assert.assertNotNull(
- rseq = ral.findSequenceMatch(tr.getName()),
+ rseq = retrieved.findSequenceMatch(tr.getName()),
"Couldn't find sequences matching expected sequence "
+ tr.getName());
Assert.assertEquals(rseq.length, 1,
"Sequences differ for " + tr.getName() + "\n" + "Exp:"
+ tr.getSequenceAsString() + "\n" + "Got:"
+ rseq[0].getSequenceAsString());
-
}
}
*/
package jalview.ext.htsjdk;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
import jalview.datamodel.SequenceI;
-import jalview.gui.JvOptionPane;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
-import org.testng.Assert;
-import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
*/
public class TestHtsContigDb
{
+ @Test(groups = "Functional")
+ public final void testGetSequenceProxy() throws Exception
+ {
+ String pathname = "test/jalview/ext/htsjdk/pgmB.fasta";
+ HtsContigDb db = new HtsContigDb("ADB", new File(pathname));
+
+ assertTrue(db.isValid());
+ assertTrue(db.isIndexed()); // htsjdk opens the .fai file
- @BeforeClass(alwaysRun = true)
- public void setUpJvOptionPane()
+ SequenceI sq = db.getSequenceProxy("Deminut");
+ assertNotNull(sq);
+ assertEquals(sq.getLength(), 606);
+
+ /*
+ * read a sequence earlier in the file
+ */
+ sq = db.getSequenceProxy("PPL_06716");
+ assertNotNull(sq);
+ assertEquals(sq.getLength(), 602);
+
+ // dict = db.getDictionary(f, truncate))
+ }
+
+ /**
+ * Trying to open a .fai file directly results in IllegalArgumentException -
+ * have to provide the unindexed file name instead
+ */
+ @Test(
+ groups = "Functional",
+ expectedExceptions = java.lang.IllegalArgumentException.class)
+ public final void testGetSequenceProxy_indexed()
{
- JvOptionPane.setInteractiveMode(false);
- JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ String pathname = "test/jalview/ext/htsjdk/pgmB.fasta.fai";
+ new HtsContigDb("ADB", new File(pathname));
+ fail("Expected exception opening .fai file");
}
+ /**
+ * Tests that exercise
+ * <ul>
+ * <li>opening an unindexed fasta file</li>
+ * <li>creating a .fai index</li>
+ * <li>opening the fasta file, now using the index</li>
+ * <li>error on creating index if overwrite not allowed</li>
+ * </ul>
+ *
+ * @throws IOException
+ */
@Test(groups = "Functional")
- public final void testHTSReferenceSequence() throws Exception
+ public void testCreateFastaSequenceIndex() throws IOException
{
- HtsContigDb remmadb = new HtsContigDb("REEMADB", new File(
- "test/jalview/ext/htsjdk/pgmb.fasta"));
+ File fasta = new File("test/jalview/ext/htsjdk/pgmB.fasta");
+
+ /*
+ * create .fai with no overwrite fails if it exists
+ */
+ try
+ {
+ HtsContigDb.createFastaSequenceIndex(fasta.toPath(), false);
+ fail("Expected exception");
+ } catch (IOException e)
+ {
+ // we expect an IO Exception because the pgmB.fasta.fai exists, since it
+ // was checked it in.
+ }
+
+ /*
+ * create a copy of the .fasta (as a temp file)
+ */
+ File copyFasta = File.createTempFile("copyFasta", ".fasta");
+ copyFasta.deleteOnExit();
+ assertTrue(copyFasta.exists());
+ Files.copy(fasta.toPath(), copyFasta.toPath(),
+ StandardCopyOption.REPLACE_EXISTING);
- Assert.assertTrue(remmadb.isValid());
+ /*
+ * open the Fasta file - not indexed, as no .fai file yet exists
+ */
+ HtsContigDb db = new HtsContigDb("ADB", copyFasta);
+ assertTrue(db.isValid());
+ assertFalse(db.isIndexed());
+ db.close();
- SequenceI sq = remmadb.getSequenceProxy("Deminut");
- Assert.assertNotNull(sq);
- Assert.assertNotEquals(0, sq.getLength());
+ /*
+ * create the .fai index, re-open the .fasta file - now indexed
+ */
+ HtsContigDb.createFastaSequenceIndex(copyFasta.toPath(), true);
+ db = new HtsContigDb("ADB", copyFasta);
+ assertTrue(db.isValid());
+ assertTrue(db.isIndexed());
+ db.close();
}
+ /**
+ * A convenience 'test' that may be run to create a .fai file for any given
+ * fasta file
+ *
+ * @throws IOException
+ */
+ @Test(enabled = false)
+ public void testCreateIndex() throws IOException
+ {
+
+ File fasta = new File("test/jalview/io/vcf/contigs.fasta");
+ HtsContigDb.createFastaSequenceIndex(fasta.toPath(), true);
+ }
}
--- /dev/null
+package jalview.ext.htsjdk;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class VCFReaderTest
+{
+ private static final String[] VCF = new String[] {
+ "##fileformat=VCFv4.2",
+ "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO",
+ "20\t3\t.\tC\tG\t.\tPASS\tDP=100", // SNP C/G
+ "20\t7\t.\tG\tGA\t.\tPASS\tDP=100", // insertion G/GA
+ "18\t2\t.\tACG\tA\t.\tPASS\tDP=100" }; // deletion ACG/A
+
+ // gnomAD exome variant dataset
+ private static final String VCF_PATH = "/Volumes/gjb/smacgowan/NOBACK/resources/gnomad/gnomad.exomes.r2.0.1.sites.vcf.gz";
+
+ // "https://storage.cloud.google.com/gnomad-public/release/2.0.1/vcf/exomes/gnomad.exomes.r2.0.1.sites.vcf.gz";
+
+ /**
+ * A test to exercise some basic functionality of the htsjdk VCF reader,
+ * reading from a non-index VCF file
+ *
+ * @throws IOException
+ */
+ @Test(groups = "Functional")
+ public void testReadVcf_plain() throws IOException
+ {
+ File f = writeVcfFile();
+ VCFReader reader = new VCFReader(f.getAbsolutePath());
+ CloseableIterator<VariantContext> variants = reader.iterator();
+
+ /*
+ * SNP C/G variant
+ */
+ VariantContext vc = variants.next();
+ assertTrue(vc.isSNP());
+ Allele ref = vc.getReference();
+ assertEquals(ref.getBaseString(), "C");
+ List<Allele> alleles = vc.getAlleles();
+ assertEquals(alleles.size(), 2);
+ assertTrue(alleles.get(0).isReference());
+ assertEquals(alleles.get(0).getBaseString(), "C");
+ assertFalse(alleles.get(1).isReference());
+ assertEquals(alleles.get(1).getBaseString(), "G");
+
+ /*
+ * Insertion G -> GA
+ */
+ vc = variants.next();
+ assertFalse(vc.isSNP());
+ assertTrue(vc.isSimpleInsertion());
+ ref = vc.getReference();
+ assertEquals(ref.getBaseString(), "G");
+ alleles = vc.getAlleles();
+ assertEquals(alleles.size(), 2);
+ assertTrue(alleles.get(0).isReference());
+ assertEquals(alleles.get(0).getBaseString(), "G");
+ assertFalse(alleles.get(1).isReference());
+ assertEquals(alleles.get(1).getBaseString(), "GA");
+
+ /*
+ * Deletion ACG -> A
+ */
+ vc = variants.next();
+ assertFalse(vc.isSNP());
+ assertTrue(vc.isSimpleDeletion());
+ ref = vc.getReference();
+ assertEquals(ref.getBaseString(), "ACG");
+ alleles = vc.getAlleles();
+ assertEquals(alleles.size(), 2);
+ assertTrue(alleles.get(0).isReference());
+ assertEquals(alleles.get(0).getBaseString(), "ACG");
+ assertFalse(alleles.get(1).isReference());
+ assertEquals(alleles.get(1).getBaseString(), "A");
+
+ assertFalse(variants.hasNext());
+
+ variants.close();
+ reader.close();
+ }
+
+ /**
+ * Creates a temporary file to be read by the htsjdk VCF reader
+ *
+ * @return
+ * @throws IOException
+ */
+ protected File writeVcfFile() throws IOException
+ {
+ File f = File.createTempFile("Test", "vcf");
+ f.deleteOnExit();
+ PrintWriter pw = new PrintWriter(f);
+ for (String vcfLine : VCF) {
+ pw.println(vcfLine);
+ }
+ pw.close();
+ return f;
+ }
+
+ /**
+ * A 'test' that demonstrates querying an indexed VCF file for features in a
+ * specified interval
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testQuery_indexed() throws IOException
+ {
+ /*
+ * if not specified, assumes index file is filename.tbi
+ */
+ VCFReader reader = new VCFReader(VCF_PATH);
+
+ /*
+ * gene NMT1 (human) is on chromosome 17
+ * GCHR38 (Ensembl): 45051610-45109016
+ * GCHR37 (gnoMAD): 43128978-43186384
+ * CDS begins at offset 9720, first CDS variant at offset 9724
+ */
+ CloseableIterator<VariantContext> features = reader.query("17",
+ 43128978 + 9724, 43128978 + 9734); // first 11 CDS positions
+
+ assertEquals(printNext(features), 43138702);
+ assertEquals(printNext(features), 43138704);
+ assertEquals(printNext(features), 43138707);
+ assertEquals(printNext(features), 43138708);
+ assertEquals(printNext(features), 43138710);
+ assertEquals(printNext(features), 43138711);
+ assertFalse(features.hasNext());
+
+ features.close();
+ reader.close();
+ }
+
+ /**
+ * Prints the toString value of the next variant, and returns its start
+ * location
+ *
+ * @param features
+ * @return
+ */
+ protected int printNext(CloseableIterator<VariantContext> features)
+ {
+ VariantContext next = features.next();
+ System.out.println(next.toString());
+ return next.getStart();
+ }
+
+ // "https://storage.cloud.google.com/gnomad-public/release/2.0.1/vcf/exomes/gnomad.exomes.r2.0.1.sites.vcf.gz";
+
+ /**
+ * Test the query method that wraps a non-indexed VCF file
+ *
+ * @throws IOException
+ */
+ @Test(groups = "Functional")
+ public void testQuery_plain() throws IOException
+ {
+ File f = writeVcfFile();
+ VCFReader reader = new VCFReader(f.getAbsolutePath());
+
+ /*
+ * query for overlap of 5-8 - should find variant at 7
+ */
+ CloseableIterator<VariantContext> variants = reader.query("20", 5, 8);
+
+ /*
+ * INDEL G/GA variant
+ */
+ VariantContext vc = variants.next();
+ assertTrue(vc.isIndel());
+ assertEquals(vc.getStart(), 7);
+ assertEquals(vc.getEnd(), 7);
+ Allele ref = vc.getReference();
+ assertEquals(ref.getBaseString(), "G");
+ List<Allele> alleles = vc.getAlleles();
+ assertEquals(alleles.size(), 2);
+ assertTrue(alleles.get(0).isReference());
+ assertEquals(alleles.get(0).getBaseString(), "G");
+ assertFalse(alleles.get(1).isReference());
+ assertEquals(alleles.get(1).getBaseString(), "GA");
+
+ assertFalse(variants.hasNext());
+
+ variants.close();
+ reader.close();
+ }
+}
String chainACommand = commands[0].commands[0];
// M colour is #82827d == (130, 130, 125) (see strand.html help page)
assertTrue(chainACommand
- .contains(";select 21:A/1.1;color[130,130,125]"));
+ .contains("select 21:A/1.1;color[130,130,125]")); // first one
// H colour is #60609f == (96, 96, 159)
assertTrue(chainACommand.contains(";select 22:A/1.1;color[96,96,159]"));
// hidden columns are Gray (128, 128, 128)
String chainBCommand = commands[1].commands[0];
// M colour is #82827d == (130, 130, 125)
assertTrue(chainBCommand
- .contains(";select 21:B/2.1;color[130,130,125]"));
+ .contains("select 21:B/2.1;color[130,130,125]"));
// V colour is #ffff00 == (255, 255, 0)
assertTrue(chainBCommand
.contains(";select 22:B/2.1;color[255,255,0]"));
* 1GAQ has been reduced to alpha carbons only
* 1QCF is the full PDB file including headers, HETATM etc
*/
- String[] testFile = new String[] { "./examples/1GAQ.txt",
+ String[] testFile = new String[] { "./examples/1gaq.txt",
"./test/jalview/ext/jmol/1xyz.pdb",
- "./test/jalview/ext/jmol/1qcf.pdb" };
+ "./test/jalview/ext/jmol/1QCF.pdb" };
//@formatter:off
// a modified and very cut-down extract of 4UJ4
JmolParser jtest = new JmolParser(pdbStr, DataSourceType.FILE);
Vector<SequenceI> seqs = jtest.getSeqs(), mcseqs = mctest.getSeqs();
- assertTrue(
- "No sequences extracted from testfile\n"
- + (jtest.hasWarningMessage() ? jtest.getWarningMessage()
- : "(No warnings raised)"), seqs != null
- && seqs.size() > 0);
+ assertTrue("No sequences extracted from testfile\n"
+ + (jtest.hasWarningMessage() ? jtest.getWarningMessage()
+ : "(No warnings raised)"),
+ seqs != null && seqs.size() > 0);
for (SequenceI sq : seqs)
{
- assertEquals("JMol didn't process " + pdbStr
- + " to the same sequence as MCView",
- sq.getSequenceAsString(), mcseqs.remove(0)
- .getSequenceAsString());
+ assertEquals(
+ "JMol didn't process " + pdbStr
+ + " to the same sequence as MCView",
+ sq.getSequenceAsString(),
+ mcseqs.remove(0).getSequenceAsString());
AlignmentI al = new Alignment(new SequenceI[] { sq });
validateSecStrRows(al);
}
private void checkFirstAAIsAssoc(SequenceI sq)
{
- assertTrue("No secondary structure assigned for protein sequence for "
- + sq.getName(),
+ assertTrue(
+ "No secondary structure assigned for protein sequence for "
+ + sq.getName(),
sq.getAnnotation() != null && sq.getAnnotation().length >= 1
&& sq.getAnnotation()[0].hasIcons);
assertTrue(
"Secondary structure not associated for sequence "
- + sq.getName(), sq.getAnnotation()[0].sequenceRef == sq);
+ + sq.getName(),
+ sq.getAnnotation()[0].sequenceRef == sq);
}
/**
{
PDBfile mctest = new PDBfile(false, false, false,
pastePDBDataWithChainBreak, DataSourceType.PASTE);
- JmolParser jtest = new JmolParser(pastePDBDataWithChainBreak, DataSourceType.PASTE);
+ JmolParser jtest = new JmolParser(pastePDBDataWithChainBreak,
+ DataSourceType.PASTE);
Vector<SequenceI> seqs = jtest.getSeqs();
Vector<SequenceI> mcseqs = mctest.getSeqs();
{
PDBfile mctest = new PDBfile(false, false, false, pdbWithAltLoc,
DataSourceType.PASTE);
- JmolParser jtest = new JmolParser(pdbWithAltLoc,
- DataSourceType.PASTE);
+ JmolParser jtest = new JmolParser(pdbWithAltLoc, DataSourceType.PASTE);
Vector<SequenceI> seqs = jtest.getSeqs();
Vector<SequenceI> mcseqs = mctest.getSeqs();
*/
package jalview.ext.jmol;
+import static org.junit.Assert.assertNotNull;
+import static org.testng.Assert.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
import jalview.bin.Jalview;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.JvOptionPane;
import jalview.gui.StructureViewer;
import jalview.gui.StructureViewer.ViewerType;
import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileLoader;
+
+import java.lang.reflect.InvocationTargetException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@BeforeClass(alwaysRun = true)
public static void setUpBeforeClass() throws Exception
{
- Jalview.main(new String[] { "-noquestionnaire", "-nonews", "-props",
- "test/jalview/ext/rbvi/chimera/testProps.jvprops" });
+ Jalview.main(
+ new String[]
+ { "-noquestionnaire", "-nonews", "-props",
+ "test/jalview/ext/rbvi/chimera/testProps.jvprops" });
}
/**
@Test(groups = { "Functional" })
public void testSingleSeqViewJMol()
{
- Cache.setProperty(Preferences.STRUCTURE_DISPLAY, ViewerType.JMOL.name());
+ Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
+ ViewerType.JMOL.name());
String inFile = "examples/1gaq.txt";
- AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
- inFile, DataSourceType.FILE);
+ AlignFrame af = new jalview.io.FileLoader()
+ .LoadFileWaitTillLoaded(inFile, DataSourceType.FILE);
assertTrue("Didn't read input file " + inFile, af != null);
for (SequenceI sq : af.getViewport().getAlignment().getSequences())
{
{
for (int q = 0; q < dsq.getAllPDBEntries().size(); q++)
{
- final StructureViewer structureViewer = new StructureViewer(af
- .getViewport().getStructureSelectionManager());
+ final StructureViewer structureViewer = new StructureViewer(
+ af.getViewport().getStructureSelectionManager());
structureViewer.setViewerType(ViewerType.JMOL);
JalviewStructureDisplayI jmolViewer = structureViewer
.viewStructures(dsq.getAllPDBEntries().elementAt(q),
- new SequenceI[] { sq }, af.getCurrentView()
- .getAlignPanel());
+ new SequenceI[]
+ { sq }, af.getCurrentView().getAlignPanel());
/*
* Wait for viewer load thread to complete
*/
}
}
+ @Test(groups = { "Functional" })
+ public void testAddStrToSingleSeqViewJMol()
+ throws InvocationTargetException, InterruptedException
+ {
+ Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
+ ViewerType.JMOL.name());
+ String inFile = "examples/1gaq.txt";
+ AlignFrame af = new jalview.io.FileLoader(true)
+ .LoadFileWaitTillLoaded(inFile, DataSourceType.FILE);
+ assertTrue("Didn't read input file " + inFile, af != null);
+ // show a structure for 4th Sequence
+ SequenceI sq1 = af.getViewport().getAlignment().getSequences().get(0);
+ final StructureViewer structureViewer = new StructureViewer(
+ af.getViewport().getStructureSelectionManager());
+ structureViewer.setViewerType(ViewerType.JMOL);
+ JalviewStructureDisplayI jmolViewer = structureViewer.viewStructures(
+ sq1.getDatasetSequence().getAllPDBEntries().elementAt(0),
+ new SequenceI[]
+ { sq1 }, af.getCurrentView().getAlignPanel());
+ /*
+ * Wait for viewer load thread to complete
+ */
+ try
+ {
+ while (!jmolViewer.getBinding().isFinishedInit())
+ {
+ Thread.sleep(500);
+ }
+ } catch (InterruptedException e)
+ {
+ }
+
+ assertTrue(jmolViewer.isVisible());
+
+ // add another pdb file and add it to view
+ final String _inFile = "examples/3W5V.pdb";
+ inFile = _inFile;
+ FileLoader fl = new FileLoader();
+ fl.LoadFile(af.getCurrentView(), _inFile, DataSourceType.FILE,
+ FileFormat.PDB);
+ try
+ {
+ int time = 0;
+ do
+ {
+ Thread.sleep(50); // hope we can avoid race condition
+
+ } while (++time < 30
+ && af.getViewport().getAlignment().getHeight() == 3);
+ } catch (Exception q)
+ {
+ }
+ ;
+ assertTrue("Didn't paste additional structure" + inFile,
+ af.getViewport().getAlignment().getHeight() > 3);
+ SequenceI sq2 = af.getViewport().getAlignment().getSequenceAt(3);
+ PDBEntry pdbe = sq2.getDatasetSequence().getAllPDBEntries().get(0);
+ assertTrue(pdbe.getFile().contains(inFile));
+ structureViewer.viewStructures(pdbe, new SequenceI[] { sq2 },
+ af.alignPanel);
+ /*
+ * Wait for viewer load thread to complete
+ */
+ try
+ {
+ while (structureViewer.isBusy())
+ {
+ Thread.sleep(500);
+ }
+ } catch (InterruptedException e)
+ {
+ }
+ assertEquals(jmolViewer.getBinding().getPdbCount(), 2);
+ String mouseOverTest = "[GLY]293:A.CA/2.1 #2164";
+ ((JalviewJmolBinding) jmolViewer.getBinding()).mouseOverStructure(2164,
+ mouseOverTest);
+ SearchResultsI highlight = af.alignPanel.getSeqPanel()
+ .getLastSearchResults();
+ assertNotNull("Didn't find highlight from second structure mouseover",
+ highlight.getResults(sq2, sq2.getStart(), sq2.getEnd()));
+ }
}
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "External" })
public void testLaunchAndExit()
{
final StructureManager structureManager = new StructureManager(true);
assertFalse(so.isA("CDS_region", "CDS"));// part_of
assertFalse(so.isA("polypeptide", "CDS")); // derives_from
}
+
+ @Test(groups = "Functional")
+ public void testIsSequenceVariant()
+ {
+ assertFalse(so.isA("CDS", "sequence_variant"));
+ assertTrue(so.isA("sequence_variant", "sequence_variant"));
+
+ /*
+ * these should all be sub-types of sequence_variant
+ */
+ assertTrue(so.isA("structural_variant", "sequence_variant"));
+ assertTrue(so.isA("feature_variant", "sequence_variant"));
+ assertTrue(so.isA("gene_variant", "sequence_variant"));
+ assertTrue(so.isA("transcript_variant", "sequence_variant"));
+ assertTrue(so.isA("NMD_transcript_variant", "sequence_variant"));
+ assertTrue(so.isA("missense_variant", "sequence_variant"));
+ assertTrue(so.isA("synonymous_variant", "sequence_variant"));
+ assertTrue(so.isA("frameshift_variant", "sequence_variant"));
+ assertTrue(so.isA("5_prime_UTR_variant", "sequence_variant"));
+ assertTrue(so.isA("3_prime_UTR_variant", "sequence_variant"));
+ assertTrue(so.isA("stop_gained", "sequence_variant"));
+ assertTrue(so.isA("stop_lost", "sequence_variant"));
+ assertTrue(so.isA("inframe_deletion", "sequence_variant"));
+ assertTrue(so.isA("inframe_insertion", "sequence_variant"));
+ }
}
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
+import jalview.api.FeatureColourI;
import jalview.bin.Cache;
import jalview.bin.Jalview;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.io.Jalview2xmlTests;
import jalview.renderer.ResidueShaderI;
import jalview.schemes.BuriedColourScheme;
+import jalview.schemes.FeatureColour;
import jalview.schemes.HelixColourScheme;
import jalview.schemes.JalviewColourScheme;
import jalview.schemes.StrandColourScheme;
import jalview.util.MessageManager;
import java.awt.Color;
-import java.util.List;
+import java.util.Iterator;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
{
SequenceI seq1 = new Sequence("Seq1", "ABCDEFGHIJ");
SequenceI seq2 = new Sequence("Seq2", "ABCDEFGHIJ");
- seq1.addSequenceFeature(new SequenceFeature("Metal", "", 1, 5,
- Float.NaN, null));
- seq2.addSequenceFeature(new SequenceFeature("Metal", "", 6, 10,
- Float.NaN, null));
+ seq1.addSequenceFeature(new SequenceFeature("Metal", "", 1, 5, 0f, null));
+ seq2.addSequenceFeature(new SequenceFeature("Metal", "", 6, 10, 10f,
+ null));
seq1.addSequenceFeature(new SequenceFeature("Turn", "", 2, 4,
Float.NaN, null));
seq2.addSequenceFeature(new SequenceFeature("Turn", "", 7, 9,
Float.NaN, null));
AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
- AlignFrame alignFrame = new AlignFrame(al, al.getWidth(), al.getHeight());
+ AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
+ al.getHeight());
+
+ /*
+ * make all features visible (select feature columns checks visibility)
+ */
+ alignFrame.getFeatureRenderer().findAllFeatures(true);
/*
* hiding a feature not present does nothing
*/
assertFalse(alignFrame.hideFeatureColumns("exon", true));
assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
- assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy()
- .isEmpty());
+
+ assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getNumberOfRegions(), 0);
+
assertFalse(alignFrame.hideFeatureColumns("exon", false));
assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
- assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy()
- .isEmpty());
+
+ assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getNumberOfRegions(), 0);
/*
* hiding a feature in all columns does nothing
*/
assertFalse(alignFrame.hideFeatureColumns("Metal", true));
assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
- List<int[]> hidden = alignFrame.getViewport().getAlignment()
- .getHiddenColumns()
- .getHiddenColumnsCopy();
- assertTrue(hidden.isEmpty());
+
+ assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getNumberOfRegions(), 0);
+
+
+ /*
+ * threshold Metal to hide features where score < 5
+ * seq1 feature in columns 1-5 is hidden
+ * seq2 feature in columns 6-10 is shown
+ */
+ FeatureColourI fc = new FeatureColour(Color.red, Color.blue, 0f, 10f);
+ fc.setAboveThreshold(true);
+ fc.setThreshold(5f);
+ alignFrame.getFeatureRenderer().setColour("Metal", fc);
+ assertTrue(alignFrame.hideFeatureColumns("Metal", true));
+ HiddenColumns hidden = alignFrame.getViewport().getAlignment().getHiddenColumns();
+ assertEquals(hidden.getNumberOfRegions(), 1);
+ Iterator<int[]> regions = hidden.iterator();
+ int[] next = regions.next();
+ assertEquals(next[0], 5);
+ assertEquals(next[1], 9);
/*
* hide a feature present in some columns
* sequence positions [2-4], [7-9] are column positions
* [1-3], [6-8] base zero
*/
+ alignFrame.getViewport().showAllHiddenColumns();
assertTrue(alignFrame.hideFeatureColumns("Turn", true));
- hidden = alignFrame.getViewport().getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy();
- assertEquals(hidden.size(), 2);
- assertEquals(hidden.get(0)[0], 1);
- assertEquals(hidden.get(0)[1], 3);
- assertEquals(hidden.get(1)[0], 6);
- assertEquals(hidden.get(1)[1], 8);
+ regions = alignFrame.getViewport().getAlignment()
+ .getHiddenColumns().iterator();
+ assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getNumberOfRegions(), 2);
+ next = regions.next();
+ assertEquals(next[0], 1);
+ assertEquals(next[1], 3);
+ next = regions.next();
+ assertEquals(next[0], 6);
+ assertEquals(next[1], 8);
}
@BeforeClass(alwaysRun = true)
* Test for JAL-1306 - conservation thread should run even when only Quality
* (and not Conservation) is enabled in Preferences
*/
- @Test(groups = { "Functional" })
+ @Test(groups = { "Functional" }, timeOut=2000)
public void testUpdateConservation_qualityOnly()
{
Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
Boolean.FALSE.toString());
AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
"examples/uniref50.fa", DataSourceType.FILE);
- AlignmentAnnotation[] anns = af.viewport.getAlignment()
+
+ /*
+ * wait for Conservation thread to complete
+ */
+ AlignViewport viewport = af.getViewport();
+ synchronized (this)
+ {
+ while (viewport.getAlignmentConservationAnnotation() != null)
+ {
+ try
+ {
+ wait(50);
+ } catch (InterruptedException e)
+ {
+ }
+ }
+ }
+ AlignmentAnnotation[] anns = viewport.getAlignment()
.getAlignmentAnnotation();
assertNotNull("No annotations found", anns);
assertEquals("More than one annotation found", 1, anns.length);
/**
* Test that update layout reverts to original (unwrapped) values for endRes
- * and endSeq when switching from wrapped to unwrapped mode (JAL-2739)
+ * when switching from wrapped back to unwrapped mode (JAL-2739)
*/
@Test(groups = "Functional")
public void TestUpdateLayout_endRes()
af.alignPanel.getAlignViewport().setWrapAlignment(true);
af.alignPanel.updateLayout();
- // endRes changes
+ // endRes has changed
assertNotEquals(ranges.getEndRes(), endres);
// unwrap
af.alignPanel.getAlignViewport().setWrapAlignment(false);
af.alignPanel.updateLayout();
- // endRes and endSeq back to original values
+ // endRes back to original value
assertEquals(ranges.getEndRes(), endres);
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.gui;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.AssertJUnit.assertEquals;
+
+import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FormatAdapter;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for AnnotationChooser
+ *
+ * @author kmourao
+ *
+ */
+public class AnnotationColumnChooserTest
+{
+ @BeforeClass(alwaysRun = true)
+ public void setUpJvOptionPane()
+ {
+ JvOptionPane.setInteractiveMode(false);
+ JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ }
+
+ // 4 sequences x 13 positions
+ final static String TEST_DATA = ">FER_CAPAA Ferredoxin\n"
+ + "TIETHKEAELVG-\n"
+ + ">FER_CAPAN Ferredoxin, chloroplast precursor\n"
+ + "TIETHKEAELVG-\n"
+ + ">FER1_SOLLC Ferredoxin-1, chloroplast precursor\n"
+ + "TIETHKEEELTA-\n" + ">Q93XJ9_SOLTU Ferredoxin I precursor\n"
+ + "TIETHKEEELTA-\n";
+
+ AnnotationChooser testee;
+
+ AlignmentPanel parentPanel;
+
+ AlignFrame af;
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp() throws IOException
+ {
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ // pin down annotation sort order for test
+ Cache.applicationProperties.setProperty(Preferences.SORT_ANNOTATIONS,
+ SequenceAnnotationOrder.NONE.name());
+ final String TRUE = Boolean.TRUE.toString();
+ Cache.applicationProperties.setProperty(Preferences.SHOW_AUTOCALC_ABOVE,
+ TRUE);
+ Cache.applicationProperties.setProperty("SHOW_QUALITY", TRUE);
+ Cache.applicationProperties.setProperty("SHOW_CONSERVATION", TRUE);
+ Cache.applicationProperties.setProperty("SHOW_IDENTITY", TRUE);
+
+ AlignmentI al = new FormatAdapter().readFile(TEST_DATA,
+ DataSourceType.PASTE, FileFormat.Fasta);
+ af = new AlignFrame(al, 700, 500);
+ parentPanel = new AlignmentPanel(af, af.getViewport());
+ addAnnotations();
+ }
+
+ /**
+ * Add 4 annotations, 3 of them sequence-specific.
+ *
+ * <PRE>
+ * ann1 - for sequence 0 - label 'IUPRED' ann2 - not sequence related - label
+ * 'Beauty' ann3 - for sequence 3 - label 'JMol' ann4 - for sequence 2 - label
+ * 'IUPRED' ann5 - for sequence 1 - label 'JMol'
+ */
+ private void addAnnotations()
+ {
+ Annotation an = new Annotation(2f);
+ Annotation[] anns = new Annotation[] { an, an, an };
+ AlignmentAnnotation ann0 = new AlignmentAnnotation("IUPRED", "", anns);
+ AlignmentAnnotation ann1 = new AlignmentAnnotation("Beauty", "", anns);
+ AlignmentAnnotation ann2 = new AlignmentAnnotation("JMol", "", anns);
+ AlignmentAnnotation ann3 = new AlignmentAnnotation("IUPRED", "", anns);
+ AlignmentAnnotation ann4 = new AlignmentAnnotation("JMol", "", anns);
+ SequenceI[] seqs = parentPanel.getAlignment().getSequencesArray();
+ ann0.setSequenceRef(seqs[0]);
+ ann2.setSequenceRef(seqs[3]);
+ ann3.setSequenceRef(seqs[2]);
+ ann4.setSequenceRef(seqs[1]);
+ parentPanel.getAlignment().addAnnotation(ann0);
+ parentPanel.getAlignment().addAnnotation(ann1);
+ parentPanel.getAlignment().addAnnotation(ann2);
+ parentPanel.getAlignment().addAnnotation(ann3);
+ parentPanel.getAlignment().addAnnotation(ann4);
+ }
+
+ /**
+ * Test reset
+ */
+ @Test(groups = { "Functional" })
+ public void testReset()
+ {
+ AnnotationColumnChooser acc = new AnnotationColumnChooser(
+ af.getViewport(), af.alignPanel);
+
+ HiddenColumns oldhidden = new HiddenColumns();
+ oldhidden.hideColumns(10, 20);
+ acc.setOldHiddenColumns(oldhidden);
+
+ HiddenColumns newHidden = new HiddenColumns();
+ newHidden.hideColumns(0, 3);
+ newHidden.hideColumns(22, 25);
+ af.getViewport().setHiddenColumns(newHidden);
+
+ HiddenColumns currentHidden = af.getViewport().getAlignment()
+ .getHiddenColumns();
+ Iterator<int[]> regions = currentHidden.iterator();
+ int[] next = regions.next();
+ assertEquals(0, next[0]);
+ assertEquals(3, next[1]);
+ next = regions.next();
+ assertEquals(22, next[0]);
+ assertEquals(25, next[1]);
+
+ // now reset hidden columns
+ acc.reset();
+ currentHidden = af.getViewport().getAlignment().getHiddenColumns();
+ regions = currentHidden.iterator();
+ next = regions.next();
+ assertEquals(10, next[0]);
+ assertEquals(20, next[1]);
+
+ // check works with empty hidden columns as old columns
+ oldhidden = new HiddenColumns();
+ acc.setOldHiddenColumns(oldhidden);
+ acc.reset();
+ currentHidden = af.getViewport().getAlignment().getHiddenColumns();
+ assertFalse(currentHidden.hasHiddenColumns());
+
+ // check works with empty hidden columns as new columns
+ oldhidden.hideColumns(10, 20);
+ acc.setOldHiddenColumns(oldhidden);
+ currentHidden = af.getViewport().getAlignment().getHiddenColumns();
+ assertFalse(currentHidden.hasHiddenColumns());
+
+ acc.reset();
+ currentHidden = af.getViewport().getAlignment().getHiddenColumns();
+ regions = currentHidden.iterator();
+ next = regions.next();
+ assertEquals(10, next[0]);
+ assertEquals(20, next[1]);
+ }
+}
--- /dev/null
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import jalview.api.FeatureColourI;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.schemes.FeatureColour;
+import jalview.util.matcher.Condition;
+
+import java.awt.Color;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.testng.annotations.Test;
+
+public class FeatureSettingsTest
+{
+ /**
+ * Test a roundtrip of save and reload of feature colours and filters as XML
+ *
+ * @throws IOException
+ */
+ @Test(groups = "Functional")
+ public void testSaveLoad() throws IOException
+ {
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+ ">Seq1\nACDEFGHIKLM", DataSourceType.PASTE);
+ SequenceI seq1 = af.getViewport().getAlignment().getSequenceAt(0);
+
+ /*
+ * add some features to the sequence
+ */
+ int score = 1;
+ addFeatures(seq1, "type1", score++);
+ addFeatures(seq1, "type2", score++);
+ addFeatures(seq1, "type3", score++);
+ addFeatures(seq1, "type4", score++);
+ addFeatures(seq1, "type5", score++);
+
+ /*
+ * set colour schemes for features
+ */
+ FeatureRenderer fr = af.getFeatureRenderer();
+
+ // type1: red
+ fr.setColour("type1", new FeatureColour(Color.red));
+
+ // type2: by label
+ FeatureColourI byLabel = new FeatureColour();
+ byLabel.setColourByLabel(true);
+ fr.setColour("type2", byLabel);
+
+ // type3: by score above threshold
+ FeatureColourI byScore = new FeatureColour(Color.BLACK, Color.BLUE, 1,
+ 10);
+ byScore.setAboveThreshold(true);
+ byScore.setThreshold(2f);
+ fr.setColour("type3", byScore);
+
+ // type4: by attribute AF
+ FeatureColourI byAF = new FeatureColour();
+ byAF.setColourByLabel(true);
+ byAF.setAttributeName("AF");
+ fr.setColour("type4", byAF);
+
+ // type5: by attribute CSQ:PolyPhen below threshold
+ FeatureColourI byPolyPhen = new FeatureColour(Color.BLACK, Color.BLUE,
+ 1, 10);
+ byPolyPhen.setBelowThreshold(true);
+ byPolyPhen.setThreshold(3f);
+ byPolyPhen.setAttributeName("CSQ", "PolyPhen");
+ fr.setColour("type5", byPolyPhen);
+
+ /*
+ * set filters for feature types
+ */
+
+ // filter type1 features by (label contains "x")
+ FeatureMatcherSetI filterByX = new FeatureMatcherSet();
+ filterByX.and(FeatureMatcher.byLabel(Condition.Contains, "x"));
+ fr.setFeatureFilter("type1", filterByX);
+
+ // filter type2 features by (score <= 2.4 and score > 1.1)
+ FeatureMatcherSetI filterByScore = new FeatureMatcherSet();
+ filterByScore.and(FeatureMatcher.byScore(Condition.LE, "2.4"));
+ filterByScore.and(FeatureMatcher.byScore(Condition.GT, "1.1"));
+ fr.setFeatureFilter("type2", filterByScore);
+
+ // filter type3 features by (AF contains X OR CSQ:PolyPhen != 0)
+ FeatureMatcherSetI filterByXY = new FeatureMatcherSet();
+ filterByXY
+ .and(FeatureMatcher.byAttribute(Condition.Contains, "X", "AF"));
+ filterByXY.or(FeatureMatcher.byAttribute(Condition.NE, "0", "CSQ",
+ "PolyPhen"));
+ fr.setFeatureFilter("type3", filterByXY);
+
+ /*
+ * save colours and filters to an XML file
+ */
+ File coloursFile = File.createTempFile("testSaveLoad", ".fc");
+ coloursFile.deleteOnExit();
+ FeatureSettings fs = new FeatureSettings(af);
+ fs.save(coloursFile);
+
+ /*
+ * change feature colours and filters
+ */
+ FeatureColourI pink = new FeatureColour(Color.pink);
+ fr.setColour("type1", pink);
+ fr.setColour("type2", pink);
+ fr.setColour("type3", pink);
+ fr.setColour("type4", pink);
+ fr.setColour("type5", pink);
+
+ FeatureMatcherSetI filter2 = new FeatureMatcherSet();
+ filter2.and(FeatureMatcher.byLabel(Condition.NotContains, "y"));
+ fr.setFeatureFilter("type1", filter2);
+ fr.setFeatureFilter("type2", filter2);
+ fr.setFeatureFilter("type3", filter2);
+ fr.setFeatureFilter("type4", filter2);
+ fr.setFeatureFilter("type5", filter2);
+
+ /*
+ * reload colours and filters from file and verify they are restored
+ */
+ fs.load(coloursFile);
+ FeatureColourI fc = fr.getFeatureStyle("type1");
+ assertTrue(fc.isSimpleColour());
+ assertEquals(fc.getColour(), Color.red);
+ fc = fr.getFeatureStyle("type2");
+ assertTrue(fc.isColourByLabel());
+ fc = fr.getFeatureStyle("type3");
+ assertTrue(fc.isGraduatedColour());
+ assertNull(fc.getAttributeName());
+ assertTrue(fc.isAboveThreshold());
+ assertEquals(fc.getThreshold(), 2f);
+ fc = fr.getFeatureStyle("type4");
+ assertTrue(fc.isColourByLabel());
+ assertTrue(fc.isColourByAttribute());
+ assertEquals(fc.getAttributeName(), new String[] { "AF" });
+ fc = fr.getFeatureStyle("type5");
+ assertTrue(fc.isGraduatedColour());
+ assertTrue(fc.isColourByAttribute());
+ assertEquals(fc.getAttributeName(), new String[] { "CSQ", "PolyPhen" });
+ assertTrue(fc.isBelowThreshold());
+ assertEquals(fc.getThreshold(), 3f);
+
+ assertEquals(fr.getFeatureFilter("type1").toStableString(), "Label Contains x");
+ assertEquals(fr.getFeatureFilter("type2").toStableString(),
+ "(Score LE 2.4) AND (Score GT 1.1)");
+ assertEquals(fr.getFeatureFilter("type3").toStableString(),
+ "(AF Contains X) OR (CSQ:PolyPhen NE 0.0)");
+ }
+
+ /**
+ * Adds two features of the given type to the given sequence, also setting the
+ * score as the value of attribute "AF" and sub-attribute "CSQ:PolyPhen"
+ *
+ * @param seq
+ * @param featureType
+ * @param score
+ */
+ private void addFeatures(SequenceI seq, String featureType, int score)
+ {
+ addFeature(seq, featureType, score++);
+ addFeature(seq, featureType, score);
+ }
+
+ private void addFeature(SequenceI seq, String featureType, int score)
+ {
+ SequenceFeature sf = new SequenceFeature(featureType, "desc", 1, 2,
+ score, "grp");
+ sf.setValue("AF", score);
+ sf.setValue("CSQ", new HashMap<String, String>()
+ {
+ {
+ put("PolyPhen", Integer.toString(score));
+ }
+ });
+ seq.addSequenceFeature(sf);
+ }
+}
package jalview.gui;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import jalview.analysis.AlignmentGenerator;
import jalview.io.DataSourceType;
import jalview.io.FileLoader;
+import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
public class FreeUpMemoryTest
{
private static final int ONE_MB = 1000 * 1000;
{
Jalview.main(new String[] { "-nonews", "-props",
"test/jalview/testProps.jvprops" });
- Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
- Boolean.TRUE.toString());
- Cache.applicationProperties.setProperty("SHOW_QUALITY",
- Boolean.TRUE.toString());
- Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
- Boolean.TRUE.toString());
- Cache.applicationProperties.setProperty("SHOW_OCCUPANCY",
- Boolean.TRUE.toString());
- Cache.applicationProperties.setProperty("SHOW_IDENTITY",
- Boolean.TRUE.toString());
+ String True = Boolean.TRUE.toString();
+ Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", True);
+ Cache.applicationProperties.setProperty("SHOW_QUALITY", True);
+ Cache.applicationProperties.setProperty("SHOW_CONSERVATION", True);
+ Cache.applicationProperties.setProperty("SHOW_OCCUPANCY", True);
+ Cache.applicationProperties.setProperty("SHOW_IDENTITY", True);
}
/**
protected void checkUsedMemory(long expectedMax)
{
/*
- * request garbage collection and wait briefly for it to run;
+ * request garbage collection and wait for it to run;
* NB there is no guarantee when, or whether, it will do so
+ * wait time depends on JRE/processor, generous allowance here
*/
System.gc();
- waitFor(100);
+ waitFor(1500);
/*
* a second gc() call should not be necessary - but it is!
* the test passes with it, and fails without it
*/
System.gc();
- waitFor(100);
+ waitFor(1500);
/*
* check used memory is 'reasonably low'
}
/*
+ * open an Overview window
+ */
+ af.overviewMenuItem_actionPerformed(null);
+ assertNotNull(af.alignPanel.overviewPanel);
+
+ /*
+ * exercise the pop-up menu in the Overview Panel (JAL-2864)
+ */
+ Object[] args = new Object[] {
+ new MouseEvent(af, 0, 0, 0, 0, 0, 1, true) };
+ PA.invokeMethod(af.alignPanel.overviewPanel,
+ "showPopupMenu(java.awt.event.MouseEvent)", args);
+
+ /*
* set a selection group - potential memory leak if it retains
* a reference to the alignment
*/
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
+import jalview.bin.Cache;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
+import jalview.datamodel.ColumnSelection;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.io.DataSourceType;
import jalview.io.FileFormat;
import jalview.io.FormatAdapter;
+import jalview.urls.api.UrlProviderFactoryI;
+import jalview.urls.desktop.DesktopUrlProviderFactory;
import jalview.util.MessageManager;
+import jalview.util.UrlConstants;
import java.awt.Component;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import javax.swing.JMenu;
@BeforeMethod(alwaysRun = true)
public void setUp() throws IOException
{
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ String inMenuString = ("EMBL-EBI Search | http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$"
+ + SEQUENCE_ID
+ + "$"
+ + "|"
+ + "UNIPROT | http://www.uniprot.org/uniprot/$" + DB_ACCESSION + "$")
+ + "|"
+ + ("INTERPRO | http://www.ebi.ac.uk/interpro/entry/$"
+ + DB_ACCESSION + "$")
+ + "|"
+ +
+ // Gene3D entry tests for case (in)sensitivity
+ ("Gene3D | http://gene3d.biochem.ucl.ac.uk/Gene3D/search?sterm=$"
+ + DB_ACCESSION + "$&mode=protein");
+
+ UrlProviderFactoryI factory = new DesktopUrlProviderFactory(
+ UrlConstants.DEFAULT_LABEL, inMenuString, "");
+ Preferences.sequenceUrlLinks = factory.createUrlProvider();
+
alignment = new FormatAdapter().readFile(TEST_DATA,
DataSourceType.PASTE, FileFormat.Fasta);
AlignFrame af = new AlignFrame(alignment, 700, 500);
public void testConfigureReferenceAnnotationsMenu_noSequenceSelected()
{
JMenuItem menu = new JMenuItem();
- List<SequenceI> seqs = new ArrayList<SequenceI>();
+ List<SequenceI> seqs = new ArrayList<>();
testee.configureReferenceAnnotationsMenu(menu, seqs);
assertFalse(menu.isEnabled());
// now try null list
List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
// create list of links and list of DBRefs
- List<String> links = new ArrayList<String>();
- List<DBRefEntry> refs = new ArrayList<DBRefEntry>();
+ List<String> links = new ArrayList<>();
+ List<DBRefEntry> refs = new ArrayList<>();
// links as might be added into Preferences | Connections dialog
links.add("EMBL-EBI Search | http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$"
// add all the dbrefs to the sequences: Uniprot 1 each, Interpro all 3 to
// seq0, Gene3D to seq1
- seqs.get(0).addDBRef(refs.get(0));
+ SequenceI seq = seqs.get(0);
+ seq.addDBRef(refs.get(0));
- seqs.get(0).addDBRef(refs.get(1));
- seqs.get(0).addDBRef(refs.get(2));
- seqs.get(0).addDBRef(refs.get(3));
+ seq.addDBRef(refs.get(1));
+ seq.addDBRef(refs.get(2));
+ seq.addDBRef(refs.get(3));
seqs.get(1).addDBRef(refs.get(4));
seqs.get(1).addDBRef(refs.get(5));
// get the Popup Menu for first sequence
- testee = new PopupMenu(parentPanel, (Sequence) seqs.get(0), links);
+ List<SequenceFeature> noFeatures = Collections.<SequenceFeature> emptyList();
+ testee = new PopupMenu(parentPanel, seq, noFeatures);
Component[] seqItems = testee.sequenceMenu.getMenuComponents();
JMenu linkMenu = (JMenu) seqItems[6];
Component[] linkItems = linkMenu.getMenuComponents();
// sequence id for each link should match corresponding DB accession id
for (int i = 1; i < 4; i++)
{
- assertEquals(refs.get(i - 1).getSource(), ((JMenuItem) linkItems[i])
+ String msg = seq.getName() + " link[" + i + "]";
+ assertEquals(msg, refs.get(i - 1).getSource(),
+ ((JMenuItem) linkItems[i])
.getText().split("\\|")[0]);
- assertEquals(refs.get(i - 1).getAccessionId(),
+ assertEquals(msg, refs.get(i - 1).getAccessionId(),
((JMenuItem) linkItems[i])
.getText().split("\\|")[1]);
}
// get the Popup Menu for second sequence
- testee = new PopupMenu(parentPanel, (Sequence) seqs.get(1), links);
+ seq = seqs.get(1);
+ testee = new PopupMenu(parentPanel, seq, noFeatures);
seqItems = testee.sequenceMenu.getMenuComponents();
linkMenu = (JMenu) seqItems[6];
linkItems = linkMenu.getMenuComponents();
// sequence id for each link should match corresponding DB accession id
for (int i = 1; i < 3; i++)
{
- assertEquals(refs.get(i + 3).getSource(), ((JMenuItem) linkItems[i])
+ String msg = seq.getName() + " link[" + i + "]";
+ assertEquals(msg, refs.get(i + 3).getSource(),
+ ((JMenuItem) linkItems[i])
.getText().split("\\|")[0].toUpperCase());
- assertEquals(refs.get(i + 3).getAccessionId(),
+ assertEquals(msg, refs.get(i + 3).getAccessionId(),
((JMenuItem) linkItems[i]).getText().split("\\|")[1]);
}
// if there are no valid links the Links submenu is disabled
- List<String> nomatchlinks = new ArrayList<String>();
+ List<String> nomatchlinks = new ArrayList<>();
nomatchlinks.add("NOMATCH | http://www.uniprot.org/uniprot/$"
+ DB_ACCESSION + "$");
- testee = new PopupMenu(parentPanel, (Sequence) seqs.get(0),
- nomatchlinks);
+ testee = new PopupMenu(parentPanel, seq, noFeatures);
seqItems = testee.sequenceMenu.getMenuComponents();
linkMenu = (JMenu) seqItems[6];
assertFalse(linkMenu.isEnabled());
}
+
+ /**
+ * Test for adding feature links
+ */
+ @Test(groups = { "Functional" })
+ public void testHideInsertions()
+ {
+ // get sequences from the alignment
+ List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
+
+ // add our own seqs to avoid problems with changes to existing sequences
+ // (gap at end of sequences varies depending on how tests are run!)
+ Sequence seqGap1 = new Sequence("GappySeq",
+ "AAAA----AA-AAAAAAA---AAA-----------AAAAAAAAAA--");
+ seqGap1.createDatasetSequence();
+ seqs.add(seqGap1);
+ Sequence seqGap2 = new Sequence("LessGappySeq",
+ "AAAAAA-AAAAA---AAA--AAAAA--AAAAAAA-AAAAAA");
+ seqGap2.createDatasetSequence();
+ seqs.add(seqGap2);
+ Sequence seqGap3 = new Sequence("AnotherGapSeq",
+ "AAAAAA-AAAAAA--AAAAAA-AAAAAAAAAAA---AAAAAAAA");
+ seqGap3.createDatasetSequence();
+ seqs.add(seqGap3);
+ Sequence seqGap4 = new Sequence("NoGaps",
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+ seqGap4.createDatasetSequence();
+ seqs.add(seqGap4);
+
+ ColumnSelection sel = new ColumnSelection();
+ parentPanel.av.getAlignment().getHiddenColumns()
+ .revealAllHiddenColumns(sel);
+
+ // get the Popup Menu for 7th sequence - no insertions
+ testee = new PopupMenu(parentPanel, seqs.get(7), null);
+ testee.hideInsertions_actionPerformed(null);
+
+ HiddenColumns hidden = parentPanel.av.getAlignment().getHiddenColumns();
+ Iterator<int[]> it = hidden.iterator();
+ assertFalse(it.hasNext());
+
+ // get the Popup Menu for GappySeq - this time we have insertions
+ testee = new PopupMenu(parentPanel, seqs.get(4), null);
+ testee.hideInsertions_actionPerformed(null);
+ hidden = parentPanel.av.getAlignment().getHiddenColumns();
+ it = hidden.iterator();
+
+ assertTrue(it.hasNext());
+ int[] region = it.next();
+ assertEquals(region[0], 4);
+ assertEquals(region[1], 7);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 10);
+ assertEquals(region[1], 10);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 18);
+ assertEquals(region[1], 20);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 24);
+ assertEquals(region[1], 34);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 45);
+ assertEquals(region[1], 46);
+
+ assertFalse(it.hasNext());
+
+ sel = new ColumnSelection();
+ hidden.revealAllHiddenColumns(sel);
+
+ // make a sequence group and hide insertions within the group
+ SequenceGroup sg = new SequenceGroup();
+ sg.setStartRes(8);
+ sg.setEndRes(42);
+ sg.addSequence(seqGap2, false);
+ sg.addSequence(seqGap3, false);
+ parentPanel.av.setSelectionGroup(sg);
+
+ // hide columns outside and within selection
+ // only hidden columns outside the collection will be retained (unless also
+ // gaps in the selection)
+ hidden.hideColumns(1, 10);
+ hidden.hideColumns(31, 40);
+
+ // get the Popup Menu for LessGappySeq in the sequence group
+ testee = new PopupMenu(parentPanel, seqs.get(5), null);
+ testee.hideInsertions_actionPerformed(null);
+ hidden = parentPanel.av.getAlignment().getHiddenColumns();
+ it = hidden.iterator();
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 1);
+ assertEquals(region[1], 7);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 13);
+ assertEquals(region[1], 14);
+
+ assertTrue(it.hasNext());
+ region = it.next();
+ assertEquals(region[0], 34);
+ assertEquals(region[1], 34);
+ }
+
}
--- /dev/null
+package jalview.gui;
+
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.awt.event.MouseEvent;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class ScalePanelTest
+{
+ @BeforeClass(alwaysRun = true)
+ public void setUpJvOptionPane()
+ {
+ JvOptionPane.setInteractiveMode(false);
+ JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ }
+
+ @Test(groups = "Functional")
+ public void testPreventNegativeStartColumn()
+ {
+ SequenceI seq1 = new Sequence("Seq1", "MATRESS");
+ SequenceI seq2 = new Sequence("Seq2", "MADNESS");
+ AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+
+ AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
+ al.getHeight());
+ ScalePanel scalePanel = new ScalePanel(
+ alignFrame.getViewport(), alignFrame.alignPanel
+ );
+
+ MouseEvent mouse = new MouseEvent(
+ scalePanel, 0, 1, 0, 4, 0, 1, false
+ );
+ scalePanel.mousePressed(mouse);
+ scalePanel.mouseDragged(mouse);
+
+ // simulate dragging selection leftwards beyond the sequences giving
+ // negative X
+ mouse = new MouseEvent(scalePanel, 0, 1, 0, -30, 0, 1, false);
+
+ scalePanel.mouseReleased(mouse);
+
+ SequenceGroup sg = scalePanel.av.getSelectionGroup();
+ int startCol = sg.getStartRes();
+
+ assertTrue(startCol >= 0);
+
+
+ }
+
+}
+/*
+ * 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 static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
-import sun.swing.SwingUtilities2;
-
public class SeqCanvasTest
{
/**
AlignmentI al = av.getAlignment();
assertEquals(al.getWidth(), 157);
assertEquals(al.getHeight(), 15);
+ av.getRanges().setStartEndSeq(0, 14);
+
+ SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
av.setWrapAlignment(true);
- av.getRanges().setStartEndSeq(0, 14);
av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
int charHeight = av.getCharHeight();
int charWidth = av.getCharWidth();
assertEquals(charHeight, 17);
assertEquals(charWidth, 12);
- SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
-
/*
* first with scales above, left, right
*/
av.setScaleAboveWrapped(true);
av.setScaleLeftWrapped(true);
av.setScaleRightWrapped(true);
- FontMetrics fm = SwingUtilities2.getFontMetrics(testee, av.getFont());
+ FontMetrics fm = testee.getFontMetrics(av.getFont());
int labelWidth = fm.stringWidth("000") + charWidth;
assertEquals(labelWidth, 39); // 3 x 9 + charWidth
av.setScaleAboveWrapped(true);
av.setScaleLeftWrapped(true);
av.setScaleRightWrapped(true);
- FontMetrics fm = SwingUtilities2.getFontMetrics(testee, av.getFont());
+ FontMetrics fm = testee.getFontMetrics(av.getFont());
int labelWidth = fm.stringWidth("000") + charWidth;
assertEquals(labelWidth, 39); // 3 x 9 + charWidth
int annotationHeight = testee.getAnnotationHeight();
testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
}
+
+ /**
+ * Test simulates loading an unwrapped alignment, shrinking it vertically so
+ * not all sequences are visible, then changing to wrapped mode. The ranges
+ * endSeq should be unchanged, but the vertical repeat height should include
+ * all sequences.
+ */
+ @Test(groups = "Functional")
+ public void testCalculateWrappedGeometry_fromScrolled()
+ {
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+ "examples/uniref50.fa", DataSourceType.FILE);
+ AlignViewport av = af.getViewport();
+ AlignmentI al = av.getAlignment();
+ assertEquals(al.getWidth(), 157);
+ assertEquals(al.getHeight(), 15);
+ av.getRanges().setStartEndSeq(0, 3);
+ av.setShowAnnotation(false);
+ av.setScaleAboveWrapped(true);
+
+ SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
+
+ av.setWrapAlignment(true);
+ av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+ assertEquals(charHeight, 17);
+ assertEquals(charWidth, 12);
+
+ int canvasWidth = 400;
+ int canvasHeight = 300;
+ testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+
+ assertEquals(av.getRanges().getEndSeq(), 3); // unchanged
+ int repeatingHeight = (int) PA.getValue(testee,
+ "wrappedRepeatHeightPx");
+ assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
+ }
}
package jalview.gui;
import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertTrue;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
import jalview.jbgui.GStructureChooser.FilterOption;
+import java.util.Collection;
import java.util.Vector;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
public class StructureChooserTest
{
PDBEntry dbRef = new PDBEntry();
dbRef.setId("1tim");
- Vector<PDBEntry> pdbIds = new Vector<PDBEntry>();
+ Vector<PDBEntry> pdbIds = new Vector<>();
pdbIds.add(dbRef);
seq.setPDBId(pdbIds);
assertTrue(sc.getCmbFilterOption().getSelectedItem() != null);
FilterOption filterOpt = (FilterOption) sc.getCmbFilterOption()
.getSelectedItem();
- assertEquals("Cached PDB Entries", filterOpt.getName());
+ assertEquals("Cached Structures", filterOpt.getName());
}
@Test(groups = { "Network" })
SequenceI[] selectedSeqs = new SequenceI[] { seq };
StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
sc.fetchStructuresMetaData();
- assertTrue(sc.getDiscoveredStructuresSet() != null);
- assertTrue(sc.getDiscoveredStructuresSet().size() > 0);
+ Collection<FTSData> ss = (Collection<FTSData>) PA.getValue(sc,
+ "discoveredStructuresSet");
+ assertNotNull(ss);
+ assertTrue(ss.size() > 0);
}
PDBEntry pdbe4 = new PDBEntry("1GAQ", "A", Type.PDB, null);
PDBEntry pdbe5 = new PDBEntry("3A6S", "B", Type.PDB, "path2");
PDBEntry pdbe6 = new PDBEntry("1GAQ", "B", Type.PDB, null);
+ PDBEntry pdbe7 = new PDBEntry("1FOO", "Q", Type.PDB, null);
+
PDBEntry[] pdbs = new PDBEntry[] { pdbe1, pdbe2, pdbe3, pdbe4, pdbe5,
- pdbe6 };
+ pdbe6, pdbe7 };
/*
* seq1 ... seq6 associated with pdbe1 ... pdbe6
assertTrue(uniques.containsKey(pdbe4));
assertFalse(uniques.containsKey(pdbe5));
assertFalse(uniques.containsKey(pdbe6));
+ assertTrue(uniques.containsKey(pdbe7));
// 1A70 associates with seq1 and seq3
SequenceI[] ss = uniques.get(pdbe1);
assertEquals(ss.length, 2);
assertSame(seqs[3], ss[0]);
assertSame(seqs[5], ss[1]);
+
+ // 1FOO has seq7
+ ss = uniques.get(pdbe7);
+ assertEquals(ss.length, 1);
+ assertSame(seqs[6], ss[0]);
}
}
import java.io.File;
import java.util.List;
+import org.junit.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
}
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "Functional" }, enabled = false)
public void checkPDBannotationSource()
{
-
+ Assert.fail(
+ "This test is incorrect - does not verify that JmolParser's annotation rows can be recognised as generated by the Jmol parser.");
for (SequenceI asq : al.getSequences())
{
for (AlignmentAnnotation aa : asq.getAnnotation())
{
System.out.println("CalcId: " + aa.getCalcId());
- if (StructureImportSettings.getDefaultPDBFileParser().equals(
- StructureParser.JALVIEW_PARSER))
+ if (StructureImportSettings.getDefaultPDBFileParser()
+ .equals(StructureParser.JALVIEW_PARSER))
{
assertTrue(MCview.PDBfile.isCalcIdForFile(aa, pdbId));
}
--- /dev/null
+package jalview.io;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.SequenceI;
+
+import java.io.IOException;
+
+import org.testng.annotations.Test;
+
+public class ClustalFileTest
+{
+ @Test(groups="Functional")
+ public void testParse_withNumbering() throws IOException
+ {
+ //@formatter:off
+ String data = "CLUSTAL\n\n"
+ + "FER_CAPAA/1-8 -----------------------------------------------------------A\t1\n"
+ + "FER_CAPAN/1-55 MA------SVSATMISTSFMPRKPAVTSL-KPIPNVGE--ALFGLKS-A--NGGKVTCMA 48\n"
+ + "FER1_SOLLC/1-55 MA------SISGTMISTSFLPRKPAVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMA 48\n"
+ + "Q93XJ9_SOLTU/1-55 MA------SISGTMISTSFLPRKPVVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMA 48\n"
+ + "FER1_PEA/1-60 MATT---PALYGTAVSTSFLRTQPMPMSV-TTTKAFSN--GFLGLKT-SLKRGDLAVAMA 53\n\n"
+ + "FER_CAPAA/1-8 SYKVKLI 8\n"
+ + "FER_CAPAN/1-55 SYKVKLI 55\n"
+ + "FER1_SOLLC/1-55 SYKVKLI 55\n"
+ + "Q93XJ9_SOLTU/1-55 SYKVKLI 55\n"
+ + "FER1_PEA/1-60 SYKVKLV 60\n"
+ + " .* .:....*******..** ..........** ********...*:::* ...\n"
+ + "\t\t.:.::. *\n";
+ //@formatter:on
+ ClustalFile cf = new ClustalFile(data, DataSourceType.PASTE);
+ cf.parse();
+ SequenceI[] seqs = cf.getSeqsAsArray();
+ assertEquals(seqs.length, 5);
+ assertEquals(seqs[0].getName(), "FER_CAPAA");
+ assertEquals(seqs[0].getStart(), 1);
+ assertEquals(seqs[0].getEnd(), 8);
+ assertTrue(seqs[0].getSequenceAsString().endsWith("ASYKVKLI"));
+ }
+
+ @Test(groups="Functional")
+ public void testParse_noNumbering() throws IOException
+ {
+ //@formatter:off
+ String data = "CLUSTAL\n\n"
+ + "FER_CAPAA/1-8 -----------------------------------------------------------A\n"
+ + "FER_CAPAN/1-55 MA------SVSATMISTSFMPRKPAVTSL-KPIPNVGE--ALFGLKS-A--NGGKVTCMA\n"
+ + "FER1_SOLLC/1-55 MA------SISGTMISTSFLPRKPAVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMA\n"
+ + "Q93XJ9_SOLTU/1-55 MA------SISGTMISTSFLPRKPVVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMA\n"
+ + "FER1_PEA/1-60 MATT---PALYGTAVSTSFLRTQPMPMSV-TTTKAFSN--GFLGLKT-SLKRGDLAVAMA\n\n"
+ + "FER_CAPAA/1-8 SYKVKLI\n"
+ + "FER_CAPAN/1-55 SYKVKLI\n"
+ + "FER1_SOLLC/1-55 SYKVKLI\n"
+ + "Q93XJ9_SOLTU/1-55 SYKVKLI\n"
+ + "FER1_PEA/1-60 SYKVKLV\n";
+ //@formatter:on
+ ClustalFile cf = new ClustalFile(data, DataSourceType.PASTE);
+ cf.parse();
+ SequenceI[] seqs = cf.getSeqsAsArray();
+ assertEquals(seqs.length, 5);
+ assertEquals(seqs[0].getName(), "FER_CAPAA");
+ assertEquals(seqs[0].getStart(), 1);
+ assertEquals(seqs[0].getEnd(), 8);
+ assertTrue(seqs[0].getSequenceAsString().endsWith("ASYKVKLI"));
+ }
+}
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+
+import junit.extensions.PA;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@Test(singleThreaded = true)
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
+ @DataProvider(name = "initialAccessions")
+ static Object[][] getAccessions()
+ {
+ return new String[][] { { "UNIPROT", "P00338" },
+ { "UNIPROT", "Q8Z9G6" },
+ { "ENSEMBLGENOMES", "CAD01290" } };
+ }
+
/**
* test store and recovery of all reachable cross refs from all reachable
* crossrefs for one or more fetched db refs. Currently, this test has a known
*
* @throws Exception
*/
- @Test(groups = { "Operational" }, enabled = true)
- public void testRetrieveAndShowCrossref() throws Exception
+ @Test(
+ groups =
+ { "Operational" },
+ dataProvider = "initialAccessions",
+ enabled = true)
+ public void testRetrieveAndShowCrossref(String forSource,
+ String forAccession) throws Exception
{
List<String> failedDBRetr = new ArrayList<>();
// . codonframes
//
//
- HashMap<String, String> dbtoviewBit = new HashMap<>();
+ Map<String, String> dbtoviewBit = new HashMap<>();
List<String> keyseq = new ArrayList<>();
- HashMap<String, File> savedProjects = new HashMap<>();
+ Map<String, File> savedProjects = new HashMap<>();
- for (String[] did : new String[][] { { "UNIPROT", "P00338" } })
- {
+// for (String[] did : new String[][] { { "UNIPROT", "P00338" } })
+// {
// pass counters - 0 - first pass, 1 means retrieve project rather than
// perform action
int pass1 = 0, pass2 = 0, pass3 = 0;
// { pass 2 = 0 { pass 3 = 0 } }
do
{
- String first = did[0] + " " + did[1];
+ String first = forSource + " " + forAccession;//did[0] + " " + did[1];
AlignFrame af = null;
boolean dna;
AlignmentI retral;
// retrieve dbref
List<AlignFrame> afs = jalview.gui.SequenceFetcher.fetchAndShow(
- did[0], did[1]);
+ forSource, forAccession);
+ // did[0], did[1]);
if (afs.size() == 0)
{
failedDBRetr.add("Didn't retrieve " + first);
if (pass2 == 0)
{ // retrieve and show cross-refs in this thread
- cra = new CrossRefAction(af, seqs, dna, db);
+ cra = CrossRefAction.getHandlerFor(seqs, dna, db, af);
cra.run();
- if (cra.getXrefViews().size() == 0)
+ cra_views = (List<AlignmentViewPanel>) PA.getValue(cra,
+ "xrefViews");
+ if (cra_views.size() == 0)
{
failedXrefMenuItems.add("No crossrefs retrieved for "
+ first + " -> " + db);
continue;
}
- cra_views = cra.getXrefViews();
assertNucleotide(cra_views.get(0),
"Nucleotide panel included proteins for " + first
+ " -> " + db);
if (pass3 == 0)
{
-
SequenceI[] xrseqs = avp.getAlignment()
.getSequencesArray();
AlignFrame nextaf = Desktop.getAlignFrameFor(avp
.getAlignViewport());
- cra = new CrossRefAction(nextaf, xrseqs, avp
- .getAlignViewport().isNucleotide(), xrefdb);
+ cra = CrossRefAction.getHandlerFor(xrseqs, avp
+ .getAlignViewport().isNucleotide(), xrefdb,
+ nextaf);
cra.run();
- if (cra.getXrefViews().size() == 0)
+ cra_views2 = (List<AlignmentViewPanel>) PA.getValue(
+ cra, "xrefViews");
+ if (cra_views2.size() == 0)
{
failedXrefMenuItems
.add("No crossrefs retrieved for '"
+ " via '" + nextaf.getTitle() + "'");
continue;
}
- cra_views2 = cra.getXrefViews();
assertNucleotide(cra_views2.get(0),
"Nucleotide panel included proteins for '"
+ nextxref + "' to " + xrefdb
pass1++;
}
} while (pass1 < 3);
- }
+
if (failedXrefMenuItems.size() > 0)
{
for (String s : failedXrefMenuItems)
* viewpanel needs to be called with a distinct xrefpath to ensure
* each one's strings are compared)
*/
- private void stringify(HashMap<String, String> dbtoviewBit,
- HashMap<String, File> savedProjects, String xrefpath,
+ private void stringify(Map<String, String> dbtoviewBit,
+ Map<String, File> savedProjects, String xrefpath,
AlignmentViewPanel avp)
{
if (savedProjects != null)
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
import jalview.api.FeatureColourI;
import jalview.api.FeatureRenderer;
import jalview.datamodel.SequenceDummy;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.datamodel.features.FeatureMatcherI;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.datamodel.features.SequenceFeatures;
import jalview.gui.AlignFrame;
import jalview.gui.Desktop;
import jalview.gui.JvOptionPane;
+import jalview.schemes.FeatureColour;
import jalview.structure.StructureSelectionManager;
+import jalview.util.matcher.Condition;
import java.awt.Color;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
*/
FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
Map<String, FeatureColourI> visible = fr.getDisplayedFeatureCols();
- List<String> visibleGroups = new ArrayList<String>(
+ List<String> visibleGroups = new ArrayList<>(
Arrays.asList(new String[] {}));
String exported = featuresFile.printJalviewFormat(
- al.getSequencesArray(), visible, visibleGroups, false);
+ al.getSequencesArray(), visible, null, visibleGroups, false);
String expected = "No Features Visible";
assertEquals(expected, exported);
*/
visibleGroups.add("uniprot");
exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
- visible, visibleGroups, true);
+ visible, null, visibleGroups, true);
expected = "Cath\tFER_CAPAA\t-1\t0\t0\tDomain\t0.0\n"
+ "desc1\tFER_CAPAN\t-1\t0\t0\tPfam\t1.3\n"
+ "desc3\tFER1_SOLLC\t-1\t0\t0\tPfam\n" // NaN is not output
fr.setVisible("GAMMA-TURN");
visible = fr.getDisplayedFeatureCols();
exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
- visible, visibleGroups, false);
+ visible, null, visibleGroups, false);
expected = "METAL\tcc9900\n"
- + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
+ + "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n"
+ "\nSTARTGROUP\tuniprot\n"
+ "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+ "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
fr.setVisible("Pfam");
visible = fr.getDisplayedFeatureCols();
exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
- visible, visibleGroups, false);
+ visible, null, visibleGroups, false);
/*
* features are output within group, ordered by sequence and by type
*/
expected = "METAL\tcc9900\n"
+ "Pfam\tff0000\n"
- + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
+ + "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n"
+ "\nSTARTGROUP\tuniprot\n"
+ "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+ "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
*/
FeaturesFile featuresFile = new FeaturesFile();
FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
- Map<String, FeatureColourI> visible = new HashMap<String, FeatureColourI>();
- List<String> visibleGroups = new ArrayList<String>(
+ Map<String, FeatureColourI> visible = new HashMap<>();
+ List<String> visibleGroups = new ArrayList<>(
Arrays.asList(new String[] {}));
String exported = featuresFile.printGffFormat(al.getSequencesArray(),
visible, visibleGroups, false);
+ "FER_CAPAN\tUniprot\tPfam\t20\t20\t0.0\t+\t2\tx=y;black=white\n";
assertEquals(expected, exported);
}
+
+ /**
+ * Test for parsing of feature filters as represented in a Jalview features
+ * file
+ *
+ * @throws Exception
+ */
+ @Test(groups = { "Functional" })
+ public void testParseFilters() throws Exception
+ {
+ Map<String, FeatureMatcherSetI> filters = new HashMap<>();
+ String text = "sequence_variant\tCSQ:PolyPhen NotContains 'damaging'\n"
+ + "missense_variant\t(label contains foobar) and (Score lt 1.3)";
+ FeaturesFile featuresFile = new FeaturesFile(text,
+ DataSourceType.PASTE);
+ featuresFile.parseFilters(filters);
+ assertEquals(filters.size(), 2);
+
+ FeatureMatcherSetI fm = filters.get("sequence_variant");
+ assertNotNull(fm);
+ Iterator<FeatureMatcherI> matchers = fm.getMatchers().iterator();
+ FeatureMatcherI matcher = matchers.next();
+ assertFalse(matchers.hasNext());
+ String[] attributes = matcher.getAttribute();
+ assertArrayEquals(attributes, new String[] { "CSQ", "PolyPhen" });
+ assertSame(matcher.getMatcher().getCondition(), Condition.NotContains);
+ assertEquals(matcher.getMatcher().getPattern(), "damaging");
+
+ fm = filters.get("missense_variant");
+ assertNotNull(fm);
+ matchers = fm.getMatchers().iterator();
+ matcher = matchers.next();
+ assertTrue(matcher.isByLabel());
+ assertSame(matcher.getMatcher().getCondition(), Condition.Contains);
+ assertEquals(matcher.getMatcher().getPattern(), "foobar");
+ matcher = matchers.next();
+ assertTrue(matcher.isByScore());
+ assertSame(matcher.getMatcher().getCondition(), Condition.LT);
+ assertEquals(matcher.getMatcher().getPattern(), "1.3");
+ assertEquals(matcher.getMatcher().getFloatValue(), 1.3f);
+
+ assertFalse(matchers.hasNext());
+ }
+
+ @Test(groups = { "Functional" })
+ public void testOutputFeatureFilters()
+ {
+ FeaturesFile ff = new FeaturesFile();
+ StringBuilder sb = new StringBuilder();
+ Map<String, FeatureColourI> visible = new HashMap<>();
+ visible.put("pfam", new FeatureColour(Color.red));
+ Map<String, FeatureMatcherSetI> featureFilters = new HashMap<>();
+
+ // with no filters, nothing is output
+ ff.outputFeatureFilters(sb, visible, featureFilters);
+ assertEquals("", sb.toString());
+
+ // with filter for not visible features only, nothing is output
+ FeatureMatcherSet filter = new FeatureMatcherSet();
+ filter.and(FeatureMatcher.byLabel(Condition.Present, null));
+ featureFilters.put("foobar", filter);
+ ff.outputFeatureFilters(sb, visible, featureFilters);
+ assertEquals("", sb.toString());
+
+ // with filters for visible feature types
+ FeatureMatcherSet filter2 = new FeatureMatcherSet();
+ filter2.and(FeatureMatcher.byAttribute(Condition.Present, null, "CSQ",
+ "PolyPhen"));
+ filter2.and(FeatureMatcher.byScore(Condition.LE, "-2.4"));
+ featureFilters.put("pfam", filter2);
+ visible.put("foobar", new FeatureColour(Color.blue));
+ ff.outputFeatureFilters(sb, visible, featureFilters);
+ String expected = "\nSTARTFILTERS\nfoobar\tLabel Present\npfam\t(CSQ:PolyPhen Present) AND (Score LE -2.4)\nENDFILTERS\n\n";
+ assertEquals(expected, sb.toString());
+ }
}
{ "examples/plantfdx.fa", FileFormat.Fasta },
{ "examples/dna_interleaved.phy", FileFormat.Phylip },
{ "examples/2GIS.pdb", FileFormat.PDB },
- { "examples/rf00031_folded.stk", FileFormat.Stockholm },
+ { "examples/RF00031_folded.stk", FileFormat.Stockholm },
{ "examples/testdata/test.rnaml", FileFormat.Rnaml },
{ "examples/testdata/test.aln", FileFormat.Clustal },
{ "examples/testdata/test.pfam", FileFormat.Pfam },
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
TEST_SEQ_HEIGHT = expectedSeqs.size();
TEST_GRP_HEIGHT = expectedGrps.size();
TEST_ANOT_HEIGHT = expectedAnnots.size();
- TEST_CS_HEIGHT = expectedColSel.getHiddenColumnsCopy().size();
+ TEST_CS_HEIGHT = expectedColSel.getNumberOfRegions();
exportSettings = new AlignExportSettingI()
{
{
HiddenColumns cs = testJsonFile.getHiddenColumns();
Assert.assertNotNull(cs);
- Assert.assertNotNull(cs.getHiddenColumnsCopy());
- List<int[]> hiddenCols = cs.getHiddenColumnsCopy();
- Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT);
- Assert.assertEquals(hiddenCols.get(0), expectedColSel
- .getHiddenColumnsCopy().get(0),
+
+ Iterator<int[]> it = cs.iterator();
+ Iterator<int[]> colselit = expectedColSel.iterator();
+ Assert.assertTrue(it.hasNext());
+ Assert.assertEquals(cs.getNumberOfRegions(), TEST_CS_HEIGHT);
+ Assert.assertEquals(it.next(), colselit.next(),
"Mismatched hidden columns!");
}
@BeforeTest(alwaysRun = true)
public static void clearDesktop()
{
- if (Desktop.instance != null && Desktop.getAlignFrames() != null)
+ if (Desktop.instance != null && Desktop.getFrames() != null
+ && Desktop.getFrames().length > 0)
{
Desktop.instance.closeAll_actionPerformed(null);
}
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureColourI;
import jalview.api.ViewStyleI;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.PDBEntry.Type;
import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.gui.AlignFrame;
import jalview.gui.AlignViewport;
import jalview.gui.AlignmentPanel;
import jalview.gui.Desktop;
+import jalview.gui.FeatureRenderer;
import jalview.gui.Jalview2XML;
import jalview.gui.JvOptionPane;
import jalview.gui.PopupMenu;
import jalview.schemes.BuriedColourScheme;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemeProperty;
+import jalview.schemes.FeatureColour;
import jalview.schemes.JalviewColourScheme;
import jalview.schemes.RNAHelicesColour;
import jalview.schemes.StrandColourScheme;
import jalview.schemes.TCoffeeColourScheme;
import jalview.structure.StructureImportSettings;
+import jalview.util.matcher.Condition;
import jalview.viewmodel.AlignmentViewport;
+import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
}
+ /**
+ * Test for JAL-2223 - multiple mappings in View Mapping report
+ *
+ * @throws Exception
+ */
+ @Test(groups = { "Functional" })
+ public void noDuplicatePdbMappingsMade() throws Exception
+ {
+ StructureImportSettings.setProcessSecondaryStructure(true);
+ StructureImportSettings.setVisibleChainAnnotation(true);
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+ "examples/exampleFile_2_7.jar", DataSourceType.FILE);
+ assertNotNull(af, "Didn't read in the example file correctly.");
+
+ // locate Jmol viewer
+ // count number of PDB mappings the structure selection manager holds -
+ String pdbFile = af.getCurrentView().getStructureSelectionManager()
+ .findFileForPDBId("1A70");
+ assertEquals(
+ af.getCurrentView().getStructureSelectionManager()
+ .getMapping(pdbFile).length,
+ 2, "Expected only two mappings for 1A70");
+
+ }
+
@Test(groups = { "Functional" })
public void viewRefPdbAnnotation() throws Exception
{
String afid = af.getViewport().getSequenceSetId();
// remember reference sequence for each panel
- Map<String, SequenceI> refseqs = new HashMap<String, SequenceI>();
+ Map<String, SequenceI> refseqs = new HashMap<>();
/*
* mark sequence 2, 3, 4.. in panels 1, 2, 3...
* remember representative and hidden sequences marked
* on each panel
*/
- Map<String, SequenceI> repSeqs = new HashMap<String, SequenceI>();
- Map<String, List<String>> hiddenSeqNames = new HashMap<String, List<String>>();
+ Map<String, SequenceI> repSeqs = new HashMap<>();
+ Map<String, List<String>> hiddenSeqNames = new HashMap<>();
/*
* mark sequence 2, 3, 4.. in panels 1, 2, 3...
repIndex = Math.max(repIndex, 1);
SequenceI repSeq = alignment.getSequenceAt(repIndex);
repSeqs.put(ap.getViewName(), repSeq);
- List<String> hiddenNames = new ArrayList<String>();
+ List<String> hiddenNames = new ArrayList<>();
hiddenSeqNames.put(ap.getViewName(), hiddenNames);
/*
assertTrue(rs.conservationApplied());
assertEquals(rs.getConservationInc(), 30);
}
+
+ /**
+ * Test save and reload of feature colour schemes and filter settings
+ *
+ * @throws IOException
+ */
+ @Test(groups = { "Functional" })
+ public void testSaveLoadFeatureColoursAndFilters() throws IOException
+ {
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+ ">Seq1\nACDEFGHIKLM", DataSourceType.PASTE);
+ SequenceI seq1 = af.getViewport().getAlignment().getSequenceAt(0);
+
+ /*
+ * add some features to the sequence
+ */
+ int score = 1;
+ addFeatures(seq1, "type1", score++);
+ addFeatures(seq1, "type2", score++);
+ addFeatures(seq1, "type3", score++);
+ addFeatures(seq1, "type4", score++);
+ addFeatures(seq1, "type5", score++);
+
+ /*
+ * set colour schemes for features
+ */
+ FeatureRenderer fr = af.getFeatureRenderer();
+ fr.findAllFeatures(true);
+
+ // type1: red
+ fr.setColour("type1", new FeatureColour(Color.red));
+
+ // type2: by label
+ FeatureColourI byLabel = new FeatureColour();
+ byLabel.setColourByLabel(true);
+ fr.setColour("type2", byLabel);
+
+ // type3: by score above threshold
+ FeatureColourI byScore = new FeatureColour(Color.BLACK, Color.BLUE, 1,
+ 10);
+ byScore.setAboveThreshold(true);
+ byScore.setThreshold(2f);
+ fr.setColour("type3", byScore);
+
+ // type4: by attribute AF
+ FeatureColourI byAF = new FeatureColour();
+ byAF.setColourByLabel(true);
+ byAF.setAttributeName("AF");
+ fr.setColour("type4", byAF);
+
+ // type5: by attribute CSQ:PolyPhen below threshold
+ FeatureColourI byPolyPhen = new FeatureColour(Color.BLACK, Color.BLUE,
+ 1, 10);
+ byPolyPhen.setBelowThreshold(true);
+ byPolyPhen.setThreshold(3f);
+ byPolyPhen.setAttributeName("CSQ", "PolyPhen");
+ fr.setColour("type5", byPolyPhen);
+
+ /*
+ * set filters for feature types
+ */
+
+ // filter type1 features by (label contains "x")
+ FeatureMatcherSetI filterByX = new FeatureMatcherSet();
+ filterByX.and(FeatureMatcher.byLabel(Condition.Contains, "x"));
+ fr.setFeatureFilter("type1", filterByX);
+
+ // filter type2 features by (score <= 2.4 and score > 1.1)
+ FeatureMatcherSetI filterByScore = new FeatureMatcherSet();
+ filterByScore.and(FeatureMatcher.byScore(Condition.LE, "2.4"));
+ filterByScore.and(FeatureMatcher.byScore(Condition.GT, "1.1"));
+ fr.setFeatureFilter("type2", filterByScore);
+
+ // filter type3 features by (AF contains X OR CSQ:PolyPhen != 0)
+ FeatureMatcherSetI filterByXY = new FeatureMatcherSet();
+ filterByXY
+ .and(FeatureMatcher.byAttribute(Condition.Contains, "X", "AF"));
+ filterByXY.or(FeatureMatcher.byAttribute(Condition.NE, "0", "CSQ",
+ "PolyPhen"));
+ fr.setFeatureFilter("type3", filterByXY);
+
+ /*
+ * save as Jalview project
+ */
+ File tfile = File.createTempFile("JalviewTest", ".jvp");
+ tfile.deleteOnExit();
+ String filePath = tfile.getAbsolutePath();
+ assertTrue(af.saveAlignment(filePath, FileFormat.Jalview),
+ "Failed to store as a project.");
+
+ /*
+ * close current alignment and load the saved project
+ */
+ af.closeMenuItem_actionPerformed(true);
+ af = null;
+ af = new FileLoader()
+ .LoadFileWaitTillLoaded(filePath, DataSourceType.FILE);
+ assertNotNull(af, "Failed to import new project");
+
+ /*
+ * verify restored feature colour schemes and filters
+ */
+ fr = af.getFeatureRenderer();
+ FeatureColourI fc = fr.getFeatureStyle("type1");
+ assertTrue(fc.isSimpleColour());
+ assertEquals(fc.getColour(), Color.red);
+ fc = fr.getFeatureStyle("type2");
+ assertTrue(fc.isColourByLabel());
+ fc = fr.getFeatureStyle("type3");
+ assertTrue(fc.isGraduatedColour());
+ assertNull(fc.getAttributeName());
+ assertTrue(fc.isAboveThreshold());
+ assertEquals(fc.getThreshold(), 2f);
+ fc = fr.getFeatureStyle("type4");
+ assertTrue(fc.isColourByLabel());
+ assertTrue(fc.isColourByAttribute());
+ assertEquals(fc.getAttributeName(), new String[] { "AF" });
+ fc = fr.getFeatureStyle("type5");
+ assertTrue(fc.isGraduatedColour());
+ assertTrue(fc.isColourByAttribute());
+ assertEquals(fc.getAttributeName(), new String[] { "CSQ", "PolyPhen" });
+ assertTrue(fc.isBelowThreshold());
+ assertEquals(fc.getThreshold(), 3f);
+
+ assertEquals(fr.getFeatureFilter("type1").toStableString(),
+ "Label Contains x");
+ assertEquals(fr.getFeatureFilter("type2").toStableString(),
+ "(Score LE 2.4) AND (Score GT 1.1)");
+ assertEquals(fr.getFeatureFilter("type3").toStableString(),
+ "(AF Contains X) OR (CSQ:PolyPhen NE 0.0)");
+ }
+
+ private void addFeature(SequenceI seq, String featureType, int score)
+ {
+ SequenceFeature sf = new SequenceFeature(featureType, "desc", 1, 2,
+ score, "grp");
+ sf.setValue("AF", score);
+ sf.setValue("CSQ", new HashMap<String, String>()
+ {
+ {
+ put("PolyPhen", Integer.toString(score));
+ }
+ });
+ seq.addSequenceFeature(sf);
+ }
+
+ /**
+ * Adds two features of the given type to the given sequence, also setting the
+ * score as the value of attribute "AF" and sub-attribute "CSQ:PolyPhen"
+ *
+ * @param seq
+ * @param featureType
+ * @param score
+ */
+ private void addFeatures(SequenceI seq, String featureType, int score)
+ {
+ addFeature(seq, featureType, score++);
+ addFeature(seq, featureType, score);
+ }
}
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
+import jalview.api.FeatureColourI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.gui.JvOptionPane;
import jalview.io.gff.GffConstants;
+import jalview.renderer.seqfeatures.FeatureRenderer;
+import jalview.schemes.FeatureColour;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
-import java.util.HashMap;
-import java.util.Hashtable;
+import java.awt.Color;
import java.util.Map;
import junit.extensions.PA;
SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
"group");
- Map<String, float[][]> minmax = new Hashtable<String, float[][]>();
- sar.appendFeature(sb, 1, minmax, sf);
+ FeatureRendererModel fr = new FeatureRenderer(null);
+ Map<String, float[][]> minmax = fr.getMinMax();
+ sar.appendFeature(sb, 1, fr, sf);
/*
* map has no entry for this feature type - score is not shown:
*/
* map has entry for this feature type - score is shown:
*/
minmax.put("METAL", new float[][] { { 0f, 1f }, null });
- sar.appendFeature(sb, 1, minmax, sf);
+ sar.appendFeature(sb, 1, fr, sf);
// <br> is appended to a buffer > 6 in length
assertEquals("METAL 1 3; Fe2-S<br>METAL 1 3; Fe2-S Score=1.3",
sb.toString());
*/
minmax.put("METAL", new float[][] { { 2f, 2f }, null });
sb.setLength(0);
- sar.appendFeature(sb, 1, minmax, sf);
+ sar.appendFeature(sb, 1, fr, sf);
assertEquals("METAL 1 3; Fe2-S", sb.toString());
}
assertEquals("METAL 1 3; Fe2-S", sb.toString());
}
+ /**
+ * A specific attribute value is included if it is used to colour the feature
+ */
@Test(groups = "Functional")
- public void testAppendFeature_clinicalSignificance()
+ public void testAppendFeature_colouredByAttribute()
{
SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
StringBuilder sb = new StringBuilder();
Float.NaN, "group");
sf.setValue("clinical_significance", "Benign");
- sar.appendFeature(sb, 1, null, sf);
- assertEquals("METAL 1 3; Fe2-S; Benign", sb.toString());
+ /*
+ * first with no colour by attribute
+ */
+ FeatureRendererModel fr = new FeatureRenderer(null);
+ sar.appendFeature(sb, 1, fr, sf);
+ assertEquals("METAL 1 3; Fe2-S", sb.toString());
+
+ /*
+ * then with colour by an attribute the feature lacks
+ */
+ FeatureColourI fc = new FeatureColour(Color.white, Color.black, 5, 10);
+ fc.setAttributeName("Pfam");
+ fr.setColour("METAL", fc);
+ sb.setLength(0);
+ sar.appendFeature(sb, 1, fr, sf);
+ assertEquals("METAL 1 3; Fe2-S", sb.toString()); // no change
+
+ /*
+ * then with colour by an attribute the feature has
+ */
+ fc.setAttributeName("clinical_significance");
+ sb.setLength(0);
+ sar.appendFeature(sb, 1, fr, sf);
+ assertEquals("METAL 1 3; Fe2-S; clinical_significance=Benign",
+ sb.toString());
}
@Test(groups = "Functional")
- public void testAppendFeature_withScoreStatusClinicalSignificance()
+ public void testAppendFeature_withScoreStatusAttribute()
{
SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
StringBuilder sb = new StringBuilder();
"group");
sf.setStatus("Confirmed");
sf.setValue("clinical_significance", "Benign");
- Map<String, float[][]> minmax = new Hashtable<String, float[][]>();
+
+ FeatureRendererModel fr = new FeatureRenderer(null);
+ Map<String, float[][]> minmax = fr.getMinMax();
+ FeatureColourI fc = new FeatureColour(Color.white, Color.blue, 12, 22);
+ fc.setAttributeName("clinical_significance");
+ fr.setColour("METAL", fc);
minmax.put("METAL", new float[][] { { 0f, 1f }, null });
- sar.appendFeature(sb, 1, minmax, sf);
+ sar.appendFeature(sb, 1, fr, sf);
- assertEquals("METAL 1 3; Fe2-S Score=1.3; (Confirmed); Benign",
+ assertEquals(
+ "METAL 1 3; Fe2-S Score=1.3; (Confirmed); clinical_significance=Benign",
sb.toString());
}
null));
sb.setLength(0);
sar.createSequenceAnnotationReport(sb, seq, true, true, null);
- String expected = "<i><br>SeqDesc<br>Type1 ; Nonpos</i>";
+ String expected = "<i><br>SeqDesc<br>Type1 ; Nonpos Score=1.0</i>";
assertEquals(expected, sb.toString());
/*
*/
seq.addSequenceFeature(new SequenceFeature("Metal", "Desc", 0, 0, 5f,
null));
- Map<String, float[][]> minmax = new HashMap<String, float[][]>();
+
+ FeatureRendererModel fr = new FeatureRenderer(null);
+ Map<String, float[][]> minmax = fr.getMinMax();
minmax.put("Metal", new float[][] { null, new float[] { 2f, 5f } });
+
sb.setLength(0);
- sar.createSequenceAnnotationReport(sb, seq, true, true, minmax);
+ sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
expected = "<i><br>SeqDesc<br>Metal ; Desc<br>Type1 ; Nonpos</i>";
assertEquals(expected, sb.toString());
sf.setValue("linkonly", Boolean.TRUE);
seq.addSequenceFeature(sf);
sb.setLength(0);
- sar.createSequenceAnnotationReport(sb, seq, true, true, minmax);
+ sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
assertEquals(expected, sb.toString()); // unchanged!
/*
- * 'clinical_significance' currently being specially included
+ * 'clinical_significance' attribute only included when
+ * used for feature colouring
*/
SequenceFeature sf2 = new SequenceFeature("Variant", "Havana", 0, 0,
5f, null);
sf2.setValue(GffConstants.CLINICAL_SIGNIFICANCE, "benign");
seq.addSequenceFeature(sf2);
sb.setLength(0);
- sar.createSequenceAnnotationReport(sb, seq, true, true, minmax);
- expected = "<i><br>SeqDesc<br>Metal ; Desc<br>Type1 ; Nonpos<br>Variant ; Havana; benign</i>";
+ sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
+ expected = "<i><br>SeqDesc<br>Metal ; Desc<br>Type1 ; Nonpos<br>Variant ; Havana</i>";
assertEquals(expected, sb.toString());
/*
*/
seq.addDBRef(new DBRefEntry("PDB", "0", "3iu1"));
seq.addDBRef(new DBRefEntry("Uniprot", "1", "P30419"));
+
// with showDbRefs = false
sb.setLength(0);
- sar.createSequenceAnnotationReport(sb, seq, false, true, minmax);
+ sar.createSequenceAnnotationReport(sb, seq, false, true, fr);
assertEquals(expected, sb.toString()); // unchanged
- // with showDbRefs = true
+
+ // with showDbRefs = true, colour Variant features by clinical_significance
sb.setLength(0);
- sar.createSequenceAnnotationReport(sb, seq, true, true, minmax);
- expected = "<i><br>SeqDesc<br>UNIPROT P30419<br>PDB 3iu1<br>Metal ; Desc<br>Type1 ; Nonpos<br>Variant ; Havana; benign</i>";
+ FeatureColourI fc = new FeatureColour(Color.green, Color.pink, 2, 3);
+ fc.setAttributeName("clinical_significance");
+ fr.setColour("Variant", fc);
+ sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
+ expected = "<i><br>SeqDesc<br>UNIPROT P30419<br>PDB 3iu1<br>Metal ; Desc<br>"
+ + "Type1 ; Nonpos<br>Variant ; Havana; clinical_significance=benign</i>";
assertEquals(expected, sb.toString());
// with showNonPositionalFeatures = false
sb.setLength(0);
- sar.createSequenceAnnotationReport(sb, seq, true, false, minmax);
+ sar.createSequenceAnnotationReport(sb, seq, true, false, fr);
expected = "<i><br>SeqDesc<br>UNIPROT P30419<br>PDB 3iu1</i>";
assertEquals(expected, sb.toString());
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
}
static String PfamFile = "examples/PF00111_seed.stk",
- RfamFile = "examples/RF00031_folded.stk";
+ RfamFile = "examples/RF00031_folded.stk",
+ RnaSSTestFile = "examples/rna_ss_test.stk";
@Test(groups = { "Functional" })
public void pfamFileIO() throws Exception
// we might want to revise this in future
int aa_new_size = (aa_new == null ? 0 : aa_new.length);
int aa_original_size = (aa_original == null ? 0 : aa_original.length);
- Map<Integer, BitSet> orig_groups = new HashMap<Integer, BitSet>();
- Map<Integer, BitSet> new_groups = new HashMap<Integer, BitSet>();
+ Map<Integer, BitSet> orig_groups = new HashMap<>();
+ Map<Integer, BitSet> new_groups = new HashMap<>();
if (aa_new != null && aa_original != null)
{
{
for (char ch : new char[] { '{', '}', '[', ']', '(', ')', '<', '>' })
{
- Assert.assertTrue(StockholmFile.DETECT_BRACKETS.matchAt("" + ch, 0),
- "Didn't recognise " + ch + " as a WUSS bracket");
+ Assert.assertTrue(StockholmFile.RNASS_BRACKETS.indexOf(ch) >= 0,
+ "Didn't recognise '" + ch + "' as a WUSS bracket");
}
- for (char ch : new char[] { '@', '!', 'V', 'Q', '*', ' ', '-', '.' })
+ for (char ch : new char[] { '@', '!', '*', ' ', '-', '.' })
{
- Assert.assertFalse(StockholmFile.DETECT_BRACKETS.matchAt("" + ch, 0),
- "Shouldn't recognise " + ch + " as a WUSS bracket");
+ Assert.assertFalse(StockholmFile.RNASS_BRACKETS.indexOf(ch) >= 0,
+ "Shouldn't recognise '" + ch + "' as a WUSS bracket");
}
}
private static void roundTripSSForRNA(String aliFile, String annFile)
testAlignmentEquivalence(al, newAl, true, true, true);
}
+
+ // this is the single sequence alignment and the SS annotations equivalent to
+ // the ones in file RnaSSTestFile
+ String aliFileRnaSS = ">Test.sequence/1-14\n"
+ + "GUACAAAAAAAAAA";
+ String annFileRnaSSAlphaChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|(,(|E,E|H,H|B,B|h,h|e,e|b,b|(,(|E,E|),)|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+ String wrongAnnFileRnaSSAlphaChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|(,(|H,H|E,E|B,B|h,h|e,e|b,b|(,(|E,E|),)|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+ @Test(groups = { "Functional" })
+ public void stockholmFileRnaSSAlphaChars() throws Exception
+ {
+ AppletFormatAdapter af = new AppletFormatAdapter();
+ AlignmentI al = af.readFile(RnaSSTestFile, DataSourceType.FILE,
+ jalview.io.FileFormat.Stockholm);
+ Iterable<AlignmentAnnotation> aai = al.findAnnotations(null, null,
+ "Secondary Structure");
+ AlignmentAnnotation aa = aai.iterator().next();
+ Assert.assertTrue(aa.isRNA(),
+ "'" + RnaSSTestFile + "' not recognised as RNA SS");
+ Assert.assertTrue(aa.isValidStruc(),
+ "'" + RnaSSTestFile + "' not recognised as valid structure");
+ Annotation[] as = aa.annotations;
+ char[] As = new char[as.length];
+ for (int i = 0; i < as.length; i++)
+ {
+ As[i] = as[i].secondaryStructure;
+ }
+ char[] shouldBe = { '<', '(', 'E', 'H', 'B', 'h', 'e', 'b', '(', 'E',
+ ')', 'e', ')', '>' };
+ Assert.assertTrue(
+ Arrays.equals(As, shouldBe),
+ "Annotation is " + new String(As) + " but should be "
+ + new String(shouldBe));
+
+ // this should result in the same RNA SS Annotations
+ AlignmentI newAl = new AppletFormatAdapter().readFile(
+ aliFileRnaSS,
+ DataSourceType.PASTE, jalview.io.FileFormat.Fasta);
+ AnnotationFile aaf = new AnnotationFile();
+ aaf.readAnnotationFile(newAl, annFileRnaSSAlphaChars,
+ DataSourceType.PASTE);
+
+ Assert.assertTrue(
+ testRnaSSAnnotationsEquivalent(al.getAlignmentAnnotation()[0],
+ newAl.getAlignmentAnnotation()[0]),
+ "RNA SS Annotations SHOULD be pair-wise equivalent (but apparently aren't): \n"
+ + "RNA SS A 1:" + al.getAlignmentAnnotation()[0] + "\n"
+ + "RNA SS A 2:" + newAl.getAlignmentAnnotation()[0]);
+
+ // this should NOT result in the same RNA SS Annotations
+ newAl = new AppletFormatAdapter().readFile(
+ aliFileRnaSS, DataSourceType.PASTE,
+ jalview.io.FileFormat.Fasta);
+ aaf = new AnnotationFile();
+ aaf.readAnnotationFile(newAl, wrongAnnFileRnaSSAlphaChars,
+ DataSourceType.PASTE);
+
+ boolean mismatch = testRnaSSAnnotationsEquivalent(al.getAlignmentAnnotation()[0],
+ newAl.getAlignmentAnnotation()[0]);
+ Assert.assertFalse(mismatch,
+ "RNA SS Annotations SHOULD NOT be pair-wise equivalent (but apparently are): \n"
+ + "RNA SS A 1:" + al.getAlignmentAnnotation()[0] + "\n"
+ + "RNA SS A 2:" + newAl.getAlignmentAnnotation()[0]);
+ }
+
+ private static boolean testRnaSSAnnotationsEquivalent(
+ AlignmentAnnotation a1,
+ AlignmentAnnotation a2)
+ {
+ return a1.rnaSecondaryStructureEquivalent(a2);
+ }
+
+ String annFileRnaSSWithSpaceChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|.,.|H,H| , |B,B|h,h| , |b,b|(,(|E,E|.,.|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+ String annFileRnaSSWithoutSpaceChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|.,.|H,H|.,.|B,B|h,h|.,.|b,b|(,(|E,E|.,.|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+
+ String wrongAnnFileRnaSSWithoutSpaceChars = "JALVIEW_ANNOTATION\n"
+ + "# Created: Thu Aug 02 14:54:57 BST 2018\n" + "\n"
+ + "NO_GRAPH\tSecondary Structure\tSecondary Structure\t<,<|.,.|H,H|Z,Z|B,B|h,h|z,z|b,b|(,(|E,E|.,.|e,e|),)|>,>|\t2.0\n"
+ + "\n"
+ + "ROWPROPERTIES\tSecondary Structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false\n"
+ + "\n" + "\n" + "ALIGNMENT\tID=RNA.SS.TEST\tTP=RNA;";
+
+ @Test(groups = { "Functional" })
+ public void stockholmFileRnaSSSpaceChars() throws Exception
+ {
+ AlignmentI alWithSpaces = new AppletFormatAdapter().readFile(
+ aliFileRnaSS, DataSourceType.PASTE,
+ jalview.io.FileFormat.Fasta);
+ AnnotationFile afWithSpaces = new AnnotationFile();
+ afWithSpaces.readAnnotationFile(alWithSpaces,
+ annFileRnaSSWithSpaceChars, DataSourceType.PASTE);
+
+ Iterable<AlignmentAnnotation> aaiWithSpaces = alWithSpaces
+ .findAnnotations(null, null, "Secondary Structure");
+ AlignmentAnnotation aaWithSpaces = aaiWithSpaces.iterator().next();
+ Assert.assertTrue(aaWithSpaces.isRNA(),
+ "'" + aaWithSpaces + "' not recognised as RNA SS");
+ Assert.assertTrue(aaWithSpaces.isValidStruc(),
+ "'" + aaWithSpaces + "' not recognised as valid structure");
+ Annotation[] annWithSpaces = aaWithSpaces.annotations;
+ char[] As = new char[annWithSpaces.length];
+ for (int i = 0; i < annWithSpaces.length; i++)
+ {
+ As[i] = annWithSpaces[i].secondaryStructure;
+ }
+ // check all spaces and dots are spaces in the internal representation
+ char[] shouldBe = { '<', ' ', 'H', ' ', 'B', 'h', ' ', 'b', '(', 'E',
+ ' ', 'e', ')', '>' };
+ Assert.assertTrue(Arrays.equals(As, shouldBe), "Annotation is "
+ + new String(As) + " but should be " + new String(shouldBe));
+
+ // this should result in the same RNA SS Annotations
+ AlignmentI alWithoutSpaces = new AppletFormatAdapter().readFile(
+ aliFileRnaSS, DataSourceType.PASTE,
+ jalview.io.FileFormat.Fasta);
+ AnnotationFile afWithoutSpaces = new AnnotationFile();
+ afWithoutSpaces.readAnnotationFile(alWithoutSpaces,
+ annFileRnaSSWithoutSpaceChars,
+ DataSourceType.PASTE);
+
+ Assert.assertTrue(
+ testRnaSSAnnotationsEquivalent(
+ alWithSpaces.getAlignmentAnnotation()[0],
+ alWithoutSpaces.getAlignmentAnnotation()[0]),
+ "RNA SS Annotations SHOULD be pair-wise equivalent (but apparently aren't): \n"
+ + "RNA SS A 1:"
+ + alWithSpaces.getAlignmentAnnotation()[0]
+ .getRnaSecondaryStructure()
+ + "\n" + "RNA SS A 2:"
+ + alWithoutSpaces.getAlignmentAnnotation()[0]
+ .getRnaSecondaryStructure());
+
+ // this should NOT result in the same RNA SS Annotations
+ AlignmentI wrongAlWithoutSpaces = new AppletFormatAdapter().readFile(
+ aliFileRnaSS, DataSourceType.PASTE,
+ jalview.io.FileFormat.Fasta);
+ AnnotationFile wrongAfWithoutSpaces = new AnnotationFile();
+ wrongAfWithoutSpaces.readAnnotationFile(wrongAlWithoutSpaces,
+ wrongAnnFileRnaSSWithoutSpaceChars,
+ DataSourceType.PASTE);
+
+ Assert.assertFalse(
+ testRnaSSAnnotationsEquivalent(
+ alWithSpaces.getAlignmentAnnotation()[0],
+ wrongAlWithoutSpaces.getAlignmentAnnotation()[0]),
+ "RNA SS Annotations SHOULD NOT be pair-wise equivalent (but apparently are): \n"
+ + "RNA SS A 1:"
+ + alWithSpaces.getAlignmentAnnotation()[0]
+ .getRnaSecondaryStructure()
+ + "\n" + "RNA SS A 2:"
+ + wrongAlWithoutSpaces.getAlignmentAnnotation()[0]
+ .getRnaSecondaryStructure());
+
+ // check no spaces in the output
+ // TODO: create a better 'save as <format>' pattern
+ alWithSpaces.getAlignmentAnnotation()[0].visible = true;
+ StockholmFile sf = new StockholmFile(alWithSpaces);
+
+ String stockholmFile = sf.print(alWithSpaces.getSequencesArray(), true);
+ Pattern noSpacesInRnaSSAnnotation = Pattern
+ .compile("\\n#=GC SS_cons\\s+\\S{14}\\n");
+ Matcher m = noSpacesInRnaSSAnnotation.matcher(stockholmFile);
+ boolean matches = m.find();
+ Assert.assertTrue(matches,
+ "StockholmFile output does not contain expected output (may contain spaces):\n"
+ + stockholmFile);
+
+ }
}
cacheBox.updateCache();
try
{
- // This 1ms delay is essential to prevent the
- // assertion below from executing before
- // cacheBox.updateCache() finishes updating the cache
- Thread.sleep(100);
+ // This delay is to let
+ // cacheBox.updateCache() finish updating the cache
+ Thread.sleep(200);
} catch (InterruptedException e)
{
e.printStackTrace();
--- /dev/null
+package jalview.io.gff;
+
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import org.testng.annotations.Test;
+
+public class SequenceOntologyLiteTest
+{
+ @Test(groups = "Functional")
+ public void testIsA_sequenceVariant()
+ {
+ SequenceOntologyI so = new SequenceOntologyLite();
+
+ assertFalse(so.isA("CDS", "sequence_variant"));
+ assertTrue(so.isA("sequence_variant", "sequence_variant"));
+
+ /*
+ * these should all be sub-types of sequence_variant
+ */
+ assertTrue(so.isA("structural_variant", "sequence_variant"));
+ assertTrue(so.isA("feature_variant", "sequence_variant"));
+ assertTrue(so.isA("gene_variant", "sequence_variant"));
+ assertTrue(so.isA("transcript_variant", "sequence_variant"));
+ assertTrue(so.isA("NMD_transcript_variant", "sequence_variant"));
+ assertTrue(so.isA("missense_variant", "sequence_variant"));
+ assertTrue(so.isA("synonymous_variant", "sequence_variant"));
+ assertTrue(so.isA("frameshift_variant", "sequence_variant"));
+ assertTrue(so.isA("5_prime_UTR_variant", "sequence_variant"));
+ assertTrue(so.isA("3_prime_UTR_variant", "sequence_variant"));
+ assertTrue(so.isA("stop_gained", "sequence_variant"));
+ assertTrue(so.isA("stop_lost", "sequence_variant"));
+ assertTrue(so.isA("inframe_deletion", "sequence_variant"));
+ assertTrue(so.isA("inframe_insertion", "sequence_variant"));
+ assertTrue(so.isA("splice_region_variant", "sequence_variant"));
+ }
+}
--- /dev/null
+package jalview.io.vcf;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.SequenceFeatures;
+import jalview.gui.AlignFrame;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.io.gff.Gff3Helper;
+import jalview.io.gff.SequenceOntologyI;
+import jalview.util.MapList;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class VCFLoaderTest
+{
+ private static final float DELTA = 0.00001f;
+
+ // columns 9717- of gene P30419 from Ensembl (much modified)
+ private static final String FASTA = ""
+ +
+ /*
+ * forward strand 'gene' and 'transcript' with two exons
+ */
+ ">gene1/1-25 chromosome:GRCh38:17:45051610:45051634:1\n"
+ + "CAAGCTGGCGGACGAGAGTGTGACA\n"
+ + ">transcript1/1-18\n--AGCTGGCG----AGAGTGTGAC-\n"
+
+ /*
+ * reverse strand gene and transcript (reverse complement alleles!)
+ */
+ + ">gene2/1-25 chromosome:GRCh38:17:45051610:45051634:-1\n"
+ + "TGTCACACTCTCGTCCGCCAGCTTG\n"
+ + ">transcript2/1-18\n" + "-GTCACACTCT----CGCCAGCT--\n"
+
+ /*
+ * 'gene' on chromosome 5 with two transcripts
+ */
+ + ">gene3/1-25 chromosome:GRCh38:5:45051610:45051634:1\n"
+ + "CAAGCTGGCGGACGAGAGTGTGACA\n"
+ + ">transcript3/1-18\n--AGCTGGCG----AGAGTGTGAC-\n"
+ + ">transcript4/1-18\n-----TGG-GGACGAGAGTGTGA-A\n";
+
+ private static final String[] VCF = { "##fileformat=VCFv4.2",
+ "##INFO=<ID=AF,Number=A,Type=Float,Description=\"Allele Frequency, for each ALT allele, in the same order as listed\">",
+ "##reference=Homo_sapiens/GRCh38",
+ "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO",
+ // A/T,C variants in position 2 of gene sequence (precedes transcript)
+ // should create 2 variant features with respective scores
+ "17\t45051611\t.\tA\tT,C\t1666.64\tRF\tAC=15;AF=5.0e-03,4.0e-03",
+ // SNP G/C in position 4 of gene sequence, position 2 of transcript
+ // insertion G/GA is transferred to nucleotide but not to peptide
+ "17\t45051613\t.\tG\tGA,C\t1666.64\tRF\tAC=15;AF=3.0e-03,2.0e-03" };
+
+ @BeforeClass
+ public void setUp()
+ {
+ /*
+ * configure to capture all available VCF and VEP (CSQ) fields
+ */
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ Cache.setProperty("VCF_FIELDS", ".*");
+ Cache.setProperty("VEP_FIELDS", ".*");
+ Cache.initLogger();
+ }
+
+ @Test(groups = "Functional")
+ public void testDoLoad() throws IOException
+ {
+ AlignmentI al = buildAlignment();
+
+ File f = makeVcf();
+ VCFLoader loader = new VCFLoader(f.getPath());
+
+ loader.doLoad(al.getSequencesArray(), null);
+
+ /*
+ * verify variant feature(s) added to gene
+ * NB alleles at a locus may not be processed, and features added,
+ * in the order in which they appear in the VCF record as method
+ * VariantContext.getAlternateAlleles() does not guarantee order
+ * - order of assertions here matches what we find (is not important)
+ */
+ List<SequenceFeature> geneFeatures = al.getSequenceAt(0)
+ .getSequenceFeatures();
+ SequenceFeatures.sortFeatures(geneFeatures, true);
+ assertEquals(geneFeatures.size(), 4);
+ SequenceFeature sf = geneFeatures.get(0);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 2);
+ assertEquals(sf.getEnd(), 2);
+ assertEquals(sf.getScore(), 4.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "A,C");
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ sf = geneFeatures.get(1);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 2);
+ assertEquals(sf.getEnd(), 2);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 5.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "A,T");
+
+ sf = geneFeatures.get(2);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 4);
+ assertEquals(sf.getEnd(), 4);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 2.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,C");
+
+ sf = geneFeatures.get(3);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 4);
+ assertEquals(sf.getEnd(), 4);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 3.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,GA");
+
+ /*
+ * verify variant feature(s) added to transcript
+ */
+ List<SequenceFeature> transcriptFeatures = al.getSequenceAt(1)
+ .getSequenceFeatures();
+ assertEquals(transcriptFeatures.size(), 2);
+ sf = transcriptFeatures.get(0);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 2);
+ assertEquals(sf.getEnd(), 2);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 2.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,C");
+ sf = transcriptFeatures.get(1);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 2);
+ assertEquals(sf.getEnd(), 2);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 3.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,GA");
+
+ /*
+ * verify SNP variant feature(s) computed and added to protein
+ * first codon AGC varies to ACC giving S/T
+ */
+ DBRefEntry[] dbRefs = al.getSequenceAt(1).getDBRefs();
+ SequenceI peptide = null;
+ for (DBRefEntry dbref : dbRefs)
+ {
+ if (dbref.getMap().getMap().getFromRatio() == 3)
+ {
+ peptide = dbref.getMap().getTo();
+ }
+ }
+ List<SequenceFeature> proteinFeatures = peptide.getSequenceFeatures();
+ assertEquals(proteinFeatures.size(), 1);
+ sf = proteinFeatures.get(0);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 1);
+ assertEquals(sf.getEnd(), 1);
+ assertEquals(sf.getType(), SequenceOntologyI.NONSYNONYMOUS_VARIANT);
+ assertEquals(sf.getDescription(), "p.Ser1Thr");
+ }
+
+ private File makeVcf() throws IOException
+ {
+ File f = File.createTempFile("Test", ".vcf");
+ f.deleteOnExit();
+ PrintWriter pw = new PrintWriter(f);
+ for (String vcfLine : VCF)
+ {
+ pw.println(vcfLine);
+ }
+ pw.close();
+ return f;
+ }
+
+ /**
+ * Make a simple alignment with one 'gene' and one 'transcript'
+ *
+ * @return
+ */
+ private AlignmentI buildAlignment()
+ {
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(FASTA,
+ DataSourceType.PASTE);
+
+ /*
+ * map gene1 sequence to chromosome (normally done when the sequence is fetched
+ * from Ensembl and transcripts computed)
+ */
+ AlignmentI alignment = af.getViewport().getAlignment();
+ SequenceI gene1 = alignment.findName("gene1");
+ int[] to = new int[] { 45051610, 45051634 };
+ int[] from = new int[] { gene1.getStart(), gene1.getEnd() };
+ gene1.setGeneLoci("homo_sapiens", "GRCh38", "17", new MapList(from, to,
+ 1, 1));
+
+ /*
+ * map 'transcript1' to chromosome via 'gene1'
+ * transcript1/1-18 is gene1/3-10,15-24
+ * which is chromosome 45051612-45051619,45051624-45051633
+ */
+ to = new int[] { 45051612, 45051619, 45051624, 45051633 };
+ SequenceI transcript1 = alignment.findName("transcript1");
+ from = new int[] { transcript1.getStart(), transcript1.getEnd() };
+ transcript1.setGeneLoci("homo_sapiens", "GRCh38", "17", new MapList(
+ from, to,
+ 1, 1));
+
+ /*
+ * map gene2 to chromosome reverse strand
+ */
+ SequenceI gene2 = alignment.findName("gene2");
+ to = new int[] { 45051634, 45051610 };
+ from = new int[] { gene2.getStart(), gene2.getEnd() };
+ gene2.setGeneLoci("homo_sapiens", "GRCh38", "17", new MapList(from, to,
+ 1, 1));
+
+ /*
+ * map 'transcript2' to chromosome via 'gene2'
+ * transcript2/1-18 is gene2/2-11,16-23
+ * which is chromosome 45051633-45051624,45051619-45051612
+ */
+ to = new int[] { 45051633, 45051624, 45051619, 45051612 };
+ SequenceI transcript2 = alignment.findName("transcript2");
+ from = new int[] { transcript2.getStart(), transcript2.getEnd() };
+ transcript2.setGeneLoci("homo_sapiens", "GRCh38", "17", new MapList(
+ from, to,
+ 1, 1));
+
+ /*
+ * add a protein product as a DBRef on transcript1
+ */
+ SequenceI peptide1 = new Sequence("ENSP001", "SWRECD");
+ MapList mapList = new MapList(new int[] { 1, 18 }, new int[] { 1, 6 },
+ 3, 1);
+ Mapping map = new Mapping(peptide1, mapList);
+ DBRefEntry product = new DBRefEntry("", "", "ENSP001", map);
+ transcript1.addDBRef(product);
+
+ /*
+ * add a protein product as a DBRef on transcript2
+ */
+ SequenceI peptide2 = new Sequence("ENSP002", "VTLSPA");
+ mapList = new MapList(new int[] { 1, 18 }, new int[] { 1, 6 }, 3, 1);
+ map = new Mapping(peptide2, mapList);
+ product = new DBRefEntry("", "", "ENSP002", map);
+ transcript2.addDBRef(product);
+
+ /*
+ * map gene3 to chromosome
+ */
+ SequenceI gene3 = alignment.findName("gene3");
+ to = new int[] { 45051610, 45051634 };
+ from = new int[] { gene3.getStart(), gene3.getEnd() };
+ gene3.setGeneLoci("homo_sapiens", "GRCh38", "5", new MapList(from, to,
+ 1, 1));
+
+ /*
+ * map 'transcript3' to chromosome
+ */
+ SequenceI transcript3 = alignment.findName("transcript3");
+ to = new int[] { 45051612, 45051619, 45051624, 45051633 };
+ from = new int[] { transcript3.getStart(), transcript3.getEnd() };
+ transcript3.setGeneLoci("homo_sapiens", "GRCh38", "5", new MapList(
+ from, to,
+ 1, 1));
+
+ /*
+ * map 'transcript4' to chromosome
+ */
+ SequenceI transcript4 = alignment.findName("transcript4");
+ to = new int[] { 45051615, 45051617, 45051619, 45051632, 45051634,
+ 45051634 };
+ from = new int[] { transcript4.getStart(), transcript4.getEnd() };
+ transcript4.setGeneLoci("homo_sapiens", "GRCh38", "5", new MapList(
+ from, to,
+ 1, 1));
+
+ /*
+ * add a protein product as a DBRef on transcript3
+ */
+ SequenceI peptide3 = new Sequence("ENSP003", "SWRECD");
+ mapList = new MapList(new int[] { 1, 18 }, new int[] { 1, 6 }, 3, 1);
+ map = new Mapping(peptide3, mapList);
+ product = new DBRefEntry("", "", "ENSP003", map);
+ transcript3.addDBRef(product);
+
+ return alignment;
+ }
+
+ /**
+ * Test with 'gene' and 'transcript' mapped to the reverse strand of the
+ * chromosome. The VCF variant positions (in forward coordinates) should get
+ * correctly located on sequence positions.
+ *
+ * @throws IOException
+ */
+ @Test(groups = "Functional")
+ public void testDoLoad_reverseStrand() throws IOException
+ {
+ AlignmentI al = buildAlignment();
+
+ File f = makeVcf();
+
+ VCFLoader loader = new VCFLoader(f.getPath());
+
+ loader.doLoad(al.getSequencesArray(), null);
+
+ /*
+ * verify variant feature(s) added to gene2
+ * gene2/1-25 maps to chromosome 45051634- reverse strand
+ */
+ List<SequenceFeature> geneFeatures = al.getSequenceAt(2)
+ .getSequenceFeatures();
+ SequenceFeatures.sortFeatures(geneFeatures, true);
+ assertEquals(geneFeatures.size(), 4);
+
+ /*
+ * variant A/T at 45051611 maps to T/A at gene position 24
+ */
+ SequenceFeature sf = geneFeatures.get(3);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 24);
+ assertEquals(sf.getEnd(), 24);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 5.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "T,A");
+
+ /*
+ * variant A/C at 45051611 maps to T/G at gene position 24
+ */
+ sf = geneFeatures.get(2);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 24);
+ assertEquals(sf.getEnd(), 24);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 4.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "T,G");
+
+ /*
+ * variant G/C at 45051613 maps to C/G at gene position 22
+ */
+ sf = geneFeatures.get(1);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 22);
+ assertEquals(sf.getEnd(), 22);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 2.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "C,G");
+
+ /*
+ * insertion G/GA at 45051613 maps to an insertion at
+ * the preceding position (21) on reverse strand gene
+ * reference: CAAGC -> GCTTG/21-25
+ * genomic variant: CAAGAC (G/GA)
+ * gene variant: GTCTTG (G/GT at 21)
+ */
+ sf = geneFeatures.get(0);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 21);
+ assertEquals(sf.getEnd(), 21);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 3.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,GT");
+
+ /*
+ * verify 2 variant features added to transcript2
+ */
+ List<SequenceFeature> transcriptFeatures = al.getSequenceAt(3)
+ .getSequenceFeatures();
+ assertEquals(transcriptFeatures.size(), 2);
+
+ /*
+ * insertion G/GT at position 21 of gene maps to position 16 of transcript
+ */
+ sf = transcriptFeatures.get(0);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 16);
+ assertEquals(sf.getEnd(), 16);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 3.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,GT");
+
+ /*
+ * SNP C/G at position 22 of gene maps to position 17 of transcript
+ */
+ sf = transcriptFeatures.get(1);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 17);
+ assertEquals(sf.getEnd(), 17);
+ assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
+ assertEquals(sf.getScore(), 2.0e-03, DELTA);
+ assertEquals(sf.getValue(Gff3Helper.ALLELES), "C,G");
+
+ /*
+ * verify variant feature(s) computed and added to protein
+ * last codon GCT varies to GGT giving A/G in the last peptide position
+ */
+ DBRefEntry[] dbRefs = al.getSequenceAt(3).getDBRefs();
+ SequenceI peptide = null;
+ for (DBRefEntry dbref : dbRefs)
+ {
+ if (dbref.getMap().getMap().getFromRatio() == 3)
+ {
+ peptide = dbref.getMap().getTo();
+ }
+ }
+ List<SequenceFeature> proteinFeatures = peptide.getSequenceFeatures();
+ assertEquals(proteinFeatures.size(), 1);
+ sf = proteinFeatures.get(0);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 6);
+ assertEquals(sf.getEnd(), 6);
+ assertEquals(sf.getType(), SequenceOntologyI.NONSYNONYMOUS_VARIANT);
+ assertEquals(sf.getDescription(), "p.Ala6Gly");
+ }
+
+ /**
+ * Tests that if VEP consequence (CSQ) data is present in the VCF data, then
+ * it is added to the variant feature, but restricted where possible to the
+ * consequences for a specific transcript
+ *
+ * @throws IOException
+ */
+ @Test(groups = "Functional")
+ public void testDoLoad_vepCsq() throws IOException
+ {
+ AlignmentI al = buildAlignment();
+
+ VCFLoader loader = new VCFLoader("test/jalview/io/vcf/testVcf.vcf");
+
+ /*
+ * VCF data file with variants at gene3 positions
+ * 1 C/A
+ * 5 C/T
+ * 9 CGT/C (deletion)
+ * 13 C/G, C/T
+ * 17 A/AC (insertion), A/G
+ */
+ loader.doLoad(al.getSequencesArray(), null);
+
+ /*
+ * verify variant feature(s) added to gene3
+ */
+ List<SequenceFeature> geneFeatures = al.findName("gene3")
+ .getSequenceFeatures();
+ SequenceFeatures.sortFeatures(geneFeatures, true);
+ assertEquals(geneFeatures.size(), 7);
+ SequenceFeature sf = geneFeatures.get(0);
+ assertEquals(sf.getBegin(), 1);
+ assertEquals(sf.getEnd(), 1);
+ assertEquals(sf.getScore(), 0.1f, DELTA);
+ assertEquals(sf.getValue("alleles"), "C,A");
+ // gene features include Consequence for all transcripts
+ Map map = (Map) sf.getValue("CSQ");
+ assertEquals(map.size(), 9);
+
+ sf = geneFeatures.get(1);
+ assertEquals(sf.getBegin(), 5);
+ assertEquals(sf.getEnd(), 5);
+ assertEquals(sf.getScore(), 0.2f, DELTA);
+ assertEquals(sf.getValue("alleles"), "C,T");
+ map = (Map) sf.getValue("CSQ");
+ assertEquals(map.size(), 9);
+
+ sf = geneFeatures.get(2);
+ assertEquals(sf.getBegin(), 9);
+ assertEquals(sf.getEnd(), 11); // deletion over 3 positions
+ assertEquals(sf.getScore(), 0.3f, DELTA);
+ assertEquals(sf.getValue("alleles"), "CGG,C");
+ map = (Map) sf.getValue("CSQ");
+ assertEquals(map.size(), 9);
+
+ sf = geneFeatures.get(3);
+ assertEquals(sf.getBegin(), 13);
+ assertEquals(sf.getEnd(), 13);
+ assertEquals(sf.getScore(), 0.5f, DELTA);
+ assertEquals(sf.getValue("alleles"), "C,T");
+ map = (Map) sf.getValue("CSQ");
+ assertEquals(map.size(), 9);
+
+ sf = geneFeatures.get(4);
+ assertEquals(sf.getBegin(), 13);
+ assertEquals(sf.getEnd(), 13);
+ assertEquals(sf.getScore(), 0.4f, DELTA);
+ assertEquals(sf.getValue("alleles"), "C,G");
+ map = (Map) sf.getValue("CSQ");
+ assertEquals(map.size(), 9);
+
+ sf = geneFeatures.get(5);
+ assertEquals(sf.getBegin(), 17);
+ assertEquals(sf.getEnd(), 17);
+ assertEquals(sf.getScore(), 0.7f, DELTA);
+ assertEquals(sf.getValue("alleles"), "A,G");
+ map = (Map) sf.getValue("CSQ");
+ assertEquals(map.size(), 9);
+
+ sf = geneFeatures.get(6);
+ assertEquals(sf.getBegin(), 17);
+ assertEquals(sf.getEnd(), 17); // insertion
+ assertEquals(sf.getScore(), 0.6f, DELTA);
+ assertEquals(sf.getValue("alleles"), "A,AC");
+ map = (Map) sf.getValue("CSQ");
+ assertEquals(map.size(), 9);
+
+ /*
+ * verify variant feature(s) added to transcript3
+ * at columns 5 (1), 17 (2), positions 3, 11
+ * note the deletion at columns 9-11 is not transferred since col 11
+ * has no mapping to transcript 3
+ */
+ List<SequenceFeature> transcriptFeatures = al.findName("transcript3")
+ .getSequenceFeatures();
+ SequenceFeatures.sortFeatures(transcriptFeatures, true);
+ assertEquals(transcriptFeatures.size(), 3);
+ sf = transcriptFeatures.get(0);
+ assertEquals(sf.getBegin(), 3);
+ assertEquals(sf.getEnd(), 3);
+ assertEquals(sf.getScore(), 0.2f, DELTA);
+ assertEquals(sf.getValue("alleles"), "C,T");
+ // transcript features only have Consequence for that transcripts
+ map = (Map) sf.getValue("CSQ");
+ assertEquals(map.size(), 9);
+ assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript3");
+
+ sf = transcriptFeatures.get(1);
+ assertEquals(sf.getBegin(), 11);
+ assertEquals(sf.getEnd(), 11);
+ assertEquals(sf.getScore(), 0.7f, DELTA);
+ assertEquals(sf.getValue("alleles"), "A,G");
+ assertEquals(map.size(), 9);
+ assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript3");
+
+ sf = transcriptFeatures.get(2);
+ assertEquals(sf.getBegin(), 11);
+ assertEquals(sf.getEnd(), 11);
+ assertEquals(sf.getScore(), 0.6f, DELTA);
+ assertEquals(sf.getValue("alleles"), "A,AC");
+ assertEquals(map.size(), 9);
+ assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript3");
+
+ /*
+ * verify variants computed on protein product for transcript3
+ * peptide is SWRECD
+ * codon variants are AGC/AGT position 1 which is synonymous
+ * and GAG/GGG which is E/G in position 4
+ * the insertion variant is not transferred to the peptide
+ */
+ DBRefEntry[] dbRefs = al.findName("transcript3").getDBRefs();
+ SequenceI peptide = null;
+ for (DBRefEntry dbref : dbRefs)
+ {
+ if (dbref.getMap().getMap().getFromRatio() == 3)
+ {
+ peptide = dbref.getMap().getTo();
+ }
+ }
+ List<SequenceFeature> proteinFeatures = peptide.getSequenceFeatures();
+ SequenceFeatures.sortFeatures(proteinFeatures, true);
+ assertEquals(proteinFeatures.size(), 2);
+ sf = proteinFeatures.get(0);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 1);
+ assertEquals(sf.getEnd(), 1);
+ assertEquals(sf.getType(), SequenceOntologyI.SYNONYMOUS_VARIANT);
+ assertEquals(sf.getDescription(), "agC/agT");
+ sf = proteinFeatures.get(1);
+ assertEquals(sf.getFeatureGroup(), "VCF");
+ assertEquals(sf.getBegin(), 4);
+ assertEquals(sf.getEnd(), 4);
+ assertEquals(sf.getType(), SequenceOntologyI.NONSYNONYMOUS_VARIANT);
+ assertEquals(sf.getDescription(), "p.Glu4Gly");
+
+ /*
+ * verify variant feature(s) added to transcript4
+ * at columns 13 (2) and 17 (2), positions 7 and 11
+ */
+ transcriptFeatures = al.findName("transcript4").getSequenceFeatures();
+ SequenceFeatures.sortFeatures(transcriptFeatures, true);
+ assertEquals(transcriptFeatures.size(), 4);
+ sf = transcriptFeatures.get(0);
+ assertEquals(sf.getBegin(), 7);
+ assertEquals(sf.getEnd(), 7);
+ assertEquals(sf.getScore(), 0.5f, DELTA);
+ assertEquals(sf.getValue("alleles"), "C,T");
+ assertEquals(map.size(), 9);
+ assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript4");
+
+ sf = transcriptFeatures.get(1);
+ assertEquals(sf.getBegin(), 7);
+ assertEquals(sf.getEnd(), 7);
+ assertEquals(sf.getScore(), 0.4f, DELTA);
+ assertEquals(sf.getValue("alleles"), "C,G");
+ assertEquals(map.size(), 9);
+ assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript4");
+
+ sf = transcriptFeatures.get(2);
+ assertEquals(sf.getBegin(), 11);
+ assertEquals(sf.getEnd(), 11);
+ assertEquals(sf.getScore(), 0.7f, DELTA);
+ assertEquals(sf.getValue("alleles"), "A,G");
+ assertEquals(map.size(), 9);
+ assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript4");
+
+ sf = transcriptFeatures.get(3);
+ assertEquals(sf.getBegin(), 11);
+ assertEquals(sf.getEnd(), 11);
+ assertEquals(sf.getScore(), 0.6f, DELTA);
+ assertEquals(sf.getValue("alleles"), "A,AC");
+ assertEquals(map.size(), 9);
+ assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript4");
+ }
+
+ /**
+ * A test that demonstrates loading a contig sequence from an indexed sequence
+ * database which is the reference for a VCF file
+ *
+ * @throws IOException
+ */
+ @Test(groups = "Functional")
+ public void testLoadVCFContig() throws IOException
+ {
+ VCFLoader loader = new VCFLoader(
+ "test/jalview/io/vcf/testVcf2.vcf");
+
+ SequenceI seq = loader.loadVCFContig("contig123");
+ assertEquals(seq.getLength(), 15);
+ assertEquals(seq.getSequenceAsString(), "AAAAACCCCCGGGGG");
+ List<SequenceFeature> features = seq.getSequenceFeatures();
+ SequenceFeatures.sortFeatures(features, true);
+ assertEquals(features.size(), 2);
+ SequenceFeature sf = features.get(0);
+ assertEquals(sf.getBegin(), 8);
+ assertEquals(sf.getEnd(), 8);
+ assertEquals(sf.getDescription(), "C,A");
+ sf = features.get(1);
+ assertEquals(sf.getBegin(), 12);
+ assertEquals(sf.getEnd(), 12);
+ assertEquals(sf.getDescription(), "G,T");
+
+ seq = loader.loadVCFContig("contig789");
+ assertEquals(seq.getLength(), 25);
+ assertEquals(seq.getSequenceAsString(), "GGGGGTTTTTAAAAACCCCCGGGGG");
+ features = seq.getSequenceFeatures();
+ SequenceFeatures.sortFeatures(features, true);
+ assertEquals(features.size(), 2);
+ sf = features.get(0);
+ assertEquals(sf.getBegin(), 2);
+ assertEquals(sf.getEnd(), 2);
+ assertEquals(sf.getDescription(), "G,T");
+ sf = features.get(1);
+ assertEquals(sf.getBegin(), 21);
+ assertEquals(sf.getEnd(), 21);
+ assertEquals(sf.getDescription(), "G,A");
+
+ seq = loader.loadVCFContig("contig456");
+ assertEquals(seq.getLength(), 20);
+ assertEquals(seq.getSequenceAsString(), "CCCCCGGGGGTTTTTAAAAA");
+ features = seq.getSequenceFeatures();
+ SequenceFeatures.sortFeatures(features, true);
+ assertEquals(features.size(), 1);
+ sf = features.get(0);
+ assertEquals(sf.getBegin(), 15);
+ assertEquals(sf.getEnd(), 15);
+ assertEquals(sf.getDescription(), "T,C");
+ }
+}
\ No newline at end of file
--- /dev/null
+>contig123
+AAAAACCCCCGGGGG
+>contig456
+CCCCCGGGGGTTTTTAAAAA
+>contig789
+GGGGGTTTTTAAAAACCCCCGGGGG
--- /dev/null
+contig123 15 11 15 16
+contig456 20 38 20 21
+contig789 25 70 25 26
--- /dev/null
+##fileformat=VCFv4.2
+##INFO=<ID=AC,Number=A,Type=Integer,Description="Allele count in genotypes, for each ALT allele, in the same order as listed">
+##INFO=<ID=AF,Number=A,Type=Float,Description="Allele Frequency, for each ALT allele, in the same order as listed">
+##INFO=<ID=AF_Female,Number=R,Type=Float,Description="Allele Frequency among Female genotypes, for each ALT allele, in the same order as listed">
+##INFO=<ID=AN,Number=1,Type=Integer,Description="Total number of alleles in called genotypes">
+##INFO=<ID=CSQ,Number=.,Type=String,Description="Consequence annotations from Ensembl VEP. Format: Allele|Consequence|IMPACT|SYMBOL|Gene|Feature_type|Feature|BIOTYPE|PolyPhen">
+##reference=/Homo_sapiens/GRCh38
+#CHROM POS ID REF ALT QUAL FILTER INFO
+5 45051610 . C A 81.96 RF;AC0 AC=1;AF=0.1;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=A|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,A|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
+5 45051614 . C T 1666.64 RF AC=1;AF=0.2;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=T|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,T|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
+5 45051618 . CGG C 41.94 AC0 AC=1;AF=0.3;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=C|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,C|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad,CSQ=CGT|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,CGT|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
+5 45051622 . C G,T 224.23 RF;AC0 AC=1,2;AF=0.4,0.5;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=G|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,G|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad,T|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,T|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
+5 45051626 . A AC,G 433.35 RF;AC0 AC=3,4;AF=0.6,0.7;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=G|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,G|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad,AC|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,AC|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
--- /dev/null
+##fileformat=VCFv4.2
+##INFO=<ID=AC,Number=A,Type=Integer,Description="Allele count in genotypes, for each ALT allele, in the same order as listed">
+##INFO=<ID=AF,Number=A,Type=Float,Description="Allele Frequency, for each ALT allele, in the same order as listed">
+##INFO=<ID=AF_Female,Number=R,Type=Float,Description="Allele Frequency among Female genotypes, for each ALT allele, in the same order as listed">
+##INFO=<ID=AN,Number=1,Type=Integer,Description="Total number of alleles in called genotypes">
+##INFO=<ID=CSQ,Number=.,Type=String,Description="Consequence annotations from Ensembl VEP. Format: Allele|Consequence|IMPACT|SYMBOL|Gene|Feature_type|Feature|BIOTYPE|PolyPhen">
+##reference=/Homo_sapiens/GRCh38
+#CHROM POS ID REF ALT QUAL FILTER INFO
+5 45051610 . C A 81.96 RF;AC0 AC=1;AF=0.1;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=A|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,A|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
+5 45051614 . C T 1666.64 RF AC=1;AF=0.2;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=T|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,T|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
+5 45051618 . CGG C 41.94 AC0 AC=1;AF=0.3;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=C|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,C|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad,CSQ=CGT|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,CGT|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
+5 45051622 . C G,T 224.23 RF;AC0 AC=1,2;AF=0.4,0.5;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=G|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,G|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad,T|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,T|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
+5 45051626 . A AC,G 433.35 RF;AC0 AC=3,4;AF=0.6,0.7;AN=0;AF_Female=2;AB_MEDIAN=6.00000e-01;CSQ=G|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,G|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad,AC|missense_variant|MODIFIER|WASH7P|gene3|Transcript|transcript3|rna|Benign,AC|downstream_gene_variant|MODIFIER|WASH7P|gene3|Transcript|transcript4|mrna|Bad
--- /dev/null
+##fileformat=VCFv4.2
+##INFO=<ID=AC,Number=A,Type=Integer,Description="Allele count in genotypes, for each ALT allele, in the same order as listed">
+##contig=<ID=contig123,length=15>
+##contig=<ID=contig456,length=20>
+##contig=<ID=contig789,length=25>
+##INFO=<ID=AF,Number=A,Type=Float,Description="Allele Frequency, for each ALT allele, in the same order as listed">
+##reference=test/jalview/io/vcf/contigs.fasta
+#CHROM POS ID REF ALT QUAL FILTER INFO
+contig123 8 . C A 81.96 . AC=1;AF=0.1
+contig123 12 . G T 1666.64 . AC=1;AF=0.2
+contig456 15 . T C 41.94 . AC=1;AF=0.3
+contig789 2 . G T 224.23 . AC=1,2;AF=0
+contig789 21 . G A 433.35 . AC=3;AF=0.6
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.renderer;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignViewport;
+import jalview.renderer.seqfeatures.FeatureRenderer;
+import jalview.schemes.FeatureColour;
+import jalview.schemes.ZappoColourScheme;
+import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.OverviewDimensions;
+import jalview.viewmodel.OverviewDimensionsShowHidden;
+import jalview.viewmodel.ViewportRanges;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+public class OverviewRendererTest
+{
+
+ @Test
+ public void testGetColumnColourFromSequence()
+ {
+ OverviewResColourFinder cf = new OverviewResColourFinder(false,
+ Color.PINK, Color.green); // gapColour, hiddenColour
+ Sequence seq1 = new Sequence("seq1", "PQ-RL-");
+ Sequence seq2 = new Sequence("seq2", "FVE");
+ AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+ AlignmentViewport av = new AlignViewport(al);
+ OverviewDimensions od = new OverviewDimensionsShowHidden(new ViewportRanges(al), false);
+ ResidueShaderI rs = new ResidueShader(new ZappoColourScheme());
+ FeatureRenderer fr = new FeatureRenderer(av);
+ OverviewRenderer or = new OverviewRenderer(fr, od, al, rs, cf);
+
+ // P is magenta (see ResidueProperties.zappo)
+ assertEquals(or.getColumnColourFromSequence(null, seq1, 0), Color.magenta.getRGB());
+ // Q is green
+ assertEquals(or.getColumnColourFromSequence(null, seq1, 1),
+ Color.green.getRGB());
+ // gap is pink (specified in OverviewResColourFinder constructor above)
+ assertEquals(or.getColumnColourFromSequence(null, seq1, 2),
+ Color.pink.getRGB());
+ // F is orange
+ assertEquals(or.getColumnColourFromSequence(null, seq2, 0),
+ Color.orange.getRGB());
+ // E is red
+ assertEquals(or.getColumnColourFromSequence(null, seq2, 2),
+ Color.red.getRGB());
+ // past end of sequence colour as gap (JAL-2929)
+ assertEquals(or.getColumnColourFromSequence(null, seq2, 3),
+ Color.pink.getRGB());
+
+ /*
+ * now add a feature on seq1
+ */
+ seq1.addSequenceFeature(
+ new SequenceFeature("Pfam", "desc", 1, 4, null));
+ fr.findAllFeatures(true);
+ av.setShowSequenceFeatures(true);
+ fr.setColour("Pfam", new FeatureColour(Color.yellow));
+ assertEquals(or.getColumnColourFromSequence(null, seq1, 0),
+ Color.yellow.getRGB());
+
+ // don't show sequence features
+ av.setShowSequenceFeatures(false);
+ assertEquals(or.getColumnColourFromSequence(null, seq1, 0),
+ Color.magenta.getRGB());
+ }
+}
import jalview.io.DataSourceType;
import jalview.io.FileLoader;
import jalview.schemes.FeatureColour;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
import java.awt.Color;
import java.util.List;
* - currently no way other than mimicking reordering of
* table in Feature Settings
*/
- Object[][] data = new Object[2][];
- data[0] = new Object[] { "Metal", red, true };
- data[1] = new Object[] { "Domain", green, true };
+ FeatureSettingsBean[] data = new FeatureSettingsBean[2];
+ data[0] = new FeatureSettingsBean("Metal", red, null, true);
+ data[1] = new FeatureSettingsBean("Domain", green, null, true);
fr.setFeaturePriority(data);
c = finder.findFeatureColour(Color.blue, seq, 10);
assertEquals(c, Color.red);
/*
* ..and turn off display of Metal
*/
- data[0][2] = false;
+ data[0] = new FeatureSettingsBean("Metal", red, null, false);
fr.setFeaturePriority(data);
c = finder.findFeatureColour(Color.blue, seq, 10);
assertEquals(c, Color.green);
/*
* turn off display of Metal - is this the easiest way to do it??
*/
- Object[][] data = new Object[1][];
- data[0] = new Object[] { "Metal", red, false };
+ FeatureSettingsBean[] data = new FeatureSettingsBean[1];
+ data[0] = new FeatureSettingsBean("Metal", red, null, false);
fr.setFeaturePriority(data);
c = finder.findFeatureColour(Color.blue, seq, 10);
assertEquals(c, Color.blue);
/*
* turn display of Metal back on
*/
- data[0] = new Object[] { "Metal", red, true };
+ data[0] = new FeatureSettingsBean("Metal", red, null, true);
fr.setFeaturePriority(data);
c = finder.findFeatureColour(Color.blue, seq, 10);
assertEquals(c, Color.red);
* 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
* 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
*/
- Object[][] data = new Object[2][];
- data[0] = new Object[] { "Metal", red, true };
- data[1] = new Object[] { "Domain", green, true };
+ FeatureSettingsBean[] data = new FeatureSettingsBean[2];
+ data[0] = new FeatureSettingsBean("Metal", red, null, true);
+ data[1] = new FeatureSettingsBean("Domain", green, null, true);
fr.setFeaturePriority(data);
c = finder.findFeatureColour(Color.cyan, seq, 10);
assertEquals(c, new Color(153, 102, 41));
* Domain (green) above background (pink)
* 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
*/
- data[0][2] = false;
+ data[0] = new FeatureSettingsBean("Metal", red, null, false);
fr.setFeaturePriority(data);
c = finder.findFeatureColour(Color.pink, seq, 10);
assertEquals(c, new Color(102, 223, 70));
/*
* turn off display of Metal
*/
- Object[][] data = new Object[1][];
- data[0] = new Object[] { "Metal", red, false };
+ FeatureSettingsBean[] data = new FeatureSettingsBean[1];
+ data[0] = new FeatureSettingsBean("Metal", red, null, false);
fr.setFeaturePriority(data);
assertTrue(finder.noFeaturesDisplayed());
/*
* render order is kd above Metal
*/
- Object[][] data = new Object[2][];
- data[0] = new Object[] { kdFeature, fc, true };
- data[1] = new Object[] { metalFeature, green, true };
+ FeatureSettingsBean[] data = new FeatureSettingsBean[2];
+ data[0] = new FeatureSettingsBean(kdFeature, fc, null, true);
+ data[1] = new FeatureSettingsBean(metalFeature, green, null, true);
fr.setFeaturePriority(data);
av.setShowSequenceFeatures(true);
+/*
+ * 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.seqfeatures;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import jalview.api.AlignViewportI;
import jalview.api.FeatureColourI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.gui.AlignFrame;
import jalview.io.DataSourceType;
import jalview.io.FileLoader;
import jalview.schemes.FeatureColour;
+import jalview.util.matcher.Condition;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
seqs.get(2).addSequenceFeature(
new SequenceFeature("Pfam", "Desc", 14, 22, 2f, "RfamGroup"));
// bug in findAllFeatures - group not checked for a known feature type
- seqs.get(2).addSequenceFeature(
- new SequenceFeature("Rfam", "Desc", 5, 9, Float.NaN,
- "RfamGroup"));
+ seqs.get(2).addSequenceFeature(new SequenceFeature("Rfam", "Desc", 5, 9,
+ Float.NaN, "RfamGroup"));
// existing feature type with null group
seqs.get(3).addSequenceFeature(
new SequenceFeature("Rfam", "Desc", 5, 9, Float.NaN, null));
* change render order (todo: an easier way)
* nb here last comes first in the data array
*/
- Object[][] data = new Object[3][];
+ FeatureSettingsBean[] data = new FeatureSettingsBean[3];
FeatureColourI colour = new FeatureColour(Color.RED);
- data[0] = new Object[] { "Rfam", colour, true };
- data[1] = new Object[] { "Pfam", colour, false };
- data[2] = new Object[] { "Scop", colour, false };
+ data[0] = new FeatureSettingsBean("Rfam", colour, null, true);
+ data[1] = new FeatureSettingsBean("Pfam", colour, null, false);
+ data[2] = new FeatureSettingsBean("Scop", colour, null, false);
fr.setFeaturePriority(data);
- assertEquals(fr.getRenderOrder(), Arrays.asList("Scop", "Pfam", "Rfam"));
+ assertEquals(fr.getRenderOrder(),
+ Arrays.asList("Scop", "Pfam", "Rfam"));
assertEquals(fr.getDisplayedFeatureTypes(), Arrays.asList("Rfam"));
/*
/*
* make "Type2" not displayed
*/
- Object[][] data = new Object[4][];
FeatureColourI colour = new FeatureColour(Color.RED);
- data[0] = new Object[] { "Type1", colour, true };
- data[1] = new Object[] { "Type2", colour, false };
- data[2] = new Object[] { "Type3", colour, true };
- data[3] = new Object[] { "Disulphide Bond", colour, true };
+ FeatureSettingsBean[] data = new FeatureSettingsBean[4];
+ data[0] = new FeatureSettingsBean("Type1", colour, null, true);
+ data[1] = new FeatureSettingsBean("Type2", colour, null, false);
+ data[2] = new FeatureSettingsBean("Type3", colour, null, true);
+ data[3] = new FeatureSettingsBean("Disulphide Bond", colour, null,
+ true);
fr.setFeaturePriority(data);
features = fr.findFeaturesAtColumn(seq, 15);
features = fr.findFeaturesAtColumn(seq, 5);
assertEquals(features.size(), 1);
assertTrue(features.contains(sf8));
+
+ /*
+ * give "Type3" features a graduated colour scheme
+ * - first with no threshold
+ */
+ FeatureColourI gc = new FeatureColour(Color.yellow, Color.red, null, 0f,
+ 10f);
+ fr.getFeatureColours().put("Type3", gc);
+ features = fr.findFeaturesAtColumn(seq, 8);
+ assertTrue(features.contains(sf4));
+ // now with threshold > 2f - feature score of 1f is excluded
+ gc.setAboveThreshold(true);
+ gc.setThreshold(2f);
+ features = fr.findFeaturesAtColumn(seq, 8);
+ assertFalse(features.contains(sf4));
+
+ /*
+ * make "Type3" graduated colour by attribute "AF"
+ * - first with no attribute held - feature should be excluded
+ */
+ gc.setAttributeName("AF");
+ features = fr.findFeaturesAtColumn(seq, 8);
+ assertFalse(features.contains(sf4));
+ // now with the attribute above threshold - should be included
+ sf4.setValue("AF", "2.4");
+ features = fr.findFeaturesAtColumn(seq, 8);
+ assertTrue(features.contains(sf4));
+ // now with the attribute below threshold - should be excluded
+ sf4.setValue("AF", "1.4");
+ features = fr.findFeaturesAtColumn(seq, 8);
+ assertFalse(features.contains(sf4));
}
@Test(groups = "Functional")
FeatureRenderer fr = new FeatureRenderer(av);
List<SequenceFeature> features = new ArrayList<>();
- fr.filterFeaturesForDisplay(features, null); // empty list, does nothing
+ fr.filterFeaturesForDisplay(features); // empty list, does nothing
SequenceI seq = av.getAlignment().getSequenceAt(0);
SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, Float.NaN,
* filter out duplicate (co-located) features
* note: which gets removed is not guaranteed
*/
- fr.filterFeaturesForDisplay(features, new FeatureColour(Color.blue));
+ fr.filterFeaturesForDisplay(features);
assertEquals(features.size(), 3);
assertTrue(features.contains(sf1) || features.contains(sf4));
assertFalse(features.contains(sf1) && features.contains(sf4));
assertTrue(features.contains(sf5));
/*
- * hide group 3 - sf3 is removed, sf2 is retained
+ * hide groups 2 and 3 makes no difference to this method
*/
+ fr.setGroupVisibility("group2", false);
fr.setGroupVisibility("group3", false);
features = seq.getSequenceFeatures();
- fr.filterFeaturesForDisplay(features, new FeatureColour(Color.blue));
+ fr.filterFeaturesForDisplay(features);
assertEquals(features.size(), 3);
assertTrue(features.contains(sf1) || features.contains(sf4));
assertFalse(features.contains(sf1) && features.contains(sf4));
- assertTrue(features.contains(sf2));
- assertFalse(features.contains(sf3));
+ assertTrue(features.contains(sf2) || features.contains(sf3));
+ assertFalse(features.contains(sf2) && features.contains(sf3));
assertTrue(features.contains(sf5));
/*
- * hide group 2, show group 3 - sf2 is removed, sf3 is retained
+ * no filtering if transparency is applied
*/
- fr.setGroupVisibility("group2", false);
- fr.setGroupVisibility("group3", true);
+ fr.setTransparency(0.5f);
features = seq.getSequenceFeatures();
- fr.filterFeaturesForDisplay(features, null);
- assertEquals(features.size(), 3);
- assertTrue(features.contains(sf1) || features.contains(sf4));
- assertFalse(features.contains(sf1) && features.contains(sf4));
- assertFalse(features.contains(sf2));
- assertTrue(features.contains(sf3));
- assertTrue(features.contains(sf5));
+ fr.filterFeaturesForDisplay(features);
+ assertEquals(features.size(), 5);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetColour()
+ {
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(">s1\nABCD\n",
+ DataSourceType.PASTE);
+ AlignViewportI av = af.getViewport();
+ FeatureRenderer fr = new FeatureRenderer(av);
/*
- * no filtering of co-located features with graduated colour scheme
- * filterFeaturesForDisplay does _not_ check colour threshold
- * sf2 is removed as its group is hidden
+ * simple colour, feature type and group displayed
*/
- features = seq.getSequenceFeatures();
- fr.filterFeaturesForDisplay(features, new FeatureColour(Color.black,
- Color.white, 0f, 1f));
- assertEquals(features.size(), 4);
- assertTrue(features.contains(sf1));
- assertTrue(features.contains(sf3));
- assertTrue(features.contains(sf4));
- assertTrue(features.contains(sf5));
+ FeatureColourI fc = new FeatureColour(Color.red);
+ fr.getFeatureColours().put("Cath", fc);
+ SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, Float.NaN,
+ "group1");
+ assertEquals(fr.getColour(sf1), Color.red);
/*
- * co-located features with colour by label
- * should not get filtered
+ * hide feature type, then unhide
+ * - feature type visibility should not affect the result
*/
- features = seq.getSequenceFeatures();
- FeatureColour fc = new FeatureColour(Color.black);
- fc.setColourByLabel(true);
- fr.filterFeaturesForDisplay(features, fc);
- assertEquals(features.size(), 4);
- assertTrue(features.contains(sf1));
- assertTrue(features.contains(sf3));
- assertTrue(features.contains(sf4));
- assertTrue(features.contains(sf5));
+ FeatureSettingsBean[] data = new FeatureSettingsBean[1];
+ data[0] = new FeatureSettingsBean("Cath", fc, null, false);
+ fr.setFeaturePriority(data);
+ assertEquals(fr.getColour(sf1), Color.red);
+ data[0] = new FeatureSettingsBean("Cath", fc, null, true);
+ fr.setFeaturePriority(data);
+ assertEquals(fr.getColour(sf1), Color.red);
+
+ /*
+ * hide feature group, then unhide
+ */
+ fr.setGroupVisibility("group1", false);
+ assertNull(fr.getColour(sf1));
+ fr.setGroupVisibility("group1", true);
+ assertEquals(fr.getColour(sf1), Color.red);
+
+ /*
+ * graduated colour by score, no threshold, no score
+ *
+ */
+ FeatureColourI gc = new FeatureColour(Color.yellow, Color.red,
+ Color.green, 1f, 11f);
+ fr.getFeatureColours().put("Cath", gc);
+ assertEquals(fr.getColour(sf1), Color.green);
+
+ /*
+ * graduated colour by score, no threshold, with score value
+ */
+ SequenceFeature sf2 = new SequenceFeature("Cath", "", 6, 8, 6f,
+ "group1");
+ // score 6 is half way from yellow(255, 255, 0) to red(255, 0, 0)
+ Color expected = new Color(255, 128, 0);
+ assertEquals(fr.getColour(sf2), expected);
+
+ /*
+ * above threshold, score is above threshold - no change
+ */
+ gc.setAboveThreshold(true);
+ gc.setThreshold(5f);
+ assertEquals(fr.getColour(sf2), expected);
+
+ /*
+ * threshold is min-max; now score 6 is 1/6 of the way from 5 to 11
+ * or from yellow(255, 255, 0) to red(255, 0, 0)
+ */
+ gc = new FeatureColour(Color.yellow, Color.red, Color.green, 5f, 11f);
+ fr.getFeatureColours().put("Cath", gc);
+ gc.setAutoScaled(false); // this does little other than save a checkbox setting!
+ assertEquals(fr.getColour(sf2), new Color(255, 213, 0));
+
+ /*
+ * feature score is below threshold - no colour
+ */
+ gc.setAboveThreshold(true);
+ gc.setThreshold(7f);
+ assertNull(fr.getColour(sf2));
+
+ /*
+ * feature score is above threshold - no colour
+ */
+ gc.setBelowThreshold(true);
+ gc.setThreshold(3f);
+ assertNull(fr.getColour(sf2));
+
+ /*
+ * colour by feature attribute value
+ * first with no value held
+ */
+ gc = new FeatureColour(Color.yellow, Color.red, Color.green, 1f, 11f);
+ fr.getFeatureColours().put("Cath", gc);
+ gc.setAttributeName("AF");
+ assertEquals(fr.getColour(sf2), Color.green);
+
+ // with non-numeric attribute value
+ sf2.setValue("AF", "Five");
+ assertEquals(fr.getColour(sf2), Color.green);
+
+ // with numeric attribute value
+ sf2.setValue("AF", "6");
+ assertEquals(fr.getColour(sf2), expected);
+
+ // with numeric value outwith threshold
+ gc.setAboveThreshold(true);
+ gc.setThreshold(10f);
+ assertNull(fr.getColour(sf2));
+
+ // with filter on AF < 4
+ gc.setAboveThreshold(false);
+ assertEquals(fr.getColour(sf2), expected);
+ FeatureMatcherSetI filter = new FeatureMatcherSet();
+ filter.and(FeatureMatcher.byAttribute(Condition.LT, "4.0", "AF"));
+ fr.setFeatureFilter("Cath", filter);
+ assertNull(fr.getColour(sf2));
+
+ // with filter on 'Consequence contains missense'
+ filter = new FeatureMatcherSet();
+ filter.and(FeatureMatcher.byAttribute(Condition.Contains, "missense",
+ "Consequence"));
+ fr.setFeatureFilter("Cath", filter);
+ // if feature has no Consequence attribute, no colour
+ assertNull(fr.getColour(sf2));
+ // if attribute does not match filter, no colour
+ sf2.setValue("Consequence", "Synonymous");
+ assertNull(fr.getColour(sf2));
+ // attribute matches filter
+ sf2.setValue("Consequence", "Missense variant");
+ assertEquals(fr.getColour(sf2), expected);
+
+ // with filter on CSQ:Feature contains "ENST01234"
+ filter = new FeatureMatcherSet();
+ filter.and(FeatureMatcher.byAttribute(Condition.Matches, "ENST01234",
+ "CSQ", "Feature"));
+ fr.setFeatureFilter("Cath", filter);
+ // if feature has no CSQ data, no colour
+ assertNull(fr.getColour(sf2));
+ // if CSQ data does not include Feature, no colour
+ Map<String, String> csqData = new HashMap<>();
+ csqData.put("BIOTYPE", "Transcript");
+ sf2.setValue("CSQ", csqData);
+ assertNull(fr.getColour(sf2));
+ // if attribute does not match filter, no colour
+ csqData.put("Feature", "ENST9876");
+ assertNull(fr.getColour(sf2));
+ // attribute matches filter
+ csqData.put("Feature", "ENST01234");
+ assertEquals(fr.getColour(sf2), expected);
}
}
* </ul>
* <ul>
*/
- @Test
+ @Test(groups = "Functional")
public void testFindColour()
{
ColourSchemeI blosum = new Blosum62ColourScheme();
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertTrue;
import static org.testng.AssertJUnit.fail;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
+import jalview.api.FeatureColourI;
import jalview.datamodel.SequenceFeature;
import jalview.gui.JvOptionPane;
import jalview.util.ColorUtils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
public class FeatureColourTest
{
assertTrue(fc1.getColour().equals(Color.RED));
assertFalse(fc1.isGraduatedColour());
assertFalse(fc1.isColourByLabel());
+ assertFalse(fc1.isColourByAttribute());
+ assertNull(fc1.getAttributeName());
/*
* min-max colour
assertTrue(fc1.isGraduatedColour());
assertFalse(fc1.isColourByLabel());
assertTrue(fc1.isAboveThreshold());
+ assertFalse(fc1.isColourByAttribute());
+ assertNull(fc1.getAttributeName());
assertEquals(12f, fc1.getThreshold());
assertEquals(Color.gray, fc1.getMinColour());
assertEquals(Color.black, fc1.getMaxColour());
+ assertEquals(Color.gray, fc1.getNoColour());
+ assertEquals(10f, fc1.getMin());
+ assertEquals(20f, fc1.getMax());
+
+ /*
+ * min-max-noValue colour
+ */
+ fc = new FeatureColour(Color.gray, Color.black, Color.green, 10f, 20f);
+ fc.setAboveThreshold(true);
+ fc.setThreshold(12f);
+ fc1 = new FeatureColour(fc);
+ assertTrue(fc1.isGraduatedColour());
+ assertFalse(fc1.isColourByLabel());
+ assertFalse(fc1.isColourByAttribute());
+ assertNull(fc1.getAttributeName());
+ assertTrue(fc1.isAboveThreshold());
+ assertEquals(12f, fc1.getThreshold());
+ assertEquals(Color.gray, fc1.getMinColour());
+ assertEquals(Color.black, fc1.getMaxColour());
+ assertEquals(Color.green, fc1.getNoColour());
assertEquals(10f, fc1.getMin());
assertEquals(20f, fc1.getMax());
fc1 = new FeatureColour(fc);
assertTrue(fc1.isColourByLabel());
assertFalse(fc1.isGraduatedColour());
+ assertFalse(fc1.isColourByAttribute());
+ assertNull(fc1.getAttributeName());
+
+ /*
+ * colour by attribute (label)
+ */
+ fc = new FeatureColour();
+ fc.setColourByLabel(true);
+ fc.setAttributeName("AF");
+ fc1 = new FeatureColour(fc);
+ assertTrue(fc1.isColourByLabel());
+ assertFalse(fc1.isGraduatedColour());
+ assertTrue(fc1.isColourByAttribute());
+ assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
+
+ /*
+ * colour by attribute (value)
+ */
+ fc = new FeatureColour(Color.gray, Color.black, Color.green, 10f, 20f);
+ fc.setAboveThreshold(true);
+ fc.setThreshold(12f);
+ fc.setAttributeName("AF");
+ fc1 = new FeatureColour(fc);
+ assertTrue(fc1.isGraduatedColour());
+ assertFalse(fc1.isColourByLabel());
+ assertTrue(fc1.isColourByAttribute());
+ assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
+ assertTrue(fc1.isAboveThreshold());
+ assertEquals(12f, fc1.getThreshold());
+ assertEquals(Color.gray, fc1.getMinColour());
+ assertEquals(Color.black, fc1.getMaxColour());
+ assertEquals(Color.green, fc1.getNoColour());
+ assertEquals(10f, fc1.getMin());
+ assertEquals(20f, fc1.getMax());
+ }
+
+ @Test(groups = { "Functional" })
+ public void testCopyConstructor_minMax()
+ {
+ /*
+ * graduated colour
+ */
+ FeatureColour fc = new FeatureColour(Color.BLUE, Color.RED, 1f, 5f);
+ assertTrue(fc.isGraduatedColour());
+ assertFalse(fc.isColourByLabel());
+ assertFalse(fc.isColourByAttribute());
+ assertNull(fc.getAttributeName());
+ assertEquals(1f, fc.getMin());
+ assertEquals(5f, fc.getMax());
+
+ /*
+ * update min-max bounds
+ */
+ FeatureColour fc1 = new FeatureColour(fc, 2f, 6f);
+ assertTrue(fc1.isGraduatedColour());
+ assertFalse(fc1.isColourByLabel());
+ assertFalse(fc1.isColourByAttribute());
+ assertNull(fc1.getAttributeName());
+ assertEquals(2f, fc1.getMin());
+ assertEquals(6f, fc1.getMax());
+ assertFalse((boolean) PA.getValue(fc1, "isHighToLow"));
+
+ /*
+ * update min-max bounds - high to low
+ */
+ fc1 = new FeatureColour(fc, 23f, 16f);
+ assertTrue(fc1.isGraduatedColour());
+ assertFalse(fc1.isColourByLabel());
+ assertFalse(fc1.isColourByAttribute());
+ assertNull(fc1.getAttributeName());
+ assertEquals(23f, fc1.getMin());
+ assertEquals(16f, fc1.getMax());
+ assertTrue((boolean) PA.getValue(fc1, "isHighToLow"));
+
+ /*
+ * graduated colour by attribute
+ */
+ fc1.setAttributeName("AF");
+ fc1 = new FeatureColour(fc1, 13f, 36f);
+ assertTrue(fc1.isGraduatedColour());
+ assertFalse(fc1.isColourByLabel());
+ assertTrue(fc1.isColourByAttribute());
+ assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
+ assertEquals(13f, fc1.getMin());
+ assertEquals(36f, fc1.getMax());
+ assertFalse((boolean) PA.getValue(fc1, "isHighToLow"));
+
+ /*
+ * colour by label
+ */
+ fc = new FeatureColour(Color.BLUE, Color.RED, 1f, 5f);
+ fc.setColourByLabel(true);
+ assertFalse(fc.isGraduatedColour());
+ assertTrue(fc.isColourByLabel());
+ assertFalse(fc.isColourByAttribute());
+ assertNull(fc.getAttributeName());
+ assertEquals(1f, fc.getMin());
+ assertEquals(5f, fc.getMax());
+
+ /*
+ * update min-max bounds
+ */
+ fc1 = new FeatureColour(fc, 2f, 6f);
+ assertFalse(fc1.isGraduatedColour());
+ assertTrue(fc1.isColourByLabel());
+ assertFalse(fc1.isColourByAttribute());
+ assertNull(fc1.getAttributeName());
+ assertEquals(2f, fc1.getMin());
+ assertEquals(6f, fc1.getMax());
+
+ /*
+ * colour by attribute text
+ */
+ fc1.setAttributeName("AC");
+ fc1 = new FeatureColour(fc1, 13f, 36f);
+ assertFalse(fc1.isGraduatedColour());
+ assertTrue(fc1.isColourByLabel());
+ assertTrue(fc1.isColourByAttribute());
+ assertArrayEquals(new String[] { "AC" }, fc1.getAttributeName());
+ assertEquals(13f, fc1.getMin());
+ assertEquals(36f, fc1.getMax());
}
@Test(groups = { "Functional" })
@Test(groups = { "Functional" })
public void testGetColor_Graduated()
{
- // graduated colour from score 0 to 100, gray(128, 128, 128) to red(255, 0,
- // 0)
+ /*
+ * graduated colour from
+ * score 0 to 100
+ * gray(128, 128, 128) to red(255, 0, 0)
+ */
FeatureColour fc = new FeatureColour(Color.GRAY, Color.RED, 0f, 100f);
// feature score is 75 which is 3/4 of the way from GRAY to RED
SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
/*
+ * colour by attribute text (no threshold)
+ */
+ fc = new FeatureColour();
+ fc.setColourByLabel(true);
+ fc.setAttributeName("CLIN_SIG");
+ assertEquals("domain\tattribute|CLIN_SIG", fc.toJalviewFormat("domain"));
+
+ /*
* colour by label (autoscaled) (an odd state you can reach by selecting
* 'above threshold', then deselecting 'threshold is min/max' then 'colour
* by label')
*/
+ fc.setAttributeName((String[]) null);
fc.setAutoScaled(true);
assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
/*
- * colour by label (above threshold) (min/max values are output though not
- * used by this scheme)
+ * colour by label (above threshold)
*/
fc.setAutoScaled(false);
fc.setThreshold(12.5f);
fc.setAboveThreshold(true);
+ // min/max values are output though not used by this scheme
assertEquals("domain\tlabel|||0.0|0.0|above|12.5",
fc.toJalviewFormat("domain"));
fc.toJalviewFormat("domain"));
/*
- * graduated colour, no threshold
+ * colour by attributes text (below threshold)
+ */
+ fc.setBelowThreshold(true);
+ fc.setAttributeName("CSQ", "Consequence");
+ assertEquals("domain\tattribute|CSQ:Consequence|||0.0|0.0|below|12.5",
+ fc.toJalviewFormat("domain"));
+
+ /*
+ * graduated colour by score, no threshold
+ * - default constructor sets noValueColor = minColor
*/
fc = new FeatureColour(Color.GREEN, Color.RED, 12f, 25f);
String greenHex = Format.getHexString(Color.GREEN);
- String expected = String.format("domain\t%s|%s|abso|12.0|25.0|none",
- greenHex, redHex);
+ String expected = String.format(
+ "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
+ redHex);
assertEquals(expected, fc.toJalviewFormat("domain"));
/*
+ * graduated colour by score, no threshold, no value gets min colour
+ */
+ fc = new FeatureColour(Color.GREEN, Color.RED, Color.GREEN, 12f, 25f);
+ expected = String.format(
+ "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
+ redHex);
+ assertEquals(expected, fc.toJalviewFormat("domain"));
+
+ /*
+ * graduated colour by score, no threshold, no value gets max colour
+ */
+ fc = new FeatureColour(Color.GREEN, Color.RED, Color.RED, 12f, 25f);
+ expected = String.format(
+ "domain\tscore|%s|%s|noValueMax|abso|12.0|25.0|none", greenHex,
+ redHex);
+ assertEquals(expected, fc.toJalviewFormat("domain"));
+
+ /*
* colour ranges over the actual score ranges (not min/max)
*/
fc.setAutoScaled(true);
- expected = String.format("domain\t%s|%s|12.0|25.0|none", greenHex,
+ expected = String.format(
+ "domain\tscore|%s|%s|noValueMax|12.0|25.0|none", greenHex,
redHex);
assertEquals(expected, fc.toJalviewFormat("domain"));
/*
- * graduated colour below threshold
+ * graduated colour by score, below threshold
*/
fc.setThreshold(12.5f);
fc.setBelowThreshold(true);
- expected = String.format("domain\t%s|%s|12.0|25.0|below|12.5",
+ expected = String.format(
+ "domain\tscore|%s|%s|noValueMax|12.0|25.0|below|12.5",
greenHex, redHex);
assertEquals(expected, fc.toJalviewFormat("domain"));
/*
- * graduated colour above threshold
+ * graduated colour by score, above threshold
*/
fc.setThreshold(12.5f);
fc.setAboveThreshold(true);
fc.setAutoScaled(false);
- expected = String.format("domain\t%s|%s|abso|12.0|25.0|above|12.5",
+ expected = String.format(
+ "domain\tscore|%s|%s|noValueMax|abso|12.0|25.0|above|12.5",
+ greenHex, redHex);
+ assertEquals(expected, fc.toJalviewFormat("domain"));
+
+ /*
+ * graduated colour by attribute, above threshold
+ */
+ fc.setAttributeName("CSQ", "AF");
+ fc.setAboveThreshold(true);
+ fc.setAutoScaled(false);
+ expected = String.format(
+ "domain\tattribute|CSQ:AF|%s|%s|noValueMax|abso|12.0|25.0|above|12.5",
greenHex, redHex);
assertEquals(expected, fc.toJalviewFormat("domain"));
}
/*
* simple colour by name
*/
- FeatureColour fc = FeatureColour.parseJalviewFeatureColour("red");
+ FeatureColourI fc = FeatureColour.parseJalviewFeatureColour("red");
assertTrue(fc.isSimpleColour());
assertEquals(Color.RED, fc.getColour());
assertEquals(12.0f, fc.getThreshold());
/*
- * graduated colour (by name) (no threshold)
+ * colour by attribute text (no threshold)
+ */
+ fc = FeatureColour.parseJalviewFeatureColour("attribute|CLIN_SIG");
+ assertTrue(fc.isColourByAttribute());
+ assertTrue(fc.isColourByLabel());
+ assertFalse(fc.hasThreshold());
+ assertArrayEquals(new String[] { "CLIN_SIG" }, fc.getAttributeName());
+
+ /*
+ * colour by attributes text (with score threshold)
+ */
+ fc = FeatureColour.parseJalviewFeatureColour(
+ "attribute|CSQ:Consequence|||0.0|0.0|above|12.0");
+ assertTrue(fc.isColourByLabel());
+ assertTrue(fc.isColourByAttribute());
+ assertArrayEquals(new String[] { "CSQ", "Consequence" },
+ fc.getAttributeName());
+ assertTrue(fc.isAboveThreshold());
+ assertEquals(12.0f, fc.getThreshold());
+
+ /*
+ * graduated colour by score (with colour names) (no threshold)
*/
fc = FeatureColour.parseJalviewFeatureColour("red|green|10.0|20.0");
assertTrue(fc.isGraduatedColour());
assertFalse(fc.hasThreshold());
assertEquals(Color.RED, fc.getMinColour());
assertEquals(Color.GREEN, fc.getMaxColour());
+ assertEquals(Color.RED, fc.getNoColour());
+ assertEquals(10f, fc.getMin());
+ assertEquals(20f, fc.getMax());
+ assertTrue(fc.isAutoScaled());
+
+ /*
+ * the same, with 'no value colour' specified as max
+ */
+ fc = FeatureColour
+ .parseJalviewFeatureColour("red|green|novaluemax|10.0|20.0");
+ assertEquals(Color.RED, fc.getMinColour());
+ assertEquals(Color.GREEN, fc.getMaxColour());
+ assertEquals(Color.GREEN, fc.getNoColour());
+ assertEquals(10f, fc.getMin());
+ assertEquals(20f, fc.getMax());
+
+ /*
+ * the same, with 'no value colour' specified as min
+ */
+ fc = FeatureColour
+ .parseJalviewFeatureColour("red|green|novalueMin|10.0|20.0");
+ assertEquals(Color.RED, fc.getMinColour());
+ assertEquals(Color.GREEN, fc.getMaxColour());
+ assertEquals(Color.RED, fc.getNoColour());
+ assertEquals(10f, fc.getMin());
+ assertEquals(20f, fc.getMax());
+
+ /*
+ * the same, with 'no value colour' specified as none
+ */
+ fc = FeatureColour
+ .parseJalviewFeatureColour("red|green|novaluenone|10.0|20.0");
+ assertEquals(Color.RED, fc.getMinColour());
+ assertEquals(Color.GREEN, fc.getMaxColour());
+ assertNull(fc.getNoColour());
+ assertEquals(10f, fc.getMin());
+ assertEquals(20f, fc.getMax());
+
+ /*
+ * the same, with invalid 'no value colour'
+ */
+ try
+ {
+ fc = FeatureColour
+ .parseJalviewFeatureColour("red|green|blue|10.0|20.0");
+ fail("expected exception");
+ } catch (IllegalArgumentException e)
+ {
+ assertEquals(
+ "Couldn't parse the minimum value for graduated colour ('blue')",
+ e.getMessage());
+ }
+
+ /*
+ * graduated colour (explicitly by 'score') (no threshold)
+ */
+ fc = FeatureColour
+ .parseJalviewFeatureColour("Score|red|green|10.0|20.0");
+ assertTrue(fc.isGraduatedColour());
+ assertFalse(fc.hasThreshold());
+ assertEquals(Color.RED, fc.getMinColour());
+ assertEquals(Color.GREEN, fc.getMaxColour());
assertEquals(10f, fc.getMin());
assertEquals(20f, fc.getMax());
assertTrue(fc.isAutoScaled());
/*
- * graduated colour (by hex code) (above threshold)
+ * graduated colour by attribute (no threshold)
+ */
+ fc = FeatureColour
+ .parseJalviewFeatureColour("attribute|AF|red|green|10.0|20.0");
+ assertTrue(fc.isGraduatedColour());
+ assertTrue(fc.isColourByAttribute());
+ assertArrayEquals(new String[] { "AF" }, fc.getAttributeName());
+ assertFalse(fc.hasThreshold());
+ assertEquals(Color.RED, fc.getMinColour());
+ assertEquals(Color.GREEN, fc.getMaxColour());
+ assertEquals(10f, fc.getMin());
+ assertEquals(20f, fc.getMax());
+ assertTrue(fc.isAutoScaled());
+
+ /*
+ * graduated colour by score (colours by hex code) (above threshold)
*/
String descriptor = String.format("%s|%s|10.0|20.0|above|15",
Format.getHexString(Color.RED),
assertTrue(fc.isAutoScaled());
/*
+ * graduated colour by attributes (below threshold)
+ */
+ fc = FeatureColour.parseJalviewFeatureColour(
+ "attribute|CSQ:AF|red|green|10.0|20.0|below|13");
+ assertTrue(fc.isGraduatedColour());
+ assertTrue(fc.isColourByAttribute());
+ assertArrayEquals(new String[] { "CSQ", "AF" }, fc.getAttributeName());
+ assertTrue(fc.hasThreshold());
+ assertTrue(fc.isBelowThreshold());
+ assertEquals(13f, fc.getThreshold());
+ assertEquals(Color.RED, fc.getMinColour());
+ assertEquals(Color.GREEN, fc.getMaxColour());
+ assertEquals(10f, fc.getMin());
+ assertEquals(20f, fc.getMax());
+ assertTrue(fc.isAutoScaled());
+
+ /*
* graduated colour (by RGB triplet) (below threshold), absolute scale
*/
- descriptor = String.format("255,0,0|0,255,0|abso|10.0|20.0|below|15");
+ descriptor = "255,0,0|0,255,0|abso|10.0|20.0|below|15";
fc = FeatureColour.parseJalviewFeatureColour(descriptor);
assertTrue(fc.isGraduatedColour());
assertFalse(fc.isAutoScaled());
assertEquals(10f, fc.getMin());
assertEquals(20f, fc.getMax());
- descriptor = String
- .format("blue|255,0,255|absolute|20.0|95.0|below|66.0");
+ descriptor = "blue|255,0,255|absolute|20.0|95.0|below|66.0";
fc = FeatureColour.parseJalviewFeatureColour(descriptor);
assertTrue(fc.isGraduatedColour());
}
+
+ @Test(groups = { "Functional" })
+ public void testGetColor_colourByAttributeText()
+ {
+ FeatureColour fc = new FeatureColour();
+ fc.setColourByLabel(true);
+ fc.setAttributeName("consequence");
+ SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
+ null);
+
+ /*
+ * if feature has no such attribute, use 'no value' colour
+ */
+ assertEquals(FeatureColour.DEFAULT_NO_COLOUR, fc.getColor(sf));
+
+ /*
+ * if feature has attribute, generate colour from value
+ */
+ sf.setValue("consequence", "benign");
+ Color expected = ColorUtils.createColourFromName("benign");
+ assertEquals(expected, fc.getColor(sf));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetColor_GraduatedByAttributeValue()
+ {
+ /*
+ * graduated colour based on attribute value for AF
+ * given a min-max range of 0-100
+ */
+ FeatureColour fc = new FeatureColour(new Color(50, 100, 150),
+ new Color(150, 200, 250), Color.yellow, 0f, 100f);
+ String attName = "AF";
+ fc.setAttributeName(attName);
+
+ /*
+ * first case: feature lacks the attribute - use 'no value' colour
+ */
+ SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
+ null);
+ assertEquals(Color.yellow, fc.getColor(sf));
+
+ /*
+ * second case: attribute present but not numeric - treat as if absent
+ */
+ sf.setValue(attName, "twelve");
+ assertEquals(Color.yellow, fc.getColor(sf));
+
+ /*
+ * third case: valid attribute value
+ */
+ sf.setValue(attName, "20.0");
+ Color expected = new Color(70, 120, 170);
+ assertEquals(expected, fc.getColor(sf));
+ }
}
@Test(groups = { "Functional" })
public void compareTransferredToRefPDBAnnot() throws Exception
{
+ StructureImportSettings.setProcessSecondaryStructure(true);
+ StructureImportSettings.setVisibleChainAnnotation(true);
StructureImportSettings.setShowSeqFeatures(true);
AlignFrame ref = new FileLoader(false)
.LoadFileWaitTillLoaded("test/jalview/ext/jmol/1QCF.pdb",
+/*
+ * 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.structure;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.util.MapList;
+
import java.util.HashMap;
import java.util.List;
public class StructureMappingTest
{
@Test(groups = "Functional")
- public void testgetPDBResNumRanges()
+ public void testGetPDBResNumRanges()
{
- HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();
+ HashMap<Integer, int[]> map = new HashMap<>();
StructureMapping mapping = new StructureMapping(null, null, null, null,
map, null);
assertEquals(ranges.get(1)[0], 15);
assertEquals(ranges.get(1)[1], 15);
}
+
+ @Test(groups = "Functional")
+ public void testEquals()
+ {
+ SequenceI seq1 = new Sequence("seq1", "ABCDE");
+ SequenceI seq2 = new Sequence("seq1", "ABCDE");
+ String pdbFile = "a/b/file1.pdb";
+ String pdbId = "1a70";
+ String chain = "A";
+ String mappingDetails = "these are the mapping details, honest";
+ HashMap<Integer, int[]> map = new HashMap<>();
+
+ Mapping seqToPdbMapping = new Mapping(seq1,
+ new MapList(new int[]
+ { 1, 5 }, new int[] { 2, 6 }, 1, 1));
+ StructureMapping sm1 = new StructureMapping(seq1, pdbFile, pdbId, chain,
+ map, mappingDetails, seqToPdbMapping);
+ assertFalse(sm1.equals(null));
+ assertFalse(sm1.equals("x"));
+
+ StructureMapping sm2 = new StructureMapping(seq1, pdbFile, pdbId, chain,
+ map, mappingDetails, seqToPdbMapping);
+ assertTrue(sm1.equals(sm2));
+ assertTrue(sm2.equals(sm1));
+ assertEquals(sm1.hashCode(), sm2.hashCode());
+
+ // with different sequence
+ sm2 = new StructureMapping(seq2, pdbFile, pdbId, chain, map,
+ mappingDetails, seqToPdbMapping);
+ assertFalse(sm1.equals(sm2));
+ assertFalse(sm2.equals(sm1));
+
+ // with different file
+ sm2 = new StructureMapping(seq1, "a/b/file2.pdb", pdbId, chain, map,
+ mappingDetails, seqToPdbMapping);
+ assertFalse(sm1.equals(sm2));
+ assertFalse(sm2.equals(sm1));
+
+ // with different pdbid (case sensitive)
+ sm2 = new StructureMapping(seq1, pdbFile, "1A70", chain, map,
+ mappingDetails, seqToPdbMapping);
+ assertFalse(sm1.equals(sm2));
+ assertFalse(sm2.equals(sm1));
+
+ // with different chain
+ sm2 = new StructureMapping(seq1, pdbFile, pdbId, "B", map,
+ mappingDetails, seqToPdbMapping);
+ assertFalse(sm1.equals(sm2));
+ assertFalse(sm2.equals(sm1));
+
+ // map is ignore for this test
+ sm2 = new StructureMapping(seq1, pdbFile, pdbId, chain, null,
+ mappingDetails, seqToPdbMapping);
+ assertTrue(sm1.equals(sm2));
+ assertTrue(sm2.equals(sm1));
+
+ // with different mapping details
+ sm2 = new StructureMapping(seq1, pdbFile, pdbId, chain, map,
+ "different details!", seqToPdbMapping);
+ assertFalse(sm1.equals(sm2));
+ assertFalse(sm2.equals(sm1));
+
+ // with different seq to pdb mapping
+ Mapping map2 = new Mapping(seq1,
+ new MapList(new int[]
+ { 1, 5 }, new int[] { 3, 7 }, 1, 1));
+ sm2 = new StructureMapping(seq1, pdbFile, pdbId, chain, map,
+ mappingDetails, map2);
+ assertFalse(sm1.equals(sm2));
+ assertFalse(sm2.equals(sm1));
+ }
}
*/
package jalview.structure;
+import static org.junit.Assert.assertArrayEquals;
+import static org.testng.Assert.assertNotNull;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
+import jalview.analysis.AlignmentUtils;
+import jalview.api.structures.JalviewStructureDisplayI;
+import jalview.bin.Cache;
import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.PDBEntry;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.ext.jmol.JmolCommands;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
import jalview.gui.JvOptionPane;
+import jalview.gui.SequenceRenderer;
+import jalview.gui.StructureChooser;
import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.io.Jalview2xmlBase;
import jalview.io.StructureFile;
import jalview.util.MapList;
+import jalview.ws.DBRefFetcher;
+import jalview.ws.sifts.SiftsSettings;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-public class StructureSelectionManagerTest
+@Test(singleThreaded = true)
+public class StructureSelectionManagerTest extends Jalview2xmlBase
{
+ @Override
@BeforeClass(alwaysRun = true)
public void setUpJvOptionPane()
{
assertEquals("1gaq", sf.getFeatureGroup());
assertEquals("ALA: 1 1gaqB", sf.getDescription());
}
+
+ /**
+ * Verify that RESNUM sequence features are present after creating a PDB
+ * mapping from a local file, then that everything stays in the same place
+ * when the file is viewed. The corner case is that 4IM2 is a fragment of a
+ * PDB file, which still includes the 'ID' field - a bug in Jalview 2.10.3
+ * causes features, annotation and positions to be remapped to the wrong place
+ * on viewing the structure
+ */
+ @Test(groups = { "Network" })
+ public void testMapping_EqualsFeatures()
+ {
+ // for some reason 'BeforeMethod' (which should be inherited from
+ // Jalview2XmlBase isn't always called)...
+ Desktop.instance.closeAll_actionPerformed(null);
+ try {
+ Thread.sleep(200);
+ } catch (Exception foo) {};
+ SequenceI seq = new Sequence("4IM2|A",
+ "LDFCIRNIEKTVMGEISDIHTKLLRLSSSQGTIE");
+ String P4IM2_MISSING = "examples/testdata/4IM2_missing.pdb";
+ StructureSelectionManager sm = new StructureSelectionManager();
+ sm.setProcessSecondaryStructure(true);
+ sm.setAddTempFacAnnot(true);
+ StructureFile pmap = sm.setMapping(true, new SequenceI[] { seq },
+ new String[]
+ { null }, P4IM2_MISSING,
+ DataSourceType.FILE);
+ assertTrue(pmap != null);
+
+ assertEquals(1, pmap.getSeqs().size());
+ assertEquals("4IM2|A", pmap.getSeqs().get(0).getName());
+
+ List<int[]> structuremap1 = new ArrayList(
+ sm.getMapping(P4IM2_MISSING)[0]
+ .getPDBResNumRanges(seq.getStart(), seq.getEnd()));
+
+ /*
+ * Verify a RESNUM sequence feature in the PDBfile sequence
+ * LEU468 - start+0
+ * VAL479 - start+11
+ * MET486 - start+12
+ * GLY496 - start+13
+ * GLU516 - start+33 (last)
+ *
+ * Expect features and mapping to resolve to same residues.
+ * Also try creating a view and test again
+ *
+ */
+ String[] feats = new String[] { "LEU", "468", "VAL", "479", "MET",
+ "486", "GLY", "496", "GLU", "516" };
+ int[] offset = new int[] { 0, 11, 12, 13, 33 };
+
+ List<String> fdesc = new ArrayList<>();
+ for (int f = 0; f < feats.length; f += 2)
+ {
+ fdesc.add(feats[f] + ": " + feats[f + 1] + " 4im2A");
+ }
+ SequenceI pdbseq = pmap.getSeqs().get(0);
+ verifySeqFeats(pdbseq, offset, fdesc);
+
+ /// Now load as a view
+
+ AlignFrame alf = new FileLoader(false).LoadFileWaitTillLoaded(
+ "examples/testdata/4IM2_missing.pdb", DataSourceType.FILE);
+ Desktop.addInternalFrame(alf, "examples/testdata/4IM2_missing.pdb", 800,
+ 400);
+ AlignmentI pdbal = alf.getViewport().getAlignment();
+ SequenceI pdb_viewseq = pdbal.getSequenceAt(0);
+ assertEquals(pdb_viewseq.getSequenceAsString(),
+ seq.getSequenceAsString());
+ // verify the feature location on the sequence when pdb imported as an
+ // alignment
+ verifySeqFeats(pdb_viewseq, offset, fdesc);
+
+
+ JalviewStructureDisplayI viewr = openStructureViaChooser(alf,
+ pdb_viewseq, "4IM2");
+
+ // and check all is good with feature location still
+ verifySeqFeats(pdb_viewseq, offset, fdesc);
+
+ // finally check positional mapping for sequence and structure
+ PDBEntry pdbe = seq.getPDBEntry("4IM2");
+ StructureSelectionManager apssm = alf.alignPanel
+ .getStructureSelectionManager();
+ StructureMapping[] smap = apssm
+ .getMapping(pdbe.getFile());
+ assertNotNull(smap);
+ assertNotNull(smap[0]);
+ // find the last position in the alignment sequence - this is not
+ // 'SequenceI.getEnd()' - which gets the last PDBRESNUM rather than
+ // SequenceI.getStart() + number of residues in file...
+ int realSeqEnd = pdb_viewseq.findPosition(pdb_viewseq.getLength());
+ List<int[]> ranges = smap[0].getPDBResNumRanges(pdb_viewseq.getStart(),
+ realSeqEnd);
+ assertEquals(structuremap1.size(), ranges.size());
+ int tot_mapped = 0;
+ for (int p = 0; p < ranges.size(); p++)
+ {
+ assertArrayEquals(structuremap1.get(p), ranges.get(p));
+ tot_mapped += 1 + (structuremap1.get(p)[1] - structuremap1.get(p)[0]);
+ }
+
+ assertEquals(pdb_viewseq.getLength(), tot_mapped);
+
+ int lastmappedp = StructureMapping.UNASSIGNED_VALUE;
+ for (int rp = pdb_viewseq.getStart(), rpEnd = pdb_viewseq
+ .findPosition(pdb_viewseq.getLength() - 1); rp <= rpEnd; rp++)
+ {
+ int mappedp = smap[0].getPDBResNum(rp);
+ if (mappedp != StructureMapping.UNASSIGNED_VALUE)
+ {
+ tot_mapped--;
+ if (lastmappedp == mappedp)
+ {
+ Assert.fail("Duplicate mapped position at " + rp + " (dupe = "
+ + mappedp + ")");
+ }
+ }
+ }
+
+ Assert.assertEquals(tot_mapped, 0,
+ "Different number of mapped residues compared to ranges of mapped residues");
+
+ // positional mapping to atoms for color by structure is still wrong, even
+ // though panel looks correct.
+
+ StructureMappingcommandSet smcr[] = JmolCommands
+ .getColourBySequenceCommand(apssm,
+ new String[]
+ { pdbe.getFile() },
+ new SequenceI[][]
+ { new SequenceI[] { pdb_viewseq } },
+ new SequenceRenderer(alf.alignPanel.getAlignViewport()),
+ alf.alignPanel);
+ // Expected - all residues are white
+ for (StructureMappingcommandSet smm : smcr)
+ {
+ for (String c : smm.commands)
+ {
+ System.out.println(c);
+ }
+ }
+ }
+
+ private void verifySeqFeats(SequenceI pdbseq, int[] offset,
+ List<String> fdesc)
+ {
+ for (int o = 0; o < offset.length; o++)
+ {
+ int res = pdbseq.findPosition(offset[o]);
+ List<SequenceFeature> sf = pdbseq.getFeatures().findFeatures(res, res,
+ "RESNUM");
+ assertEquals("Expected sequence feature at position " + res + "("
+ + offset[o] + ")", 1, sf.size());
+ assertEquals("Wrong description at " + res + "(" + offset[o] + ")",
+ fdesc.get(o), sf.get(0).getDescription());
+ }
+
+ }
+
+ @Test(groups = { "Network" })
+ public void testAssociatedMappingToSubSeq() throws Exception
+ {
+
+ // currently this test fails if trimming is enabled
+ Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES,
+ Boolean.FALSE.toString());
+ String TEMP_FACTOR_AA="Temperature Factor";
+ String PDBID = "4IM2";
+ String FullLengthSeq = ">TBK1_HUMAN Serine/threonine-protein kinase TBK1\n" +
+ "MQSTSNHLWLLSDILGQGATANVFRGRHKKTGDLFAIKVFNNISFLRPVDVQMREFEVLKKLNHKNIVKLFA\n" +
+ "IEEETTTRHKVLIMEFCPCGSLYTVLEEPSNAYGLPESEFLIVLRDVVGGMNHLRENGIVHRDIKPGNIMRV\n" +
+ "IGEDGQSVYKLTDFGAARELEDDEQFVSLYGTEEYLHPDMYERAVLRKDHQKKYGATVDLWSIGVTFYHAAT\n" +
+ "GSLPFRPFEGPRRNKEVMYKIITGKPSGAISGVQKAENGPIDWSGDMPVSCSLSRGLQVLLTPVLANILEAD\n" +
+ "QEKCWGFDQFFAETSDILHRMVIHVFSLQQMTAHKIYIHSYNTATIFHELVYKQTKIISSNQELIYEGRRLV\n" +
+ "LEPGRLAQHFPKTTEENPIFVVSREPLNTIGLIYEKISLPKVHPRYDLDGDASMAKAITGVVCYACRIASTL\n" +
+ "LLYQELMRKGIRWLIELIKDDYNETVHKKTEVVITLDFCIRNIEKTVKVYEKLMKINLEAAELGEISDIHTK\n" +
+ "LLRLSSSQGTIETSLQDIDSRLSPGGSLADAWAHQEGTHPKDRNVEKLQVLLNCMTEIYYQFKKDKAERRLA\n" +
+ "YNEEQIHKFDKQKLYYHATKAMTHFTDECVKKYEAFLNKSEEWIRKMLHLRKQLLSLTNQCFDIEEEVSKYQ\n" +
+ "EYTNELQETLPQKMFTASSGIKHTMTPIYPSSNTLVEMTLGMKKLKEEMEGVVKELAENNHILERFGSLTMD\n" +
+ "GGLRNVDCL";
+ /*
+ * annotation exported after importing full length sequence to desktop, opening 4IM2 and selecting 'Add Reference Annotation'.
+ *
+ * Note - tabs must be replaced with \t - Eclipse expands them to spaces otherwise.
+ */
+ String FullLengthAnnot = "JALVIEW_ANNOTATION\n" +
+ "# Created: Mon Feb 05 15:30:20 GMT 2018\n" +
+ "# Updated: Fri Feb 09 17:05:17 GMT 2018\n" +
+ "\n" +
+ "\n" +
+ "SEQUENCE_REF\tTBK1_HUMAN\n"
+ + "LINE_GRAPH\tTemperature Factor\tTemperature Factor for 4im2A\t125.22|128.51|120.35|113.12|122.6|114.44|91.49|102.53|98.22|111.41|111.32|116.64|103.55|100.53|95.07|105.55|114.76|128.29|133.55|142.14|121.12|110.36|95.79|95.39|87.14|99.56|93.55|94.21|100.33|110.68|97.85|82.37|75.87|76.53|77.85|82.49|80.92|96.88|122.58|133.31|160.15|180.51|||||242.88|258.97|247.01|227.12|223.24|211.62|184.65|183.51|168.96|160.04|150.88|131.68|130.43|139.87|148.59|136.57|125.7|96.51|74.49|74.08|85.87|70.93|86.47|101.59|97.51|97.39|117.19|114.27|129.5|112.98|147.52|170.26|154.98|168.18|157.51|131.95|105.85|97.78|97.35|76.51|76.31|72.55|71.43|78.82|79.94|75.04|79.54|77.95|83.56|88.5|71.51|71.73|75.96|82.36|81.75|66.51|67.23|69.35|67.92|54.75|71.19|61.85|65.34|67.97|64.51|67.41|62.28|72.85|72.76|70.64|65.23|71.07|67.73|87.72|64.93|75.92|94.02|99.35|93.71|103.59|106.29|115.46|118.69|147.18|130.62|171.64|158.95|164.11||107.42|88.53|83.52|88.06|94.06|80.82|59.01|59.73|78.89|69.21|70.34|81.95|74.53|60.92|64.65|55.79|75.71|68.86|70.95|75.08|87.76|85.43|105.84|||||||||||||||||137.46|151.33|145.17|122.79|111.56|126.72|124.06|161.75|176.84|180.51|198.49|196.75|187.41||195.23|202.27|203.16|226.55|221.75|193.83||||||172.33|177.97|151.47|132.65|99.22|93.7|91.15|88.24|72.35|70.05|70.0|74.92|66.51|68.37|65.76|70.12|74.97|76.89|80.83|70.21|69.48|79.54|82.65|96.54|114.31|140.46|168.51|176.99|205.08|209.27|155.83|139.41|151.3|129.33|111.31|119.62|121.37|102.26|115.39|129.97|128.65|110.38|110.66|116.1|82.53|84.02|82.17|87.63|86.42|77.23|91.23|95.53|102.21|120.73|133.26|109.67|108.49|93.25|92.85|86.39|95.66|94.92|85.82|80.13|76.17|86.61|78.9|77.97|105.6|70.66|69.35|78.94|66.68|63.03|69.91|79.05|75.43|70.73|70.02|80.57|81.74|77.99|84.1|91.66|92.42|94.03|116.47|132.01|154.55|163.99|161.37|155.23|132.78|109.3|90.38|101.83|99.61|91.68|82.77|86.12|82.73|90.13|85.14|79.54|74.27|74.06|72.88|86.34|72.0|69.32|60.9|68.15|52.99|63.53|61.3|66.01|68.28|77.41|71.52|67.18|66.17|71.51|65.47|52.63|65.08|66.37|73.76|77.79|67.58|79.53|84.75|87.42|78.9|79.19|85.57|73.67|80.56|86.19|72.17|66.27|72.8|86.28|78.89|74.5|90.6|80.42|92.5|92.84|96.18|92.08|88.5|87.25|64.6|68.95|65.56|67.55|71.62|78.24|84.95|71.35|86.41|84.73|94.41|95.09|84.74|87.64|88.85|75.1|86.42|79.28|73.14|78.54|80.81|60.66|67.93|71.64|59.85|64.7|61.22|63.84|65.9|62.18|74.95|72.92|93.37|90.47|96.0|93.8|88.46|79.78|83.4|66.55|68.7|73.2|78.76|85.67|84.8|89.59|96.52|79.53|103.51|134.72|126.7|145.31|156.17|149.35|128.48|117.29|118.98|131.59|109.36|90.39|87.68|91.81|78.77|80.11|91.39|75.57|78.98|71.53|76.85|70.9|64.71|73.55|73.45|60.0|69.92|57.89|69.07|66.45|62.85|57.83|57.89|66.4|61.61|60.85|66.47|63.53|63.84|65.96|73.06|70.82|64.51|63.66|73.37|73.59|68.09|78.93|76.99|75.05|71.32|88.4|78.88|93.08|110.61|94.32|99.24|128.99|129.49|132.74|124.21|120.32|142.06|166.41|149.87|153.29|172.19|165.89|181.6|223.11|237.73|176.41|171.09|189.65|188.61|154.84|142.72|154.25|170.99|175.65|||||||110.61||||||||||158.07|170.73|167.93|198.47|212.36|181.71|157.69|163.31|138.96|120.29|131.63|152.26|125.06|136.66|148.97|129.68|120.52|135.31|136.05|119.39|124.18|128.94|123.02|103.37|128.44|134.12|118.88|120.94|130.38|124.67|112.21|113.69|123.65|132.06|114.97|110.75|92.38|101.2|103.25|94.84|85.3|82.19|89.81|98.81|83.03|68.91|65.24|70.31|63.49|86.38|71.07|62.65|63.95|66.98|58.06|68.28|62.11|63.86|67.4|68.69|69.57|68.03|74.23|75.66|70.67|81.08|81.31|82.49|88.15|95.99|92.97|100.01|113.18|122.37|110.99|122.19|159.27|147.74|133.96|111.2|115.64|126.55|107.15|102.85|117.06|116.56|109.55|96.82|98.92|96.53|86.0|88.11|92.76|85.77|79.41|93.06|86.96|76.35|72.37|74.19|68.6|67.46|74.47|76.25|66.73|73.18|75.2|88.21|84.93|75.04|71.09|82.6|80.03|76.22|75.76|83.72|75.85|79.36|90.35|86.9|78.24|95.64|97.38|86.41|85.02|91.87|87.36|77.56|81.25|91.66|83.65|77.67|85.07|89.21|92.66|92.46|89.0|100.83|96.71|94.81|101.37|111.28|124.48|119.73|127.81|134.41|132.4|140.32|140.86|166.52|160.16|168.39|176.74|174.63|172.86|168.55|155.9|132.71|113.44|113.49|123.9|151.11|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n"
+ +
+ "\n" +
+ "";
+ AlignFrame alf_full=new
+ FileLoader(false).LoadFileWaitTillLoaded(FullLengthSeq,DataSourceType.PASTE);
+ alf_full.loadJalviewDataFile(FullLengthAnnot, DataSourceType.PASTE, null, null);
+ AlignmentI al_full = alf_full.getViewport().getAlignment();
+ AlignmentAnnotation fullseq_tf = al_full.findAnnotations(al_full.getSequences().get(0), null, TEMP_FACTOR_AA).iterator()
+ .next();
+ assertNotNull(fullseq_tf);
+
+ // getMappingFor
+ // AlignmentI al_full=alf_full.getViewport().getAlignment();
+ //
+ // // load 4IM2 (full length, SIFTS onto full alingnment)
+ // SiftsSettings.setMapWithSifts(true);
+ // StructureChooser schoose = new StructureChooser(selectedSeqs_full,
+ // seq_full,
+ // alf_full.getViewport().getAlignPanel());
+ // schoose.selectStructure(PDBID);
+ // schoose.ok_ActionPerformed();
+
+ AlignFrame alf = new FileLoader(false).LoadFileWaitTillLoaded(
+ ">TBK1_HUMAN/470-502 Serine/threonine-protein kinase TBK1\nFCIRNIEKTVKVYEKLMKINLEAAELGEISDIH",
+ DataSourceType.PASTE);
+ Desktop.addInternalFrame(alf, "Foo", 800, 600);
+ ;
+ AlignmentI al = alf.getViewport().getAlignment();
+ SequenceI seq = al.getSequenceAt(0);
+ assertEquals(470, seq.getStart());
+ // load 4IM2 (full length, SIFTS)
+ SiftsSettings.setMapWithSifts(true);
+ StructureImportSettings.setProcessSecondaryStructure(true);
+ StructureImportSettings.setVisibleChainAnnotation(true);
+ JalviewStructureDisplayI sview = openStructureViaChooser(alf, seq,
+ PDBID);
+
+ AlignmentAnnotation subseq_tf=null;
+ assertTrue(seq.getDBRefs() != null && seq.getDBRefs().length > 0);
+
+ if (!al.findAnnotations(seq, null, TEMP_FACTOR_AA).iterator().hasNext())
+ {
+ // FIXME JAL-2321 - don't see reference annotation on alignment the first
+ // time
+ // around
+ SortedMap<String, String> tipEntries = new TreeMap<>();
+ final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
+
+ AlignmentUtils.findAddableReferenceAnnotations(al.getSequences(),
+ tipEntries, candidates, al);
+ AlignmentUtils.addReferenceAnnotations(candidates, al, null);
+
+ if (!al.findAnnotations(seq, null, TEMP_FACTOR_AA).iterator()
+ .hasNext())
+ {
+ Assert.fail(
+ "JAL-2321 or worse has occured. No secondary structure added to alignment.");
+ }
+ }
+ subseq_tf = al.findAnnotations(seq, null, TEMP_FACTOR_AA).iterator()
+ .next();
+ // verify against annotation after loading 4IM2 to full length TBK1_HUMAN
+ // verify location of mapped residues
+ // verify location of secondary structure annotation
+ // Specific positions: LYS477 (h),THR478 (no helix), ... GLY496(no helix),
+ // GLU497 (helix),
+
+ // check there is or is not a tempfactor for each mapped position, and that
+ // values are equal for those positions.
+ for (int p=seq.getStart();p<=seq.getEnd();p++)
+ {
+ Annotation orig,subseq;
+ orig = fullseq_tf.getAnnotationForPosition(p);
+ subseq = subseq_tf.getAnnotationForPosition(p);
+ if (orig == null)
+ {
+ Assert.assertNull(subseq,
+ "Expected no annotation transferred at position " + p);
+ }
+ ;
+ if (orig != null)
+ {
+ Assert.assertNotNull(subseq,
+ "Expected annotation transfer at position " + p);
+ assertEquals(orig.value, subseq.value);
+ }
+ ;
+
+ }
+ }
+
+ private JalviewStructureDisplayI openStructureViaChooser(AlignFrame alf,
+ SequenceI seq,
+ String pDBID)
+ {
+
+ SequenceI[] selectedSeqs = new SequenceI[] { seq };
+
+ StructureChooser schoose = new StructureChooser(selectedSeqs, seq,
+ alf.getViewport().getAlignPanel());
+
+ try
+ {
+ Thread.sleep(5000);
+ } catch (InterruptedException q)
+ {
+ }
+ ;
+ Assert.assertTrue(schoose.selectStructure(pDBID),
+ "Couldn't select structure via structure chooser: " + pDBID);
+ schoose.showStructures(true);
+ return schoose.getOpenedStructureViewer();
+ }
+
}
MapList ml7 = new MapList(codons, protein, 3, 1); // toShifts differ
assertTrue(ml.equals(ml));
+ assertEquals(ml.hashCode(), ml.hashCode());
assertTrue(ml.equals(ml1));
+ assertEquals(ml.hashCode(), ml1.hashCode());
assertTrue(ml1.equals(ml));
assertFalse(ml.equals(null));
@Test(groups = { "Functional" })
public void testGetRanges()
{
- List<int[]> ranges = new ArrayList<int[]>();
+ List<int[]> ranges = new ArrayList<>();
ranges.add(new int[] { 2, 3 });
ranges.add(new int[] { 5, 6 });
assertEquals("[2, 3, 5, 6]", Arrays.toString(MapList.getRanges(ranges)));
public void testAddRange()
{
int[] range = { 1, 5 };
- List<int[]> ranges = new ArrayList<int[]>();
+ List<int[]> ranges = new ArrayList<>();
// add to empty list:
MapList.addRange(range, ranges);
public void testCoalesceRanges()
{
assertNull(MapList.coalesceRanges(null));
- List<int[]> ranges = new ArrayList<int[]>();
+ List<int[]> ranges = new ArrayList<>();
assertSame(ranges, MapList.coalesceRanges(ranges));
ranges.add(new int[] { 1, 3 });
assertSame(ranges, MapList.coalesceRanges(ranges));
@Test(groups = { "Functional" })
public void testCoalesceRanges_withOverlap()
{
- List<int[]> ranges = new ArrayList<int[]>();
+ List<int[]> ranges = new ArrayList<>();
ranges.add(new int[] { 1, 3 });
ranges.add(new int[] { 2, 5 });
assertEquals(1, merged.size());
assertArrayEquals(new int[] { 9, 0 }, merged.get(0));
}
+
+ /**
+ * Test the method that compounds ('traverses') two mappings
+ */
+ @Test(groups = "Functional")
+ public void testTraverse()
+ {
+ /*
+ * simple 1:1 plus 1:1 forwards
+ */
+ MapList ml1 = new MapList(new int[] { 3, 4, 8, 12 }, new int[] { 5, 8,
+ 11, 13 }, 1, 1);
+ assertEquals("{[3, 4], [8, 12]}", prettyPrint(ml1.getFromRanges()));
+ assertEquals("{[5, 8], [11, 13]}", prettyPrint(ml1.getToRanges()));
+
+ MapList ml2 = new MapList(new int[] { 1, 50 }, new int[] { 40, 45, 70,
+ 75, 90, 127 }, 1, 1);
+ assertEquals("{[1, 50]}", prettyPrint(ml2.getFromRanges()));
+ assertEquals("{[40, 45], [70, 75], [90, 127]}",
+ prettyPrint(ml2.getToRanges()));
+
+ MapList compound = ml1.traverse(ml2);
+
+ assertEquals(1, compound.getFromRatio());
+ assertEquals(1, compound.getToRatio());
+ List<int[]> fromRanges = compound.getFromRanges();
+ assertEquals(2, fromRanges.size());
+ assertArrayEquals(new int[] { 3, 4 }, fromRanges.get(0));
+ assertArrayEquals(new int[] { 8, 12 }, fromRanges.get(1));
+ List<int[]> toRanges = compound.getToRanges();
+ assertEquals(4, toRanges.size());
+ // 5-8 maps to 44-45,70-71
+ // 11-13 maps to 74-75,90
+ assertArrayEquals(new int[] { 44, 45 }, toRanges.get(0));
+ assertArrayEquals(new int[] { 70, 71 }, toRanges.get(1));
+ assertArrayEquals(new int[] { 74, 75 }, toRanges.get(2));
+ assertArrayEquals(new int[] { 90, 90 }, toRanges.get(3));
+
+ /*
+ * 1:1 over 1:1 backwards ('reverse strand')
+ */
+ ml1 = new MapList(new int[] { 1, 50 }, new int[] { 70, 119 }, 1, 1);
+ ml2 = new MapList(new int[] { 1, 500 },
+ new int[] { 1000, 901, 600, 201 }, 1, 1);
+ compound = ml1.traverse(ml2);
+
+ assertEquals(1, compound.getFromRatio());
+ assertEquals(1, compound.getToRatio());
+ fromRanges = compound.getFromRanges();
+ assertEquals(1, fromRanges.size());
+ assertArrayEquals(new int[] { 1, 50 }, fromRanges.get(0));
+ toRanges = compound.getToRanges();
+ assertEquals(2, toRanges.size());
+ assertArrayEquals(new int[] { 931, 901 }, toRanges.get(0));
+ assertArrayEquals(new int[] { 600, 582 }, toRanges.get(1));
+
+ /*
+ * 1:1 plus 1:3 should result in 1:3
+ */
+ ml1 = new MapList(new int[] { 1, 30 }, new int[] { 11, 40 }, 1, 1);
+ ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 50, 91, 340 },
+ 1, 3);
+ compound = ml1.traverse(ml2);
+
+ assertEquals(1, compound.getFromRatio());
+ assertEquals(3, compound.getToRatio());
+ fromRanges = compound.getFromRanges();
+ assertEquals(1, fromRanges.size());
+ assertArrayEquals(new int[] { 1, 30 }, fromRanges.get(0));
+ // 11-40 maps to 31-50,91-160
+ toRanges = compound.getToRanges();
+ assertEquals(2, toRanges.size());
+ assertArrayEquals(new int[] { 31, 50 }, toRanges.get(0));
+ assertArrayEquals(new int[] { 91, 160 }, toRanges.get(1));
+
+ /*
+ * 3:1 plus 1:1 should result in 3:1
+ */
+ ml1 = new MapList(new int[] { 1, 30 }, new int[] { 11, 20 }, 3, 1);
+ ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 15, 91, 175 },
+ 1, 1);
+ compound = ml1.traverse(ml2);
+
+ assertEquals(3, compound.getFromRatio());
+ assertEquals(1, compound.getToRatio());
+ fromRanges = compound.getFromRanges();
+ assertEquals(1, fromRanges.size());
+ assertArrayEquals(new int[] { 1, 30 }, fromRanges.get(0));
+ // 11-20 maps to 11-15, 91-95
+ toRanges = compound.getToRanges();
+ assertEquals(2, toRanges.size());
+ assertArrayEquals(new int[] { 11, 15 }, toRanges.get(0));
+ assertArrayEquals(new int[] { 91, 95 }, toRanges.get(1));
+
+ /*
+ * 1:3 plus 3:1 should result in 1:1
+ */
+ ml1 = new MapList(new int[] { 21, 40 }, new int[] { 13, 72 }, 1, 3);
+ ml2 = new MapList(new int[] { 1, 300 }, new int[] { 51, 70, 121, 200 },
+ 3, 1);
+ compound = ml1.traverse(ml2);
+
+ assertEquals(1, compound.getFromRatio());
+ assertEquals(1, compound.getToRatio());
+ fromRanges = compound.getFromRanges();
+ assertEquals(1, fromRanges.size());
+ assertArrayEquals(new int[] { 21, 40 }, fromRanges.get(0));
+ // 13-72 maps 3:1 to 55-70, 121-124
+ toRanges = compound.getToRanges();
+ assertEquals(2, toRanges.size());
+ assertArrayEquals(new int[] { 55, 70 }, toRanges.get(0));
+ assertArrayEquals(new int[] { 121, 124 }, toRanges.get(1));
+
+ /*
+ * 3:1 plus 1:3 should result in 1:1
+ */
+ ml1 = new MapList(new int[] { 31, 90 }, new int[] { 13, 32 }, 3, 1);
+ ml2 = new MapList(new int[] { 11, 40 }, new int[] { 41, 50, 71, 150 },
+ 1, 3);
+ compound = ml1.traverse(ml2);
+
+ assertEquals(1, compound.getFromRatio());
+ assertEquals(1, compound.getToRatio());
+ fromRanges = compound.getFromRanges();
+ assertEquals(1, fromRanges.size());
+ assertArrayEquals(new int[] { 31, 90 }, fromRanges.get(0));
+ // 13-32 maps to 47-50,71-126
+ toRanges = compound.getToRanges();
+ assertEquals(2, toRanges.size());
+ assertArrayEquals(new int[] { 47, 50 }, toRanges.get(0));
+ assertArrayEquals(new int[] { 71, 126 }, toRanges.get(1));
+
+ /*
+ * method returns null if not all regions are mapped through
+ */
+ ml1 = new MapList(new int[] { 1, 50 }, new int[] { 101, 150 }, 1, 1);
+ ml2 = new MapList(new int[] { 131, 180 }, new int[] { 201, 250 }, 1, 3);
+ compound = ml1.traverse(ml2);
+ assertNull(compound);
+ }
+
+ /**
+ * Test that method that inspects for the (first) forward or reverse 'to' range.
+ * Single position ranges are ignored.
+ */
+ @Test(groups = { "Functional" })
+ public void testIsToForwardsStrand()
+ {
+ // [3-9] declares forward strand
+ MapList ml = new MapList(new int[] { 20, 11 },
+ new int[]
+ { 2, 2, 3, 9, 12, 11 }, 1, 1);
+ assertTrue(ml.isToForwardStrand());
+
+ // [11-5] declares reverse strand ([13-14] is ignored)
+ ml = new MapList(new int[] { 20, 11 },
+ new int[]
+ { 2, 2, 11, 5, 13, 14 }, 1, 1);
+ assertFalse(ml.isToForwardStrand());
+
+ // all single position ranges - defaults to forward strand
+ ml = new MapList(new int[] { 3, 1 }, new int[] { 2, 2, 4, 4, 6, 6 }, 1,
+ 1);
+ assertTrue(ml.isToForwardStrand());
+ }
}
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
import org.testng.annotations.BeforeClass;
MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
proteinView, dnaView, dnaSelection, dnaHidden);
assertEquals("[]", dnaSelection.getSelected().toString());
- List<int[]> hidden = dnaHidden.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[0, 4]", Arrays.toString(hidden.get(0)));
+ Iterator<int[]> regions = dnaHidden.iterator();
+ assertEquals(1, dnaHidden.getNumberOfRegions());
+ assertEquals("[0, 4]", Arrays.toString(regions.next()));
/*
* Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
proteinSelection.hideSelectedColumns(1, hiddenCols);
MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
proteinView, dnaView, dnaSelection, dnaHidden);
- hidden = dnaHidden.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
+ regions = dnaHidden.iterator();
+ assertEquals(1, dnaHidden.getNumberOfRegions());
+ assertEquals("[0, 3]", Arrays.toString(regions.next()));
/*
* Column 2 in protein picks up gaps only - no mapping
proteinSelection.hideSelectedColumns(2, hiddenCols);
MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
proteinView, dnaView, dnaSelection, dnaHidden);
- assertTrue(dnaHidden.getHiddenColumnsCopy().isEmpty());
+ assertEquals(0, dnaHidden.getNumberOfRegions());
/*
* Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
proteinView, dnaView, dnaSelection, dnaHidden);
assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString());
- hidden = dnaHidden.getHiddenColumnsCopy();
- assertEquals(1, hidden.size());
- assertEquals("[5, 10]", Arrays.toString(hidden.get(0)));
+ regions = dnaHidden.iterator();
+ assertEquals(1, dnaHidden.getNumberOfRegions());
+ assertEquals("[5, 10]", Arrays.toString(regions.next()));
/*
* Combine hiding columns 1 and 3 to get discontiguous hidden columns
proteinSelection.hideSelectedColumns(3, hiddenCols);
MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
proteinView, dnaView, dnaSelection, dnaHidden);
- hidden = dnaHidden.getHiddenColumnsCopy();
- assertEquals(2, hidden.size());
- assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
- assertEquals("[5, 10]", Arrays.toString(hidden.get(1)));
+ regions = dnaHidden.iterator();
+ assertEquals(2, dnaHidden.getNumberOfRegions());
+ assertEquals("[0, 3]", Arrays.toString(regions.next()));
+ assertEquals("[5, 10]", Arrays.toString(regions.next()));
}
@Test(groups = { "Functional" })
assertEquals("[12, 11, 8, 4]", Arrays.toString(ranges));
}
+ @Test(groups = { "Functional" })
+ public void testRangeContains()
+ {
+ /*
+ * both forward ranges
+ */
+ assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 1, 10 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 2, 10 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 1, 9 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 4, 5 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 0, 9 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ -10, -9 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 1, 11 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 11, 12 }));
+
+ /*
+ * forward range, reverse query
+ */
+ assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 10, 1 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 9, 1 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 10, 2 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 5, 5 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 11, 1 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
+ 10, 0 }));
+
+ /*
+ * reverse range, forward query
+ */
+ assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 1, 10 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 1, 9 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 2, 10 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 6, 6 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 6, 11 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 11, 20 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ -3, -2 }));
+
+ /*
+ * both reverse
+ */
+ assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 10, 1 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 9, 1 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 10, 2 }));
+ assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 3, 3 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 11, 1 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 10, 0 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ 12, 11 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
+ -5, -8 }));
+
+ /*
+ * bad arguments
+ */
+ assertFalse(MappingUtils.rangeContains(new int[] { 1, 10, 12 },
+ new int[] {
+ 1, 10 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 },
+ new int[] { 1 }));
+ assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, null));
+ assertFalse(MappingUtils.rangeContains(null, new int[] { 1, 10 }));
+ }
+
@Test(groups = "Functional")
public void testRemoveEndPositions()
{
--- /dev/null
+package jalview.util;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+public class MathUtilsTest
+{
+ @Test(groups = "Functional")
+ public void testGcd()
+ {
+ assertEquals(MathUtils.gcd(0, 0), 0);
+ assertEquals(MathUtils.gcd(0, 1), 1);
+ assertEquals(MathUtils.gcd(1, 0), 1);
+ assertEquals(MathUtils.gcd(1, 1), 1);
+ assertEquals(MathUtils.gcd(1, -1), 1);
+ assertEquals(MathUtils.gcd(-1, 1), 1);
+ assertEquals(MathUtils.gcd(2, 3), 1);
+ assertEquals(MathUtils.gcd(4, 2), 2);
+ assertEquals(MathUtils.gcd(2, 4), 2);
+ assertEquals(MathUtils.gcd(2, -4), 2);
+ assertEquals(MathUtils.gcd(-2, 4), 2);
+ assertEquals(MathUtils.gcd(-2, -4), 2);
+ assertEquals(MathUtils.gcd(2 * 3 * 5 * 7 * 11, 3 * 7 * 13 * 17), 3 * 7);
+ }
+}
assertEquals("", StringUtils.toSentenceCase(""));
assertNull(StringUtils.toSentenceCase(null));
}
+
+ @Test(groups = { "Functional" })
+ public void testStripHtmlTags()
+ {
+ assertNull(StringUtils.stripHtmlTags(null));
+ assertEquals("", StringUtils.stripHtmlTags(""));
+ assertEquals(
+ "<a href=\"something\">label</href>",
+ StringUtils
+ .stripHtmlTags("<html><a href=\"something\">label</href></html>"));
+
+ // if no "<html>" tag, < and > get html-encoded (not sure why)
+ assertEquals("<a href=\"something\">label</href>",
+ StringUtils.stripHtmlTags("<a href=\"something\">label</href>"));
+
+ // </body> gets removed but not <body> (is this intentional?)
+ assertEquals("<body><p>hello",
+ StringUtils.stripHtmlTags("<html><body><p>hello</body></html>"));
+
+ assertEquals("kdHydro < 12.53",
+ StringUtils.stripHtmlTags("kdHydro < 12.53"));
+ }
}
--- /dev/null
+package jalview.util.matcher;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import java.util.Locale;
+
+import org.testng.annotations.Test;
+
+public class ConditionTest
+{
+ @Test(groups = "Functional")
+ public void testToString()
+ {
+ Locale.setDefault(Locale.UK);
+ assertEquals(Condition.Contains.toString(), "Contains");
+ assertEquals(Condition.NotContains.toString(), "Does not contain");
+ assertEquals(Condition.Matches.toString(), "Matches");
+ assertEquals(Condition.NotMatches.toString(), "Does not match");
+ assertEquals(Condition.Present.toString(), "Is present");
+ assertEquals(Condition.NotPresent.toString(), "Is not present");
+ assertEquals(Condition.LT.toString(), "<");
+ assertEquals(Condition.LE.toString(), "<=");
+ assertEquals(Condition.GT.toString(), ">");
+ assertEquals(Condition.GE.toString(), ">=");
+ assertEquals(Condition.EQ.toString(), "=");
+ assertEquals(Condition.NE.toString(), "not =");
+
+ /*
+ * repeat call to get coverage of value caching
+ */
+ assertEquals(Condition.NE.toString(), "not =");
+ }
+
+ @Test(groups = "Functional")
+ public void testGetStableName()
+ {
+ assertEquals(Condition.Contains.getStableName(), "Contains");
+ assertEquals(Condition.NotContains.getStableName(), "NotContains");
+ assertEquals(Condition.Matches.getStableName(), "Matches");
+ assertEquals(Condition.NotMatches.getStableName(), "NotMatches");
+ assertEquals(Condition.Present.getStableName(), "Present");
+ assertEquals(Condition.NotPresent.getStableName(), "NotPresent");
+ assertEquals(Condition.LT.getStableName(), "LT");
+ assertEquals(Condition.LE.getStableName(), "LE");
+ assertEquals(Condition.GT.getStableName(), "GT");
+ assertEquals(Condition.GE.getStableName(), "GE");
+ assertEquals(Condition.EQ.getStableName(), "EQ");
+ assertEquals(Condition.NE.getStableName(), "NE");
+ }
+
+ @Test(groups = "Functional")
+ public void testFromString()
+ {
+ assertEquals(Condition.fromString("Contains"), Condition.Contains);
+ // not case sensitive
+ assertEquals(Condition.fromString("contains"), Condition.Contains);
+ assertEquals(Condition.fromString("CONTAINS"), Condition.Contains);
+ assertEquals(Condition.fromString("NotContains"),
+ Condition.NotContains);
+ assertEquals(Condition.fromString("Matches"), Condition.Matches);
+ assertEquals(Condition.fromString("NotMatches"), Condition.NotMatches);
+ assertEquals(Condition.fromString("Present"), Condition.Present);
+ assertEquals(Condition.fromString("NotPresent"), Condition.NotPresent);
+ assertEquals(Condition.fromString("LT"), Condition.LT);
+ assertEquals(Condition.fromString("LE"), Condition.LE);
+ assertEquals(Condition.fromString("GT"), Condition.GT);
+ assertEquals(Condition.fromString("GE"), Condition.GE);
+ assertEquals(Condition.fromString("EQ"), Condition.EQ);
+ assertEquals(Condition.fromString("NE"), Condition.NE);
+
+ assertNull(Condition.fromString("Equals"));
+ assertNull(Condition.fromString(""));
+ assertNull(Condition.fromString(null));
+ }
+}
--- /dev/null
+package jalview.util.matcher;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.Locale;
+
+import org.testng.annotations.Test;
+
+import junit.extensions.PA;
+
+public class MatcherTest
+{
+ @Test(groups = "Functional")
+ public void testConstructor()
+ {
+ MatcherI m = new Matcher(Condition.Contains, "foo");
+ assertEquals(m.getCondition(), Condition.Contains);
+ assertEquals(m.getPattern(), "foo");
+ assertEquals(PA.getValue(m, "uppercasePattern"), "FOO");
+ assertEquals(m.getFloatValue(), 0f);
+
+ m = new Matcher(Condition.GT, -2.1f);
+ assertEquals(m.getCondition(), Condition.GT);
+ assertEquals(m.getPattern(), "-2.1");
+ assertEquals(m.getFloatValue(), -2.1f);
+
+ m = new Matcher(Condition.NotContains, "-1.2f");
+ assertEquals(m.getCondition(), Condition.NotContains);
+ assertEquals(m.getPattern(), "-1.2f");
+ assertEquals(m.getFloatValue(), 0f);
+
+ m = new Matcher(Condition.GE, "-1.2f");
+ assertEquals(m.getCondition(), Condition.GE);
+ assertEquals(m.getPattern(), "-1.2");
+ assertEquals(m.getFloatValue(), -1.2f);
+
+ try
+ {
+ new Matcher(null, 0f);
+ fail("Expected exception");
+ } catch (NullPointerException e)
+ {
+ // expected
+ }
+
+ try
+ {
+ new Matcher(Condition.LT, "123,456");
+ fail("Expected exception");
+ } catch (NumberFormatException e)
+ {
+ // expected
+ }
+ }
+
+ /**
+ * Tests for float comparison conditions
+ */
+ @Test(groups = "Functional")
+ public void testMatches_float()
+ {
+ /*
+ * EQUALS test
+ */
+ MatcherI m = new Matcher(Condition.EQ, 2f);
+ assertTrue(m.matches("2"));
+ assertTrue(m.matches("2.0"));
+ assertFalse(m.matches("2.01"));
+
+ /*
+ * NOT EQUALS test
+ */
+ m = new Matcher(Condition.NE, 2f);
+ assertFalse(m.matches("2"));
+ assertFalse(m.matches("2.0"));
+ assertTrue(m.matches("2.01"));
+
+ /*
+ * >= test
+ */
+ m = new Matcher(Condition.GE, 2f);
+ assertTrue(m.matches("2"));
+ assertTrue(m.matches("2.1"));
+ assertFalse(m.matches("1.9"));
+
+ /*
+ * > test
+ */
+ m = new Matcher(Condition.GT, 2f);
+ assertFalse(m.matches("2"));
+ assertTrue(m.matches("2.1"));
+ assertFalse(m.matches("1.9"));
+
+ /*
+ * <= test
+ */
+ m = new Matcher(Condition.LE, 2f);
+ assertTrue(m.matches("2"));
+ assertFalse(m.matches("2.1"));
+ assertTrue(m.matches("1.9"));
+
+ /*
+ * < test
+ */
+ m = new Matcher(Condition.LT, 2f);
+ assertFalse(m.matches("2"));
+ assertFalse(m.matches("2.1"));
+ assertTrue(m.matches("1.9"));
+ }
+
+ @Test(groups = "Functional")
+ public void testMatches_floatNullOrInvalid()
+ {
+ for (Condition cond : Condition.values())
+ {
+ if (cond.isNumeric())
+ {
+ MatcherI m = new Matcher(cond, 2f);
+ assertFalse(m.matches(null));
+ assertFalse(m.matches(""));
+ assertFalse(m.matches("two"));
+ }
+ }
+ }
+
+ /**
+ * Tests for string comparison conditions
+ */
+ @Test(groups = "Functional")
+ public void testMatches_pattern()
+ {
+ /*
+ * Contains
+ */
+ MatcherI m = new Matcher(Condition.Contains, "benign");
+ assertTrue(m.matches("benign"));
+ assertTrue(m.matches("MOSTLY BENIGN OBSERVED")); // not case-sensitive
+ assertFalse(m.matches("pathogenic"));
+ assertFalse(m.matches(null));
+
+ /*
+ * does not contain
+ */
+ m = new Matcher(Condition.NotContains, "benign");
+ assertFalse(m.matches("benign"));
+ assertFalse(m.matches("MOSTLY BENIGN OBSERVED")); // not case-sensitive
+ assertTrue(m.matches("pathogenic"));
+ assertTrue(m.matches(null)); // null value passes this condition
+
+ /*
+ * matches
+ */
+ m = new Matcher(Condition.Matches, "benign");
+ assertTrue(m.matches("benign"));
+ assertTrue(m.matches(" Benign ")); // trim before testing
+ assertFalse(m.matches("MOSTLY BENIGN"));
+ assertFalse(m.matches("pathogenic"));
+ assertFalse(m.matches(null));
+
+ /*
+ * does not match
+ */
+ m = new Matcher(Condition.NotMatches, "benign");
+ assertFalse(m.matches("benign"));
+ assertFalse(m.matches(" Benign ")); // trim before testing
+ assertTrue(m.matches("MOSTLY BENIGN"));
+ assertTrue(m.matches("pathogenic"));
+ assertTrue(m.matches(null));
+
+ /*
+ * value is present (is not null)
+ */
+ m = new Matcher(Condition.Present, null);
+ assertTrue(m.matches("benign"));
+ assertTrue(m.matches(""));
+ assertFalse(m.matches(null));
+
+ /*
+ * value is not present (is null)
+ */
+ m = new Matcher(Condition.NotPresent, null);
+ assertFalse(m.matches("benign"));
+ assertFalse(m.matches(""));
+ assertTrue(m.matches(null));
+
+ /*
+ * a float with a string match condition will be treated as string
+ */
+ Matcher m1 = new Matcher(Condition.Contains, "32");
+ assertFalse(m1.matches(-203f));
+ assertTrue(m1.matches(-4321.0f));
+ }
+
+ /**
+ * If a float is passed with a string condition it gets converted to a string
+ */
+ @Test(groups = "Functional")
+ public void testMatches_floatWithStringCondition()
+ {
+ MatcherI m = new Matcher(Condition.Contains, 1.2e-6f);
+ assertTrue(m.matches("1.2e-6"));
+
+ m = new Matcher(Condition.Contains, 0.0000001f);
+ assertTrue(m.matches("1.0e-7"));
+ assertTrue(m.matches("1.0E-7"));
+ assertFalse(m.matches("0.0000001f"));
+ }
+
+ @Test(groups = "Functional")
+ public void testToString()
+ {
+ Locale.setDefault(Locale.ENGLISH);
+
+ MatcherI m = new Matcher(Condition.LT, 1.2e-6f);
+ assertEquals(m.toString(), "< 1.2E-6");
+
+ m = new Matcher(Condition.NotMatches, "ABC");
+ assertEquals(m.toString(), "Does not match 'ABC'");
+
+ m = new Matcher(Condition.Contains, -1.2f);
+ assertEquals(m.toString(), "Contains '-1.2'");
+ }
+
+ @Test(groups = "Functional")
+ public void testEquals()
+ {
+ /*
+ * string condition
+ */
+ MatcherI m = new Matcher(Condition.NotMatches, "ABC");
+ assertFalse(m.equals(null));
+ assertFalse(m.equals("foo"));
+ assertTrue(m.equals(m));
+ assertTrue(m.equals(new Matcher(Condition.NotMatches, "ABC")));
+ // not case-sensitive:
+ assertTrue(m.equals(new Matcher(Condition.NotMatches, "abc")));
+ assertFalse(m.equals(new Matcher(Condition.Matches, "ABC")));
+ assertFalse(m.equals(new Matcher(Condition.NotMatches, "def")));
+
+ /*
+ * numeric conditions
+ */
+ m = new Matcher(Condition.LT, -1f);
+ assertFalse(m.equals(null));
+ assertFalse(m.equals("foo"));
+ assertTrue(m.equals(m));
+ assertTrue(m.equals(new Matcher(Condition.LT, -1f)));
+ assertTrue(m.equals(new Matcher(Condition.LT, "-1f")));
+ assertTrue(m.equals(new Matcher(Condition.LT, "-1.00f")));
+ assertFalse(m.equals(new Matcher(Condition.LE, -1f)));
+ assertFalse(m.equals(new Matcher(Condition.GE, -1f)));
+ assertFalse(m.equals(new Matcher(Condition.NE, -1f)));
+ assertFalse(m.equals(new Matcher(Condition.LT, 1f)));
+ assertFalse(m.equals(new Matcher(Condition.LT, -1.1f)));
+ }
+
+ @Test(groups = "Functional")
+ public void testHashCode()
+ {
+ MatcherI m1 = new Matcher(Condition.NotMatches, "ABC");
+ MatcherI m2 = new Matcher(Condition.NotMatches, "ABC");
+ MatcherI m3 = new Matcher(Condition.NotMatches, "AB");
+ MatcherI m4 = new Matcher(Condition.Matches, "ABC");
+ assertEquals(m1.hashCode(), m2.hashCode());
+ assertNotEquals(m1.hashCode(), m3.hashCode());
+ assertNotEquals(m1.hashCode(), m4.hashCode());
+ assertNotEquals(m3.hashCode(), m4.hashCode());
+ }
+}
for (Field field : fields)
{
field.setAccessible(true);
- if (!copyConstructorIgnores(field.getName()))
+ if (!copyConstructorIgnores(field))
{
changeValue(vs1, field);
}
for (Field field1 : fields)
{
- final Object value1 = field1.get(vs1);
- final Object value2 = field1.get(vs2);
- String msg = "Mismatch in " + field1.getName() + "(" + value1 + "/"
+ if (!copyConstructorIgnores(field1))
+ {
+ final Object value1 = field1.get(vs1);
+ final Object value2 = field1.get(vs2);
+ String msg = "Mismatch in " + field1.getName() + "(" + value1 + "/"
+ value2 + ") - not set in copy constructor?";
- assertEquals(msg, value1, value2);
+ assertEquals(msg, value1, value2);
+ }
}
assertEquals("Hashcode not equals", vs1.hashCode(), vs2.hashCode());
}
/**
- * Add any field names in here that we expect to be ignored by the copy
- * constructor
+ * Add tests here for any fields that we expect to be ignored by
+ * the copy constructor
*
- * @param name
+ * @param field
* @return
*/
- private boolean copyConstructorIgnores(String name)
+ private boolean copyConstructorIgnores(Field field)
{
/*
- * currently none!
+ * just instrumentation added by test coverage while testing
*/
+ String type = field.getClass().toString();
+ if (type.toString().contains("com_atlassian_clover"))
+ {
+ // instrumentation added for test coverage - ignore
+ return true;
+ }
return false;
}
Field[] fields = ViewStyle.class.getDeclaredFields();
for (Field field : fields)
{
- field.setAccessible(true);
- Object oldValue = field.get(vs2);
- changeValue(vs2, field);
- assertFalse("equals method ignores " + field.getName(),
+ if (!copyConstructorIgnores(field))
+ {
+ field.setAccessible(true);
+ Object oldValue = field.get(vs2);
+ changeValue(vs2, field);
+ assertFalse("equals method ignores " + field.getName(),
vs1.equals(vs2));
- if (vs1.hashCode() == vs2.hashCode())
- {
- // uncomment next line to see which fields hashCode ignores
- // System.out.println("hashCode ignores " + field.getName());
+ if (vs1.hashCode() == vs2.hashCode())
+ {
+ // uncomment next line to see which fields hashCode ignores
+ // System.out.println("hashCode ignores " + field.getName());
+ }
+ // restore original value before testing the next field
+ field.set(vs2, oldValue);
}
- // restore original value before testing the next field
- field.set(vs2, oldValue);
}
}
}
*/
package jalview.ws;
+import static org.testng.Assert.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.gui.JvOptionPane;
import jalview.structure.StructureImportSettings;
import jalview.structure.StructureImportSettings.StructureParser;
import jalview.ws.seqfetcher.DbSourceProxy;
+import java.util.Arrays;
import java.util.List;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
Cache.applicationProperties.setProperty("ADD_SS_ANN",
Boolean.TRUE.toString());
- sf = new SequenceFetcher(false);
+ sf = new SequenceFetcher();
}
/**
testRetrieveProteinSeqFromPDB();
}
+ private class TestRetrieveObject
+ {
+ String id;
+
+ int expectedHeight;
+
+ public TestRetrieveObject(String id, int expectedHeight)
+ {
+ super();
+ this.id = id;
+ this.expectedHeight = expectedHeight;
+ }
+
+ }
+
+ private List<TestRetrieveObject> toRetrieve = Arrays.asList(
+ new TestRetrieveObject("1QIP", 4),
+ new TestRetrieveObject("4IM2", 1));
+
private void testRetrieveProteinSeqFromPDB() throws Exception
{
List<DbSourceProxy> sps = sf.getSourceProxy("PDB");
- AlignmentI response = sps.get(0).getSequenceRecords("1QIP");
- assertTrue(response != null);
- assertTrue(response.getHeight() == 4);
- for (SequenceI sq : response.getSequences())
+ StringBuilder errors = new StringBuilder();
+ for (TestRetrieveObject str : toRetrieve)
{
- assertTrue("No annotation transfered to sequence.",
- sq.getAnnotation().length > 0);
- assertTrue("No PDBEntry on sequence.",
- sq.getAllPDBEntries().size() > 0);
- org.testng.Assert
- .assertEquals(sq.getEnd() - sq.getStart() + 1,
- sq.getLength(),
- "Sequence start/end doesn't match number of residues in sequence");
+ AlignmentI response = sps.get(0).getSequenceRecords(str.id);
+ assertTrue("No aligment for " + str.id, response != null);
+ assertEquals(response.getHeight(), str.expectedHeight,
+ "Number of chains for " + str.id);
+ for (SequenceI sq : response.getSequences())
+ {
+ assertTrue("No annotation transfered to sequence " + sq.getName(),
+ sq.getAnnotation().length > 0);
+ assertTrue("No PDBEntry on sequence " + sq.getName(),
+ sq.getAllPDBEntries().size() > 0);
+ // FIXME: should test that all residues extracted as sequences from
+ // chains in structure have a mapping to data in the structure
+ List<SequenceFeature> prev = null;
+ int lastp = -1;
+ for (int col = 1; col <= sq.getLength(); col++)
+ {
+ List<SequenceFeature> sf = sq.findFeatures(col, col, "RESNUM");
+ if (sf.size() != 1)
+ {
+ errors.append(
+ str.id + ": " +
+ "Expected one feature at column (position): "
+ + (col - 1)
+ + " (" + sq.findPosition(col - 1) + ")"
+ + ": saw "
+ + sf.size());
+ errors.append("\n");
+ if (prev != null)
+ {
+ errors.append("Last Feature was at position " + lastp + ": "
+ + prev.get(0).toString());
+ errors.append("\n");
+ }
+ }
+ else
+ {
+ prev = sf;
+ lastp = sq.findPosition(col - 1);
+ }
+ }
+ }
+ }
+ if (errors.length() > 0)
+ {
+ Assert.fail(errors.toString());
}
}
-
}
*/
public static void main(String[] argv)
{
- // TODO: extracted from SequenceFetcher - convert to proper unit test with
+ // TODO: extracted from SequenceFetcher - convert to network dependent
+ // functional integration test with
// assertions
String usage = "SequenceFetcher.main [-nodas] [<DBNAME> [<ACCNO>]]\n"
+ "With no arguments, all DbSources will be queried with their test Accession number.\n"
+ "With one argument, the argument will be resolved to one or more db sources and each will be queried with their test accession only.\n"
- + "If given two arguments, SequenceFetcher will try to find the DbFetcher corresponding to <DBNAME> and retrieve <ACCNO> from it.\n"
- + "The -nodas option will exclude DAS sources from the database fetchers Jalview will try to use.";
- boolean withDas = true;
- if (argv != null && argv.length > 0
- && argv[0].toLowerCase().startsWith("-nodas"))
+ + "If given two arguments, SequenceFetcher will try to find the DbFetcher corresponding to <DBNAME> and retrieve <ACCNO> from it.";
+
+ if (argv != null && argv.length > 0)
{
- withDas = false;
String targs[] = new String[argv.length - 1];
System.arraycopy(argv, 1, targs, 0, targs.length);
argv = targs;
}
if (argv != null && argv.length > 0)
{
- List<DbSourceProxy> sps = new SequenceFetcher(withDas)
+ List<DbSourceProxy> sps = new SequenceFetcher()
.getSourceProxy(argv[0]);
if (sps != null)
System.out.println(usage);
return;
}
- ASequenceFetcher sfetcher = new SequenceFetcher(withDas);
+ ASequenceFetcher sfetcher = new SequenceFetcher();
String[] dbSources = sfetcher.getSupportedDb();
for (int dbsource = 0; dbsource < dbSources.length; dbsource++)
{
String testQuery)
{
AlignmentI ds = null;
- Vector<Object[]> noProds = new Vector<Object[]>();
+ Vector<Object[]> noProds = new Vector<>();
System.out.println("Source: " + sp.getDbName() + " (" + db
+ "): retrieving test:" + sp.getTestQuery());
{
* along with Jalview. If not, see <http://www.gnu.org/licenses/>.
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
-package jalview.ws.seqfetcher;
+package jalview.ws.dbsources;
-import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertEquals;
import jalview.bin.Cache;
-import jalview.gui.JvOptionPane;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-public class DasSequenceFetcher
+public class PfamFullTest
{
-
@BeforeClass(alwaysRun = true)
- public void setUpJvOptionPane()
+ public void setUp()
{
- JvOptionPane.setInteractiveMode(false);
- JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
}
- @Test(groups = { "Network" })
- public void testDasRegistryContact()
+ @Test(groups = "Functional")
+ public void testGetURL()
{
- Cache.getDasSourceRegistry().refreshSources();
- assertTrue(Cache.getDasSourceRegistry().getSources().isEmpty(),
- "Expected to find no DAS sources at the registry. Check config.");
- }
+ String path = "pfam.xfam.org/family/ABC/alignment/full";
+ // with default value for domain
+ String url = new PfamFull().getURL(" abc ");
+ assertEquals(url, "https://" + path);
+
+ // with override in properties
+ Cache.setProperty(Pfam.PFAM_BASEURL_KEY, "http://pfam.xfam.org");
+ url = new PfamFull().getURL(" abc ");
+ assertEquals(url, "http://" + path);
+ }
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ws.dbsources;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.bin.Cache;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class PfamSeedTest
+{
+ @BeforeClass(alwaysRun = true)
+ public void setUp()
+ {
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ }
+
+ @Test(groups = "Functional")
+ public void testGetURL()
+ {
+ String path = "pfam.xfam.org/family/ABC/alignment/seed";
+
+ // with default value for domain
+ String url = new PfamSeed().getURL(" abc ");
+ assertEquals(url, "https://" + path);
+
+ // with override in properties
+ Cache.setProperty(Pfam.PFAM_BASEURL_KEY, "http://pfam.xfam.org");
+ url = new PfamSeed().getURL(" abc ");
+ assertEquals(url, "http://" + path);
+ }
+}
Cache.applicationProperties.setProperty("ADD_SS_ANN",
Boolean.TRUE.toString());
- sf = new SequenceFetcher(false);
+ sf = new SequenceFetcher();
}
@DataProvider(name = "AccessionData")
@Test(groups = { "Network" })
public void testUniprotFreeTextSearch() throws Exception
{
- List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+ List<FTSDataColumnI> wantedFields = new ArrayList<>();
FTSRestClientI client = UniProtFTSRestClient.getInstance();
wantedFields.add(client.getDataColumnByNameOrCode("id"));
wantedFields.add(client.getDataColumnByNameOrCode("entry name"));
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ws.dbsources;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.bin.Cache;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class RfamFullTest
+{
+ @BeforeClass(alwaysRun = true)
+ public void setUp()
+ {
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ }
+
+ @Test(groups = "Functional")
+ public void testGetURL()
+ {
+ String path = "rfam.xfam.org/family/ABC/alignment/full";
+
+ // with default value for domain
+ String url = new RfamFull().getURL(" abc ");
+ assertEquals(url, "https://" + path);
+
+ // with override in properties
+ Cache.setProperty(Rfam.RFAM_BASEURL_KEY, "http://rfam.xfam.org");
+ url = new RfamFull().getURL(" abc ");
+ assertEquals(url, "http://" + path);
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ws.dbsources;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.bin.Cache;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class RfamSeedTest
+{
+ @BeforeClass(alwaysRun = true)
+ public void setUp()
+ {
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ }
+
+ @Test(groups = "Functional")
+ public void testGetURL()
+ {
+ String path = "rfam.xfam.org/family/ABC/alignment/stockholm";
+
+ // with default value for domain
+ String url = new RfamSeed().getURL(" abc ");
+ assertEquals(url, "https://" + path);
+
+ // with override in properties
+ Cache.setProperty(Rfam.RFAM_BASEURL_KEY, "http://rfam.xfam.org");
+ url = new RfamSeed().getURL(" abc ");
+ assertEquals(url, "http://" + path);
+ }
+}
import java.io.StringReader;
import java.util.Vector;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+ "<feature type=\"signal peptide\" evidence=\"7\"><location><begin position=\"1\"/><end position=\"18\"/></location></feature>"
+ "<feature type=\"propeptide\" description=\"Activation peptide\" id=\"PRO_0000027399\" evidence=\"9 16 17 18\"><location><begin position=\"19\"/><end position=\"20\"/></location></feature>"
+ "<feature type=\"chain\" description=\"Granzyme B\" id=\"PRO_0000027400\"><location><begin position=\"21\"/><end position=\"247\"/></location></feature>"
+ + "<feature type=\"sequence variant\"><original>M</original><variation>L</variation><location><position position=\"41\"/></location></feature>"
+ + "<feature type=\"sequence variant\" description=\"Pathogenic\"><original>M</original><variation>L</variation><location><position position=\"41\"/></location></feature>"
+ + "<feature type=\"sequence variant\" description=\"Pathogenic\"><original>M</original><location><position position=\"41\"/></location></feature>"
+ + "<feature type=\"sequence variant\" description=\"Foo\"><variation>L</variation><variation>LMV</variation><original>M</original><location><position position=\"42\"/></location></feature>"
+ + "<feature type=\"sequence variant\" description=\"Foo\"><variation>LL</variation><variation>LMV</variation><original>ML</original><location><begin position=\"42\"/><end position=\"43\"/></location></feature>"
+ + "<feature type=\"sequence variant\" description=\"Foo Too\"><variation>LL</variation><variation>LMVK</variation><original>MLML</original><location><begin position=\"42\"/><end position=\"45\"/></location></feature>"
+ "<sequence length=\"10\" mass=\"27410\" checksum=\"8CB760AACF88FE6C\" modified=\"2008-01-15\" version=\"1\">MHAPL VSKDL</sequence></entry>"
+ "</uniprot>";
* Check sequence features
*/
Vector<UniprotFeature> features = entry.getFeature();
- assertEquals(3, features.size());
+ assertEquals(9, features.size());
UniprotFeature sf = features.get(0);
assertEquals("signal peptide", sf.getType());
assertNull(sf.getDescription());
assertEquals(21, sf.getBegin());
assertEquals(247, sf.getEnd());
+ sf = features.get(3);
+ assertEquals("sequence variant", sf.getType());
+ assertNull(sf.getDescription());
+ assertEquals(41, sf.getPosition());
+ assertEquals(41, sf.getBegin());
+ assertEquals(41, sf.getEnd());
+
+ sf = features.get(4);
+ assertEquals("sequence variant", sf.getType());
+ assertEquals("Pathogenic", sf.getDescription());
+ assertEquals(41, sf.getPosition());
+ assertEquals(41, sf.getBegin());
+ assertEquals(41, sf.getEnd());
+
+ sf = features.get(5);
+ assertEquals("sequence variant", sf.getType());
+ assertEquals("Pathogenic", sf.getDescription());
+ assertEquals(41, sf.getPosition());
+ assertEquals(41, sf.getBegin());
+ assertEquals(41, sf.getEnd());
+
+ sf = features.get(6);
+ assertEquals("sequence variant", sf.getType());
+ assertEquals("Foo",
+ sf.getDescription());
+ assertEquals(42, sf.getPosition());
+ assertEquals(42, sf.getBegin());
+ assertEquals(42, sf.getEnd());
+ Assert.assertEquals(Uniprot.getDescription(sf),
+ "<html>p.Met42Leu" + "<br/> "
+ + "p.Met42LeuMetVal Foo</html>");
+
+ sf = features.get(7);
+ assertEquals(42, sf.getBegin());
+ assertEquals(43, sf.getEnd());
+ Assert.assertEquals(Uniprot.getDescription(sf),
+ "<html>p.MetLeu42LeuLeu" + "<br/> "
+ + "p.MetLeu42LeuMetVal Foo</html>");
+
+ sf = features.get(8);
+ assertEquals(42, sf.getBegin());
+ assertEquals(45, sf.getEnd());
+ Assert.assertEquals(Uniprot.getDescription(sf),
+ "<html>p.MLML42LeuLeu" + "<br/> "
+ + "p.MLML42LMVK Foo Too</html>");
+
/*
* Check cross-references
*/
assertEquals(expectedDescription,
Uniprot.getUniprotEntryDescription(entry));
}
+
+ @Test(groups = { "Functional" })
+ public void testGetDescription()
+ {
+ UniprotFeature uf = new UniprotFeature();
+ assertEquals("", Uniprot.getDescription(uf));
+
+ uf.setDescription("Hello");
+ assertEquals("Hello", Uniprot.getDescription(uf));
+
+ uf.setPosition(23);
+ uf.setOriginal("K");
+ Vector<String> vars = new Vector<>();
+ vars.add("y");
+ uf.setVariation(vars);
+ assertEquals("p.Lys23Tyr Hello", Uniprot.getDescription(uf));
+
+ // multiple variants generate an html description over more than one line
+ vars.add("W");
+ assertEquals("<html>p.Lys23Tyr<br/> p.Lys23Trp Hello</html>",
+ Uniprot.getDescription(uf));
+
+ /*
+ * indel cases
+ * up to 3 bases (original or variant) are shown using 3 letter code
+ */
+ vars.clear();
+ vars.add("KWE");
+ uf.setOriginal("KLS");
+ assertEquals("p.LysLeuSer23LysTrpGlu Hello",
+ Uniprot.getDescription(uf));
+
+ // adding a fourth original base switches to single letter code
+ uf.setOriginal("KLST");
+ assertEquals("p.KLST23LysTrpGlu Hello", Uniprot.getDescription(uf));
+
+ // adding a fourth variant switches to single letter code
+ vars.clear();
+ vars.add("KWES");
+ assertEquals("p.KLST23KWES Hello", Uniprot.getDescription(uf));
+
+ vars.clear();
+ vars.add("z"); // unknown variant - fails gracefully
+ uf.setOriginal("K");
+ assertEquals("p.Lys23z Hello", Uniprot.getDescription(uf));
+
+ uf.setVariation(null); // variant missing - is ignored
+ assertEquals("Hello", Uniprot.getDescription(uf));
+ }
}
@Test(groups = { "External" })
public void testPfamFullAndSeed() throws Exception
{
- PfamFull pff = new PfamFull();
+ Pfam pff = new PfamFull();
PfamSeed pfseed = new PfamSeed();
AlignmentI fullpf = pff.getSequenceRecords(pff.getTestQuery());
@BeforeTest(alwaysRun = true)
public void populateExpectedMapping() throws SiftsException
{
- expectedMapping.put(51, new int[] { 1, 2 });
- expectedMapping.put(52, new int[] { 2, 7 });
- expectedMapping.put(53, new int[] { 3, 12 });
- expectedMapping.put(54, new int[] { 4, 24 });
- expectedMapping.put(55, new int[] { 5, 33 });
- expectedMapping.put(56, new int[] { 6, 40 });
- expectedMapping.put(57, new int[] { 7, 47 });
- expectedMapping.put(58, new int[] { 8, 55 });
- expectedMapping.put(59, new int[] { 9, 62 });
- expectedMapping.put(60, new int[] { 10, 69 });
- expectedMapping.put(61, new int[] { 11, 76 });
- expectedMapping.put(62, new int[] { 12, 83 });
- expectedMapping.put(63, new int[] { 13, 87 });
- expectedMapping.put(64, new int[] { 14, 95 });
- expectedMapping.put(65, new int[] { 15, 102 });
- expectedMapping.put(66, new int[] { 16, 111 });
- expectedMapping.put(67, new int[] { 17, 122 });
- expectedMapping.put(68, new int[] { 18, 131 });
- expectedMapping.put(69, new int[] { 19, 137 });
- expectedMapping.put(70, new int[] { 20, 144 });
- expectedMapping.put(71, new int[] { 21, 152 });
- expectedMapping.put(72, new int[] { 22, 160 });
- expectedMapping.put(73, new int[] { 23, 167 });
- expectedMapping.put(74, new int[] { 24, 179 });
- expectedMapping.put(75, new int[] { 25, 187 });
- expectedMapping.put(76, new int[] { 26, 195 });
- expectedMapping.put(77, new int[] { 27, 203 });
- expectedMapping.put(78, new int[] { 28, 208 });
- expectedMapping.put(79, new int[] { 29, 213 });
- expectedMapping.put(80, new int[] { 30, 222 });
- expectedMapping.put(81, new int[] { 31, 231 });
- expectedMapping.put(82, new int[] { 32, 240 });
- expectedMapping.put(83, new int[] { 33, 244 });
- expectedMapping.put(84, new int[] { 34, 252 });
- expectedMapping.put(85, new int[] { 35, 260 });
- expectedMapping.put(86, new int[] { 36, 268 });
- expectedMapping.put(87, new int[] { 37, 275 });
- expectedMapping.put(88, new int[] { 38, 287 });
- expectedMapping.put(89, new int[] { 39, 293 });
- expectedMapping.put(90, new int[] { 40, 299 });
- expectedMapping.put(91, new int[] { 41, 310 });
- expectedMapping.put(92, new int[] { 42, 315 });
- expectedMapping.put(93, new int[] { 43, 319 });
- expectedMapping.put(94, new int[] { 44, 325 });
- expectedMapping.put(95, new int[] { 45, 331 });
- expectedMapping.put(96, new int[] { 46, 337 });
- expectedMapping.put(97, new int[] { 47, 343 });
- expectedMapping.put(98, new int[] { 48, 349 });
- expectedMapping.put(99, new int[] { 49, 354 });
- expectedMapping.put(100, new int[] { 50, 358 });
- expectedMapping.put(101, new int[] { 51, 367 });
- expectedMapping.put(102, new int[] { 52, 375 });
- expectedMapping.put(103, new int[] { 53, 384 });
- expectedMapping.put(104, new int[] { 54, 391 });
- expectedMapping.put(105, new int[] { 55, 395 });
- expectedMapping.put(106, new int[] { 56, 401 });
- expectedMapping.put(107, new int[] { 57, 409 });
- expectedMapping.put(108, new int[] { 58, 417 });
- expectedMapping.put(109, new int[] { 59, 426 });
- expectedMapping.put(110, new int[] { 60, 434 });
- expectedMapping.put(111, new int[] { 61, 442 });
- expectedMapping.put(112, new int[] { 62, 451 });
- expectedMapping.put(113, new int[] { 63, 457 });
- expectedMapping.put(114, new int[] { 64, 468 });
- expectedMapping.put(115, new int[] { 65, 476 });
- expectedMapping.put(116, new int[] { 66, 484 });
- expectedMapping.put(117, new int[] { 67, 492 });
- expectedMapping.put(118, new int[] { 68, 500 });
- expectedMapping.put(119, new int[] { 69, 509 });
- expectedMapping.put(120, new int[] { 70, 517 });
- expectedMapping.put(121, new int[] { 71, 525 });
- expectedMapping.put(122, new int[] { 72, 534 });
- expectedMapping.put(123, new int[] { 73, 538 });
- expectedMapping.put(124, new int[] { 74, 552 });
- expectedMapping.put(125, new int[] { 75, 559 });
- expectedMapping.put(126, new int[] { 76, 567 });
- expectedMapping.put(127, new int[] { 77, 574 });
- expectedMapping.put(128, new int[] { 78, 580 });
- expectedMapping.put(129, new int[] { 79, 585 });
- expectedMapping.put(130, new int[] { 80, 590 });
- expectedMapping.put(131, new int[] { 81, 602 });
- expectedMapping.put(132, new int[] { 82, 609 });
- expectedMapping.put(133, new int[] { 83, 616 });
- expectedMapping.put(134, new int[] { 84, 622 });
- expectedMapping.put(135, new int[] { 85, 630 });
- expectedMapping.put(136, new int[] { 86, 637 });
- expectedMapping.put(137, new int[] { 87, 644 });
- expectedMapping.put(138, new int[] { 88, 652 });
- expectedMapping.put(139, new int[] { 89, 661 });
- expectedMapping.put(140, new int[] { 90, 668 });
- expectedMapping.put(141, new int[] { 91, 678 });
- expectedMapping.put(142, new int[] { 92, 687 });
- expectedMapping.put(143, new int[] { 93, 696 });
- expectedMapping.put(144, new int[] { 94, 705 });
- expectedMapping.put(145, new int[] { 95, 714 });
- expectedMapping.put(146, new int[] { 96, 722 });
- expectedMapping.put(147, new int[] { 97, 729 });
+ expectedMapping.put(51, new int[] { 1, 2, 1 });
+ expectedMapping.put(52, new int[] { 2, 7, 2 });
+ expectedMapping.put(53, new int[] { 3, 12, 3 });
+ expectedMapping.put(54, new int[] { 4, 24, 4 });
+ expectedMapping.put(55, new int[] { 5, 33, 5 });
+ expectedMapping.put(56, new int[] { 6, 40, 6 });
+ expectedMapping.put(57, new int[] { 7, 47, 7 });
+ expectedMapping.put(58, new int[] { 8, 55, 8 });
+ expectedMapping.put(59, new int[] { 9, 62, 9 });
+ expectedMapping.put(60, new int[] { 10, 69, 10 });
+ expectedMapping.put(61, new int[] { 11, 76, 11 });
+ expectedMapping.put(62, new int[] { 12, 83, 12 });
+ expectedMapping.put(63, new int[] { 13, 87, 13 });
+ expectedMapping.put(64, new int[] { 14, 95, 14 });
+ expectedMapping.put(65, new int[] { 15, 102, 15 });
+ expectedMapping.put(66, new int[] { 16, 111, 16 });
+ expectedMapping.put(67, new int[] { 17, 122, 17 });
+ expectedMapping.put(68, new int[] { 18, 131, 18 });
+ expectedMapping.put(69, new int[] { 19, 137, 19 });
+ expectedMapping.put(70, new int[] { 20, 144, 20 });
+ expectedMapping.put(71, new int[] { 21, 152, 21 });
+ expectedMapping.put(72, new int[] { 22, 160, 22 });
+ expectedMapping.put(73, new int[] { 23, 167, 23 });
+ expectedMapping.put(74, new int[] { 24, 179, 24 });
+ expectedMapping.put(75, new int[] { 25, 187, 25 });
+ expectedMapping.put(76, new int[] { 26, 195, 26 });
+ expectedMapping.put(77, new int[] { 27, 203, 27 });
+ expectedMapping.put(78, new int[] { 28, 208, 28 });
+ expectedMapping.put(79, new int[] { 29, 213, 29 });
+ expectedMapping.put(80, new int[] { 30, 222, 30 });
+ expectedMapping.put(81, new int[] { 31, 231, 31 });
+ expectedMapping.put(82, new int[] { 32, 240, 32 });
+ expectedMapping.put(83, new int[] { 33, 244, 33 });
+ expectedMapping.put(84, new int[] { 34, 252, 34 });
+ expectedMapping.put(85, new int[] { 35, 260, 35 });
+ expectedMapping.put(86, new int[] { 36, 268, 36 });
+ expectedMapping.put(87, new int[] { 37, 275, 37 });
+ expectedMapping.put(88, new int[] { 38, 287, 38 });
+ expectedMapping.put(89, new int[] { 39, 293, 39 });
+ expectedMapping.put(90, new int[] { 40, 299, 40 });
+ expectedMapping.put(91, new int[] { 41, 310, 41 });
+ expectedMapping.put(92, new int[] { 42, 315, 42 });
+ expectedMapping.put(93, new int[] { 43, 319, 43 });
+ expectedMapping.put(94, new int[] { 44, 325, 44 });
+ expectedMapping.put(95, new int[] { 45, 331, 45 });
+ expectedMapping.put(96, new int[] { 46, 337, 46 });
+ expectedMapping.put(97, new int[] { 47, 343, 47 });
+ expectedMapping.put(98, new int[] { 48, 349, 48 });
+ expectedMapping.put(99, new int[] { 49, 354, 49 });
+ expectedMapping.put(100, new int[] { 50, 358, 50 });
+ expectedMapping.put(101, new int[] { 51, 367, 51 });
+ expectedMapping.put(102, new int[] { 52, 375, 52 });
+ expectedMapping.put(103, new int[] { 53, 384, 53 });
+ expectedMapping.put(104, new int[] { 54, 391, 54 });
+ expectedMapping.put(105, new int[] { 55, 395, 55 });
+ expectedMapping.put(106, new int[] { 56, 401, 56 });
+ expectedMapping.put(107, new int[] { 57, 409, 57 });
+ expectedMapping.put(108, new int[] { 58, 417, 58 });
+ expectedMapping.put(109, new int[] { 59, 426, 59 });
+ expectedMapping.put(110, new int[] { 60, 434, 60 });
+ expectedMapping.put(111, new int[] { 61, 442, 61 });
+ expectedMapping.put(112, new int[] { 62, 451, 62 });
+ expectedMapping.put(113, new int[] { 63, 457, 63 });
+ expectedMapping.put(114, new int[] { 64, 468, 64 });
+ expectedMapping.put(115, new int[] { 65, 476, 65 });
+ expectedMapping.put(116, new int[] { 66, 484, 66 });
+ expectedMapping.put(117, new int[] { 67, 492, 67 });
+ expectedMapping.put(118, new int[] { 68, 500, 68 });
+ expectedMapping.put(119, new int[] { 69, 509, 69 });
+ expectedMapping.put(120, new int[] { 70, 517, 70 });
+ expectedMapping.put(121, new int[] { 71, 525, 71 });
+ expectedMapping.put(122, new int[] { 72, 534, 72 });
+ expectedMapping.put(123, new int[] { 73, 538, 73 });
+ expectedMapping.put(124, new int[] { 74, 552, 74 });
+ expectedMapping.put(125, new int[] { 75, 559, 75 });
+ expectedMapping.put(126, new int[] { 76, 567, 76 });
+ expectedMapping.put(127, new int[] { 77, 574, 77 });
+ expectedMapping.put(128, new int[] { 78, 580, 78 });
+ expectedMapping.put(129, new int[] { 79, 585, 79 });
+ expectedMapping.put(130, new int[] { 80, 590, 80 });
+ expectedMapping.put(131, new int[] { 81, 602, 81 });
+ expectedMapping.put(132, new int[] { 82, 609, 82 });
+ expectedMapping.put(133, new int[] { 83, 616, 83 });
+ expectedMapping.put(134, new int[] { 84, 622, 84 });
+ expectedMapping.put(135, new int[] { 85, 630, 85 });
+ expectedMapping.put(136, new int[] { 86, 637, 86 });
+ expectedMapping.put(137, new int[] { 87, 644, 87 });
+ expectedMapping.put(138, new int[] { 88, 652, 88 });
+ expectedMapping.put(139, new int[] { 89, 661, 89 });
+ expectedMapping.put(140, new int[] { 90, 668, 90 });
+ expectedMapping.put(141, new int[] { 91, 678, 91 });
+ expectedMapping.put(142, new int[] { 92, 687, 92 });
+ expectedMapping.put(143, new int[] { 93, 696, 93 });
+ expectedMapping.put(144, new int[] { 94, 705, 94 });
+ expectedMapping.put(145, new int[] { 95, 714, 95 });
+ expectedMapping.put(146, new int[] { 96, 722, 96 });
+ expectedMapping.put(147, new int[] { 97, 729, 97 });
}
@BeforeTest(alwaysRun = true)
atom.atomIndex = 7;
atoms.add(atom);
int actualAtomIndex = siftsClient.getAtomIndex(1, atoms);
- Assert.assertEquals(actualAtomIndex, -1);
+ Assert.assertEquals(actualAtomIndex, siftsClient.UNASSIGNED);
actualAtomIndex = siftsClient.getAtomIndex(43, atoms);
Assert.assertEquals(actualAtomIndex, 7);
}
<method name="addElement">
<object class="com.zerog.ia.installer.util.LAXPropertyData" objectID="97fa91cfa6f7">
<property name="propertyValue">
- <string><![CDATA[268400000]]></string>
+ <string><![CDATA[1060000000]]></string>
</property>
<property name="propertyName">
<string><![CDATA[lax.nl.java.option.java.heap.size.max]]></string>
<method name="addElement">
<object class="com.zerog.ia.installer.util.LAXPropertyData" objectID="97f991ffa6f7">
<property name="propertyValue">
- <string><![CDATA[33554432]]></string>
+ <string><![CDATA[1000000000]]></string>
</property>
<property name="propertyName">
<string><![CDATA[lax.nl.java.option.java.heap.size.initial]]></string>
<string><![CDATA[logo.gif]]></string>
</property>
<property name="smallIconPath">
- <string><![CDATA[/home/cruisecontrol/jalview/resources/images/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/resources/images/]]></string>
</property>
<property name="largeIconPath">
- <string><![CDATA[/home/cruisecontrol/jalview/resources/images/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/resources/images/]]></string>
</property>
<property name="macOSXIconPath">
- <string><![CDATA[/home/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
</property>
<property name="macOSXIconName">
<string><![CDATA[mac_logo.icns]]></string>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/dist/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/dist/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<string><![CDATA[664]]></string>
</property>
<property name="sourceName">
- <string><![CDATA[groovy-all-2.4.6-indy.jar]]></string>
+ <string><![CDATA[groovy-all-2.4.12-indy.jar]]></string>
</property>
<property name="overrideUnixPermissions">
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>true</boolean>
</property>
<property name="destinationName">
- <string><![CDATA[groovy-all-2.4.6-indy.jar]]></string>
+ <string><![CDATA[groovy-all-2.4.12-indy.jar]]></string>
</property>
<property name="fileSize">
<long>6149494</long>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
</object>
</method>
<method name="addElement">
+ <object class="com.zerog.ia.installer.actions.InstallZipfile" objectID="9a1f46efeef911a">
+ <property name="belongsToUninstallPhase">
+ <boolean>false</boolean>
+ </property>
+ <property name="rollbackEnabledCancel">
+ <boolean>true</boolean>
+ </property>
+ <property name="rollbackEnabledError">
+ <boolean>true</boolean>
+ </property>
+ <property name="ruleExpression">
+ <string><![CDATA[]]></string>
+ </property>
+ <property name="unixPermissions">
+ <string><![CDATA[664]]></string>
+ </property>
+ <property name="sourceName">
+ <string><![CDATA[VAqua5-patch.jar]]></string>
+ </property>
+ <property name="overrideUnixPermissions">
+ <boolean>false</boolean>
+ </property>
+ <property name="sourcePath">
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
+ </property>
+ <property name="shouldUninstall">
+ <boolean>true</boolean>
+ </property>
+ <property name="rollbackEnabledCancel">
+ <boolean>true</boolean>
+ </property>
+ <property name="rollbackEnabledError">
+ <boolean>true</boolean>
+ </property>
+ <property name="destinationName">
+ <string><![CDATA[VAqua5-patch.jar]]></string>
+ </property>
+ <property name="fileSize">
+ <long>1370564</long>
+ </property>
+ <property name="macBinary">
+ <boolean>false</boolean>
+ </property>
+ <property name="targetCheckKind">
+ <int>0</int>
+ </property>
+ <property name="ruleExpression">
+ <string><![CDATA[]]></string>
+ </property>
+ </object>
+ </method>
+ <method name="addElement">
<object class="com.zerog.ia.installer.actions.InstallZipfile" objectID="1936efeefab93">
<property name="belongsToUninstallPhase">
<boolean>false</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<string><![CDATA[The installer cannot run on your configuration. It will now quit.]]></string>
</property>
<property name="userSplashPath">
- <string><![CDATA[/home/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
</property>
<property name="userSplashName">
<string><![CDATA[jalview.gif]]></string>
<boolean>true</boolean>
</property>
<property name="buildOutputLocation">
- <string><![CDATA[/opt/homes/cruisecontrol/live/cruisecontrol/checkout/next-release-jalview/utils/InstallAnywhere/Jalview_Build_Output]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/utils/InstallAnywhere/Jalview_Build_Output]]></string>
</property>
<property name="relatedProjectSettings">
<object class="com.zerog.ia.installer.RelatedProjectSettings" objectID="97f2363da6ac">
</method>
<method name="put">
<string><![CDATA[com.zerog.ia.installer.options.valid.vm.list]]></string>
- <string><![CDATA[1.8+]]></string>
+ <string><![CDATA[1.8*]]></string>
</method>
<method name="put">
<string><![CDATA[com.zerog.ia.project.build.last.date]]></string>
</method>
<method name="put">
<string><![CDATA[com.zerog.ia.installer.options.platform.macosx.vm.version]]></string>
- <string><![CDATA[1.8+]]></string>
+ <string><![CDATA[1.8*]]></string>
</method>
<method name="put">
<string><![CDATA[com.zerog.ia.build.platform.java.novm]]></string>
<boolean>true</boolean>
</property>
<property name="backgroundImagePath">
- <string><![CDATA[/home/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
</property>
<property name="backgroundImageName">
<string><![CDATA[align.gif]]></string>
<object refID="24485f8ca673"/>
<object refID="24485f8ba674"/>
<object refID="24485f8ca674"/>
+ <object refID="9a1f46efeef911a"/>
<object class="com.zerog.ia.installer.actions.CreateShortcut" objectID="3cd8e2ffa672">
<property name="belongsToUninstallPhase">
<boolean>false</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/doc/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/doc/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/lib]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/lib]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<object refID="24485f8ca673"/>
<object refID="24485f8ba674"/>
<object refID="24485f8ca674"/>
+ <object refID="9a1f46efeef911a"/>
<object refID="b1a16838a449"/>
<object refID="b1a16839a449"/>
<object refID="495aeddb8b3d"/>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples/groovy]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples/groovy]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/home/cruisecontrol/jalview/examples]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/examples]]></string>
</property>
<property name="shouldUninstall">
<boolean>false</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/opt/homes/cruisecontrol/live/cruisecontrol/checkout/next-release-jalview/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<boolean>false</boolean>
</property>
<property name="sourcePath">
- <string><![CDATA[/opt/homes/cruisecontrol/live/cruisecontrol/checkout/next-release-jalview/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/]]></string>
</property>
<property name="shouldUninstall">
<boolean>true</boolean>
<string><![CDATA[]]></string>
</property>
<property name="imagePath">
- <string><![CDATA[/home/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
+ <string><![CDATA[/homes/cruisecontrol/jalview/utils/InstallAnywhere/]]></string>
</property>
<property name="imageName">
<string><![CDATA[bartonGroup.gif]]></string>
To run application:
-java -Djava.ext.dirs=JALVIEW_HOME/lib -jar JALVIEW_HOME/jalview.jar [-help ... ]
+java -classpath "JALVIEW_HOME/lib/*" -jar JALVIEW_HOME/jalview.jar [-help ... ]
Replace JALVIEW_HOME with the full path to Jalview Installation Directory.
Use -help to see the available command line arguments.
For best results use a Sun java run time environment (not the gcj gnu java, sorry!).
-If you want to the java runtime bundled with Jalview, then launch jalview like this:
+If you want to use the java runtime bundled with Jalview, then launch jalview like this:
-JAVA_HOME=JALVIEW_HOME/jre JALVIEW_HOME/jre/bin/java -Djava.ext.dirs=JALVIEW_HOME/lib -jar JALVIEW_HOME/jalview.jar
+in Windows:
+JAVA_HOME=JALVIEW_HOME/jre JALVIEW_HOME/jre/bin/java -classpath "JALVIEW_HOME/lib/*;JALVIEW_HOME/jalview.jar" jalview.bin.Jalview
+
+in Linux:
+JAVA_HOME=JALVIEW_HOME/jre JALVIEW_HOME/jre/bin/java -classpath "JALVIEW_HOME/lib/*:JALVIEW_HOME/jalview.jar" jalview.bin.Jalview
+
+in macOS:
+JAVA_HOME=JALVIEW_HOME/jre/Contents/Home JALVIEW_HOME/jre/Contents/Home/bin/java -classpath "JALVIEW_HOME/lib/*:JALVIEW_HOME/jalview.jar" jalview.bin.Jalview
+
+Note: ensure the -classpath argument is quoted and only use a terminating wildcard (e.g. 'DIR/*') to refer to all jar files in a directory, don't use e.g. 'DIR/*.jar'
-Please Note: the -jar jalview.jar option launches the jalview.bin.Jalview class in the jalview.jar
##################
<project name="jalviewInstallAnywhere" default="build" basedir=".">
<property name="IA_LOCATION" value="/home/cruisecontrol/InstallAnywhere 2013/"/>
<property name="IA_PROJECT" location="Jalview.iap_xml"/>
- <property name="ABS_PATH" value="/home/cruisecontrol/jalview"/> <!-- \/utils\/InstallAnywhere"/> --> <!--/home/cruisecontrol/jalview"/> -->
+ <property name="ABS_PATH" value="/homes/cruisecontrol/jalview"/> <!-- \/utils\/InstallAnywhere"/> --> <!--/home/cruisecontrol/jalview"/> -->
<!-- location of top level of jalview distribution directory -->
<property name="CUR_PATH" location="../../." />
<property name="USER_HOME" location="~" />
import java.io.IOException;
import java.util.HashSet;
import java.util.Properties;
+import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
private int javaCount;
- private HashSet<String> invalidKeys;
+ private Set<String> invalidKeys;
+
+ private Set<String> dynamicKeys;
/**
* Runs the scan given the path to the root of Java source directories
private void doMain(String srcPath) throws IOException
{
System.out.println("Scanning " + srcPath
- + " for calls to MessageManager");
+ + " for calls to MessageManager\n");
sourcePath = srcPath;
loadMessages();
File dir = new File(srcPath);
System.out.println(srcPath + " not found");
return;
}
- invalidKeys = new HashSet<String>();
+
+ invalidKeys = new HashSet<>();
+ dynamicKeys = new HashSet<>();
+
if (dir.isDirectory())
{
scanDirectory(dir);
private void reportResults()
{
System.out.println("\nScanned " + javaCount + " source files");
- System.out.println("Message.properties has " + messages.size()
+ System.out.println(
+ "Messages.properties has " + messages.size()
+ " keys");
- System.out.println("Found " + invalidKeys.size()
- + " possibly invalid parameter calls");
+ if (!invalidKeys.isEmpty())
+ {
+ System.out.println("Found " + invalidKeys.size()
+ + " possibly invalid parameter call"
+ + (invalidKeys.size() > 1 ? "s" : ""));
+ }
- System.out.println(messageKeys.size()
- + " keys not found, either unused or constructed dynamically");
+ System.out.println("Keys not found, assumed constructed dynamically:");
+ int dynamicCount = 0;
for (String key : messageKeys)
{
- System.out.println(" " + key);
+ if (isDynamic(key))
+ {
+ System.out.println(" " + key);
+ dynamicCount++;
+ }
+ }
+
+ if (dynamicCount < messageKeys.size())
+ {
+ System.out.println((messageKeys.size() - dynamicCount)
+ + " keys not found, possibly unused");
+ for (String key : messageKeys)
+ {
+ if (!isDynamic(key))
+ {
+ System.out.println(" " + key);
+ }
+ }
+ }
+ System.out
+ .println("(Run i18nAnt.xml to compare other message bundles)");
+ }
+
+ /**
+ * Answers true if the key starts with one of the recorded dynamic key stubs,
+ * else false
+ *
+ * @param key
+ * @return
+ */
+ private boolean isDynamic(String key)
+ {
+ for (String dynamic : dynamicKeys)
+ {
+ if (key.startsWith(dynamic))
+ {
+ return true;
+ }
}
+ return false;
}
/**
continue;
}
+ String messageKey = getMessageKey(method, methodArgs);
+
if (METHOD3 == method)
{
System.out.println(String.format("Dynamic key at %s line %s %s",
path.substring(sourcePath.length()), lineNos, line));
+ String key = messageKey.substring(1, messageKey.length() - 1);
+ dynamicKeys.add(key);
continue;
}
- String messageKey = getMessageKey(method, methodArgs);
if (messageKey == null)
{
System.out.println(String.format("Trouble parsing %s line %s %s",
messages.load(reader);
reader.close();
- messageKeys = new TreeSet<String>();
+ messageKeys = new TreeSet<>();
for (Object key : messages.keySet())
{
messageKeys.add((String) key);
Checkstyle for Jalview
----------------------
+See
+https://issues.jalview.org/browse/JAL-1854
http://checkstyle.sourceforge.net/
GNU LGPL
- Help | Eclipse Marketplace
- search for checkstyle
- install eclipse-cs checkstyle plugin
-The current version is 6.19.1 (August 2016).
+Change Log
+----------
+See http://checkstyle.sourceforge.net/releasenotes.html
+Aug 2016 Initial version used is 6.19.1
+Dec 2018 Updated to 8.12.0 (latest on Eclipse Marketplace, 8.15 is latest release)
+ SuppressionCommentFilter relocated (changed in 8.1)
+ FileContentsHolder removed (changed in 8.2)
+ Updates to import-control.xml for code changes (htsjdk, stackoverflowusers)
+
Config
------
Option 2: on demand on selected code
- right-click on a class or package and Checkstyle | Check code with checkstyle
- (or Clear Checkstyle violations to remove checkstyle warnings)
+ - recommended to use this as a QA step when changing or reviewing code
Checkstyle rules
----------------
Tips
----
Sometimes checkstyle needs a kick before it will refresh its findings.
- A whitespace edit in checkstyle.xml usually does this. There may be better ways.
+ Click the 'refresh' icon at top right in Eclipse | Preferences | Checkstyle.
Invalid configuration files may result in checkstyle failing with an error reported
in the Eclipse log file.
- Help | Installation Details | Configuration takes you to a screen with a
+ Eclipse | About | Installation Details | Configuration takes you to a screen with a
'View Error Log' button.
Sometimes checkstyle can fail silently. Try 'touching' (editing) config files, failing
<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="[\\/]org[\\/]stackoverflowusers*"/>
<suppress checks="[a-zA-Z0-9]*" files="[\\/]uk[\\/]ac*"/>
<!--
</module>
<!--
- Allow suppression of rules by comments, e.g.:
- // CHECKSTYLE.OFF: ParameterNumber
- ..method declaration
- // CHECKSTYLE.ON: ParameterNumber
- -->
- <module name="SuppressionCommentFilter">
- <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
- <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
- <property name="checkFormat" value="$1"/>
- </module>
-
- <!--
Check language bundles have the same keys and no duplicates
(ensure Checkstyle is configured to scan non-source files)
-->
<property name="tabWidth" value="4"/>
<!--
- Enables parsing of suppressions comments
- see http://checkstyle.sourceforge.net/config_filters.html#SuppressionCommentFilter
+ Allow suppression of rules by comments, e.g.:
+ // CHECKSTYLE.OFF: ParameterNumber
+ ..method declaration
+ // CHECKSTYLE.ON: ParameterNumber
-->
- <module name="FileContentsHolder"/>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
+ <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
+ <property name="checkFormat" value="$1"/>
+ </module>
<!-- ****************************** -->
<!-- NAMING STANDARDS -->
<allow pkg="compbio.metadata" class="jalview.gui.WsJobParameters"/>
<allow pkg="fr.orsay.lri.varna" class="jalview.gui.AppVarna"/>
<allow pkg="fr.orsay.lri.varna" class="jalview.gui.AppVarnaBinding"/>
+ <allow pkg="org.stackoverflowusers.file" class="jalview.gui.Desktop"/>
<allow pkg="uk.ac.vamsas" class="jalview.gui.VamsasApplication"/>
</subpackage>
<allow pkg="uk.ac.vamsas"/>
<allow pkg="fr.orsay.lri.varna"/>
<allow pkg="MCview"/>
+ <subpackage name="vcf">
+ <allow pkg="htsjdk\.*" regex="true"/>
+ </subpackage>
</subpackage>
<subpackage name="javascript">