From: Jim Procter Date: Wed, 9 May 2018 20:20:00 +0000 (+0100) Subject: Merge branch 'releases/Release_2_10_4_Branch' X-Git-Tag: Release_2_10_4b1~2 X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=3f53fef393541cb63beb8766a4f3922b8c420579;hp=4e176cf637cfbbb4dbb3414ad35ff36f6a5907d3 Merge branch 'releases/Release_2_10_4_Branch' --- diff --git a/.ant-targets-build.xml b/.ant-targets-build.xml index 15432a1..7ef21f1 100644 --- a/.ant-targets-build.xml +++ b/.ant-targets-build.xml @@ -1,31 +1,2 @@ -build -buildPropertiesFile -buildTests -buildextclients -buildindices -castorbinding -clean -compileApplet -distclean help -init -linkcheck -makeApplet -makedist -makefulldist -obfuscate -packageApplet -prepare -prepareTests -preparejnlp -prepubapplet_1 -pubapplet -runenv -signApplet -sourcedist -sourcedoc -sourcescrub -testclean -testng usage -writejnlpf diff --git a/.classpath b/.classpath index d704f10..3a05b47 100644 --- a/.classpath +++ b/.classpath @@ -49,10 +49,10 @@ + - @@ -69,5 +69,6 @@ + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 8a5e7a7..5908bb2 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ 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 diff --git a/RELEASE b/RELEASE index eb9d7cd..5ad87c8 100644 --- a/RELEASE +++ b/RELEASE @@ -1,2 +1,2 @@ -jalview.release=releases/Release_2_10_3_Branch -jalview.version=2.10.3b1 +jalview.release=releases/Release_2_10_4_Branch +jalview.version=2.10.4 diff --git a/THIRDPARTYLIBS b/THIRDPARTYLIBS index e0be904..e2baa85 100644 --- a/THIRDPARTYLIBS +++ b/THIRDPARTYLIBS @@ -49,6 +49,8 @@ jfreesvg-2.1.jar : GPL v3 licensed library from the JFree suite: http://www.jfre quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/ +vaqua: v4 (latest stable) by Alan Snyder et al. GPLv2 with Classpathe xception, also includes contributions from Quaqua: ownloaded from http://violetlib.org/vaqua/overview.html + 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 lib/biojava-core-4.1.0.jar LGPLv2.1 - latest license at https://github.com/biojava/biojava/blob/master/LICENSE diff --git a/benchmarking/README b/benchmarking/README index ccf53c1..d1ec146 100644 --- a/benchmarking/README +++ b/benchmarking/README @@ -27,6 +27,9 @@ to install the jalview.jar file in the local maven repository. The pom.xml in th To get JSON output instead use: java -jar target/benchmarks.jar -rf json + To run a specific benchmark file use: + java -jar target/benchmarks.jar + JSON output can be viewed quickly by drag-dropping on http://jmh.morethan.io/ To get help use the standard -h option: @@ -38,3 +41,4 @@ to install the jalview.jar file in the local maven repository. The pom.xml in th 6. If you make changes to the Jalview code everything will need to be refreshed, by performing steps 3-5 again. + diff --git a/benchmarking/src/main/java/org/jalview/HiddenColsIteratorsBenchmark.java b/benchmarking/src/main/java/org/jalview/HiddenColsIteratorsBenchmark.java new file mode 100644 index 0000000..477bfad --- /dev/null +++ b/benchmarking/src/main/java/org/jalview/HiddenColsIteratorsBenchmark.java @@ -0,0 +1,140 @@ +/* + * 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 . + * 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 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 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 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; + } +} diff --git a/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java b/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java index d3c67d7..07b76f9 100644 --- a/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java +++ b/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java @@ -47,128 +47,111 @@ import jalview.datamodel.HiddenColumns; @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 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 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 benchFindHiddenRegionPositions( - HiddenColsAndStartState tstate) - { - return tstate.h.findHiddenRegionPositions(); - } - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public ArrayList 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 diff --git a/benchmarking/src/main/java/org/jalview/SeqWidthBenchmark.java b/benchmarking/src/main/java/org/jalview/SeqWidthBenchmark.java new file mode 100644 index 0000000..a92d4f0 --- /dev/null +++ b/benchmarking/src/main/java/org/jalview/SeqWidthBenchmark.java @@ -0,0 +1,96 @@ +/* + * 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 . + * 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. * The Jalview Authors are detailed in the 'AUTHORS' file. --> - + @@ -36,7 +38,7 @@ - + @@ -96,6 +98,10 @@ + + + + @@ -106,8 +112,8 @@ - - + + @@ -176,17 +182,14 @@ - - - + - + @@ -298,6 +301,8 @@ + + @@ -425,7 +430,7 @@ - + @@ -452,8 +457,8 @@ - - j2se version="1.7+" + + j2se version="1.8+" @@ -582,7 +587,6 @@ - @@ -600,7 +604,6 @@ - @@ -625,7 +628,7 @@ - + diff --git a/examples/testdata/4IM2_missing.pdb b/examples/testdata/4IM2_missing.pdb new file mode 100644 index 0000000..35f94b2 --- /dev/null +++ b/examples/testdata/4IM2_missing.pdb @@ -0,0 +1,525 @@ +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 diff --git a/examples/testdata/4IM2_missing_noid.pdb b/examples/testdata/4IM2_missing_noid.pdb new file mode 100644 index 0000000..5a5ef94 --- /dev/null +++ b/examples/testdata/4IM2_missing_noid.pdb @@ -0,0 +1,524 @@ +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 diff --git a/examples/testdata/4IM2_nterm.pdb b/examples/testdata/4IM2_nterm.pdb new file mode 100644 index 0000000..48f7803 --- /dev/null +++ b/examples/testdata/4IM2_nterm.pdb @@ -0,0 +1,139 @@ +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 diff --git a/help/help.jhm b/help/help.jhm index 732f01b..d9a201a 100755 --- a/help/help.jhm +++ b/help/help.jhm @@ -22,7 +22,7 @@ - + @@ -54,6 +54,7 @@ + diff --git a/help/helpTOC.xml b/help/helpTOC.xml index 20dd8db..b218b88 100755 --- a/help/helpTOC.xml +++ b/help/helpTOC.xml @@ -24,6 +24,8 @@ + + diff --git a/help/html/features/chimera.html b/help/html/features/chimera.html index 68ac465..e1227de 100644 --- a/help/html/features/chimera.html +++ b/help/html/features/chimera.html @@ -211,41 +211,32 @@ 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.

+ trace.
+
-
  • EXPERIMENTAL FEATURES
    - - These are only available if the Tools→Enable - Experimental Features option is enabled. (Since Jalview 2.10.2) -
      -
    • Write Jalview features
      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).
      -
      If you use this option, please remember to select - the Refresh Menus option in Chimera's Render by - Attribute dialog box in order to see the attributes - derived from Jalview sequence features. -

      - View - this function's issue in Jalview's bug tracker
    • -
    • Fetch Chimera Attributes
      This - submenu lists available Chimera residue attributes that - can be imported as Jalview features on associated - sequences.
      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 Graduated feature colour - scheme. -
      View - this function's issue in Jalview's bug tracker
    • -
  • -
  • Help
    +
  • Write Jalview + features
    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).

    If you use this option, please + remember to select the Refresh Menus option in + Chimera's Render by Attribute dialog box in order to see the + attributes derived from Jalview sequence features. +
  • +
  • Fetch Chimera Attributes
    This + submenu lists available Chimera residue attributes that can + be imported as Jalview features on associated sequences.
    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 Graduated feature colour + scheme.
  • + +
  • Help
    • Chimera Help
      diff --git a/help/html/features/jmol.html b/help/html/features/jmol.html index 0cd6168..ac2489b 100644 --- a/help/html/features/jmol.html +++ b/help/html/features/jmol.html @@ -61,16 +61,10 @@

      -->

      Superposing structures based on - their aligned sequences
      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 Jmol→Align menu option from - the menu bar of the structure view window to superpose the - structures using the updated alignment.
      Sequence + their aligned sequences

      If several structures are shown + in a view, you can superimpose them using the corresponding + positions from the alignment via the Jmol→Align + menu option from the menu bar of the structure view window.
      Sequence based structure superposition was added in Jalview 2.6

      diff --git a/help/html/features/preferences.html b/help/html/features/preferences.html index b29b66b..50f864b 100755 --- a/help/html/features/preferences.html +++ b/help/html/features/preferences.html @@ -367,7 +367,7 @@ and PDB file association (if available). The Jalview id/start-end option is ignored if Modeller output is selected.

      - e"Editinge" Preferences tab + "Editing" Preferences tab

      There are currently three options available which can be selected / deselected.

      diff --git a/help/html/features/schooser_enter-id.png b/help/html/features/schooser_enter-id.png index f551c50..4af0d53 100644 Binary files a/help/html/features/schooser_enter-id.png and b/help/html/features/schooser_enter-id.png differ diff --git a/help/html/features/schooser_main.png b/help/html/features/schooser_main.png index ab69427..ca793fd 100644 Binary files a/help/html/features/schooser_main.png and b/help/html/features/schooser_main.png differ diff --git a/help/html/features/splitView.html b/help/html/features/splitView.html index be1bd66..e1c07c1 100644 --- a/help/html/features/splitView.html +++ b/help/html/features/splitView.html @@ -76,7 +76,7 @@ or "View→Nucleotide" (in the protein panel) allows you to show or hide one or other of the linked alignment panels.
    • -
    • Panel heights are adjusted dragging the divider between +
    • Panel heights are adjusted by dragging the divider between them using the mouse
    • "View→New View / Expand Views / Gather Views" behave as for a normal diff --git a/help/html/features/structurechooser.html b/help/html/features/structurechooser.html index fc71826..785c429 100644 --- a/help/html/features/structurechooser.html +++ b/help/html/features/structurechooser.html @@ -25,14 +25,14 @@

      - Structure Chooser + Structure Chooser Dialog Box

      - 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 "3D - Structure Data.." option from the Sequence ID panel's option from the Sequence ID panel's pop-up menu. The dialog provides:

      @@ -49,11 +49,16 @@

      Selecting and Viewing Structures

      +

      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.

      Once one or more structures have been selected, pressing the View - button will import them into Add button will import them a new or existing - structure view. + structure view. When multiple views are available, use the + drop-down menu to pick the target viewer for the structures.

      Automated discovery of structure data @@ -89,17 +94,16 @@ criteria (e.g. worst quality rather than best).

      - + -
      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). -

      +
      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).

      Exploration of meta-data for available structures

      Information on each structure available is displayed in columns @@ -109,7 +113,7 @@ Columns' tab and tick the columns which you want to see.

      + style="width: 464px; height: 173px;">
      Manual selection/association of PDB files with Sequences diff --git a/help/html/features/viewingpdbs.html b/help/html/features/viewingpdbs.html index 45d979f..b1ad4ba 100755 --- a/help/html/features/viewingpdbs.html +++ b/help/html/features/viewingpdbs.html @@ -82,6 +82,7 @@ provided it is installed and can be launched by Jalview. The default viewer can be configured in the Structure tab in the Tools→Preferences dialog box. +

      Structure data imported into Jalview can also be processed to display secondary structure and temperature factor annotation. See @@ -89,44 +90,30 @@ for more information.

      - After pressing the - 'View' button in the Structure Chooser
      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. +
      Controlling where the new structures + will be shown +
      The Structure Chooser offers several options + for viewing a structure.
      New View 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 Add + button. Jalview can automatically superimpose new structures based + on the linked alignments - but if this is not desirable, simple + un-tick the Superpose Structures checkbox. +

      -

      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.

      - If a single PDB structure is selected, one of the - following will happen: + Superposing structures
      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.

      - -
        -
      • If no structures are open, then an interactive display of - the structure will be opened in a new window.
      • - -
      • If another structure is already shown for the current - alignment, then you will be asked if you want to add and to the structure in the existing view. - (new feature in Jalview 2.6). -
      • - -
      • 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.
      • - -
      • See the Jmol - and Chimera PDB viewer help pages for - more information about the display. -
      • -
      - +

      + See the Jmol + and Chimera help pages for + more information about their capabilities.

      +

      Retrieving sequences from the PDB
      You can diff --git a/help/html/menus/desktopMenu.html b/help/html/menus/desktopMenu.html index a93ce4b..d716e33 100755 --- a/help/html/menus/desktopMenu.html +++ b/help/html/menus/desktopMenu.html @@ -86,7 +86,7 @@ the Groovy Console for interactive scripting.

    • -
    • Enable Experimental Features Enable or disable features still under development in Jalview's user interface. This setting is remembered in your preferences. +
  • Vamsas For more details, read the diff --git a/help/html/releases.html b/help/html/releases.html index 83d2ce4..993fcd5 100755 --- a/help/html/releases.html +++ b/help/html/releases.html @@ -70,6 +70,158 @@ li:before {
    + 2.10.4
    10/05/2018
    +
    + +
    + +
      +
    • + New Structure Chooser control + for disabling automatic superposition of multiple + structures and open structures in existing views +
    • +
    • + Mouse cursor changes to indicate Sequence + ID and annotation area margins can be click-dragged to + adjust them. +
    • +
    • + Jalview uses HTTPS for Uniprot, Xfam and + Ensembl services +
    • +
    • + Improved performance for large alignments + and lots of hidden columns +
    • +
    • + Improved performance when rendering lots + of features (particularly when transparency is disabled) +
    • +
    +
    + +
    +
      +
    • + Structure and Overview aren't updated + when Colour By Annotation threshold slider is adjusted +
    • +
    • + Slow redraw when Overview panel shown + overlapping alignment panel +
    • +
    • + Overview doesn't show end of unpadded + sequence as gaps +
    • +
    • + Cross-reference handling + improved: CDS not handled correctly if transcript has no + UTR +
    • +
    • + Secondary structure and temperature + factor annotation not added to sequence when local PDB + file associated with it by drag'n'drop or structure + chooser +
    • +
    • + Answering 'No' to PDB Autoassociate + dialog doesn't import PDB files dropped on an alignment +
    • +
    • + Linked scrolling via protein horizontal + scroll bar doesn't work for some CDS/Protein views +
    • +
    • + Trackpad scrolling is broken on OSX on + Java 1.8u153 onwards and Java 1.9u4+. +
    • +
    • + Tooltip shouldn't be displayed for empty + columns in annotation row +
    • +
    • + Preferences panel's ID Width control is not + honored in batch mode +
    • +
    • + Linked sequence highlighting doesn't work + for structures added to existing Jmol view +
    • +
    • + 'View Mappings' includes duplicate + entries after importing project with multiple views +
    • +
    • + Viewing or annotating Uniprot + protein sequences via SIFTS from associated PDB entries + with negative residue numbers or missing residues fails +
    • +
    • + Exception when shading sequence with negative + Temperature Factor values from annotated PDB files (e.g. + as generated by CONSURF) +
    • +
    • + Invert displayed features very slow when + structure and/or overview windows are also shown +
    • +
    • + Selecting columns from highlighted regions + very slow for alignments with large numbers of sequences +
    • +
    • + Copy Consensus fails for group consensus + with 'StringIndexOutOfBounds' +
    • +
    • + VAqua(4) provided as fallback Look and Feel for OSX + platforms running Java 10 +
    • +
    • + Adding a structure to existing structure + view appears to do nothing because the view is hidden behind the alignment view +
    • +
    + Applet +
      +
    • + Copy consensus sequence option in applet + should copy the group consensus when popup is opened on it +
    • +
    + Batch Mode +
      +
    • + Fixed ID width preference is not respected +
    • +
    + New Known Defects +
      +
    • + Exceptions occasionally raised when + editing a large alignment and overview is displayed +
    • +
    • + 'Overview updating' progress bar is shown + repeatedly after a series of edits even when the overview + is no longer reflecting updates +
    • +
    • + '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) +
    • +
    +
    + + + + +
    2.10.3b1
    24/1/2018
    diff --git a/help/html/whatsNew.html b/help/html/whatsNew.html index 6d75f0f..0abd2a7 100755 --- a/help/html/whatsNew.html +++ b/help/html/whatsNew.html @@ -24,40 +24,27 @@

    - What's new in Jalview 2.10.3b1 ? + What's new in Jalview 2.10.4 ?

    - This is the January 2018 patch release, which addresses critical bugs including trackpad function in OSX, and display of multiple 3D structures. - The full list bugs fixed in this release can be found in the 2.10.3b1 - Release Notes. In addition, Jalview 2.10.3 provides: + This is the May 2018 release of Jalview, and the last in the 2.10.x series. Jalview 2.10.4 includes:

      -
    • Faster and more responsive UI when importing and working - with wide alignments and handling hundreds and thousands of - sequence features
    • -
    • Improved usability with PDB and UniProt Free Text - Search dialog, and new tab for retrieval of sequences for lists of - IDs. -
    • -
    • Short names assigned to sequences retrieved from UniProt
    • -
    • Groovy console upgraded to 2.4.12 (improved support for Java 9)
    • +
    • Numerous efficiency improvements in the renderer and overview when working with large alignments with lots of hidden columns
    • +
    • Use of HTTPS when connecting to Uniprot, Ensembl and other EBI web services
    • +
    • Critical patches for running Jalview on OSX with Java 10
    • +
    • Easier adjustment of the Alignment ID panel and Annotation panel
    • +
    • Improved support for mapping between 3D Structures and Uniprot Protein Sequences
    • +
    • Improved support for discovering CDS and transcripts for Proteins and Ensembl gene IDs
    • +
    • New buttons on the Structure Chooser for adding structures + to an existing view, and disabling automatic superposition + according to linked alignments
    • +
    • Annotation transfer between Chimera and Jalview (formerly only + available in 'Experimental' mode)

    - Experimental Features + The full list of bugs fixed in this release can be found in the 2.10.4 + Release Notes.

    -

    - Remember, please enable the Experimental Features option in - the Jalview Desktop's Tools menu, and then restart Jalview - if you want to try out features below: -

    - - diff --git a/lib/VAqua4.jar b/lib/VAqua4.jar new file mode 100644 index 0000000..c1e7cfc Binary files /dev/null and b/lib/VAqua4.jar differ diff --git a/resources/images/idwidth.gif b/resources/images/idwidth.gif deleted file mode 100755 index c1bd8cb..0000000 Binary files a/resources/images/idwidth.gif and /dev/null differ diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index f526699..a80ac17 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -400,10 +400,6 @@ label.view_name_original = Original 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. @@ -1213,7 +1209,6 @@ label.pdb_sequence_fetcher = PDB Sequence Fetcher 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 diff --git a/resources/lang/Messages_es.properties b/resources/lang/Messages_es.properties index 77f053e..61bf42a 100644 --- a/resources/lang/Messages_es.properties +++ b/resources/lang/Messages_es.properties @@ -367,10 +367,6 @@ label.ignore_unmatched_dropped_files = Ignorar los ficheros sin coincidencias? 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. @@ -1172,7 +1168,6 @@ label.structures_filter=Filtro de Estructuras 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 diff --git a/src/MCview/PDBChain.java b/src/MCview/PDBChain.java index f4bd31c..904a860 100755 --- a/src/MCview/PDBChain.java +++ b/src/MCview/PDBChain.java @@ -45,11 +45,11 @@ public class PDBChain public String id; - public Vector bonds = new Vector(); + public Vector bonds = new Vector<>(); - public Vector atoms = new Vector(); + public Vector atoms = new Vector<>(); - public Vector residues = new Vector(); + public Vector residues = new Vector<>(); public int offset; @@ -162,6 +162,50 @@ public class PDBChain } /** + * 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 * @@ -299,12 +343,13 @@ public class PDBChain boolean deoxyn = false; boolean nucleotide = false; StringBuilder seq = new StringBuilder(256); - Vector resFeatures = new Vector(); - Vector resAnnotation = new Vector(); - int i, iSize = atoms.size() - 1; + Vector resFeatures = new Vector<>(); + Vector 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; @@ -318,7 +363,7 @@ public class PDBChain offset = resNumber; } - Vector resAtoms = new Vector(); + Vector 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())) @@ -425,7 +470,8 @@ public class PDBChain 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); @@ -434,20 +480,20 @@ public class PDBChain 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); } @@ -550,6 +596,12 @@ public class PDBChain { 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) diff --git a/src/jalview/analysis/AlignmentUtils.java b/src/jalview/analysis/AlignmentUtils.java index 90d9197..343ebc7 100644 --- a/src/jalview/analysis/AlignmentUtils.java +++ b/src/jalview/analysis/AlignmentUtils.java @@ -117,7 +117,7 @@ public class AlignmentUtils */ public static AlignmentI expandContext(AlignmentI core, int flankSize) { - List sq = new ArrayList(); + List sq = new ArrayList<>(); int maxoffset = 0; for (SequenceI s : core.getSequences()) { @@ -247,7 +247,7 @@ public class AlignmentUtils public static Map> getSequencesByName( AlignmentI al) { - Map> theMap = new LinkedHashMap>(); + Map> theMap = new LinkedHashMap<>(); for (SequenceI seq : al.getSequences()) { String name = seq.getName(); @@ -256,7 +256,7 @@ public class AlignmentUtils List seqs = theMap.get(name); if (seqs == null) { - seqs = new ArrayList(); + seqs = new ArrayList<>(); theMap.put(name, seqs); } seqs.add(seq); @@ -283,8 +283,8 @@ public class AlignmentUtils return false; } - Set mappedDna = new HashSet(); - Set mappedProtein = new HashSet(); + Set mappedDna = new HashSet<>(); + Set mappedProtein = new HashSet<>(); /* * First pass - map sequences where cross-references exist. This include @@ -870,7 +870,7 @@ public class AlignmentUtils System.err.println("Wrong alignment type in alignProteinAsDna"); return 0; } - List unmappedProtein = new ArrayList(); + List unmappedProtein = new ArrayList<>(); Map> alignedCodons = buildCodonColumnsMap( protein, dna, unmappedProtein); return alignProteinAs(protein, alignedCodons, unmappedProtein); @@ -1081,7 +1081,7 @@ public class AlignmentUtils * {dnaSequence, {proteinSequence, codonProduct}} at that position. The * comparator keeps the codon positions ordered. */ - Map> alignedCodons = new TreeMap>( + Map> alignedCodons = new TreeMap<>( new CodonComparator()); for (SequenceI dnaSeq : dna.getSequences()) @@ -1127,9 +1127,9 @@ public class AlignmentUtils // TODO delete this ugly hack once JAL-2022 is resolved // i.e. we can model startPhase > 0 (incomplete start codon) - List sequencesChecked = new ArrayList(); + List sequencesChecked = new ArrayList<>(); AlignedCodon lastCodon = null; - Map toAdd = new HashMap(); + Map toAdd = new HashMap<>(); for (Entry> entry : alignedCodons .entrySet()) @@ -1308,7 +1308,7 @@ public class AlignmentUtils Map seqProduct = alignedCodons.get(codon); if (seqProduct == null) { - seqProduct = new HashMap(); + seqProduct = new HashMap<>(); alignedCodons.put(codon, seqProduct); } seqProduct.put(protein, codon); @@ -1445,7 +1445,7 @@ public class AlignmentUtils { continue; } - final List result = new ArrayList(); + final List result = new ArrayList<>(); for (AlignmentAnnotation dsann : datasetAnnotations) { /* @@ -1627,13 +1627,13 @@ public class AlignmentUtils throw new IllegalArgumentException( "IMPLEMENTATION ERROR: dataset.getDataset() must be null!"); } - List foundSeqs = new ArrayList(); - List cdsSeqs = new ArrayList(); + List foundSeqs = new ArrayList<>(); + List cdsSeqs = new ArrayList<>(); List mappings = dataset.getCodonFrames(); HashSet productSeqs = null; if (products != null) { - productSeqs = new HashSet(); + productSeqs = new HashSet<>(); for (SequenceI seq : products) { productSeqs.add(seq.getDatasetSequence() == null ? seq @@ -1833,7 +1833,7 @@ public class AlignmentUtils * @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 mappings, @@ -1858,7 +1858,15 @@ public class AlignmentUtils 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; + } } /* @@ -1883,10 +1891,12 @@ public class AlignmentUtils { /* * 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 dnaToCdsMaps = MappingUtils .findMappingsForSequence(cdsSeq, seqMappings); if (!dnaToCdsMaps.isEmpty()) @@ -2002,8 +2012,8 @@ public class AlignmentUtils { // gather direct refs from contig congrent with mapping - List direct = new ArrayList(); - HashSet directSources = new HashSet(); + List direct = new ArrayList<>(); + HashSet directSources = new HashSet<>(); if (contig.getDBRefs() != null) { for (DBRefEntry dbr : contig.getDBRefs()) @@ -2023,7 +2033,7 @@ public class AlignmentUtils DBRefEntry[] onSource = DBRefUtils.selectRefs( proteinProduct.getDBRefs(), directSources.toArray(new String[0])); - List propagated = new ArrayList(); + List propagated = new ArrayList<>(); // and generate appropriate mappings for (DBRefEntry cdsref : direct) @@ -2180,12 +2190,13 @@ public class AlignmentUtils 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(); @@ -2202,7 +2213,7 @@ public class AlignmentUtils proteinStart++; proteinLength--; } - List proteinRange = new ArrayList(); + List proteinRange = new ArrayList<>(); /* * dna length should map to protein (or protein plus stop codon) @@ -2237,7 +2248,7 @@ public class AlignmentUtils */ public static List findCdsPositions(SequenceI dnaSeq) { - List result = new ArrayList(); + List result = new ArrayList<>(); List sfs = dnaSeq.getFeatures().getFeaturesByOntology( SequenceOntologyI.CDS); @@ -2523,7 +2534,7 @@ public class AlignmentUtils * 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[]> variants = new LinkedHashMap[]>(); + LinkedHashMap[]> variants = new LinkedHashMap<>(); List dnaFeatures = dnaSeq.getFeatures() .getFeaturesByOntology(SequenceOntologyI.SEQUENCE_VARIANT); @@ -2558,9 +2569,9 @@ public class AlignmentUtils if (codonVariants == null) { codonVariants = new ArrayList[CODON_LENGTH]; - codonVariants[0] = new ArrayList(); - codonVariants[1] = new ArrayList(); - codonVariants[2] = new ArrayList(); + codonVariants[0] = new ArrayList<>(); + codonVariants[1] = new ArrayList<>(); + codonVariants[2] = new ArrayList<>(); variants.put(peptidePosition, codonVariants); } @@ -2699,7 +2710,7 @@ public class AlignmentUtils /* * fancy case - aligning via mappings between sequences */ - List unmapped = new ArrayList(); + List unmapped = new ArrayList<>(); Map> columnMap = buildMappedColumnsMap( unaligned, aligned, unmapped); int width = columnMap.size(); @@ -2774,7 +2785,7 @@ public class AlignmentUtils } // map from dataset sequence to alignment sequence(s) - Map> alignedDatasets = new HashMap>(); + Map> alignedDatasets = new HashMap<>(); for (SequenceI seq : aligned.getSequences()) { SequenceI ds = seq.getDatasetSequence(); @@ -2837,7 +2848,7 @@ public class AlignmentUtils * {unalignedSequence, characterPerSequence} at that position. * TreeMap keeps the entries in ascending column order. */ - SortedMap> map = new TreeMap>(); + SortedMap> map = new TreeMap<>(); /* * record any sequences that have no mapping so can't be realigned @@ -2942,7 +2953,7 @@ public class AlignmentUtils Map seqsMap = map.get(fromCol); if (seqsMap == null) { - seqsMap = new HashMap(); + seqsMap = new HashMap<>(); map.put(fromCol, seqsMap); } seqsMap.put(seq, seq.getCharAt(mappedCharPos - toStart)); diff --git a/src/jalview/analysis/Dna.java b/src/jalview/analysis/Dna.java index a10b037..d534c8f 100644 --- a/src/jalview/analysis/Dna.java +++ b/src/jalview/analysis/Dna.java @@ -44,6 +44,7 @@ import jalview.util.ShiftList; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.Iterator; import java.util.List; public class Dna @@ -56,19 +57,23 @@ public class Dna * 'final' variables describe the inputs to the translation, which should not * be modified. */ - final private List selection; + private final List selection; - final private String[] seqstring; + private final String[] seqstring; - final private int[] contigs; + private final Iterator 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. @@ -91,7 +96,7 @@ public class Dna * @param viewport * @param visibleContigs */ - public Dna(AlignViewportI viewport, int[] visibleContigs) + public Dna(AlignViewportI viewport, Iterator visibleContigs) { this.selection = Arrays.asList(viewport.getSequenceSelection()); this.seqstring = viewport.getViewAsString(true); @@ -100,6 +105,45 @@ public class Dna 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 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; } /** @@ -161,7 +205,7 @@ public class Dna int s; int sSize = selection.size(); - List pepseqs = new ArrayList(); + List pepseqs = new ArrayList<>(); for (s = 0; s < sSize; s++) { SequenceI newseq = translateCodingRegion(selection.get(s), @@ -213,7 +257,7 @@ public class Dna if (dnarefs != null) { // intersect with pep - List mappedrefs = new ArrayList(); + List mappedrefs = new ArrayList<>(); DBRefEntry[] refs = dna.getDBRefs(); for (int d = 0; d < refs.length; d++) { @@ -391,27 +435,13 @@ public class Dna String seqstring, AlignedCodonFrame acf, List proteinSeqs) { - List skip = new ArrayList(); - int skipint[] = null; - ShiftList vismapping = new ShiftList(); // map from viscontigs to seqstring - // intervals - int vc; - int[] scontigs = new int[contigs.length]; + List 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); @@ -800,7 +830,7 @@ public class Dna public AlignmentI reverseCdna(boolean complement) { int sSize = selection.size(); - List reversed = new ArrayList(); + List reversed = new ArrayList<>(); for (int s = 0; s < sSize; s++) { SequenceI newseq = reverseSequence(selection.get(s).getName(), diff --git a/src/jalview/api/structures/JalviewStructureDisplayI.java b/src/jalview/api/structures/JalviewStructureDisplayI.java index fd66388..8f778f7 100644 --- a/src/jalview/api/structures/JalviewStructureDisplayI.java +++ b/src/jalview/api/structures/JalviewStructureDisplayI.java @@ -20,6 +20,9 @@ */ 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; @@ -62,4 +65,64 @@ public interface JalviewStructureDisplayI */ 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(); + } diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index ef87671..63f2745 100644 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -1905,7 +1905,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, static StringBuffer copiedSequences; - static Vector copiedHiddenColumns; + static HiddenColumns copiedHiddenColumns; protected void copy_actionPerformed() { @@ -1929,14 +1929,14 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, 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 { @@ -2005,13 +2005,13 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, { 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()) { @@ -2043,14 +2043,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } 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); diff --git a/src/jalview/appletgui/AlignmentPanel.java b/src/jalview/appletgui/AlignmentPanel.java index 270b2f7..83d8ade 100644 --- a/src/jalview/appletgui/AlignmentPanel.java +++ b/src/jalview/appletgui/AlignmentPanel.java @@ -421,8 +421,8 @@ public class AlignmentPanel extends Panel 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)) @@ -675,7 +675,7 @@ public class AlignmentPanel extends Panel if (av.hasHiddenColumns()) { width = av.getAlignment().getHiddenColumns() - .findColumnPosition(width); + .absoluteToVisibleColumn(width); } if (x < 0) { diff --git a/src/jalview/appletgui/AnnotationLabels.java b/src/jalview/appletgui/AnnotationLabels.java index d8f65a5..1366f31 100755 --- a/src/jalview/appletgui/AnnotationLabels.java +++ b/src/jalview/appletgui/AnnotationLabels.java @@ -23,6 +23,7 @@ package jalview.appletgui; 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; @@ -31,6 +32,7 @@ import jalview.util.ParseHtmlBodyAndLinks; 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; @@ -50,13 +52,22 @@ import java.awt.event.MouseListener; 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; @@ -92,23 +103,6 @@ public class AnnotationLabels extends Panel 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); } @@ -208,7 +202,9 @@ public class AnnotationLabels extends Panel } 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); @@ -268,7 +264,10 @@ public class AnnotationLabels extends Panel @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) @@ -406,6 +405,7 @@ public class AnnotationLabels extends Panel resizePanel = false; dragEvent = null; dragCancelled = false; + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); repaint(); ap.annotationPanel.repaint(); } @@ -418,6 +418,8 @@ public class AnnotationLabels extends Panel resizePanel = true; repaint(); } + setCursor(Cursor.getPredefinedCursor( + resizePanel ? Cursor.S_RESIZE_CURSOR : Cursor.DEFAULT_CURSOR)); } @Override @@ -843,8 +845,8 @@ public class AnnotationLabels extends Panel + "\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()); } } @@ -903,14 +905,8 @@ public class AnnotationLabels extends Panel } } 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(), diff --git a/src/jalview/appletgui/AnnotationPanel.java b/src/jalview/appletgui/AnnotationPanel.java index 50a9e33..50bc184 100755 --- a/src/jalview/appletgui/AnnotationPanel.java +++ b/src/jalview/appletgui/AnnotationPanel.java @@ -480,7 +480,7 @@ public class AnnotationPanel extends Panel if (av.hasHiddenColumns()) { column = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(column); + .visibleToAbsoluteColumn(column); } if (row > -1 && column < aa[row].annotations.length diff --git a/src/jalview/appletgui/FeatureSettings.java b/src/jalview/appletgui/FeatureSettings.java index 9a67499..cd85ab7 100755 --- a/src/jalview/appletgui/FeatureSettings.java +++ b/src/jalview/appletgui/FeatureSettings.java @@ -65,7 +65,7 @@ import java.util.Set; public class FeatureSettings extends Panel implements ItemListener, MouseListener, MouseMotionListener, - ActionListener, AdjustmentListener, FeatureSettingsControllerI + AdjustmentListener, FeatureSettingsControllerI { FeatureRenderer fr; @@ -120,8 +120,17 @@ public class FeatureSettings extends Panel 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); @@ -545,8 +554,7 @@ public class FeatureSettings extends Panel } } - @Override - public void actionPerformed(ActionEvent evt) + protected void invertSelection() { for (int i = 0; i < featurePanel.getComponentCount(); i++) { diff --git a/src/jalview/appletgui/IdCanvas.java b/src/jalview/appletgui/IdCanvas.java index f5ea12e..296f898 100755 --- a/src/jalview/appletgui/IdCanvas.java +++ b/src/jalview/appletgui/IdCanvas.java @@ -286,7 +286,7 @@ public class IdCanvas extends Panel implements ViewportListenerI if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; + .absoluteToVisibleColumn(maxwidth) - 1; } int annotationHeight = 0; diff --git a/src/jalview/appletgui/IdwidthAdjuster.java b/src/jalview/appletgui/IdwidthAdjuster.java index 75e3243..2602268 100755 --- a/src/jalview/appletgui/IdwidthAdjuster.java +++ b/src/jalview/appletgui/IdwidthAdjuster.java @@ -21,9 +21,8 @@ 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; @@ -36,29 +35,24 @@ public class IdwidthAdjuster extends Panel 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; @@ -85,18 +79,24 @@ public class IdwidthAdjuster extends Panel // } } + @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; @@ -112,25 +112,13 @@ public class IdwidthAdjuster extends Panel } } + @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); - } - } - } - } diff --git a/src/jalview/appletgui/OverviewCanvas.java b/src/jalview/appletgui/OverviewCanvas.java index 9597b44..a556bdb 100644 --- a/src/jalview/appletgui/OverviewCanvas.java +++ b/src/jalview/appletgui/OverviewCanvas.java @@ -128,8 +128,7 @@ public class OverviewCanvas extends Component { 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(); diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index 8ce597d..3bbbe95 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -155,6 +155,10 @@ public class OverviewPanel extends Panel implements Runnable, 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()); @@ -172,6 +176,7 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void mouseReleased(MouseEvent evt) { + draggingBox = false; } @Override diff --git a/src/jalview/appletgui/ScalePanel.java b/src/jalview/appletgui/ScalePanel.java index 04fb22b..c91449f 100755 --- a/src/jalview/appletgui/ScalePanel.java +++ b/src/jalview/appletgui/ScalePanel.java @@ -42,6 +42,7 @@ import java.awt.event.MouseEvent; 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 @@ -86,7 +87,7 @@ public class ScalePanel extends Panel if (av.hasHiddenColumns()) { - res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x); + res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(x); } else { @@ -173,7 +174,7 @@ public class ScalePanel extends Panel }); 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() @@ -234,7 +235,7 @@ public class ScalePanel extends Panel if (av.hasHiddenColumns()) { res = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(res); + .visibleToAbsoluteColumn(res); } if (!stretchingGroup) @@ -275,7 +276,7 @@ public class ScalePanel extends Panel 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); @@ -377,7 +378,7 @@ public class ScalePanel extends Panel { if (hidden.isVisible(sel)) { - sel = hidden.findColumnPosition(sel); + sel = hidden.absoluteToVisibleColumn(sel); } else { @@ -436,24 +437,17 @@ public class ScalePanel extends Panel if (av.getShowHiddenMarkers()) { int widthx = 1 + endx - startx; - List positions = hidden.findHiddenRegionPositions(); - for (int pos : positions) + Iterator 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); } } } diff --git a/src/jalview/appletgui/SeqCanvas.java b/src/jalview/appletgui/SeqCanvas.java index 2420cf7..35d73de 100755 --- a/src/jalview/appletgui/SeqCanvas.java +++ b/src/jalview/appletgui/SeqCanvas.java @@ -25,6 +25,7 @@ import jalview.datamodel.HiddenColumns; 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; @@ -37,7 +38,7 @@ import java.awt.Graphics; 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 { @@ -130,16 +131,16 @@ 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 @@ -180,7 +181,7 @@ public class SeqCanvas extends Panel implements ViewportListenerI if (av.hasHiddenColumns()) { endx = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(endx); + .visibleToAbsoluteColumn(endx); } SequenceI seq; @@ -417,71 +418,71 @@ public class SeqCanvas extends Panel implements ViewportListenerI 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); @@ -491,37 +492,27 @@ public class SeqCanvas extends Panel implements ViewportListenerI HiddenColumns hidden = av.getAlignment().getHiddenColumns(); g.setColor(Color.blue); int res; - List positions = hidden.findHiddenRegionPositions(); - for (int pos : positions) + Iterator 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); @@ -529,17 +520,17 @@ public class SeqCanvas extends Panel implements ViewportListenerI { 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; @@ -570,70 +561,44 @@ public class SeqCanvas extends Panel implements ViewportListenerI 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, diff --git a/src/jalview/appletgui/SeqPanel.java b/src/jalview/appletgui/SeqPanel.java index d74bbb7..e07dae6 100644 --- a/src/jalview/appletgui/SeqPanel.java +++ b/src/jalview/appletgui/SeqPanel.java @@ -647,7 +647,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, if (av.hasHiddenColumns()) { res = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(res); + .visibleToAbsoluteColumn(res); } return res; @@ -1123,9 +1123,9 @@ public class SeqPanel extends Panel implements MouseMotionListener, { 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)) @@ -1197,7 +1197,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, if (sg.getSize() == av.getAlignment().getHeight()) { if ((av.hasHiddenColumns() && startres < av.getAlignment() - .getHiddenColumns().getHiddenBoundaryRight(startres))) + .getHiddenColumns() + .getNextHiddenBoundary(false, startres))) { endEditing(); return; diff --git a/src/jalview/bin/Cache.java b/src/jalview/bin/Cache.java index dc50843..dcd6546 100755 --- a/src/jalview/bin/Cache.java +++ b/src/jalview/bin/Cache.java @@ -281,7 +281,7 @@ public class Cache @Override public synchronized Enumeration keys() { - return Collections.enumeration(new TreeSet(super.keySet())); + return Collections.enumeration(new TreeSet<>(super.keySet())); } }; @@ -334,7 +334,10 @@ public class Cache } } - /** 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; @@ -369,6 +372,7 @@ public class Cache { fis = new FileInputStream(propertiesFile); } + applicationProperties.clear(); applicationProperties.load(fis); // remove any old build properties @@ -621,14 +625,14 @@ public class Cache * @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); @@ -640,7 +644,7 @@ public class Cache System.out.println( "Error setting property: " + key + " " + obj + "\n" + ex); } - return obj; + return oldValue; } /** diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index 9ec0033..30620a1 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -20,9 +20,6 @@ */ package jalview.bin; -import groovy.lang.Binding; -import groovy.util.GroovyScriptEngine; - import jalview.ext.so.SequenceOntology; import jalview.gui.AlignFrame; import jalview.gui.Desktop; @@ -64,8 +61,12 @@ import java.util.HashMap; 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
    *
    @@ -275,20 +276,43 @@ public class Jalview 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()); + } } } @@ -970,7 +994,7 @@ public class Jalview } try { - Map vbinding = new HashMap(); + Map vbinding = new HashMap<>(); vbinding.put("Jalview", this); if (af != null) { @@ -1036,7 +1060,7 @@ public class Jalview + nickname + "|" + url); if (source == null) { - source = new Vector(); + source = new Vector<>(); } source.addElement(nickname); } @@ -1054,7 +1078,7 @@ public class Jalview System.out.println("adding source '" + data + "'"); if (source == null) { - source = new Vector(); + source = new Vector<>(); } source.addElement(data); } diff --git a/src/jalview/bin/JalviewLite.java b/src/jalview/bin/JalviewLite.java index 6504290..a60496c 100644 --- a/src/jalview/bin/JalviewLite.java +++ b/src/jalview/bin/JalviewLite.java @@ -31,7 +31,6 @@ import jalview.datamodel.Alignment; 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; @@ -471,7 +470,7 @@ public class JalviewLite extends Applet SequenceI rs = sel.getSequenceAt(0); start = rs.findIndex(start); end = rs.findIndex(end); - List cs = new ArrayList(csel.getSelected()); + List cs = new ArrayList<>(csel.getSelected()); csel.clear(); for (Integer selectedCol : cs) { @@ -921,7 +920,7 @@ public class JalviewLite extends Applet setMouseoverListener(currentAlignFrame, listener); } - private Vector javascriptListeners = new Vector(); + private Vector javascriptListeners = new Vector<>(); /* * (non-Javadoc) @@ -2165,8 +2164,8 @@ public class JalviewLite extends Applet else { param = st.nextToken(); - List tmp = new ArrayList(); - List tmp2 = new ArrayList(); + List tmp = new ArrayList<>(); + List tmp2 = new ArrayList<>(); while (st.hasMoreTokens()) { @@ -2279,12 +2278,9 @@ public class JalviewLite extends Applet 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; @@ -2802,9 +2798,9 @@ public class JalviewLite extends Applet // callInitCallback(); } - private Hashtable jshashes = new Hashtable(); + private Hashtable jshashes = new Hashtable<>(); - private Hashtable> jsmessages = new Hashtable>(); + private Hashtable> jsmessages = new Hashtable<>(); public void setJsMessageSet(String messageclass, String viewId, String[] colcommands) @@ -2812,7 +2808,7 @@ public class JalviewLite extends Applet Hashtable msgset = jsmessages.get(messageclass); if (msgset == null) { - msgset = new Hashtable(); + msgset = new Hashtable<>(); jsmessages.put(messageclass, msgset); } msgset.put(viewId, colcommands); diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index f268d37..3ba35b6 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -29,10 +29,12 @@ import jalview.util.MessageManager; 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; @@ -49,7 +51,7 @@ public class Alignment implements AlignmentI { private Alignment dataset; - protected List sequences; + private List sequences; protected List groups; @@ -198,6 +200,7 @@ public class Alignment implements AlignmentI return sequences.get(i); } } + return null; } @@ -706,7 +709,7 @@ public class Alignment implements AlignmentI public int getWidth() { int maxLength = -1; - + for (int i = 0; i < sequences.size(); i++) { if (getSequenceAt(i).getLength() > maxLength) @@ -714,9 +717,34 @@ public class Alignment implements AlignmentI maxLength = getSequenceAt(i).getLength(); } } - + return maxLength; } + /* + @Override + public int getWidth() + { + final Wrapper temp = new Wrapper(); + + forEachSequence(new Consumer() + { + @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! @@ -1603,7 +1631,10 @@ public class Alignment implements AlignmentI 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) { @@ -1895,4 +1926,117 @@ public class Alignment implements AlignmentI { 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 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)); + } + } + } + } diff --git a/src/jalview/datamodel/AlignmentAnnotation.java b/src/jalview/datamodel/AlignmentAnnotation.java index f7bf4d8..0098d76 100755 --- a/src/jalview/datamodel/AlignmentAnnotation.java +++ b/src/jalview/datamodel/AlignmentAnnotation.java @@ -666,7 +666,7 @@ public class AlignmentAnnotation this.calcId = annotation.calcId; if (annotation.properties != null) { - properties = new HashMap(); + properties = new HashMap<>(); for (Map.Entry val : annotation.properties.entrySet()) { properties.put(val.getKey(), val.getValue()); @@ -702,7 +702,7 @@ public class AlignmentAnnotation if (annotation.sequenceMapping != null) { Integer p = null; - sequenceMapping = new HashMap(); + sequenceMapping = new HashMap<>(); Iterator pos = annotation.sequenceMapping.keySet() .iterator(); while (pos.hasNext()) @@ -782,7 +782,7 @@ public class AlignmentAnnotation int epos = sequenceRef.findPosition(endRes); if (sequenceMapping != null) { - Map newmapping = new HashMap(); + Map newmapping = new HashMap<>(); Iterator e = sequenceMapping.keySet().iterator(); while (e.hasNext()) { @@ -909,7 +909,7 @@ public class AlignmentAnnotation { return; } - sequenceMapping = new HashMap(); + sequenceMapping = new HashMap<>(); int seqPos; @@ -1124,7 +1124,7 @@ public class AlignmentAnnotation { return; } - hidden.makeVisibleAnnotation(this); + makeVisibleAnnotation(hidden); } public void setPadGaps(boolean padgaps, char gapchar) @@ -1190,7 +1190,7 @@ public class AlignmentAnnotation /** * properties associated with the calcId */ - protected Map properties = new HashMap(); + protected Map properties = new HashMap<>(); /** * base colour for line graphs. If null, will be set automatically by @@ -1236,7 +1236,7 @@ public class AlignmentAnnotation : false; // TODO build a better annotation element map and get rid of annotations[] - Map mapForsq = new HashMap(); + Map mapForsq = new HashMap<>(); if (sequenceMapping != null) { if (sp2sq != null) @@ -1289,7 +1289,7 @@ public class AlignmentAnnotation if (mapping != null) { Map old = sequenceMapping; - Map remap = new HashMap(); + Map remap = new HashMap<>(); int index = -1; for (int mp[] : mapping.values()) { @@ -1347,7 +1347,7 @@ public class AlignmentAnnotation { if (properties == null) { - properties = new HashMap(); + properties = new HashMap<>(); } properties.put(property, value); } @@ -1473,6 +1473,115 @@ public class AlignmentAnnotation 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 annels = new ArrayList<>(); + Annotation[] els = null; + + int w = 0; + + Iterator 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 findAnnotations( Iterable list, SequenceI seq, String calcId, String label) diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index 084b80e..5fb16d6 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -580,6 +580,32 @@ public interface AlignmentI extends AnnotatedCollectionI */ 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); + } diff --git a/src/jalview/datamodel/CigarArray.java b/src/jalview/datamodel/CigarArray.java index 1723f1d..17e9ea6 100644 --- a/src/jalview/datamodel/CigarArray.java +++ b/src/jalview/datamodel/CigarArray.java @@ -20,7 +20,7 @@ */ package jalview.datamodel; -import java.util.List; +import java.util.Iterator; public class CigarArray extends CigarBase { @@ -90,9 +90,7 @@ 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, @@ -154,33 +152,25 @@ public class CigarArray extends CigarBase * @param selectionGroup */ private void constructFromAlignment(AlignmentI alignment, - List 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 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)) @@ -204,6 +194,7 @@ public class CigarArray extends CigarBase addOperation(CigarArray.D, 1 + hideEnd - hideStart); last = hideEnd + 1; } + // Final match if necessary. if (last <= end) { diff --git a/src/jalview/datamodel/DBRefSource.java b/src/jalview/datamodel/DBRefSource.java index 0ac14e5..7a30141 100755 --- a/src/jalview/datamodel/DBRefSource.java +++ b/src/jalview/datamodel/DBRefSource.java @@ -96,7 +96,7 @@ public class DBRefSource * 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 }; @@ -105,7 +105,7 @@ public class DBRefSource public static String[] allSources() { - List src = new ArrayList(); + List src = new ArrayList<>(); for (Field f : DBRefSource.class.getFields()) { if (String.class.equals(f.getType())) diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index c0a43ee..a7e93da 100644 --- a/src/jalview/datamodel/HiddenColumns.java +++ b/src/jalview/datamodel/HiddenColumns.java @@ -20,25 +20,71 @@ */ 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 hiddenColumns; + private List hiddenColumns = new ArrayList<>(); /** * Constructor @@ -51,19 +97,263 @@ public class HiddenColumns * 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 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 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(); @@ -71,16 +361,46 @@ public class HiddenColumns } /** - * 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 getHiddenRegions() + public void revealHiddenColumns(int start, ColumnSelection sel) { - return hiddenColumns == null ? Collections. 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(); + } } /** @@ -99,16 +419,22 @@ public class HiddenColumns { 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 { @@ -123,18 +449,20 @@ public class HiddenColumns */ 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(); @@ -157,25 +485,23 @@ public class HiddenColumns /* * 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 it = this.iterator(); + Iterator 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(); @@ -189,23 +515,19 @@ public class HiddenColumns * 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 { @@ -216,54 +538,52 @@ public class HiddenColumns /** * 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 @@ -274,113 +594,75 @@ public class HiddenColumns /** * 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 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 findHiddenRegionPositions() + public int getNextHiddenBoundary(boolean left, int alPos) { try { LOCK.readLock().lock(); - List 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(); @@ -388,69 +670,54 @@ public class HiddenColumns } /** - * 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(); @@ -458,258 +725,169 @@ public class HiddenColumns } /** - * 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 copyHiddenRegionsToArrayList() - { - int size = 0; - if (hiddenColumns != null) - { - size = hiddenColumns.size(); - } - ArrayList 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 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 compensateForEdit(int start, int change, - ColumnSelection sel) + private void clearHiddenColumnsInRange(int start, int end) { try { LOCK.writeLock().lock(); - List 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(); @@ -717,47 +895,24 @@ public class HiddenColumns } /** - * 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(); @@ -765,135 +920,80 @@ public class HiddenColumns } /** - * 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 0) - { - List visiblecontigs = new ArrayList<>(); - List 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 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(); @@ -901,92 +1001,14 @@ public class HiddenColumns } /** - * 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 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 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(); @@ -994,120 +1016,54 @@ public class HiddenColumns } /** - * 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 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 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 annels = new Vector<>(); - Annotation[] els = null; - List 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(); @@ -1115,15 +1071,21 @@ public class HiddenColumns } /** + * 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 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(); @@ -1131,577 +1093,36 @@ public class HiddenColumns } /** + * 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 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 shifts, - ArrayList 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 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 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 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(); - } - } - } diff --git a/src/jalview/datamodel/HiddenColumnsCursor.java b/src/jalview/datamodel/HiddenColumnsCursor.java new file mode 100644 index 0000000..2e9d798 --- /dev/null +++ b/src/jalview/datamodel/HiddenColumnsCursor.java @@ -0,0 +1,213 @@ +/* + * 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 . + * 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 hiddenColumns = new ArrayList<>(); + + private HiddenCursorPosition cursorPos = new HiddenCursorPosition(0, 0); + + protected HiddenColumnsCursor() + { + + } + + protected HiddenColumnsCursor(List hiddenCols) + { + resetCursor(hiddenCols, 0, 0); + } + + protected HiddenColumnsCursor(List 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 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); + } + +} diff --git a/src/jalview/datamodel/HiddenCursorPosition.java b/src/jalview/datamodel/HiddenCursorPosition.java new file mode 100644 index 0000000..bdca6d0 --- /dev/null +++ b/src/jalview/datamodel/HiddenCursorPosition.java @@ -0,0 +1,46 @@ +/* + * 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 . + * 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; + } +} diff --git a/src/jalview/datamodel/RangeElementsIterator.java b/src/jalview/datamodel/RangeElementsIterator.java new file mode 100644 index 0000000..9ca6b2a --- /dev/null +++ b/src/jalview/datamodel/RangeElementsIterator.java @@ -0,0 +1,108 @@ +/* + * 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 . + * 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 +{ + private int last; + + private int current; + + private int next; + + private Iterator rangeIterator; + + private int[] nextRange = null; + + RangeElementsIterator(Iterator 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(); + } +} diff --git a/src/jalview/datamodel/RangeIterator.java b/src/jalview/datamodel/RangeIterator.java new file mode 100644 index 0000000..5d45236 --- /dev/null +++ b/src/jalview/datamodel/RangeIterator.java @@ -0,0 +1,134 @@ +/* + * 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 . + * 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 +{ + // current index in rangeList + private int currentPosition = 0; + + // current range in rangeList + private int[] currentRange; + + // local copy or reference to rangeList + private List localRanges; + + /** + * Unbounded constructor + * + * @param rangeList + * list of ranges to iterate over + */ + RangeIterator(List 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 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 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); + } +} diff --git a/src/jalview/datamodel/SearchResults.java b/src/jalview/datamodel/SearchResults.java index cde50e5..d1e3fcc 100755 --- a/src/jalview/datamodel/SearchResults.java +++ b/src/jalview/datamodel/SearchResults.java @@ -267,9 +267,12 @@ public class SearchResults implements SearchResultsI { 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) diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java index 15d1378..abf334c 100755 --- a/src/jalview/datamodel/Sequence.java +++ b/src/jalview/datamodel/Sequence.java @@ -34,6 +34,7 @@ import java.util.Arrays; 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; @@ -408,7 +409,7 @@ public class Sequence extends ASequence implements SequenceI { if (pdbIds == null) { - pdbIds = new Vector(); + pdbIds = new Vector<>(); pdbIds.add(entry); return true; } @@ -1071,6 +1072,27 @@ public class Sequence extends ASequence implements SequenceI 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() { @@ -1094,7 +1116,7 @@ public class Sequence extends ASequence implements SequenceI @Override public List getInsertions() { - ArrayList map = new ArrayList(); + ArrayList map = new ArrayList<>(); int lastj = -1, j = 0; int pos = start; int seqlen = sequence.length; @@ -1405,7 +1427,7 @@ public class Sequence extends ASequence implements SequenceI { if (this.annotation == null) { - this.annotation = new Vector(); + this.annotation = new Vector<>(); } if (!this.annotation.contains(annotation)) { @@ -1572,7 +1594,7 @@ public class Sequence extends ASequence implements SequenceI return null; } - Vector subset = new Vector(); + Vector subset = new Vector<>(); Enumeration e = annotation.elements(); while (e.hasMoreElements()) { @@ -1706,7 +1728,7 @@ public class Sequence extends ASequence implements SequenceI public List getAlignmentAnnotations(String calcId, String label) { - List result = new ArrayList(); + List result = new ArrayList<>(); if (this.annotation != null) { for (AlignmentAnnotation ann : annotation) @@ -1762,7 +1784,7 @@ public class Sequence extends ASequence implements SequenceI } synchronized (dbrefs) { - List primaries = new ArrayList(); + List primaries = new ArrayList<>(); DBRefEntry[] tmp = new DBRefEntry[1]; for (DBRefEntry ref : dbrefs) { @@ -1904,4 +1926,73 @@ public class Sequence extends ASequence implements SequenceI return count; } + + @Override + public String getSequenceStringFromIterator(Iterator 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 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; + } } diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java index 6b797d7..944f263 100755 --- a/src/jalview/datamodel/SequenceGroup.java +++ b/src/jalview/datamodel/SequenceGroup.java @@ -1189,9 +1189,10 @@ public class SequenceGroup implements AnnotatedCollectionI { 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 { diff --git a/src/jalview/datamodel/SequenceI.java b/src/jalview/datamodel/SequenceI.java index 2f3e925..b22e48f 100755 --- a/src/jalview/datamodel/SequenceI.java +++ b/src/jalview/datamodel/SequenceI.java @@ -23,6 +23,7 @@ package jalview.datamodel; import jalview.datamodel.features.SequenceFeaturesI; import java.util.BitSet; +import java.util.Iterator; import java.util.List; import java.util.Vector; @@ -223,6 +224,13 @@ public interface SequenceI extends ASequenceI 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. @@ -524,4 +532,25 @@ public interface SequenceI extends ASequenceI * @param c2 */ public int replace(char c1, char c2); + + /** + * 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 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 it); } diff --git a/src/jalview/datamodel/StartRegionIterator.java b/src/jalview/datamodel/StartRegionIterator.java new file mode 100644 index 0000000..c21f04a --- /dev/null +++ b/src/jalview/datamodel/StartRegionIterator.java @@ -0,0 +1,143 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * 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 +{ + // 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 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 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 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; + } +} + diff --git a/src/jalview/datamodel/VisibleColsCollection.java b/src/jalview/datamodel/VisibleColsCollection.java index e9437a7..4ca51b5 100644 --- a/src/jalview/datamodel/VisibleColsCollection.java +++ b/src/jalview/datamodel/VisibleColsCollection.java @@ -32,17 +32,17 @@ public class VisibleColsCollection implements AlignmentColsCollectionI 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 iterator() { - return new VisibleColsIterator(start, end, hidden); + return hidden.getVisibleColsIterator(start, end); } @Override diff --git a/src/jalview/datamodel/VisibleColsIterator.java b/src/jalview/datamodel/VisibleColsIterator.java deleted file mode 100644 index 9de468d..0000000 --- a/src/jalview/datamodel/VisibleColsIterator.java +++ /dev/null @@ -1,130 +0,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 . - * 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 -{ - private int last; - - private int current; - - private int next; - - private List 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(); - } -} diff --git a/src/jalview/datamodel/VisibleContigsIterator.java b/src/jalview/datamodel/VisibleContigsIterator.java new file mode 100644 index 0000000..0185978 --- /dev/null +++ b/src/jalview/datamodel/VisibleContigsIterator.java @@ -0,0 +1,116 @@ +/* + * 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 . + * 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 +{ + private List vcontigs = new ArrayList<>(); + + private int currentPosition = 0; + + private boolean endsAtHidden = false; + + VisibleContigsIterator(int start, int end, + List 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; + } +} + diff --git a/src/jalview/ext/ensembl/EnsemblGenomes.java b/src/jalview/ext/ensembl/EnsemblGenomes.java index bbd1f26..9fc6a53 100644 --- a/src/jalview/ext/ensembl/EnsemblGenomes.java +++ b/src/jalview/ext/ensembl/EnsemblGenomes.java @@ -20,6 +20,9 @@ */ 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 @@ -35,13 +38,15 @@ public class EnsemblGenomes extends EnsemblGene */ 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 @@ -56,7 +61,7 @@ public class EnsemblGenomes extends EnsemblGene @Override public String getDbSource() { - return "EnsemblGenomes"; + return DBRefSource.ENSEMBLGENOMES; } } diff --git a/src/jalview/ext/ensembl/EnsemblLookup.java b/src/jalview/ext/ensembl/EnsemblLookup.java index 92763a1..877331d 100644 --- a/src/jalview/ext/ensembl/EnsemblLookup.java +++ b/src/jalview/ext/ensembl/EnsemblLookup.java @@ -135,12 +135,11 @@ public class EnsemblLookup extends EnsemblRestClient } /** - * Calls the Ensembl lookup REST endpoint and retrieves the 'Parent' for the - * given identifier, or null if not found + * Returns the gene id related to the given identifier (which may be for a + * gene, transcript or protein) * * @param identifier * @param objectType - * (optional) * @return */ public String getGeneId(String identifier, String objectType) diff --git a/src/jalview/ext/ensembl/EnsemblRestClient.java b/src/jalview/ext/ensembl/EnsemblRestClient.java index b1bc8e5..b19f557 100644 --- a/src/jalview/ext/ensembl/EnsemblRestClient.java +++ b/src/jalview/ext/ensembl/EnsemblRestClient.java @@ -72,10 +72,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log"; - private static Map 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 domainData = new HashMap<>(); private final static long AVAILABILITY_RETEST_INTERVAL = 10000L; // 10 seconds @@ -85,11 +82,11 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher 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 EnsemblInfo(DEFAULT_ENSEMBL_BASEURL, LATEST_ENSEMBL_REST_VERSION)); + domainData.put(DEFAULT_ENSEMBL_GENOMES_BASEURL, + new EnsemblInfo( + DEFAULT_ENSEMBL_GENOMES_BASEURL, LATEST_ENSEMBLGENOMES_REST_VERSION)); } protected volatile boolean inProgress = false; @@ -99,7 +96,21 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher */ public EnsemblRestClient() { - this(ENSEMBL_REST); + super(); + + /* + * initialise domain info lazily + */ + if (!domainData.containsKey(ensemblDomain)) + { + domainData.put(ensemblDomain, + new EnsemblInfo(ensemblDomain, LATEST_ENSEMBL_REST_VERSION)); + } + if (!domainData.containsKey(ensemblGenomesDomain)) + { + domainData.put(ensemblGenomesDomain, new EnsemblInfo( + ensemblGenomesDomain, LATEST_ENSEMBLGENOMES_REST_VERSION)); + } } /** @@ -169,11 +180,12 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher 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 @@ -192,7 +204,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher } catch (Throwable t) { System.err.println( - "Error connecting to " + PING_URL + ": " + t.getMessage()); + "Error connecting to " + pingUrl + ": " + t.getMessage()); } finally { if (br != null) diff --git a/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java b/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java index c4abb20..0aaaf93 100644 --- a/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java +++ b/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java @@ -20,6 +20,7 @@ */ package jalview.ext.ensembl; +import jalview.bin.Cache; import jalview.datamodel.DBRefSource; import jalview.ws.seqfetcher.DbSourceProxyImpl; @@ -32,6 +33,16 @@ import com.stevesoft.pat.Regex; */ 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 @@ -41,9 +52,9 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl "(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 static final String ENSEMBL_REST = "http://rest.ensembl.org"; + protected final String ensemblDomain; protected static final String OBJECT_TYPE_TRANSLATION = "Translation"; @@ -68,13 +79,29 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl 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; } diff --git a/src/jalview/ext/jmol/JalviewJmolBinding.java b/src/jalview/ext/jmol/JalviewJmolBinding.java index 41bc116..8832278 100644 --- a/src/jalview/ext/jmol/JalviewJmolBinding.java +++ b/src/jalview/ext/jmol/JalviewJmolBinding.java @@ -478,6 +478,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel lastCommand = command; } + Thread colourby = null; /** * Sends a set of colour commands to the structure viewer * @@ -485,15 +486,28 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel */ @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(); } /** @@ -862,19 +876,30 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel 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) { } diff --git a/src/jalview/ext/jmol/JmolCommands.java b/src/jalview/ext/jmol/JmolCommands.java index 6bf7010..8fb0de6 100644 --- a/src/jalview/ext/jmol/JmolCommands.java +++ b/src/jalview/ext/jmol/JmolCommands.java @@ -77,7 +77,6 @@ public class JmolCommands continue; } - int lastPos = -1; for (int s = 0; s < sequence[pdbfnum].length; s++) { for (int sp, m = 0; m < mapping.length; m++) @@ -85,6 +84,7 @@ public class JmolCommands 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++) { @@ -95,10 +95,22 @@ public class JmolCommands } 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; @@ -128,7 +140,12 @@ public class JmolCommands // 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 diff --git a/src/jalview/ext/jmol/JmolParser.java b/src/jalview/ext/jmol/JmolParser.java index dc3d0ee..2a510a2 100644 --- a/src/jalview/ext/jmol/JmolParser.java +++ b/src/jalview/ext/jmol/JmolParser.java @@ -28,7 +28,6 @@ import jalview.io.DataSourceType; import jalview.io.FileParse; import jalview.io.StructureFile; import jalview.schemes.ResidueProperties; -import jalview.structure.StructureImportSettings; import jalview.util.Format; import jalview.util.MessageManager; @@ -60,6 +59,12 @@ public class JmolParser extends StructureFile implements JmolStatusListener { 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 { @@ -183,7 +188,11 @@ public class JmolParser extends StructureFile implements JmolStatusListener } lastID = tmpatom.resNumIns.trim(); } - xferSettings(); + if (isParseImmediately()) + { + // configure parsing settings from the static singleton + xferSettings(); + } makeResidueList(); makeCaBondList(); @@ -200,7 +209,8 @@ public class JmolParser extends StructureFile implements JmolStatusListener prot.add(chainseq); } - if (StructureImportSettings.isProcessSecondaryStructure()) + // look at local setting for adding secondary tructure + if (predictSecondaryStructure) { createAnnotation(chainseq, chain, ms.at); } diff --git a/src/jalview/fts/core/FTSRestClient.java b/src/jalview/fts/core/FTSRestClient.java index 076e212..f94d455 100644 --- a/src/jalview/fts/core/FTSRestClient.java +++ b/src/jalview/fts/core/FTSRestClient.java @@ -284,7 +284,8 @@ public abstract class FTSRestClient implements FTSRestClientI 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()); } diff --git a/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java b/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java index 250fba0..262ed86 100644 --- a/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java +++ b/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java @@ -21,6 +21,7 @@ package jalview.fts.service.uniprot; +import jalview.bin.Cache; import jalview.fts.api.FTSData; import jalview.fts.api.FTSDataColumnI; import jalview.fts.api.FTSRestClientI; @@ -44,9 +45,18 @@ import com.sun.jersey.api.client.config.DefaultClientConfig; 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) @@ -81,7 +91,7 @@ public class UniProtFTSRestClient extends FTSRestClient } WebResource webResource = null; - webResource = client.resource(UNIPROT_SEARCH_ENDPOINT) + webResource = client.resource(uniprotSearchEndpoint) .queryParam("format", "tab") .queryParam("columns", wantedFields) .queryParam("limit", String.valueOf(responseSize)) @@ -158,7 +168,7 @@ public class UniProtFTSRestClient extends FTSRestClient String[] foundDataRow = uniProtTabDelimittedResponseString.split("\n"); if (foundDataRow != null && foundDataRow.length > 0) { - result = new ArrayList(); + result = new ArrayList<>(); boolean firstRow = true; for (String dataRow : foundDataRow) { diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 298688b..9821e9e 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -1862,23 +1862,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return; } - ArrayList hiddenColumns = null; + HiddenColumns hiddenColumns = null; if (viewport.hasHiddenColumns()) { - hiddenColumns = new ArrayList<>(); int hiddenOffset = viewport.getSelectionGroup().getStartRes(); int hiddenCutoff = viewport.getSelectionGroup().getEndRes(); - ArrayList 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, @@ -2207,11 +2201,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (Desktop.jalviewClipboard != null && Desktop.jalviewClipboard[2] != null) { - List hc = (List) 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 @@ -2266,11 +2257,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (Desktop.jalviewClipboard != null && Desktop.jalviewClipboard[2] != null) { - List hc = (List) 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 @@ -4471,17 +4459,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, 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) { @@ -4507,6 +4499,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, alignPanel.paintAlignment(true, false); } } + else + { + /* + * add declined structures as sequences + */ + for (Object[] o : filesmatched) + { + filesnotmatched.add((String) o[0]); + } + } } if (filesnotmatched.size() > 0) { @@ -4639,11 +4641,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, 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)) @@ -4865,14 +4863,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, 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()); }; }); diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 4d09084..7e77bec 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -22,7 +22,6 @@ package jalview.gui; 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; @@ -36,7 +35,6 @@ import jalview.datamodel.Alignment; 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; @@ -58,10 +56,9 @@ import java.awt.Dimension; 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; @@ -453,10 +450,10 @@ public class AlignViewport extends AlignmentViewport * area * @return */ - public int[] getViewAsVisibleContigs(boolean selectedRegionOnly) + public Iterator getViewAsVisibleContigs(boolean selectedRegionOnly) { - int[] viscontigs = null; - int start = 0, end = 0; + int start = 0; + int end = 0; if (selectedRegionOnly && selectionGroup != null) { start = selectionGroup.getStartRes(); @@ -466,8 +463,8 @@ public class AlignViewport extends AlignmentViewport { end = alignment.getWidth(); } - viscontigs = alignment.getHiddenColumns().getVisibleContigs(start, end); - return viscontigs; + return (alignment.getHiddenColumns().getVisContigsIterator(start, end, + false)); } /** @@ -604,7 +601,7 @@ public class AlignViewport extends AlignmentViewport return validCharWidth; } - private Hashtable calcIdParams = new Hashtable(); + private Hashtable calcIdParams = new Hashtable<>(); public AutoCalcSetting getCalcIdSettingsFor(String calcId) { diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 3a1dbe8..f5634d2 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -419,8 +419,8 @@ public class AlignmentPanel extends GAlignmentPanel implements 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])) @@ -678,7 +678,7 @@ public class AlignmentPanel extends GAlignmentPanel implements { // reset the width to exclude hidden columns width = av.getAlignment().getHiddenColumns() - .findColumnPosition(width); + .absoluteToVisibleColumn(width); } hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); @@ -874,15 +874,17 @@ public class AlignmentPanel extends GAlignmentPanel implements @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()); @@ -1174,7 +1176,7 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; + .absoluteToVisibleColumn(maxwidth) - 1; } int resWidth = getSeqPanel().seqCanvas @@ -1366,7 +1368,7 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth); + .absoluteToVisibleColumn(maxwidth); } int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight()) @@ -1584,7 +1586,7 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; + .absoluteToVisibleColumn(maxwidth) - 1; } int height = ((maxwidth / chunkWidth) + 1) * cHeight; @@ -1813,35 +1815,6 @@ public class AlignmentPanel extends GAlignmentPanel implements */ 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 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); } diff --git a/src/jalview/gui/AnnotationColourChooser.java b/src/jalview/gui/AnnotationColourChooser.java index 153f70c..384635b 100644 --- a/src/jalview/gui/AnnotationColourChooser.java +++ b/src/jalview/gui/AnnotationColourChooser.java @@ -459,4 +459,11 @@ public class AnnotationColourChooser extends AnnotationRowFilter } } + @Override + protected void sliderDragReleased() + { + super.sliderDragReleased(); + ap.paintAlignment(true, true); + } + } diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java index b94a615..b58269d 100755 --- a/src/jalview/gui/AnnotationLabels.java +++ b/src/jalview/gui/AnnotationLabels.java @@ -20,25 +20,28 @@ */ 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; @@ -52,6 +55,7 @@ import java.awt.image.BufferedImage; 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; @@ -62,63 +66,74 @@ import javax.swing.SwingUtilities; 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) { @@ -126,30 +141,6 @@ public class AnnotationLabels extends JPanel 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()); @@ -607,10 +598,9 @@ public class AnnotationLabels extends JPanel } /** - * DOCUMENT ME! + * Reorders annotation rows after a drag of a label * * @param evt - * DOCUMENT ME! */ @Override public void mouseReleased(MouseEvent evt) @@ -625,6 +615,9 @@ public class AnnotationLabels extends JPanel getSelectedRow(evt.getY() - getScrollOffset()); int end = selectedRow; + /* + * if dragging to resize instead, start == end + */ if (start != end) { // Swap these annotations @@ -648,31 +641,13 @@ public class AnnotationLabels extends JPanel } /** - * 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(); @@ -680,10 +655,11 @@ public class AnnotationLabels extends JPanel } /** - * 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) @@ -717,15 +693,14 @@ public class AnnotationLabels extends JPanel } /** - * 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()); @@ -801,6 +776,26 @@ public class AnnotationLabels extends JPanel } } + /** + * 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) { @@ -820,11 +815,9 @@ public class AnnotationLabels extends JPanel // 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( @@ -883,8 +876,7 @@ public class AnnotationLabels extends JPanel // 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(); @@ -892,7 +884,7 @@ public class AnnotationLabels extends JPanel } else { - if (jalview.util.Platform.isControlDown(evt)) + if (Platform.isControlDown(evt)) { sg.addOrRemove(aa[selectedRow].sequenceRef, true); } @@ -937,16 +929,17 @@ public class AnnotationLabels extends JPanel 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 it = av.getAlignment().getHiddenColumns() + .getVisContigsIterator(0, sq.getLength(), false); + omitHidden = new String[] { sq.getSequenceStringFromIterator(it) }; } int[] alignmentStartEnd = new int[] { 0, ds.getWidth() - 1 }; @@ -962,12 +955,12 @@ public class AnnotationLabels extends JPanel Toolkit.getDefaultToolkit().getSystemClipboard() .setContents(new StringSelection(output), Desktop.instance); - ArrayList 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 @@ -1020,8 +1013,6 @@ public class AnnotationLabels extends JPanel drawComponent(g, false, width); } - private final boolean debugRedraw = false; - /** * Draw the full set of annotation Labels for the alignment at the given * cursor @@ -1204,11 +1195,7 @@ public class AnnotationLabels extends JPanel } } - 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(), @@ -1227,4 +1214,9 @@ public class AnnotationLabels extends JPanel { return scrollOffset; } + + @Override + public void mouseEntered(MouseEvent e) + { + } } diff --git a/src/jalview/gui/AnnotationPanel.java b/src/jalview/gui/AnnotationPanel.java index 438e81b..dee56b0 100755 --- a/src/jalview/gui/AnnotationPanel.java +++ b/src/jalview/gui/AnnotationPanel.java @@ -175,11 +175,12 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, 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); } @@ -724,7 +725,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, if (av.hasHiddenColumns()) { column = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(column); + .visibleToAbsoluteColumn(column); } AlignmentAnnotation ann = aa[row]; @@ -782,6 +783,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, { this.setToolTipText(JvSwingUtils.wrapTooltip(true, description)); } + else + { + this.setToolTipText(null); // no tooltip if null or empty description + } } else { @@ -904,6 +909,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, @Override public void paintComponent(Graphics g) { + super.paintComponent(g); + g.setColor(Color.white); g.fillRect(0, 0, getWidth(), getHeight()); @@ -959,7 +966,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, gg.fillRect(0, 0, imgWidth, image.getHeight()); imageFresh = true; } - + drawComponent(gg, av.getRanges().getStartRes(), av.getRanges().getEndRes() + 1); imageFresh = false; @@ -992,10 +999,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, 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 { @@ -1012,17 +1017,13 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, 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; diff --git a/src/jalview/gui/AnnotationRowFilter.java b/src/jalview/gui/AnnotationRowFilter.java index 71ad6a5..f13cb10 100644 --- a/src/jalview/gui/AnnotationRowFilter.java +++ b/src/jalview/gui/AnnotationRowFilter.java @@ -172,11 +172,7 @@ public abstract class AnnotationRowFilter extends JPanel @Override public void mouseReleased(MouseEvent evt) { - if (sliderDragging) - { - sliderDragging = false; - valueChanged(true); - } + sliderDragReleased(); } }); } @@ -523,4 +519,13 @@ public abstract class AnnotationRowFilter extends JPanel { this.annotations = anns; } + + protected void sliderDragReleased() + { + if (sliderDragging) + { + sliderDragging = false; + valueChanged(true); + } + } } diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index fef7451..6c934c8 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -44,7 +44,6 @@ import java.util.List; import java.util.Vector; import javax.swing.JCheckBoxMenuItem; -import javax.swing.JInternalFrame; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.SwingUtilities; @@ -58,7 +57,7 @@ public class AppJmol extends StructureViewerBase private static final String SPACE = " "; - private static final String BACKSLASH = "\""; + private static final String QUOTE = "\""; AppJmolBinding jmb; @@ -162,8 +161,9 @@ public class AppJmol extends StructureViewerBase { 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 @@ -174,33 +174,14 @@ public class AppJmol extends StructureViewerBase 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; @@ -209,11 +190,9 @@ public class AppJmol extends StructureViewerBase 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(); @@ -234,41 +213,21 @@ public class AppJmol extends StructureViewerBase } /** - * 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 getViewersFor(AlignmentPanel apanel) - { - List 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) { @@ -300,8 +259,6 @@ public class AppJmol extends StructureViewerBase jmb.setFinishedInit(true); } - boolean allChainsSelected = false; - @Override void showSelectedChains() { @@ -368,8 +325,8 @@ public class AppJmol extends StructureViewerBase 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(); @@ -444,7 +401,7 @@ public class AppJmol extends StructureViewerBase jmb.updateColours(ap); } // do superposition if asked to - if (Cache.getDefault("AUTOSUPERIMPOSE", true) && alignAddedStructures) + if (alignAddedStructures) { alignAddedStructures(); } @@ -478,7 +435,7 @@ public class AppJmol extends StructureViewerBase } } }); - alignAddedStructures = false; + } /** @@ -507,6 +464,7 @@ public class AppJmol extends StructureViewerBase 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(); diff --git a/src/jalview/gui/AquaInternalFrameManager.java b/src/jalview/gui/AquaInternalFrameManager.java index ea809eb..956c119 100644 --- a/src/jalview/gui/AquaInternalFrameManager.java +++ b/src/jalview/gui/AquaInternalFrameManager.java @@ -60,7 +60,7 @@ import javax.swing.JInternalFrame; * 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 { diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index 89de2e8..d07a7c2 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -100,41 +100,34 @@ public class ChimeraViewFrame extends StructureViewerBase 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); } /** @@ -202,7 +195,7 @@ public class ChimeraViewFrame extends StructureViewerBase } /** - * 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 @@ -213,30 +206,7 @@ public class ChimeraViewFrame extends StructureViewerBase 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 }); @@ -264,7 +234,6 @@ public class ChimeraViewFrame extends StructureViewerBase if (pdbentrys.length > 1) { - alignAddedStructures = true; useAlignmentPanelForSuperposition(ap); } jmb.setColourBySequence(true); @@ -323,17 +292,19 @@ public class ChimeraViewFrame extends StructureViewerBase } /** - * 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); } @@ -352,29 +323,6 @@ public class ChimeraViewFrame extends StructureViewerBase } /** - * 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 getViewersFor(AlignmentPanel ap) - { - List 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. */ @@ -641,7 +589,7 @@ public class ChimeraViewFrame extends StructureViewerBase jmb.updateColours(ap); } // do superposition if asked to - if (Cache.getDefault("AUTOSUPERIMPOSE", true) && alignAddedStructures) + if (alignAddedStructures) { new Thread(new Runnable() { @@ -651,7 +599,6 @@ public class ChimeraViewFrame extends StructureViewerBase alignStructs_withAllAlignPanels(); } }).start(); - alignAddedStructures = false; } addingStructures = false; } @@ -681,7 +628,6 @@ public class ChimeraViewFrame extends StructureViewerBase 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; diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 128481c..9a696e9 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -849,6 +849,7 @@ public class Desktop extends jalview.jbgui.GDesktop frame.setResizable(resizable); frame.setMaximizable(resizable); frame.setIconifiable(resizable); + frame.setOpaque(false); if (frame.getX() < 1 && frame.getY() < 1) { @@ -3398,4 +3399,41 @@ public class Desktop extends jalview.jbgui.GDesktop { 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 getStructureViewers( + AlignmentPanel apanel, + Class structureViewerClass) + { + List 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; + } } diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java index 3f1d9c7..12f9db9 100644 --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@ -961,12 +961,13 @@ public class FeatureSettings extends JPanel 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][2] = !(Boolean) data[i][2]; } + updateFeatureRenderer(data, true); + table.repaint(); } public void orderByAvWidth() diff --git a/src/jalview/gui/IdCanvas.java b/src/jalview/gui/IdCanvas.java index 085b259..cd7b0b7 100755 --- a/src/jalview/gui/IdCanvas.java +++ b/src/jalview/gui/IdCanvas.java @@ -83,7 +83,7 @@ public class IdCanvas extends JPanel implements ViewportListenerI this.av = av; PaintRefresher.Register(this, av.getSequenceSetId()); av.getRanges().addPropertyChangeListener(this); - } + } /** * DOCUMENT ME! @@ -204,7 +204,11 @@ public class IdCanvas extends JPanel implements ViewportListenerI 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(); } /** @@ -216,41 +220,43 @@ public class IdCanvas extends JPanel implements ViewportListenerI @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()); - + g.drawImage(image, 0, 0, this); } @@ -374,7 +380,7 @@ public class IdCanvas extends JPanel implements ViewportListenerI if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; + .absoluteToVisibleColumn(maxwidth) - 1; } int annotationHeight = 0; diff --git a/src/jalview/gui/IdPanel.java b/src/jalview/gui/IdPanel.java index 1f2a3ad..f2761ab 100755 --- a/src/jalview/gui/IdPanel.java +++ b/src/jalview/gui/IdPanel.java @@ -148,7 +148,8 @@ public class IdPanel extends JPanel public void mouseWheelMoved(MouseWheelEvent e) { e.consume(); - if (e.getWheelRotation() > 0) + double wheelRotation = e.getPreciseWheelRotation(); + if (wheelRotation > 0) { if (e.isShiftDown()) { @@ -159,7 +160,7 @@ public class IdPanel extends JPanel av.getRanges().scrollUp(false); } } - else + else if (wheelRotation < 0) { if (e.isShiftDown()) { diff --git a/src/jalview/gui/IdwidthAdjuster.java b/src/jalview/gui/IdwidthAdjuster.java index 8400543..0cffc3b 100755 --- a/src/jalview/gui/IdwidthAdjuster.java +++ b/src/jalview/gui/IdwidthAdjuster.java @@ -23,8 +23,8 @@ package jalview.gui; 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; @@ -44,8 +44,6 @@ public class IdwidthAdjuster extends JPanel int oldX = 0; - Image image; - AlignmentPanel ap; /** @@ -57,14 +55,7 @@ public class IdwidthAdjuster extends JPanel 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); } @@ -196,10 +187,7 @@ public class IdwidthAdjuster extends JPanel if (active) { - if (image != null) - { - g.drawImage(image, getWidth() - 20, 2, this); - } + setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); } } } diff --git a/src/jalview/gui/JDatabaseTree.java b/src/jalview/gui/JDatabaseTree.java index 0a6b9d6..1018d6e 100644 --- a/src/jalview/gui/JDatabaseTree.java +++ b/src/jalview/gui/JDatabaseTree.java @@ -101,10 +101,10 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener * identical DB sources, and should be collapsed. */ DefaultMutableTreeNode tn = null, root = new DefaultMutableTreeNode(); - Hashtable source = new Hashtable(); + Hashtable source = new Hashtable<>(); sfetcher = sfetch; String dbs[] = sfetch.getSupportedDb(); - Hashtable ht = new Hashtable(); + Hashtable ht = new Hashtable<>(); for (int i = 0; i < dbs.length; i++) { tn = source.get(dbs[i]); @@ -370,7 +370,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener tsel = dbviews.getSelectionPaths(); boolean forcedFirstChild = false; - List srcs = new ArrayList(); + List srcs = new ArrayList<>(); if (tsel != null) { for (TreePath tp : tsel) @@ -489,7 +489,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener return null; } StringBuffer sb = new StringBuffer(); - HashSet hs = new HashSet(); + HashSet hs = new HashSet<>(); for (DbSourceProxy dbs : getSelectedSources()) { String tq = dbs.getTestQuery(); @@ -506,7 +506,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener return sb.toString(); } - List lstners = new Vector(); + List lstners = new Vector<>(); public void addActionListener(ActionListener actionListener) { @@ -596,4 +596,11 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener // TODO Auto-generated method stub } + + @Override + public void setVisible(boolean arg0) + { + System.out.println("setVisible: " + arg0); + super.setVisible(arg0); + } } diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index 4a15024..c7ec757 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -1389,9 +1389,10 @@ public class Jalview2XML } else { - ArrayList hiddenRegions = hidden.getHiddenColumnsCopy(); - for (int[] region : hiddenRegions) + Iterator hiddenRegions = hidden.iterator(); + while (hiddenRegions.hasNext()) { + int[] region = hiddenRegions.next(); HiddenColumns hc = new HiddenColumns(); hc.setStart(region[0]); hc.setEnd(region[1]); diff --git a/src/jalview/gui/OverviewCanvas.java b/src/jalview/gui/OverviewCanvas.java index 2991889..1f55ea6 100644 --- a/src/jalview/gui/OverviewCanvas.java +++ b/src/jalview/gui/OverviewCanvas.java @@ -157,8 +157,7 @@ public class OverviewCanvas extends JComponent { 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(); @@ -183,7 +182,7 @@ public class OverviewCanvas extends JComponent @Override public void paintComponent(Graphics g) { - // super.paintComponent(g); + super.paintComponent(g); if (restart) { diff --git a/src/jalview/gui/OverviewPanel.java b/src/jalview/gui/OverviewPanel.java index 43b4310..02d54a8 100755 --- a/src/jalview/gui/OverviewPanel.java +++ b/src/jalview/gui/OverviewPanel.java @@ -170,15 +170,20 @@ public class OverviewPanel extends JPanel @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)); + } } } }); @@ -203,6 +208,10 @@ public class OverviewPanel extends JPanel 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()); @@ -225,6 +234,13 @@ public class OverviewPanel extends JPanel showPopupMenu(evt); } } + + @Override + public void mouseReleased(MouseEvent evt) + { + draggingBox = false; + } + }); } diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index 850a09a..759c63b 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -1453,15 +1453,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener 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 @@ -1469,10 +1462,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener { // 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()) @@ -1483,29 +1473,18 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener } 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()); - } + inserts.or(sequence.getInsertionsAsBits()); - // finally, preserve hidden regions outside selection - inserts.or(mask); - - // and set hidden columns accordingly - hidden.hideMarkedBits(inserts); - - ap.av.getAlignment().setHiddenColumns(hidden); + // and set hidden columns accordingly + hidden.hideColumns(inserts); + } refresh(); } diff --git a/src/jalview/gui/Preferences.java b/src/jalview/gui/Preferences.java index aa8369a..5aab26d 100755 --- a/src/jalview/gui/Preferences.java +++ b/src/jalview/gui/Preferences.java @@ -525,7 +525,7 @@ public class Preferences extends GPreferences 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 @@ -784,7 +784,7 @@ public class Preferences extends GPreferences Cache.applicationProperties.setProperty("FIGURE_AUTOIDWIDTH", Boolean.toString(autoIdWidth.isSelected())); userIdWidth_actionPerformed(); - Cache.applicationProperties.setProperty("FIGURE_USERIDWIDTH", + Cache.applicationProperties.setProperty("FIGURE_FIXEDIDWIDTH", userIdWidth.getText()); /* diff --git a/src/jalview/gui/RotatableCanvas.java b/src/jalview/gui/RotatableCanvas.java index 4ef18d4..02368df 100755 --- a/src/jalview/gui/RotatableCanvas.java +++ b/src/jalview/gui/RotatableCanvas.java @@ -128,7 +128,6 @@ public class RotatableCanvas extends JPanel implements MouseListener, boolean applyToAllViews = false; - // Controller controller; public RotatableCanvas(AlignmentPanel ap) { this.av = ap.av; @@ -136,16 +135,23 @@ public class RotatableCanvas extends JPanel implements MouseListener, 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(); } @@ -162,6 +168,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, boolean first = true; + @Override public void setPoints(Vector points, int npoint) { this.points = points; @@ -327,7 +334,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, dim = height; } - return (float) ((dim * scalefactor) / (2 * maxwidth)); + return (dim * scalefactor) / (2 * maxwidth); } /** @@ -352,6 +359,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * * @return DOCUMENT ME! */ + @Override public Dimension getPreferredSize() { if (prefsize != null) @@ -369,6 +377,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * * @return DOCUMENT ME! */ + @Override public Dimension getMinimumSize() { return getPreferredSize(); @@ -380,6 +389,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param g * DOCUMENT ME! */ + @Override public void paintComponent(Graphics g1) { @@ -475,8 +485,8 @@ public class RotatableCanvas extends JPanel implements MouseListener, 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]; @@ -547,6 +557,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void keyTyped(KeyEvent evt) { } @@ -557,6 +568,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void keyReleased(KeyEvent evt) { } @@ -567,6 +579,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void keyPressed(KeyEvent evt) { if (evt.getKeyCode() == KeyEvent.VK_UP) @@ -598,6 +611,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseClicked(MouseEvent evt) { } @@ -608,6 +622,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseEntered(MouseEvent evt) { } @@ -618,6 +633,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseExited(MouseEvent evt) { } @@ -628,6 +644,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseReleased(MouseEvent evt) { } @@ -638,6 +655,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mousePressed(MouseEvent evt) { int x = evt.getX(); @@ -690,6 +708,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, // controller.handleSequenceSelectionEvent(new // SequenceSelectionEvent(this,sel)); // } + @Override public void mouseMoved(MouseEvent evt) { SequenceI found = findPoint(evt.getX(), evt.getY()); @@ -710,6 +729,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseDragged(MouseEvent evt) { mx = evt.getX(); @@ -725,8 +745,8 @@ public class RotatableCanvas extends JPanel implements MouseListener, { 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++) { @@ -774,9 +794,9 @@ public class RotatableCanvas extends JPanel implements MouseListener, { 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)) { @@ -816,9 +836,9 @@ public class RotatableCanvas extends JPanel implements MouseListener, 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)) diff --git a/src/jalview/gui/ScalePanel.java b/src/jalview/gui/ScalePanel.java index 798c833..e6bba02 100755 --- a/src/jalview/gui/ScalePanel.java +++ b/src/jalview/gui/ScalePanel.java @@ -42,6 +42,7 @@ import java.awt.event.MouseEvent; 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; @@ -112,7 +113,7 @@ public class ScalePanel extends JPanel if (av.hasHiddenColumns()) { - x = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x); + x = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(x); } if (x >= av.getAlignment().getWidth()) @@ -174,7 +175,7 @@ public class ScalePanel extends JPanel }); 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() @@ -281,7 +282,7 @@ public class ScalePanel extends JPanel if (av.hasHiddenColumns()) { res = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(res); + .visibleToAbsoluteColumn(res); } if (res >= av.getAlignment().getWidth()) @@ -336,7 +337,7 @@ public class ScalePanel extends JPanel 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); @@ -392,7 +393,7 @@ public class ScalePanel extends JPanel reveal = av.getAlignment().getHiddenColumns() .getRegionWithEdgeAtRes(res); - res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(res); ToolTipManager.sharedInstance().registerComponent(this); this.setToolTipText( @@ -409,6 +410,8 @@ public class ScalePanel extends JPanel @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 @@ -457,7 +460,7 @@ public class ScalePanel extends JPanel { if (hidden.isVisible(sel)) { - sel = hidden.findColumnPosition(sel); + sel = hidden.absoluteToVisibleColumn(sel); } else { @@ -487,23 +490,18 @@ public class ScalePanel extends JPanel if (av.getShowHiddenMarkers()) { - List positions = hidden.findHiddenRegionPositions(); - for (int pos : positions) + Iterator 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); } } } @@ -554,7 +552,11 @@ public class ScalePanel extends JPanel || 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(); } } diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 1e1105f..2d8eb7d 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -25,6 +25,7 @@ import jalview.datamodel.HiddenColumns; 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; @@ -42,6 +43,7 @@ import java.awt.RenderingHints; 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; @@ -198,8 +200,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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()); @@ -295,7 +297,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int endSeq = ranges.getEndSeq(); int transX = 0; int transY = 0; - + gg.copyArea(horizontal * charWidth, vertical * charHeight, img.getWidth(), img.getHeight(), -horizontal * charWidth, -vertical * charHeight); @@ -337,7 +339,10 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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; @@ -351,20 +356,20 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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))) @@ -388,16 +393,16 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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()); @@ -407,7 +412,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(), 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); @@ -504,8 +509,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI private BufferedImage buildLocalImage(BufferedImage selectImage) { // clone the cached image - BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(), - img.getType()); + BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(), + img.getType()); + + // BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(), + // img.getType()); Graphics2D g2d = lcimg.createGraphics(); g2d.drawImage(img, 0, 0, null); @@ -545,8 +553,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI try { - lcimg = new BufferedImage(width, height, - BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works + lcimg = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works } catch (OutOfMemoryError er) { System.gc(); @@ -890,11 +898,14 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int charWidth = av.getCharWidth(); g.setColor(Color.blue); + int res; HiddenColumns hidden = av.getAlignment().getHiddenColumns(); - List positions = hidden.findHiddenRegionPositions(); - for (int pos : positions) + + Iterator it = hidden.getStartRegionIterator(startColumn, + endColumn); + while (it.hasNext()) { - int res = pos - startColumn; + res = it.next() - startColumn; if (res < 0 || res > endColumn - startColumn + 1) { @@ -943,7 +954,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth); + .absoluteToVisibleColumn(maxwidth); } // chop the wrapped alignment extent up into panel-sized blocks and treat @@ -1021,29 +1032,23 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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); @@ -1052,7 +1057,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * 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); @@ -1063,23 +1069,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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); } } @@ -1137,16 +1126,16 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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)); } } } @@ -1278,7 +1267,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI // 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)) { @@ -1377,22 +1366,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { // 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, @@ -1400,24 +1384,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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); } } } @@ -1681,9 +1647,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(firstVisibleColumn); + .visibleToAbsoluteColumn(firstVisibleColumn); lastVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(lastVisibleColumn); + .visibleToAbsoluteColumn(lastVisibleColumn); } for (int seqNo = ranges.getStartSeq(); seqNo <= ranges @@ -1726,8 +1692,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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(); @@ -1784,14 +1750,30 @@ public class SeqCanvas extends JComponent implements ViewportListenerI 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 - // paint, so scroll events are identified as changes to the horizontal or - // vertical start value. - if (eventName.equals(ViewportRanges.STARTRES)) - { - if (av.getWrapAlignment()) + // 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 + // paint, so scroll events are identified as changes to the horizontal or + // vertical start value. + if (eventName.equals(ViewportRanges.STARTRES)) + { + if (av.getWrapAlignment()) + { + fastPaintWrapped(scrollX); + } + else + { + fastPaint(scrollX, 0); + } + } + 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); } @@ -1811,14 +1793,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { fastPaintWrapped(scrollX); } - else - { - 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. } } @@ -1835,9 +1809,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { 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 @@ -2115,9 +2087,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(firstVisibleColumn); + .visibleToAbsoluteColumn(firstVisibleColumn); lastVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(lastVisibleColumn); + .visibleToAbsoluteColumn(lastVisibleColumn); } int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1); @@ -2156,7 +2128,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { displayColumn = alignment.getHiddenColumns() - .findColumnPosition(displayColumn); + .absoluteToVisibleColumn(displayColumn); } /* diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 61cac46..e36fa53 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -250,7 +250,7 @@ public class SeqPanel extends JPanel if (av.hasHiddenColumns()) { res = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(res); + .visibleToAbsoluteColumn(res); } return res; @@ -363,13 +363,25 @@ public class SeqPanel extends JPanel int original = seqCanvas.cursorX - dx; int maxWidth = av.getAlignment().getWidth(); - // TODO: once JAL-2759 is ready, change this loop to something more - // efficient - while (!hidden.isVisible(seqCanvas.cursorX) - && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0 - && dx != 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 @@ -424,7 +436,7 @@ public class SeqPanel extends JPanel { // 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 @@ -1259,9 +1271,9 @@ public class SeqPanel extends JPanel { 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)) @@ -1337,7 +1349,8 @@ public class SeqPanel extends JPanel if (sg.getSize() == av.getAlignment().getHeight()) { if ((av.hasHiddenColumns() && startres < av.getAlignment() - .getHiddenColumns().getHiddenBoundaryRight(startres))) + .getHiddenColumns() + .getNextHiddenBoundary(false, startres))) { endEditing(); return; @@ -1656,7 +1669,8 @@ public class SeqPanel extends JPanel public void mouseWheelMoved(MouseWheelEvent e) { e.consume(); - if (e.getWheelRotation() > 0) + double wheelRotation = e.getPreciseWheelRotation(); + if (wheelRotation > 0) { if (e.isShiftDown()) { @@ -1668,7 +1682,7 @@ public class SeqPanel extends JPanel av.getRanges().scrollUp(false); } } - else + else if (wheelRotation < 0) { if (e.isShiftDown()) { @@ -2288,4 +2302,13 @@ public class SeqPanel extends JPanel return true; } + + /** + * + * @return null or last search results handled by this panel + */ + public SearchResultsI getLastSearchResults() + { + return lastSearchResults; + } } diff --git a/src/jalview/gui/SequenceFetcher.java b/src/jalview/gui/SequenceFetcher.java index 8d46792..f545e70 100755 --- a/src/jalview/gui/SequenceFetcher.java +++ b/src/jalview/gui/SequenceFetcher.java @@ -273,7 +273,7 @@ public class SequenceFetcher extends JPanel implements Runnable return Collections.emptyList(); } } - sf.newAlframes = new ArrayList(); + sf.newAlframes = new ArrayList<>(); sf.run(); return sf.newAlframes; } @@ -674,10 +674,10 @@ public class SequenceFetcher extends JPanel implements Runnable // TODO: Refactor to GUI independent code and write tests. // indicate if successive sources should be merged into one alignment. boolean addToLast = false; - List aresultq = new ArrayList(); - List presultTitle = new ArrayList(); - List presult = new ArrayList(); - List aresult = new ArrayList(); + List aresultq = new ArrayList<>(); + List presultTitle = new ArrayList<>(); + List presult = new ArrayList<>(); + List aresult = new ArrayList<>(); Iterator proxies = database.getSelectedSources() .iterator(); String[] qries; @@ -695,7 +695,7 @@ public class SequenceFetcher extends JPanel implements Runnable nqueries = nextFetch.size(); // save the remaining queries in the original array qries = nextFetch.toArray(new String[nqueries]); - nextFetch = new ArrayList(); + nextFetch = new ArrayList<>(); } DbSourceProxy proxy = proxies.next(); @@ -861,7 +861,7 @@ public class SequenceFetcher extends JPanel implements Runnable List aresult, List nextFetch) throws Exception { StringBuilder multiacc = new StringBuilder(); - List tosend = new ArrayList(); + List tosend = new ArrayList<>(); while (accessions.hasNext()) { String nel = accessions.next(); diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java index 217f653..e18d6af 100644 --- a/src/jalview/gui/StructureChooser.java +++ b/src/jalview/gui/StructureChooser.java @@ -21,6 +21,8 @@ package jalview.gui; +import jalview.api.structures.JalviewStructureDisplayI; +import jalview.bin.Cache; import jalview.bin.Jalview; import jalview.datamodel.DBRefEntry; import jalview.datamodel.DBRefSource; @@ -53,6 +55,8 @@ import java.util.Vector; 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; /** @@ -65,6 +69,8 @@ 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; @@ -85,6 +91,8 @@ public class StructureChooser extends GStructureChooser private boolean cachedPDBExists; + private static StructureViewer lastTargetedView = null; + public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq, AlignmentPanel ap) { @@ -98,13 +106,15 @@ public class StructureChooser extends GStructureChooser /** * 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() @@ -122,6 +132,7 @@ public class StructureChooser extends GStructureChooser fetchStructuresMetaData(); // revise filter options if no results were found populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists); + discoverStructureViews(); updateProgressIndicator(null, startTime); mainFrame.setVisible(true); updateCurrentView(); @@ -131,6 +142,59 @@ public class StructureChooser extends GStructureChooser } /** + * 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 @@ -138,7 +202,7 @@ public class StructureChooser extends GStructureChooser * @param id * unique handle for this indicator */ - public void updateProgressIndicator(String message, long id) + protected void updateProgressIndicator(String message, long id) { if (progressIndicator != null) { @@ -150,7 +214,7 @@ public class StructureChooser extends GStructureChooser * 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(); @@ -221,7 +285,7 @@ public class StructureChooser extends GStructureChooser } } - public void loadLocalCachedPDBEntries() + protected void loadLocalCachedPDBEntries() { ArrayList entries = new ArrayList<>(); for (SequenceI seq : selectedSequences) @@ -252,7 +316,7 @@ public class StructureChooser extends GStructureChooser * @return the built query string */ - public static String buildQuery(SequenceI seq) + static String buildQuery(SequenceI seq) { boolean isPDBRefsFound = false; boolean isUniProtRefsFound = false; @@ -354,7 +418,7 @@ public class StructureChooser extends GStructureChooser * @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"; @@ -377,7 +441,7 @@ public class StructureChooser extends GStructureChooser return true; } - public static String getDBRefId(DBRefEntry dbRef) + static String getDBRefId(DBRefEntry dbRef) { String ref = dbRef.getAccessionId().replaceAll("GO:", ""); return ref; @@ -389,7 +453,7 @@ public class StructureChooser extends GStructureChooser * @param fieldToFilterBy * the field to filter by */ - public void filterResultSet(final String fieldToFilterBy) + void filterResultSet(final String fieldToFilterBy) { Thread filterThread = new Thread(new Runnable() { @@ -499,7 +563,7 @@ public class StructureChooser extends GStructureChooser * 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")); @@ -600,28 +664,37 @@ public class StructureChooser extends GStructureChooser } /** - * 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. + *

    + * 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) @@ -632,12 +705,21 @@ public class StructureChooser extends GStructureChooser { 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(); @@ -663,7 +745,7 @@ public class StructureChooser extends GStructureChooser txt_search.setEnabled(true); if (isValidPBDEntry) { - btn_view.setEnabled(true); + btn_add.setEnabled(true); lbl_pdbManualFetchStatus.setToolTipText(""); lbl_pdbManualFetchStatus.setIcon(goodImage); } @@ -678,7 +760,7 @@ public class StructureChooser extends GStructureChooser /** * Validates inputs for the manual PDB file selection options */ - public void validateAssociationFromFile() + protected void validateAssociationFromFile() { AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel .getCmb_assSeq().getSelectedItem(); @@ -689,7 +771,7 @@ public class StructureChooser extends GStructureChooser btn_pdbFromFile.setEnabled(true); if (selectedPdbFileName != null && selectedPdbFileName.length() > 0) { - btn_view.setEnabled(true); + btn_add.setEnabled(true); lbl_fromFileStatus.setIcon(goodImage); } } @@ -701,7 +783,7 @@ public class StructureChooser extends GStructureChooser } @Override - public void cmbAssSeqStateChanged() + protected void cmbAssSeqStateChanged() { validateSelections(); } @@ -728,16 +810,76 @@ public class StructureChooser extends GStructureChooser } /** - * 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() @@ -745,21 +887,24 @@ public class StructureChooser extends GStructureChooser 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 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); @@ -780,7 +925,8 @@ public class StructureChooser extends GStructureChooser } 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) { @@ -803,7 +949,8 @@ public class StructureChooser extends GStructureChooser } 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) { @@ -832,7 +979,7 @@ public class StructureChooser extends GStructureChooser } PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry }; - launchStructureViewer(ssm, pdbEntriesToView, ap, + sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap, new SequenceI[] { selectedSequence }); } @@ -849,14 +996,40 @@ public class StructureChooser extends GStructureChooser 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 pdbEntries) @@ -874,16 +1047,49 @@ public class StructureChooser extends GStructureChooser 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 seqsWithoutSourceDBRef = new ArrayList<>(); @@ -908,7 +1114,7 @@ public class StructureChooser extends GStructureChooser } } } - if (seq.getPrimaryDBRefs().size() == 0) + if (seq.getPrimaryDBRefs().isEmpty()) { seqsWithoutSourceDBRef.add(seq); continue; @@ -920,13 +1126,8 @@ public class StructureChooser extends GStructureChooser 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); @@ -938,16 +1139,19 @@ public class StructureChooser extends GStructureChooser 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; } /** @@ -955,7 +1159,7 @@ public class StructureChooser extends GStructureChooser * a unique sequence when more than one sequence selection is made. */ @Override - public void populateCmbAssociateSeqOptions( + protected void populateCmbAssociateSeqOptions( JComboBox cmb_assSeq, JLabel lbl_associateSeq) { @@ -980,17 +1184,12 @@ public class StructureChooser extends GStructureChooser } } - public boolean isStructuresDiscovered() + protected boolean isStructuresDiscovered() { return discoveredStructuresSet != null && !discoveredStructuresSet.isEmpty(); } - public Collection getDiscoveredStructuresSet() - { - return discoveredStructuresSet; - } - @Override protected void txt_search_ActionPerformed() { @@ -1040,7 +1239,7 @@ public class StructureChooser extends GStructureChooser } @Override - public void tabRefresh() + protected void tabRefresh() { if (selectedSequences != null) { @@ -1178,4 +1377,9 @@ public class StructureChooser extends GStructureChooser { return progressBar.operationInProgress(); } + + public JalviewStructureDisplayI getOpenedStructureViewer() + { + return sViewer == null ? null : sViewer.sview; + } } diff --git a/src/jalview/gui/StructureViewer.java b/src/jalview/gui/StructureViewer.java index fb37b77..0c8354b 100644 --- a/src/jalview/gui/StructureViewer.java +++ b/src/jalview/gui/StructureViewer.java @@ -49,6 +49,11 @@ public class StructureViewer StructureSelectionManager ssm; + /** + * decide if new structures are aligned to existing ones + */ + private boolean superposeAdded = true; + public enum ViewerType { JMOL, CHIMERA @@ -64,6 +69,27 @@ public class StructureViewer 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, @@ -104,14 +130,40 @@ public class StructureViewer 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 { @@ -203,7 +255,7 @@ public class StructureViewer private JalviewStructureDisplayI onlyOnePdb(PDBEntry[] pdbs, SequenceI[] seqsForPdbs, AlignmentPanel ap) { - List seqs = new ArrayList(); + List seqs = new ArrayList<>(); if (pdbs == null || pdbs.length == 0) { return null; @@ -227,11 +279,24 @@ public class StructureViewer 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); @@ -270,7 +335,6 @@ public class StructureViewer final boolean usetoColourbyseq = viewerData.isColourWithAlignPanel(); final boolean viewerColouring = viewerData.isColourByViewer(); - JalviewStructureDisplayI sview = null; switch (type) { case JMOL: @@ -287,4 +351,41 @@ public class StructureViewer 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; + } + } diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 31c20ed..72b0bcc 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -20,6 +20,7 @@ */ package jalview.gui; +import jalview.api.AlignmentViewPanel; import jalview.bin.Cache; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; @@ -34,6 +35,7 @@ import jalview.io.JalviewFileView; 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; @@ -102,9 +104,9 @@ public abstract class StructureViewerBase extends GStructureViewer 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; @@ -113,6 +115,13 @@ public abstract class StructureViewerBase extends GStructureViewer 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() @@ -121,6 +130,26 @@ public abstract class StructureViewerBase extends GStructureViewer } /** + * @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 @@ -326,7 +355,7 @@ public abstract class StructureViewerBase extends GStructureViewer */ 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) { @@ -350,7 +379,7 @@ public abstract class StructureViewerBase extends GStructureViewer } } // and call ourselves again. - addStructure(pdbentry, seqs, chains, align, alignFrame); + addStructure(pdbentry, seqs, chains, alignFrame); } }).start(); return; @@ -362,87 +391,42 @@ public abstract class StructureViewerBase extends GStructureViewer { 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 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 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); } /** @@ -454,9 +438,12 @@ public abstract class StructureViewerBase extends GStructureViewer * @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 @@ -503,47 +490,20 @@ public abstract class StructureViewerBase extends GStructureViewer } } - /** - * 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 chainNames) @@ -823,11 +783,11 @@ public abstract class StructureViewerBase extends GStructureViewer 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) @@ -839,9 +799,9 @@ public abstract class StructureViewerBase extends GStructureViewer } 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); @@ -905,10 +865,11 @@ public abstract class StructureViewerBase extends GStructureViewer } } // 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; } } @@ -988,6 +949,7 @@ public abstract class StructureViewerBase extends GStructureViewer /** * Configures the title and menu items of the viewer panel. */ + @Override public void updateTitleAndMenus() { AAStructureBindingModel binding = getBinding(); @@ -1028,4 +990,54 @@ public abstract class StructureViewerBase extends GStructureViewer 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(); + } + } diff --git a/src/jalview/gui/VamsasApplication.java b/src/jalview/gui/VamsasApplication.java index d2086e0..973cfe8 100644 --- a/src/jalview/gui/VamsasApplication.java +++ b/src/jalview/gui/VamsasApplication.java @@ -1074,16 +1074,16 @@ public class VamsasApplication implements SelectionSource, VamsasSource } 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 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); } diff --git a/src/jalview/io/AlignFile.java b/src/jalview/io/AlignFile.java index 2340283..497f0a5 100755 --- a/src/jalview/io/AlignFile.java +++ b/src/jalview/io/AlignFile.java @@ -72,7 +72,20 @@ public abstract class AlignFile extends FileParse 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. @@ -153,6 +166,11 @@ public abstract class AlignFile extends FileParse { 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(); diff --git a/src/jalview/io/AnnotationFile.java b/src/jalview/io/AnnotationFile.java index 00476d6..e578a45 100755 --- a/src/jalview/io/AnnotationFile.java +++ b/src/jalview/io/AnnotationFile.java @@ -968,7 +968,7 @@ public class AnnotationFile else { // consider deferring this till after the file has been parsed ? - hidden.hideInsertionsFor(sr); + hidden.hideList(sr.getInsertions()); } } modified = true; diff --git a/src/jalview/io/FormatAdapter.java b/src/jalview/io/FormatAdapter.java index 7647a16..6d3c18a 100755 --- a/src/jalview/io/FormatAdapter.java +++ b/src/jalview/io/FormatAdapter.java @@ -212,12 +212,12 @@ public class FormatAdapter extends AppletFormatAdapter 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); } diff --git a/src/jalview/jbgui/GStructureChooser.java b/src/jalview/jbgui/GStructureChooser.java index 9bcaa5a..240e1fd 100644 --- a/src/jalview/jbgui/GStructureChooser.java +++ b/src/jalview/jbgui/GStructureChooser.java @@ -1,6 +1,6 @@ /* - * 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. * @@ -29,6 +29,7 @@ import jalview.fts.service.pdb.PDBFTSRestClient; import jalview.gui.AlignmentPanel; import jalview.gui.Desktop; import jalview.gui.JvSwingUtils; +import jalview.gui.StructureViewer; import jalview.util.MessageManager; import java.awt.BorderLayout; @@ -36,6 +37,7 @@ import java.awt.CardLayout; 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; @@ -70,6 +72,8 @@ import javax.swing.event.DocumentListener; import javax.swing.event.InternalFrameEvent; import javax.swing.table.TableColumn; +import net.miginfocom.swing.MigLayout; + @SuppressWarnings("serial") /** * GUI layout for structure chooser @@ -80,12 +84,23 @@ import javax.swing.table.TableColumn; 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"); @@ -97,41 +112,22 @@ public abstract class GStructureChooser extends JPanel 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")); @@ -147,33 +143,20 @@ public abstract class GStructureChooser extends JPanel 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 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( @@ -262,8 +245,6 @@ public abstract class GStructureChooser extends JPanel } }; - protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary); - public GStructureChooser() { try @@ -319,9 +300,9 @@ public abstract class GStructureChooser extends JPanel 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 @@ -331,7 +312,7 @@ public abstract class GStructureChooser extends JPanel } else { - btn_view.requestFocus(); + btn_add.requestFocus(); } evt.consume(); break; @@ -340,6 +321,30 @@ public abstract class GStructureChooser extends JPanel } } }); + + 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() @@ -368,9 +373,9 @@ public abstract class GStructureChooser extends JPanel 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 @@ -380,9 +385,9 @@ public abstract class GStructureChooser extends JPanel } else { - if (btn_view.isEnabled()) + if (btn_add.isEnabled()) { - btn_view.requestFocus(); + btn_add.requestFocus(); } else { @@ -396,51 +401,52 @@ public abstract class GStructureChooser extends JPanel } } }); - 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() @@ -463,20 +469,17 @@ public abstract class GStructureChooser extends JPanel } }); + 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_tip"))); - cmb_filterOption.setToolTipText( - MessageManager.getString("info.select_filter_option")); txt_search.getDocument().addDocumentListener(new DocumentListener() { @Override @@ -498,8 +501,10 @@ public abstract class GStructureChooser extends JPanel } }); + 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) cmb_filterOption.getRenderer()) @@ -514,23 +519,33 @@ public abstract class GStructureChooser extends JPanel 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); @@ -546,13 +561,15 @@ public abstract class GStructureChooser extends JPanel 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() @@ -578,6 +595,7 @@ public abstract class GStructureChooser extends JPanel 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); @@ -585,12 +603,14 @@ public abstract class GStructureChooser extends JPanel 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); @@ -801,13 +821,13 @@ public abstract class GStructureChooser extends JPanel * @author tcnofoegbu * */ - public class AssciateSeqPanel extends JPanel implements ItemListener + public class AssociateSeqPanel extends JPanel implements ItemListener { private JComboBox cmb_assSeq = new JComboBox<>(); private JLabel lbl_associateSeq = new JLabel(); - public AssciateSeqPanel() + public AssociateSeqPanel() { this.setLayout(new FlowLayout()); this.add(cmb_assSeq); @@ -901,19 +921,21 @@ public abstract class GStructureChooser extends JPanel 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 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 diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 8a80d41..adca17e 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -163,7 +163,7 @@ public class AnnotationRenderer { g.setColor(STEM_COLOUR); int sCol = (lastSSX / charWidth) - + hiddenColumns.adjustForHiddenColumns(startRes); + + hiddenColumns.visibleToAbsoluteColumn(startRes); int x1 = lastSSX; int x2 = (x * charWidth); @@ -230,7 +230,7 @@ public class AnnotationRenderer g.setColor(nonCanColor); int sCol = (lastSSX / charWidth) - + hiddenColumns.adjustForHiddenColumns(startRes); + + hiddenColumns.visibleToAbsoluteColumn(startRes); int x1 = lastSSX; int x2 = (x * charWidth); @@ -602,7 +602,7 @@ public class AnnotationRenderer { if (hasHiddenColumns) { - column = hiddenColumns.adjustForHiddenColumns(startRes + x); + column = hiddenColumns.visibleToAbsoluteColumn(startRes + x); if (column > row_annotations.length - 1) { break; @@ -1150,7 +1150,7 @@ public class AnnotationRenderer g.setColor(HELIX_COLOUR); int sCol = (lastSSX / charWidth) - + hiddenColumns.adjustForHiddenColumns(startRes); + + hiddenColumns.visibleToAbsoluteColumn(startRes); int x1 = lastSSX; int x2 = (x * charWidth); @@ -1250,7 +1250,7 @@ public class AnnotationRenderer column = sRes + x; if (hasHiddenColumns) { - column = hiddenColumns.adjustForHiddenColumns(column); + column = hiddenColumns.visibleToAbsoluteColumn(column); } if (column > aaMax) @@ -1330,7 +1330,7 @@ public class AnnotationRenderer column = sRes + x; if (hasHiddenColumns) { - column = hiddenColumns.adjustForHiddenColumns(column); + column = hiddenColumns.visibleToAbsoluteColumn(column); } if (column > aaMax) diff --git a/src/jalview/renderer/OverviewRenderer.java b/src/jalview/renderer/OverviewRenderer.java index 1c50aab..e9b4de4 100644 --- a/src/jalview/renderer/OverviewRenderer.java +++ b/src/jalview/renderer/OverviewRenderer.java @@ -44,8 +44,6 @@ public class OverviewRenderer // 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; @@ -152,7 +150,7 @@ public class OverviewRenderer if (pixelCol <= endCol) { rgbcolor = getColumnColourFromSequence(allGroups, seq, - alignmentCol, finder); + alignmentCol); // fill in the appropriate number of pixels for (int row = pixelRow; row <= endRow; ++row) @@ -216,27 +214,23 @@ public class OverviewRenderer } /* - * 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(); @@ -359,15 +353,13 @@ public class OverviewRenderer * 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); diff --git a/src/jalview/renderer/ScaleRenderer.java b/src/jalview/renderer/ScaleRenderer.java index d92608c..dc3272f 100644 --- a/src/jalview/renderer/ScaleRenderer.java +++ b/src/jalview/renderer/ScaleRenderer.java @@ -21,9 +21,11 @@ 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; /** @@ -60,27 +62,19 @@ public class ScaleRenderer 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 calculateMarks(AlignViewportI av, int startx, int endx) @@ -88,17 +82,27 @@ public class ScaleRenderer 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 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; } @@ -106,41 +110,40 @@ public class ScaleRenderer { scalestartx += 5; } - List marks = new ArrayList(); + List 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 { diff --git a/src/jalview/structure/StructureMapping.java b/src/jalview/structure/StructureMapping.java index 40789ed..4174f5b 100644 --- a/src/jalview/structure/StructureMapping.java +++ b/src/jalview/structure/StructureMapping.java @@ -21,6 +21,7 @@ package jalview.structure; import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.Mapping; import jalview.datamodel.SequenceI; import java.util.ArrayList; @@ -29,6 +30,12 @@ import java.util.List; 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; @@ -39,16 +46,12 @@ public class StructureMapping 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 mapping; + jalview.datamodel.Mapping seqToPdbMapping = null; + /** * Constructor * @@ -73,6 +76,14 @@ public class StructureMapping this.mappingDetails = mappingDetails; } + public StructureMapping(SequenceI seq, String pdbFile2, String pdbId2, + String chain, HashMap mapping2, + String mappingOutput, Mapping seqToPdbMapping) + { + this(seq, pdbFile2, pdbId2, chain, mapping2, mappingOutput); + this.seqToPdbMapping = seqToPdbMapping; + } + public SequenceI getSequence() { return sequence; @@ -109,7 +120,8 @@ public class StructureMapping /** * * @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) { @@ -134,7 +146,7 @@ public class StructureMapping */ public List getPDBResNumRanges(int fromSeqPos, int toSeqPos) { - List result = new ArrayList(); + List result = new ArrayList<>(); int startRes = -1; int endRes = -1; @@ -247,4 +259,110 @@ public class StructureMapping { 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; + } } diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index 35e2536..cd986c0 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -74,8 +74,6 @@ public class StructureSelectionManager private boolean addTempFacAnnot = false; - private SiftsClient siftsClient = null; - /* * Set of any registered mappings between (dataset) sequences. */ @@ -287,7 +285,8 @@ public class StructureSelectionManager } /** - * 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 @@ -296,7 +295,7 @@ public class StructureSelectionManager { for (StructureMapping sm : mappings) { - if (sm.getPdbId().equals(pdbid)) + if (sm.getPdbId().equalsIgnoreCase(pdbid)) { return sm.pdbfile; } @@ -328,22 +327,20 @@ public class StructureSelectionManager } /** - * 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>, 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 */ @@ -355,49 +352,57 @@ public class StructureSelectionManager 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>, 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) { @@ -411,7 +416,10 @@ public class StructureSelectionManager ex.printStackTrace(); return null; } - + /* + * sifts client - non null if SIFTS mappings are to be used + */ + SiftsClient siftsClient = null; try { if (isMapUsingSIFTs) @@ -422,6 +430,7 @@ public class StructureSelectionManager { isMapUsingSIFTs = false; e.printStackTrace(); + siftsClient = null; } String targetChainId; @@ -524,12 +533,12 @@ public class StructureSelectionManager 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) @@ -540,7 +549,8 @@ public class StructureSelectionManager 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)); @@ -551,24 +561,32 @@ public class StructureSelectionManager List 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 @@ -598,7 +616,10 @@ public class StructureSelectionManager } if (forStructureView) { - mappings.addAll(seqToStrucMapping); + for (StructureMapping sm : seqToStrucMapping) + { + addStructureMapping(sm); // not addAll! + } } if (progress != null) { @@ -608,9 +629,52 @@ public class StructureSelectionManager 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); + } } /** @@ -624,13 +688,15 @@ public class StructureSelectionManager * @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); @@ -639,7 +705,7 @@ public class StructureSelectionManager PDBChain chain = pdb.findChain(targetChainId); if (chain != null) { - chain.transferResidueAnnotation(curChainMapping, sqmpping); + chain.transferResidueAnnotation(curChainMapping, null); } } catch (Exception e) { diff --git a/src/jalview/util/MapList.java b/src/jalview/util/MapList.java index 4658724..ae530f9 100644 --- a/src/jalview/util/MapList.java +++ b/src/jalview/util/MapList.java @@ -77,8 +77,8 @@ public class MapList */ public MapList() { - fromShifts = new ArrayList(); - toShifts = new ArrayList(); + fromShifts = new ArrayList<>(); + toShifts = new ArrayList<>(); } /** @@ -116,8 +116,17 @@ public class MapList { 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; } @@ -347,7 +356,7 @@ public class MapList } boolean changed = false; - List merged = new ArrayList(); + List merged = new ArrayList<>(); int[] lastRange = ranges.get(0); int lastDirection = lastRange[1] >= lastRange[0] ? 1 : -1; lastRange = new int[] { lastRange[0], lastRange[1] }; @@ -803,7 +812,7 @@ public class MapList { return null; } - List ranges = new ArrayList(); + List ranges = new ArrayList<>(); if (fs <= fe) { intv = fs; diff --git a/src/jalview/util/MappingUtils.java b/src/jalview/util/MappingUtils.java index 9c5c109..5a26ed6 100644 --- a/src/jalview/util/MappingUtils.java +++ b/src/jalview/util/MappingUtils.java @@ -542,9 +542,11 @@ public final class MappingUtils toSequences, fromGapChar); } - for (int[] hidden : hiddencols.getHiddenColumnsCopy()) + Iterator regions = hiddencols.iterator(); + while (regions.hasNext()) { - mapHiddenColumns(hidden, codonFrames, newHidden, fromSequences, + mapHiddenColumns(regions.next(), codonFrames, newHidden, + fromSequences, toSequences, fromGapChar); } return; // mappedColumns; diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index a0cbff4..1366ada 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -67,6 +67,7 @@ import java.util.BitSet; import java.util.Deque; import java.util.HashMap; import java.util.Hashtable; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -1740,8 +1741,12 @@ public abstract class AlignmentViewport if (alignment.getHiddenColumns() != null && alignment.getHiddenColumns().hasHiddenColumns()) { - selection = alignment.getHiddenColumns() - .getVisibleSequenceStrings(start, end, seqs); + for (i = 0; i < iSize; i++) + { + Iterator blocks = alignment.getHiddenColumns() + .getVisContigsIterator(start, end + 1, false); + selection[i] = seqs[i].getSequenceStringFromIterator(blocks); + } } else { @@ -1768,10 +1773,10 @@ public abstract class AlignmentViewport { 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; @@ -1786,8 +1791,8 @@ public abstract class AlignmentViewport 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); @@ -1809,13 +1814,13 @@ public abstract class AlignmentViewport 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); } @@ -2781,7 +2786,7 @@ public abstract class AlignmentViewport int lastSeq = alignment.getHeight() - 1; List 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)) diff --git a/src/jalview/viewmodel/OverviewDimensions.java b/src/jalview/viewmodel/OverviewDimensions.java index 170f4e9..0235081 100644 --- a/src/jalview/viewmodel/OverviewDimensions.java +++ b/src/jalview/viewmodel/OverviewDimensions.java @@ -58,6 +58,10 @@ public abstract class OverviewDimensions protected int alheight; + protected float widthRatio; + + protected float heightRatio; + /** * Create an OverviewDimensions object * @@ -157,23 +161,25 @@ public abstract class OverviewDimensions 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; } /** @@ -273,14 +279,14 @@ public abstract class OverviewDimensions // 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); } /** diff --git a/src/jalview/viewmodel/OverviewDimensionsHideHidden.java b/src/jalview/viewmodel/OverviewDimensionsHideHidden.java index c158ce7..de90a21 100644 --- a/src/jalview/viewmodel/OverviewDimensionsHideHidden.java +++ b/src/jalview/viewmodel/OverviewDimensionsHideHidden.java @@ -50,6 +50,8 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions public void updateViewportFromMouse(int mousex, int mousey, HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) { + resetAlignmentDims(); + int xAsRes = getLeftXFromCentreX(mousex, hiddenCols); int yAsSeq = getTopYFromCentreY(mousey, hiddenSeqs); @@ -61,24 +63,29 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions 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) { @@ -147,7 +154,7 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions public AlignmentColsCollectionI getColumns(AlignmentI al) { return new VisibleColsCollection(0, - ranges.getAbsoluteAlignmentWidth() - 1, al); + ranges.getAbsoluteAlignmentWidth() - 1, al.getHiddenColumns()); } @Override @@ -162,19 +169,30 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions { 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; } @@ -182,10 +200,12 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions 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; diff --git a/src/jalview/viewmodel/OverviewDimensionsShowHidden.java b/src/jalview/viewmodel/OverviewDimensionsShowHidden.java index 9dde16e..3aa6e1b 100644 --- a/src/jalview/viewmodel/OverviewDimensionsShowHidden.java +++ b/src/jalview/viewmodel/OverviewDimensionsShowHidden.java @@ -72,13 +72,15 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions 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 @@ -93,27 +95,32 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions 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) { @@ -136,7 +143,7 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions 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 @@ -144,8 +151,8 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions // 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 { @@ -195,8 +202,8 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions 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()); @@ -225,20 +232,32 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions { 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); } @@ -246,12 +265,14 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions 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); } diff --git a/src/jalview/viewmodel/ViewportRanges.java b/src/jalview/viewmodel/ViewportRanges.java index c7a3fa1..691e492 100644 --- a/src/jalview/viewmodel/ViewportRanges.java +++ b/src/jalview/viewmodel/ViewportRanges.java @@ -609,14 +609,14 @@ public class ViewportRanges extends ViewportProperties } 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)) { @@ -638,7 +638,7 @@ public class ViewportRanges extends ViewportProperties 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 diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index 2f30e94..43b0550 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -54,9 +54,9 @@ public abstract class FeatureRendererModel */ protected float transparency = 1.0f; - protected Map featureColours = new ConcurrentHashMap(); + protected Map featureColours = new ConcurrentHashMap<>(); - protected Map featureGroups = new ConcurrentHashMap(); + protected Map featureGroups = new ConcurrentHashMap<>(); protected String[] renderOrder; @@ -156,7 +156,7 @@ public abstract class FeatureRendererModel { av.setFeaturesDisplayed(fdi = new FeaturesDisplayed()); } - List nft = new ArrayList(); + List nft = new ArrayList<>(); for (String featureType : featureTypes) { if (!fdi.isRegistered(featureType)) @@ -192,7 +192,7 @@ public abstract class FeatureRendererModel renderOrder = neworder; } - protected Map minmax = new Hashtable(); + protected Map minmax = new Hashtable<>(); public Map getMinMax() { @@ -271,7 +271,7 @@ public abstract class FeatureRendererModel * include features at the position provided their feature type is * displayed, and feature group is null or marked for display */ - List result = new ArrayList(); + List result = new ArrayList<>(); if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null) { return result; @@ -320,7 +320,7 @@ public abstract class FeatureRendererModel } FeaturesDisplayedI featuresDisplayed = av.getFeaturesDisplayed(); - Set oldfeatures = new HashSet(); + Set oldfeatures = new HashSet<>(); if (renderOrder != null) { for (int i = 0; i < renderOrder.length; i++) @@ -333,7 +333,7 @@ public abstract class FeatureRendererModel } AlignmentI alignment = av.getAlignment(); - List allfeatures = new ArrayList(); + List allfeatures = new ArrayList<>(); for (int i = 0; i < alignment.getHeight(); i++) { @@ -413,7 +413,7 @@ public abstract class FeatureRendererModel */ if (minmax == null) { - minmax = new Hashtable(); + minmax = new Hashtable<>(); } synchronized (minmax) { @@ -450,7 +450,7 @@ public abstract class FeatureRendererModel */ private void updateRenderOrder(List allFeatures) { - List allfeatures = new ArrayList(allFeatures); + List allfeatures = new ArrayList<>(allFeatures); String[] oldRender = renderOrder; renderOrder = new String[allfeatures.size()]; boolean initOrders = (featureOrder == null); @@ -617,7 +617,7 @@ public abstract class FeatureRendererModel { if (featureOrder == null) { - featureOrder = new Hashtable(); + featureOrder = new Hashtable<>(); } featureOrder.put(type, new Float(position)); return position; @@ -676,7 +676,7 @@ public abstract class FeatureRendererModel * note visible feature ordering and colours before update */ List visibleFeatures = getDisplayedFeatureTypes(); - Map visibleColours = new HashMap( + Map visibleColours = new HashMap<>( getFeatureColours()); FeaturesDisplayedI av_featuresdisplayed = null; @@ -836,7 +836,7 @@ public abstract class FeatureRendererModel { if (featureGroups != null) { - List gp = new ArrayList(); + List gp = new ArrayList<>(); for (String grp : featureGroups.keySet()) { @@ -882,7 +882,7 @@ public abstract class FeatureRendererModel @Override public Map getDisplayedFeatureCols() { - Map fcols = new Hashtable(); + Map fcols = new Hashtable<>(); if (getViewport().getFeaturesDisplayed() == null) { return fcols; @@ -910,7 +910,7 @@ public abstract class FeatureRendererModel public List getDisplayedFeatureTypes() { List typ = getRenderOrder(); - List displayed = new ArrayList(); + List displayed = new ArrayList<>(); FeaturesDisplayedI feature_disp = av.getFeaturesDisplayed(); if (feature_disp != null) { @@ -931,7 +931,7 @@ public abstract class FeatureRendererModel @Override public List getDisplayedFeatureGroups() { - List _gps = new ArrayList(); + List _gps = new ArrayList<>(); for (String gp : getFeatureGroups()) { if (checkGroupVisibility(gp, false)) @@ -966,7 +966,7 @@ public abstract class FeatureRendererModel public List findFeaturesAtResidue(SequenceI sequence, int resNo) { - List result = new ArrayList(); + List result = new ArrayList<>(); if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null) { return result; @@ -1011,6 +1011,7 @@ public abstract class FeatureRendererModel { return; } + SequenceFeatures.sortFeatures(features, true); boolean simpleColour = fc == null || fc.isSimpleColour(); SequenceFeature lastFeature = null; @@ -1030,8 +1031,10 @@ public abstract class FeatureRendererModel * same extent as another (so would just redraw the same colour); * (checking type and isContactFeature as a fail-safe here, although * currently they are guaranteed to match in this context) + * don't remove 'redundant' features if transparency is applied + * (as feature count affects depth of feature colour) */ - if (simpleColour) + if (simpleColour && transparency == 1f) { if (lastFeature != null && sf.getBegin() == lastFeature.getBegin() && sf.getEnd() == lastFeature.getEnd() diff --git a/src/jalview/ws/DBRefFetcher.java b/src/jalview/ws/DBRefFetcher.java index fb8864d..1677eca 100644 --- a/src/jalview/ws/DBRefFetcher.java +++ b/src/jalview/ws/DBRefFetcher.java @@ -61,6 +61,8 @@ public class DBRefFetcher implements Runnable { private static final String NEWLINE = System.lineSeparator(); + public static final String TRIM_RETRIEVED_SEQUENCES = "TRIM_FETCHED_DATASET_SEQS"; + public interface FetchFinishedListenerI { void finished(); @@ -139,7 +141,7 @@ public class DBRefFetcher implements Runnable .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); diff --git a/src/jalview/ws/dbsources/Pfam.java b/src/jalview/ws/dbsources/Pfam.java index 0227e35..8877c34 100644 --- a/src/jalview/ws/dbsources/Pfam.java +++ b/src/jalview/ws/dbsources/Pfam.java @@ -20,6 +20,7 @@ */ package jalview.ws.dbsources; +import jalview.bin.Cache; import jalview.datamodel.DBRefSource; import com.stevesoft.pat.Regex; @@ -34,6 +35,9 @@ 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() { @@ -48,7 +52,6 @@ abstract public class Pfam extends Xfam @Override public String getAccessionSeparator() { - // TODO Auto-generated method stub return null; } @@ -60,7 +63,6 @@ abstract public class Pfam extends Xfam @Override public Regex getAccessionValidator() { - // TODO Auto-generated method stub return null; } @@ -91,17 +93,14 @@ abstract public class Pfam extends Xfam @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) diff --git a/src/jalview/ws/dbsources/PfamFull.java b/src/jalview/ws/dbsources/PfamFull.java index ec9fcbb..0600427 100644 --- a/src/jalview/ws/dbsources/PfamFull.java +++ b/src/jalview/ws/dbsources/PfamFull.java @@ -31,20 +31,8 @@ public class PfamFull extends Pfam 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"; } diff --git a/src/jalview/ws/dbsources/PfamSeed.java b/src/jalview/ws/dbsources/PfamSeed.java index 33c39b1..dff8a17 100644 --- a/src/jalview/ws/dbsources/PfamSeed.java +++ b/src/jalview/ws/dbsources/PfamSeed.java @@ -33,19 +33,8 @@ public class PfamSeed extends Pfam 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"; } diff --git a/src/jalview/ws/dbsources/Rfam.java b/src/jalview/ws/dbsources/Rfam.java index 97f73d0..1d9d99a 100644 --- a/src/jalview/ws/dbsources/Rfam.java +++ b/src/jalview/ws/dbsources/Rfam.java @@ -20,6 +20,7 @@ */ package jalview.ws.dbsources; +import jalview.bin.Cache; import jalview.datamodel.DBRefSource; import com.stevesoft.pat.Regex; @@ -31,6 +32,15 @@ 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() { @@ -46,7 +56,6 @@ abstract public class Rfam extends Xfam @Override public String getAccessionSeparator() { - // TODO Auto-generated method stub return null; } @@ -58,7 +67,6 @@ abstract public class Rfam extends Xfam @Override public Regex getAccessionValidator() { - // TODO Auto-generated method stub return null; } @@ -82,18 +90,9 @@ abstract public class Rfam extends Xfam @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) * diff --git a/src/jalview/ws/dbsources/RfamFull.java b/src/jalview/ws/dbsources/RfamFull.java index b2ca31a..d815336 100644 --- a/src/jalview/ws/dbsources/RfamFull.java +++ b/src/jalview/ws/dbsources/RfamFull.java @@ -33,20 +33,8 @@ public class RfamFull extends Rfam 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"; } diff --git a/src/jalview/ws/dbsources/RfamSeed.java b/src/jalview/ws/dbsources/RfamSeed.java index f714547..a74e829 100644 --- a/src/jalview/ws/dbsources/RfamSeed.java +++ b/src/jalview/ws/dbsources/RfamSeed.java @@ -33,19 +33,8 @@ public class RfamSeed extends Rfam 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"; diff --git a/src/jalview/ws/dbsources/Uniprot.java b/src/jalview/ws/dbsources/Uniprot.java index 73775cf..6b09eb6 100644 --- a/src/jalview/ws/dbsources/Uniprot.java +++ b/src/jalview/ws/dbsources/Uniprot.java @@ -20,6 +20,7 @@ */ package jalview.ws.dbsources; +import jalview.bin.Cache; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.DBRefEntry; @@ -52,6 +53,8 @@ import com.stevesoft.pat.Regex; */ public class Uniprot extends DbSourceProxyImpl { + private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org"; + private static final String BAR_DELIMITER = "|"; /* @@ -67,6 +70,11 @@ public class Uniprot extends DbSourceProxyImpl super(); } + private String getDomain() + { + return Cache.getDefault("UNIPROT_DOMAIN", DEFAULT_UNIPROT_DOMAIN); + } + /* * (non-Javadoc) * @@ -163,7 +171,7 @@ public class Uniprot extends DbSourceProxyImpl "(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; diff --git a/src/jalview/ws/dbsources/Xfam.java b/src/jalview/ws/dbsources/Xfam.java index 26291eb..b83f558 100644 --- a/src/jalview/ws/dbsources/Xfam.java +++ b/src/jalview/ws/dbsources/Xfam.java @@ -42,7 +42,12 @@ public abstract class Xfam extends DbSourceProxyImpl super(); } - protected abstract String getXFAMURL(); + /** + * the base URL for this Xfam-like service + * + * @return + */ + protected abstract String getURLPrefix(); @Override public abstract String getDbVersion(); @@ -57,8 +62,7 @@ public abstract class Xfam extends DbSourceProxyImpl // 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) { @@ -83,6 +87,12 @@ public abstract class Xfam extends DbSourceProxyImpl return rcds; } + String getURL(String queries) + { + return getURLPrefix() + "/family/" + queries.trim().toUpperCase() + + getURLSuffix(); + } + /** * Pfam and Rfam provide alignments */ @@ -97,7 +107,7 @@ public abstract class Xfam extends DbSourceProxyImpl * * @return "" for most Xfam sources */ - public String getXFAMURLSUFFIX() + public String getURLSuffix() { return ""; } diff --git a/src/jalview/ws/jws1/JPredThread.java b/src/jalview/ws/jws1/JPredThread.java index a239625..23d9eb0 100644 --- a/src/jalview/ws/jws1/JPredThread.java +++ b/src/jalview/ws/jws1/JPredThread.java @@ -235,8 +235,7 @@ class JPredThread extends JWS1Thread implements WSClientI { // Adjust input view for gaps // propagate insertions into profile - alhidden = HiddenColumns.propagateInsertions(profileseq, al, - input); + alhidden = al.propagateInsertions(profileseq, input); } } } diff --git a/src/jalview/ws/sifts/SiftsClient.java b/src/jalview/ws/sifts/SiftsClient.java index 68af7c3..b5f9653 100644 --- a/src/jalview/ws/sifts/SiftsClient.java +++ b/src/jalview/ws/sifts/SiftsClient.java @@ -92,14 +92,24 @@ public class SiftsClient implements SiftsClientI 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/"; @@ -413,6 +423,11 @@ public class SiftsClient implements SiftsClientI 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()); @@ -435,8 +450,9 @@ public class SiftsClient implements SiftsClientI HashMap 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; } @@ -444,8 +460,8 @@ public class SiftsClient implements SiftsClientI public HashMap getGreedyMapping(String entityId, SequenceI seq, java.io.PrintStream os) throws SiftsException { - List omitNonObserved = new ArrayList(); - int nonObservedShiftIndex = 0; + List omitNonObserved = new ArrayList<>(); + int nonObservedShiftIndex = 0,pdbeNonObserved=0; // System.out.println("Generating mappings for : " + entityId); Entity entity = null; entity = getEntityById(entityId); @@ -476,7 +492,7 @@ public class SiftsClient implements SiftsClientI TreeMap resNumMap = new TreeMap(); List segments = entity.getSegment(); SegmentHelperPojo shp = new SegmentHelperPojo(seq, mapping, resNumMap, - omitNonObserved, nonObservedShiftIndex); + omitNonObserved, nonObservedShiftIndex,pdbeNonObserved); processSegments(segments, shp); try { @@ -498,15 +514,61 @@ public class SiftsClient implements SiftsClientI { throw new SiftsException("SIFTS mapping failed"); } + // also construct a mapping object between the seq-coord sys and the PDB seq's coord sys Integer[] keys = mapping.keySet().toArray(new Integer[0]); Arrays.sort(keys); seqStart = keys[0]; seqEnd = keys[keys.length - 1]; - + List 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(); @@ -559,6 +621,8 @@ public class SiftsClient implements SiftsClientI TreeMap resNumMap = shp.getResNumMap(); List 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 @@ -566,6 +630,9 @@ public class SiftsClient implements SiftsClientI List residues = segment.getListResidue().getResidue(); for (Residue residue : residues) { + boolean isObserved = isResidueObserved(residue); + int pdbeIndex = getLeadingIntegerValue(residue.getDbResNum(), + UNASSIGNED); int currSeqIndex = UNASSIGNED; List cRefDbs = residue.getCrossRefDb(); CrossRefDb pdbRefDb = null; @@ -574,6 +641,19 @@ public class SiftsClient implements SiftsClientI 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())) @@ -586,11 +666,45 @@ public class SiftsClient implements SiftsClientI } } } + 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) @@ -599,22 +713,18 @@ public class SiftsClient implements SiftsClientI : 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 }); } } } @@ -904,17 +1014,36 @@ public class SiftsClient implements SiftsClientI 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 mapping, TreeMap resNumMap, - List omitNonObserved, int nonObservedShiftIndex) + List 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; @@ -964,6 +1093,7 @@ public class SiftsClient implements SiftsClientI { this.nonObservedShiftIndex = nonObservedShiftIndex; } + } @Override diff --git a/test/MCview/PDBChainTest.java b/test/MCview/PDBChainTest.java index defcdbc..533c0af 100644 --- a/test/MCview/PDBChainTest.java +++ b/test/MCview/PDBChainTest.java @@ -91,7 +91,7 @@ public class PDBChainTest a3.resName = "ASP"; a3.resNumber = 41; - Vector v = new Vector(); + Vector v = new Vector<>(); v.add(new Bond(a1, a2)); v.add(new Bond(a2, a3)); v.add(new Bond(a3, a1)); @@ -234,7 +234,7 @@ public class PDBChainTest @Test(groups = { "Functional" }) public void testMakeResidueList_noAnnotation() { - Vector atoms = new Vector(); + Vector atoms = new Vector<>(); c.atoms = atoms; c.isNa = true; atoms.add(makeAtom(4, "N", "MET")); @@ -292,7 +292,7 @@ public class PDBChainTest @Test(groups = { "Functional" }) public void testMakeResidueList_withTempFactor() { - Vector atoms = new Vector(); + Vector atoms = new Vector<>(); c.atoms = atoms; atoms.add(makeAtom(4, "N", "MET")); atoms.get(atoms.size() - 1).tfactor = 1f; @@ -307,7 +307,7 @@ public class PDBChainTest 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")); @@ -320,7 +320,7 @@ public class PDBChainTest /* * 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); @@ -328,12 +328,12 @@ public class PDBChainTest 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); } /** @@ -344,7 +344,7 @@ public class PDBChainTest public void testMakeCaBondList() { c.isNa = true; - Vector atoms = new Vector(); + Vector atoms = new Vector<>(); c.atoms = atoms; atoms.add(makeAtom(4, "N", "MET")); atoms.add(makeAtom(4, "CA", "MET")); @@ -375,7 +375,7 @@ public class PDBChainTest public void testMakeCaBondList_nucleotide() { c.isNa = false; - Vector atoms = new Vector(); + Vector atoms = new Vector<>(); c.atoms = atoms; atoms.add(makeAtom(4, "N", "G")); atoms.add(makeAtom(4, "P", "G")); @@ -406,7 +406,7 @@ public class PDBChainTest @Test(groups = { "Functional" }) public void testMakeExactMapping() { - Vector atoms = new Vector(); + Vector atoms = new Vector<>(); c.atoms = atoms; atoms.add(makeAtom(4, "N", "MET")); atoms.add(makeAtom(4, "CA", "MET")); diff --git a/test/jalview/analysis/AlignmentUtilsTests.java b/test/jalview/analysis/AlignmentUtilsTests.java index 06b51e6..35196fa 100644 --- a/test/jalview/analysis/AlignmentUtilsTests.java +++ b/test/jalview/analysis/AlignmentUtilsTests.java @@ -47,6 +47,7 @@ import jalview.io.DataSourceType; 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; @@ -263,14 +264,14 @@ public class AlignmentUtilsTests @Test(groups = { "Functional" }) public void testMapProteinAlignmentToCdna_noXrefs() throws IOException { - List protseqs = new ArrayList(); + List 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 dnaseqs = new ArrayList(); + List 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 @@ -507,7 +508,7 @@ public class AlignmentUtilsTests acf.addMap(dna1.getDatasetSequence(), prot1.getDatasetSequence(), map); acf.addMap(dna2.getDatasetSequence(), prot2.getDatasetSequence(), map); acf.addMap(dna3.getDatasetSequence(), prot3.getDatasetSequence(), map); - ArrayList acfs = new ArrayList(); + ArrayList acfs = new ArrayList<>(); acfs.add(acf); protein.setCodonFrames(acfs); @@ -605,14 +606,14 @@ public class AlignmentUtilsTests public void testMapProteinAlignmentToCdna_withStartAndStopCodons() throws IOException { - List protseqs = new ArrayList(); + List 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 dnaseqs = new ArrayList(); + List dnaseqs = new ArrayList<>(); // start + SAR: dnaseqs.add(new Sequence("EMBL|A11111", "ATGTCAGCACGC")); // = EIQ + stop @@ -697,14 +698,14 @@ public class AlignmentUtilsTests @Test(groups = { "Functional" }) public void testMapProteinAlignmentToCdna_withXrefs() throws IOException { - List protseqs = new ArrayList(); + List 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 dnaseqs = new ArrayList(); + List 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 @@ -774,14 +775,14 @@ public class AlignmentUtilsTests public void testMapProteinAlignmentToCdna_prioritiseXrefs() throws IOException { - List protseqs = new ArrayList(); + List 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 dnaseqs = new ArrayList(); + List 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 @@ -848,8 +849,8 @@ public class AlignmentUtilsTests al.addAnnotation(ann4); // Temp for seq1 al.addAnnotation(ann5); // Temp for seq2 al.addAnnotation(ann6); // Temp for no sequence - List types = new ArrayList(); - List scope = new ArrayList(); + List types = new ArrayList<>(); + List scope = new ArrayList<>(); /* * Set all sequence related Structure to hidden (ann1, ann2) @@ -1747,7 +1748,7 @@ public class AlignmentUtilsTests map = new MapList(new int[] { 9, 11 }, new int[] { 2, 2 }, 3, 1); acf.addMap(dna3.getDatasetSequence(), prot3.getDatasetSequence(), map); - ArrayList acfs = new ArrayList(); + ArrayList acfs = new ArrayList<>(); acfs.add(acf); protein.setCodonFrames(acfs); @@ -2030,9 +2031,9 @@ public class AlignmentUtilsTests sf6.setValue("ID", "var6"); sf6.setValue("clinical_significance", "Good"); - List codon1Variants = new ArrayList(); - List codon2Variants = new ArrayList(); - List codon3Variants = new ArrayList(); + List codon1Variants = new ArrayList<>(); + List codon2Variants = new ArrayList<>(); + List codon3Variants = new ArrayList<>(); List codonVariants[] = new ArrayList[3]; codonVariants[0] = codon1Variants; codonVariants[1] = codon2Variants; @@ -2272,7 +2273,7 @@ public class AlignmentUtilsTests seq1.createDatasetSequence(); Mapping mapping = new Mapping(seq1, new MapList( new int[] { 3, 6, 9, 10 }, new int[] { 1, 6 }, 1, 1)); - Map> map = new TreeMap>(); + Map> map = new TreeMap<>(); AlignmentUtils.addMappedPositions(seq1, from, mapping, map); /* @@ -2304,7 +2305,7 @@ public class AlignmentUtilsTests seq1.createDatasetSequence(); Mapping mapping = new Mapping(seq1, new MapList( new int[] { 3, 6, 9, 10 }, new int[] { 1, 6 }, 1, 1)); - Map> map = new TreeMap>(); + Map> map = new TreeMap<>(); AlignmentUtils.addMappedPositions(seq1, from, mapping, map); /* @@ -2561,7 +2562,7 @@ public class AlignmentUtilsTests * 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)); @@ -2574,17 +2575,42 @@ public class AlignmentUtilsTests 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(); @@ -2600,4 +2626,151 @@ public class AlignmentUtilsTests 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 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 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 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 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()); + } } diff --git a/test/jalview/analysis/CrossRefTest.java b/test/jalview/analysis/CrossRefTest.java index 95be1ff..0265af3 100644 --- a/test/jalview/analysis/CrossRefTest.java +++ b/test/jalview/analysis/CrossRefTest.java @@ -106,7 +106,7 @@ public class CrossRefTest public void testFindXrefSourcesForSequence_proteinToDna() { SequenceI seq = new Sequence("Seq1", "MGKYQARLSS"); - List sources = new ArrayList(); + List sources = new ArrayList<>(); AlignmentI al = new Alignment(new SequenceI[] {}); /* @@ -132,8 +132,9 @@ public class CrossRefTest 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 @@ -270,7 +271,7 @@ public class CrossRefTest pep1.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2")); AlignmentI al = new Alignment(new SequenceI[] { dna1, pep1 }); - List result = new ArrayList(); + List result = new ArrayList<>(); /* * first search for a dbref nowhere on the alignment: diff --git a/test/jalview/analysis/DnaTest.java b/test/jalview/analysis/DnaTest.java index d2fa99a..6a31b31 100644 --- a/test/jalview/analysis/DnaTest.java +++ b/test/jalview/analysis/DnaTest.java @@ -38,6 +38,7 @@ 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.Test; @@ -135,7 +136,9 @@ public class DnaTest FileFormat.Fasta); HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(alf, cs); - Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 }); + Iterator 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); @@ -163,7 +166,8 @@ public class DnaTest cs.hideColumns(0, ipos - 1); } cs.hideColumns(ipos + vwidth, alf.getWidth()); - int[] vcontigs = cs.getVisibleContigs(0, alf.getWidth()); + Iterator vcontigs = cs.getVisContigsIterator(0, + alf.getWidth(), false); AlignViewportI av = new AlignViewport(alf, cs); Dna dna = new Dna(av, vcontigs); AlignmentI transAlf = dna.translateCdna(); @@ -190,7 +194,9 @@ public class DnaTest 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 contigs = cs.getVisContigsIterator(0, alf.getWidth(), + false); + Dna dna = new Dna(av, contigs); AlignmentI translated = dna.translateCdna(); String aa = translated.getSequenceAt(0).getSequenceAsString(); assertEquals( @@ -213,7 +219,9 @@ public class DnaTest 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 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); @@ -298,7 +306,9 @@ public class DnaTest .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 contigs = cs.getVisContigsIterator(0, cdna.getWidth(), + false); + Dna dna = new Dna(av, contigs); AlignmentI translated = dna.translateCdna(); /* @@ -313,7 +323,8 @@ public class DnaTest } 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(); /* @@ -544,7 +555,9 @@ public class DnaTest HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(al, cs); - Dna testee = new Dna(av, new int[] { 0, al.getWidth() - 1 }); + Iterator 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()); diff --git a/test/jalview/datamodel/AlignmentAnnotationTests.java b/test/jalview/datamodel/AlignmentAnnotationTests.java index e47e9d6..19a725e 100644 --- a/test/jalview/datamodel/AlignmentAnnotationTests.java +++ b/test/jalview/datamodel/AlignmentAnnotationTests.java @@ -20,8 +20,8 @@ */ 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; @@ -335,4 +335,92 @@ public class AlignmentAnnotationTests 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]); + } } diff --git a/test/jalview/datamodel/AlignmentTest.java b/test/jalview/datamodel/AlignmentTest.java index 4b5d096..1d1ebd6 100644 --- a/test/jalview/datamodel/AlignmentTest.java +++ b/test/jalview/datamodel/AlignmentTest.java @@ -34,6 +34,7 @@ import jalview.io.DataSourceType; import jalview.io.FileFormat; import jalview.io.FileFormatI; import jalview.io.FormatAdapter; +import jalview.util.Comparison; import jalview.util.MapList; import java.io.IOException; @@ -247,7 +248,9 @@ public class AlignmentTest 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; } @@ -668,6 +671,17 @@ public class AlignmentTest // 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(); @@ -1321,4 +1335,153 @@ public class AlignmentTest // 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 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 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()); + } } diff --git a/test/jalview/datamodel/ColumnSelectionTest.java b/test/jalview/datamodel/ColumnSelectionTest.java index e99e952..8709961 100644 --- a/test/jalview/datamodel/ColumnSelectionTest.java +++ b/test/jalview/datamodel/ColumnSelectionTest.java @@ -32,6 +32,7 @@ import java.util.Arrays; 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; @@ -132,9 +133,9 @@ public class ColumnSelectionTest // hide column 5 (and adjacent): cs.hideSelectedColumns(5, al.getHiddenColumns()); // 4,5,6 now hidden: - List hidden = al.getHiddenColumns().getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[4, 6]", Arrays.toString(hidden.get(0))); + Iterator regions = al.getHiddenColumns().iterator(); + assertEquals(1, al.getHiddenColumns().getNumberOfRegions()); + assertEquals("[4, 6]", Arrays.toString(regions.next())); // none now selected: assertTrue(cs.getSelected().isEmpty()); @@ -145,9 +146,9 @@ public class ColumnSelectionTest 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 @@ -157,9 +158,9 @@ public class ColumnSelectionTest 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 @@ -168,9 +169,9 @@ public class ColumnSelectionTest 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()); } @@ -196,12 +197,12 @@ public class ColumnSelectionTest cs.hideSelectedColumns(al); assertTrue(cs.getSelected().isEmpty()); - List 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 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())); } /** diff --git a/test/jalview/datamodel/HiddenColumnsCursorTest.java b/test/jalview/datamodel/HiddenColumnsCursorTest.java new file mode 100644 index 0000000..97402b8 --- /dev/null +++ b/test/jalview/datamodel/HiddenColumnsCursorTest.java @@ -0,0 +1,157 @@ +/* + * 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 . + * 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 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 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 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); + } +} diff --git a/test/jalview/datamodel/HiddenColumnsTest.java b/test/jalview/datamodel/HiddenColumnsTest.java index 7c88d71..2916199 100644 --- a/test/jalview/datamodel/HiddenColumnsTest.java +++ b/test/jalview/datamodel/HiddenColumnsTest.java @@ -26,26 +26,15 @@ import static org.testng.AssertJUnit.assertFalse; 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 */ @@ -77,22 +66,22 @@ public class HiddenColumnsTest 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 @@ -102,105 +91,82 @@ public class HiddenColumnsTest 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 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" }) @@ -216,14 +182,31 @@ public class HiddenColumnsTest 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") @@ -232,102 +215,50 @@ public class HiddenColumnsTest HiddenColumns cs = new HiddenColumns(); cs.hideColumns(10, 11); cs.hideColumns(5, 7); + Iterator 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 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() @@ -339,80 +270,103 @@ public class HiddenColumnsTest ColumnSelection colsel = new ColumnSelection(); HiddenColumns cs = al.getHiddenColumns(); colsel.hideSelectedColumns(5, al.getHiddenColumns()); - List hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[5, 5]", Arrays.toString(hidden.get(0))); + Iterator 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); } /** @@ -424,11 +378,18 @@ public class HiddenColumnsTest { 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()); @@ -436,36 +397,67 @@ public class HiddenColumnsTest colsel = new ColumnSelection(); cs = new HiddenColumns(); cs.hideColumns(5, 8); - List 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)); @@ -477,6 +469,7 @@ public class HiddenColumnsTest assertTrue(cs.isVisible(5)); assertFalse(cs.isVisible(6)); assertFalse(cs.isVisible(7)); + assertTrue(cs.isVisible(8)); } /** @@ -493,15 +486,17 @@ public class HiddenColumnsTest HiddenColumns cs = new HiddenColumns(); cs.hideColumns(49, 59); cs.hideColumns(69, 79); - List hidden = cs.getHiddenColumnsCopy(); - assertEquals(2, hidden.size()); - assertEquals("[49, 59]", Arrays.toString(hidden.get(0))); - assertEquals("[69, 79]", Arrays.toString(hidden.get(1))); + Iterator 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 @@ -512,9 +507,10 @@ public class HiddenColumnsTest 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, @@ -528,14 +524,15 @@ public class HiddenColumnsTest 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; @@ -544,80 +541,45 @@ public class HiddenColumnsTest // 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 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" }) @@ -637,7 +599,7 @@ public class HiddenColumnsTest } @Test(groups = "Functional") - public void getVisibleStartAndEndIndexTest() + public void testGetVisibleStartAndEndIndex() { Sequence seq = new Sequence("testSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); AlignmentI align = new Alignment(new SequenceI[] { seq }); @@ -663,6 +625,13 @@ public class HiddenColumnsTest 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") @@ -677,58 +646,683 @@ public class HiddenColumnsTest 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 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 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 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 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 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 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()); } } diff --git a/test/jalview/datamodel/VisibleColsIteratorTest.java b/test/jalview/datamodel/RangeElementsIteratorTest.java similarity index 84% rename from test/jalview/datamodel/VisibleColsIteratorTest.java rename to test/jalview/datamodel/RangeElementsIteratorTest.java index b2d747b..9d14822 100644 --- a/test/jalview/datamodel/VisibleColsIteratorTest.java +++ b/test/jalview/datamodel/RangeElementsIteratorTest.java @@ -22,12 +22,13 @@ package jalview.datamodel; 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; @@ -50,11 +51,12 @@ public class VisibleColsIteratorTest @Test(groups = { "Functional" }) public void testHasNextAndNextWithHidden() { - VisibleColsIterator it = new VisibleColsIterator(0, 6, hiddenCols); + Iterator 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"); @@ -67,8 +69,8 @@ public class VisibleColsIteratorTest @Test(groups = { "Functional" }) public void testHasNextAndNextNoHidden() { - VisibleColsIterator it2 = new VisibleColsIterator(0, 3, - new HiddenColumns()); + HiddenColumns test = new HiddenColumns(); + Iterator it2 = test.getVisibleColsIterator(0, 3); int count = 0; while (it2.hasNext()) { @@ -85,8 +87,7 @@ public class VisibleColsIteratorTest @Test(groups = { "Functional" }) public void testHasNextAndNextStartHidden() { - VisibleColsIterator it3 = new VisibleColsIterator(0, 6, - hiddenColsAtStart); + Iterator it3 = hiddenColsAtStart.getVisibleColsIterator(0, 6); int count = 0; while (it3.hasNext()) { @@ -103,7 +104,7 @@ public class VisibleColsIteratorTest @Test(groups = { "Functional" }) public void testHasNextAndNextEndHidden() { - VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols); + Iterator it4 = hiddenCols.getVisibleColsIterator(0, 4); int count = 0; while (it4.hasNext()) { @@ -123,7 +124,7 @@ public class VisibleColsIteratorTest expectedExceptions = { NoSuchElementException.class }) public void testLastNextWithHidden() throws NoSuchElementException { - VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols); + Iterator it = hiddenCols.getVisibleColsIterator(0, 3); while (it.hasNext()) { it.next(); @@ -140,8 +141,8 @@ public class VisibleColsIteratorTest expectedExceptions = { NoSuchElementException.class }) public void testLastNextNoHidden() throws NoSuchElementException { - VisibleColsIterator it2 = new VisibleColsIterator(0, 3, - new HiddenColumns()); + HiddenColumns test = new HiddenColumns(); + Iterator it2 = test.getVisibleColsIterator(0, 3); while (it2.hasNext()) { it2.next(); @@ -158,8 +159,7 @@ public class VisibleColsIteratorTest expectedExceptions = { NoSuchElementException.class }) public void testLastNextStartHidden() throws NoSuchElementException { - VisibleColsIterator it3 = new VisibleColsIterator(0, 6, - hiddenColsAtStart); + Iterator it3 = hiddenColsAtStart.getVisibleColsIterator(0, 6); while (it3.hasNext()) { it3.next(); @@ -176,7 +176,7 @@ public class VisibleColsIteratorTest expectedExceptions = { NoSuchElementException.class }) public void testLastNextEndHidden() throws NoSuchElementException { - VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols); + Iterator it4 = hiddenCols.getVisibleColsIterator(0, 4); while (it4.hasNext()) { it4.next(); @@ -192,7 +192,7 @@ public class VisibleColsIteratorTest expectedExceptions = { UnsupportedOperationException.class }) public void testRemove() throws UnsupportedOperationException { - VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols); + Iterator it = hiddenCols.getVisibleColsIterator(0, 3); it.remove(); } } diff --git a/test/jalview/datamodel/SequenceTest.java b/test/jalview/datamodel/SequenceTest.java index a084a8e..5a14514 100644 --- a/test/jalview/datamodel/SequenceTest.java +++ b/test/jalview/datamodel/SequenceTest.java @@ -28,6 +28,7 @@ import static org.testng.AssertJUnit.assertNull; 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; @@ -38,16 +39,17 @@ import java.io.File; 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 { @@ -799,7 +801,7 @@ public class SequenceTest Assert.assertEquals(pdbe1a, sq.getDatasetSequence().getPDBEntry("1PDB"), "PDB Entry '1PDB' not found on dataset sequence via getPDBEntry."); - ArrayList annotsList = new ArrayList(); + ArrayList 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)); @@ -1674,6 +1676,20 @@ public class SequenceTest } @Test(groups = { "Functional" }) + 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); + + assertTrue(bs.equals(expected)); + + } + public void testFindFeatures_largeEndPos() { /* @@ -1881,4 +1897,162 @@ public class SequenceTest 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 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())); + + } } diff --git a/test/jalview/datamodel/StartRegionIteratorTest.java b/test/jalview/datamodel/StartRegionIteratorTest.java new file mode 100644 index 0000000..23d0b00 --- /dev/null +++ b/test/jalview/datamodel/StartRegionIteratorTest.java @@ -0,0 +1,214 @@ +/* + * 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 . + * 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 hiddenColumns = null; + + // null hidden columns + Iterator 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 hiddenColumns = null; + HiddenCursorPosition pos = null; + + // null hidden columns + Iterator 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 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 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()); + } +} diff --git a/test/jalview/datamodel/VisibleContigsIteratorTest.java b/test/jalview/datamodel/VisibleContigsIteratorTest.java new file mode 100644 index 0000000..8f31dae --- /dev/null +++ b/test/jalview/datamodel/VisibleContigsIteratorTest.java @@ -0,0 +1,223 @@ +/* + * 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 . + * 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 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 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 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]); + } +} diff --git a/test/jalview/ext/ensembl/EnsemblGeneTest.java b/test/jalview/ext/ensembl/EnsemblGeneTest.java index 1b1a2b4..217742d 100644 --- a/test/jalview/ext/ensembl/EnsemblGeneTest.java +++ b/test/jalview/ext/ensembl/EnsemblGeneTest.java @@ -25,6 +25,7 @@ import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertTrue; import jalview.api.FeatureSettingsModelI; +import jalview.bin.Cache; import jalview.datamodel.SequenceDummy; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; @@ -53,6 +54,7 @@ public class EnsemblGeneTest @BeforeClass(alwaysRun = true) public void setUp() { + Cache.loadProperties("test/jalview/io/testProps.jvprops"); SequenceOntologyFactory.setInstance(new SequenceOntologyLite()); } diff --git a/test/jalview/ext/jmol/JmolCommandsTest.java b/test/jalview/ext/jmol/JmolCommandsTest.java index 3309adf..e42b54f 100644 --- a/test/jalview/ext/jmol/JmolCommandsTest.java +++ b/test/jalview/ext/jmol/JmolCommandsTest.java @@ -115,7 +115,7 @@ public class JmolCommandsTest 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) @@ -128,7 +128,7 @@ public class JmolCommandsTest 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]")); diff --git a/test/jalview/ext/jmol/JmolViewerTest.java b/test/jalview/ext/jmol/JmolViewerTest.java index 792f7ad..e451ed2 100644 --- a/test/jalview/ext/jmol/JmolViewerTest.java +++ b/test/jalview/ext/jmol/JmolViewerTest.java @@ -20,11 +20,15 @@ */ 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; @@ -32,6 +36,10 @@ import jalview.gui.Preferences; 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; @@ -54,8 +62,10 @@ public class JmolViewerTest @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" }); } /** @@ -70,10 +80,11 @@ public class JmolViewerTest @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()) { @@ -87,13 +98,13 @@ public class JmolViewerTest { 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 */ @@ -116,5 +127,86 @@ public class JmolViewerTest } } + @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())); + } } diff --git a/test/jalview/gui/AlignFrameTest.java b/test/jalview/gui/AlignFrameTest.java index af9c045..dd1a4de 100644 --- a/test/jalview/gui/AlignFrameTest.java +++ b/test/jalview/gui/AlignFrameTest.java @@ -46,7 +46,7 @@ import jalview.schemes.TurnColourScheme; 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; @@ -85,24 +85,20 @@ public class AlignFrameTest */ 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 hidden = alignFrame.getViewport().getAlignment() - .getHiddenColumns() - .getHiddenColumnsCopy(); - assertTrue(hidden.isEmpty()); + assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns() + .getNumberOfRegions(), 0); /* * hide a feature present in some columns @@ -110,13 +106,16 @@ public class AlignFrameTest * [1-3], [6-8] base zero */ 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); + Iterator regions = alignFrame.getViewport().getAlignment() + .getHiddenColumns().iterator(); + assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns() + .getNumberOfRegions(), 2); + int[] 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) diff --git a/test/jalview/gui/AnnotationColumnChooserTest.java b/test/jalview/gui/AnnotationColumnChooserTest.java index 06478d5..912cd27 100644 --- a/test/jalview/gui/AnnotationColumnChooserTest.java +++ b/test/jalview/gui/AnnotationColumnChooserTest.java @@ -35,7 +35,7 @@ import jalview.io.FileFormat; import jalview.io.FormatAdapter; import java.io.IOException; -import java.util.List; +import java.util.Iterator; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; @@ -141,18 +141,21 @@ public class AnnotationColumnChooserTest HiddenColumns currentHidden = af.getViewport().getAlignment() .getHiddenColumns(); - List regions = currentHidden.getHiddenColumnsCopy(); - assertEquals(regions.get(0)[0], 0); - assertEquals(regions.get(0)[1], 3); - assertEquals(regions.get(1)[0], 22); - assertEquals(regions.get(1)[1], 25); + Iterator 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.getHiddenColumnsCopy(); - assertEquals(regions.get(0)[0], 10); - assertEquals(regions.get(0)[1], 20); + 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(); @@ -169,8 +172,9 @@ public class AnnotationColumnChooserTest acc.reset(); currentHidden = af.getViewport().getAlignment().getHiddenColumns(); - regions = currentHidden.getHiddenColumnsCopy(); - assertEquals(regions.get(0)[0], 10); - assertEquals(regions.get(0)[1], 20); + regions = currentHidden.iterator(); + next = regions.next(); + assertEquals(10, next[0]); + assertEquals(20, next[1]); } } diff --git a/test/jalview/gui/PopupMenuTest.java b/test/jalview/gui/PopupMenuTest.java index 335240b..8f60021 100644 --- a/test/jalview/gui/PopupMenuTest.java +++ b/test/jalview/gui/PopupMenuTest.java @@ -29,9 +29,12 @@ import static org.testng.AssertJUnit.assertTrue; 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.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.io.DataSourceType; import jalview.io.FileFormat; @@ -41,6 +44,7 @@ import jalview.util.MessageManager; import java.awt.Component; import java.io.IOException; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import javax.swing.JMenu; @@ -100,7 +104,7 @@ public class PopupMenuTest public void testConfigureReferenceAnnotationsMenu_noSequenceSelected() { JMenuItem menu = new JMenuItem(); - List seqs = new ArrayList(); + List seqs = new ArrayList<>(); testee.configureReferenceAnnotationsMenu(menu, seqs); assertFalse(menu.isEnabled()); // now try null list @@ -469,8 +473,8 @@ public class PopupMenuTest List seqs = parentPanel.getAlignment().getSequences(); // create list of links and list of DBRefs - List links = new ArrayList(); - List refs = new ArrayList(); + List links = new ArrayList<>(); + List 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=$" @@ -548,7 +552,7 @@ public class PopupMenuTest } // if there are no valid links the Links submenu is disabled - List nomatchlinks = new ArrayList(); + List nomatchlinks = new ArrayList<>(); nomatchlinks.add("NOMATCH | http://www.uniprot.org/uniprot/$" + DB_ACCESSION + "$"); @@ -559,4 +563,117 @@ public class PopupMenuTest assertFalse(linkMenu.isEnabled()); } + + /** + * Test for adding feature links + */ + @Test(groups = { "Functional" }) + public void testHideInsertions() + { + // get sequences from the alignment + List 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, (Sequence) seqs.get(7), null); + testee.hideInsertions_actionPerformed(null); + + HiddenColumns hidden = parentPanel.av.getAlignment().getHiddenColumns(); + Iterator it = hidden.iterator(); + assertFalse(it.hasNext()); + + // get the Popup Menu for GappySeq - this time we have insertions + testee = new PopupMenu(parentPanel, (Sequence) 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, (Sequence) 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); + } + } diff --git a/test/jalview/gui/SeqCanvasTest.java b/test/jalview/gui/SeqCanvasTest.java index a27bc3f..ee1270e 100644 --- a/test/jalview/gui/SeqCanvasTest.java +++ b/test/jalview/gui/SeqCanvasTest.java @@ -1,3 +1,23 @@ +/* + * 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 . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ package jalview.gui; import static org.testng.Assert.assertEquals; @@ -9,11 +29,9 @@ import jalview.io.FileLoader; import java.awt.Font; import java.awt.FontMetrics; -import junit.extensions.PA; - import org.testng.annotations.Test; -import sun.swing.SwingUtilities2; +import junit.extensions.PA; public class SeqCanvasTest { @@ -48,7 +66,7 @@ public class SeqCanvasTest 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 @@ -218,7 +236,7 @@ public class SeqCanvasTest 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(); diff --git a/test/jalview/gui/StructureChooserTest.java b/test/jalview/gui/StructureChooserTest.java index 91fe602..f69e6b5 100644 --- a/test/jalview/gui/StructureChooserTest.java +++ b/test/jalview/gui/StructureChooserTest.java @@ -21,6 +21,7 @@ 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; @@ -28,8 +29,10 @@ import jalview.datamodel.DBRefSource; 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; @@ -37,6 +40,8 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import junit.extensions.PA; + public class StructureChooserTest { @@ -142,8 +147,10 @@ public class StructureChooserTest SequenceI[] selectedSeqs = new SequenceI[] { seq }; StructureChooser sc = new StructureChooser(selectedSeqs, seq, null); sc.fetchStructuresMetaData(); - assertTrue(sc.getDiscoveredStructuresSet() != null); - assertTrue(sc.getDiscoveredStructuresSet().size() > 0); + Collection ss = (Collection) PA.getValue(sc, + "discoveredStructuresSet"); + assertNotNull(ss); + assertTrue(ss.size() > 0); } diff --git a/test/jalview/io/AnnotatedPDBFileInputTest.java b/test/jalview/io/AnnotatedPDBFileInputTest.java index e14a478..c0038a1 100644 --- a/test/jalview/io/AnnotatedPDBFileInputTest.java +++ b/test/jalview/io/AnnotatedPDBFileInputTest.java @@ -39,6 +39,7 @@ import jalview.structure.StructureImportSettings.StructureParser; 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; @@ -101,18 +102,19 @@ public class AnnotatedPDBFileInputTest } } - @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)); } diff --git a/test/jalview/io/CrossRef2xmlTests.java b/test/jalview/io/CrossRef2xmlTests.java index 0715857..ef7615b 100644 --- a/test/jalview/io/CrossRef2xmlTests.java +++ b/test/jalview/io/CrossRef2xmlTests.java @@ -42,6 +42,7 @@ import java.util.List; import org.testng.Assert; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @Test(singleThreaded = true) @@ -56,6 +57,14 @@ public class CrossRef2xmlTests extends Jalview2xmlBase 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 @@ -63,8 +72,13 @@ public class CrossRef2xmlTests extends Jalview2xmlBase * * @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 failedDBRetr = new ArrayList<>(); @@ -94,8 +108,8 @@ public class CrossRef2xmlTests extends Jalview2xmlBase List keyseq = new ArrayList<>(); HashMap 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; @@ -105,7 +119,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase // { 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; @@ -117,7 +131,8 @@ public class CrossRef2xmlTests extends Jalview2xmlBase // retrieve dbref List 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); @@ -411,7 +426,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase pass1++; } } while (pass1 < 3); - } + if (failedXrefMenuItems.size() > 0) { for (String s : failedXrefMenuItems) diff --git a/test/jalview/io/JSONFileTest.java b/test/jalview/io/JSONFileTest.java index 158c901..5e835bf 100644 --- a/test/jalview/io/JSONFileTest.java +++ b/test/jalview/io/JSONFileTest.java @@ -42,6 +42,7 @@ import jalview.schemes.ResidueColourScheme; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -205,7 +206,7 @@ public class JSONFileTest 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() { @@ -325,11 +326,12 @@ public class JSONFileTest { HiddenColumns cs = testJsonFile.getHiddenColumns(); Assert.assertNotNull(cs); - Assert.assertNotNull(cs.getHiddenColumnsCopy()); - List hiddenCols = cs.getHiddenColumnsCopy(); - Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT); - Assert.assertEquals(hiddenCols.get(0), expectedColSel - .getHiddenColumnsCopy().get(0), + + Iterator it = cs.iterator(); + Iterator colselit = expectedColSel.iterator(); + Assert.assertTrue(it.hasNext()); + Assert.assertEquals(cs.getNumberOfRegions(), TEST_CS_HEIGHT); + Assert.assertEquals(it.next(), colselit.next(), "Mismatched hidden columns!"); } diff --git a/test/jalview/io/Jalview2xmlBase.java b/test/jalview/io/Jalview2xmlBase.java index 15e18e3..fbdd782 100644 --- a/test/jalview/io/Jalview2xmlBase.java +++ b/test/jalview/io/Jalview2xmlBase.java @@ -76,7 +76,8 @@ public class Jalview2xmlBase @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); } diff --git a/test/jalview/io/Jalview2xmlTests.java b/test/jalview/io/Jalview2xmlTests.java index 6abb7e5..c0eb8c5 100644 --- a/test/jalview/io/Jalview2xmlTests.java +++ b/test/jalview/io/Jalview2xmlTests.java @@ -247,6 +247,31 @@ public class Jalview2xmlTests extends Jalview2xmlBase } + /** + * 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 { @@ -413,7 +438,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase String afid = af.getViewport().getSequenceSetId(); // remember reference sequence for each panel - Map refseqs = new HashMap(); + Map refseqs = new HashMap<>(); /* * mark sequence 2, 3, 4.. in panels 1, 2, 3... @@ -551,8 +576,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase * remember representative and hidden sequences marked * on each panel */ - Map repSeqs = new HashMap(); - Map> hiddenSeqNames = new HashMap>(); + Map repSeqs = new HashMap<>(); + Map> hiddenSeqNames = new HashMap<>(); /* * mark sequence 2, 3, 4.. in panels 1, 2, 3... @@ -568,7 +593,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase repIndex = Math.max(repIndex, 1); SequenceI repSeq = alignment.getSequenceAt(repIndex); repSeqs.put(ap.getViewName(), repSeq); - List hiddenNames = new ArrayList(); + List hiddenNames = new ArrayList<>(); hiddenSeqNames.put(ap.getViewName(), hiddenNames); /* diff --git a/test/jalview/renderer/OverviewRendererTest.java b/test/jalview/renderer/OverviewRendererTest.java new file mode 100644 index 0000000..1d532f7 --- /dev/null +++ b/test/jalview/renderer/OverviewRendererTest.java @@ -0,0 +1,93 @@ +/* + * 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 . + * 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()); + } +} diff --git a/test/jalview/renderer/seqfeatures/FeatureRendererTest.java b/test/jalview/renderer/seqfeatures/FeatureRendererTest.java index d3cddf9..6bb611c 100644 --- a/test/jalview/renderer/seqfeatures/FeatureRendererTest.java +++ b/test/jalview/renderer/seqfeatures/FeatureRendererTest.java @@ -1,3 +1,23 @@ +/* + * 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 . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ package jalview.renderer.seqfeatures; import static org.testng.Assert.assertEquals; @@ -341,10 +361,7 @@ public class FeatureRendererTest 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)); + assertFalse(features.contains(sf2)); /* * co-located features with colour by label @@ -359,5 +376,14 @@ public class FeatureRendererTest assertTrue(features.contains(sf3)); assertTrue(features.contains(sf4)); assertTrue(features.contains(sf5)); + + /* + * no filtering if transparency is applied + */ + fr.setTransparency(0.5f); + features = seq.getSequenceFeatures(); + fr.setGroupVisibility("group2", true); + fr.filterFeaturesForDisplay(features, new FeatureColour(Color.RED)); + assertEquals(features.size(), 5); } } diff --git a/test/jalview/structure/Mapping.java b/test/jalview/structure/Mapping.java index 85aea40..4bee3f5 100644 --- a/test/jalview/structure/Mapping.java +++ b/test/jalview/structure/Mapping.java @@ -260,6 +260,8 @@ public class Mapping @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", diff --git a/test/jalview/structure/StructureMappingTest.java b/test/jalview/structure/StructureMappingTest.java index f26c5f1..808e662 100644 --- a/test/jalview/structure/StructureMappingTest.java +++ b/test/jalview/structure/StructureMappingTest.java @@ -1,8 +1,34 @@ +/* + * 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 . + * 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; @@ -11,9 +37,9 @@ import org.testng.annotations.Test; public class StructureMappingTest { @Test(groups = "Functional") - public void testgetPDBResNumRanges() + public void testGetPDBResNumRanges() { - HashMap map = new HashMap(); + HashMap map = new HashMap<>(); StructureMapping mapping = new StructureMapping(null, null, null, null, map, null); @@ -43,4 +69,75 @@ public class StructureMappingTest 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 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)); + } } diff --git a/test/jalview/structure/StructureSelectionManagerTest.java b/test/jalview/structure/StructureSelectionManagerTest.java index a59fbde..286be1b 100644 --- a/test/jalview/structure/StructureSelectionManagerTest.java +++ b/test/jalview/structure/StructureSelectionManagerTest.java @@ -20,28 +20,53 @@ */ 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() { @@ -160,4 +185,313 @@ public class StructureSelectionManagerTest 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 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 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 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 fdesc) + { + for (int o = 0; o < offset.length; o++) + { + int res = pdbseq.findPosition(offset[o]); + List 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 tipEntries = new TreeMap<>(); + final Map> 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(); + } + } diff --git a/test/jalview/util/MapListTest.java b/test/jalview/util/MapListTest.java index a2f38e2..95d7efe 100644 --- a/test/jalview/util/MapListTest.java +++ b/test/jalview/util/MapListTest.java @@ -391,7 +391,9 @@ public class MapListTest 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)); @@ -426,7 +428,7 @@ public class MapListTest @Test(groups = { "Functional" }) public void testGetRanges() { - List ranges = new ArrayList(); + List 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))); @@ -603,7 +605,7 @@ public class MapListTest public void testAddRange() { int[] range = { 1, 5 }; - List ranges = new ArrayList(); + List ranges = new ArrayList<>(); // add to empty list: MapList.addRange(range, ranges); @@ -702,7 +704,7 @@ public class MapListTest public void testCoalesceRanges() { assertNull(MapList.coalesceRanges(null)); - List ranges = new ArrayList(); + List ranges = new ArrayList<>(); assertSame(ranges, MapList.coalesceRanges(ranges)); ranges.add(new int[] { 1, 3 }); assertSame(ranges, MapList.coalesceRanges(ranges)); @@ -763,7 +765,7 @@ public class MapListTest @Test(groups = { "Functional" }) public void testCoalesceRanges_withOverlap() { - List ranges = new ArrayList(); + List ranges = new ArrayList<>(); ranges.add(new int[] { 1, 3 }); ranges.add(new int[] { 2, 5 }); diff --git a/test/jalview/util/MappingUtilsTest.java b/test/jalview/util/MappingUtilsTest.java index 5226819..022e2d6 100644 --- a/test/jalview/util/MappingUtilsTest.java +++ b/test/jalview/util/MappingUtilsTest.java @@ -50,6 +50,7 @@ import java.awt.Color; 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; @@ -913,9 +914,9 @@ public class MappingUtilsTest MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, proteinView, dnaView, dnaSelection, dnaHidden); assertEquals("[]", dnaSelection.getSelected().toString()); - List hidden = dnaHidden.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[0, 4]", Arrays.toString(hidden.get(0))); + Iterator 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 @@ -930,9 +931,9 @@ public class MappingUtilsTest 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 @@ -944,7 +945,7 @@ public class MappingUtilsTest 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 @@ -959,9 +960,9 @@ public class MappingUtilsTest 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 @@ -974,10 +975,10 @@ public class MappingUtilsTest 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" }) diff --git a/test/jalview/ws/PDBSequenceFetcherTest.java b/test/jalview/ws/PDBSequenceFetcherTest.java index 95863e7..cc3dca8 100644 --- a/test/jalview/ws/PDBSequenceFetcherTest.java +++ b/test/jalview/ws/PDBSequenceFetcherTest.java @@ -20,18 +20,22 @@ */ 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; @@ -106,23 +110,76 @@ public class PDBSequenceFetcherTest testRetrieveProteinSeqFromPDB(); } + private class TestRetrieveObject + { + String id; + + int expectedHeight; + + public TestRetrieveObject(String id, int expectedHeight) + { + super(); + this.id = id; + this.expectedHeight = expectedHeight; + } + + } + + private List toRetrieve = Arrays.asList( + new TestRetrieveObject("1QIP", 4), + new TestRetrieveObject("4IM2", 1)); + private void testRetrieveProteinSeqFromPDB() throws Exception { List 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 prev = null; + int lastp = -1; + for (int col = 1; col <= sq.getLength(); col++) + { + List 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()); } } - } diff --git a/test/jalview/ws/dbsources/PfamFullTest.java b/test/jalview/ws/dbsources/PfamFullTest.java new file mode 100644 index 0000000..f5cc640 --- /dev/null +++ b/test/jalview/ws/dbsources/PfamFullTest.java @@ -0,0 +1,52 @@ +/* + * 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 . + * 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 PfamFullTest +{ + @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/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); + } +} diff --git a/test/jalview/ws/dbsources/PfamSeedTest.java b/test/jalview/ws/dbsources/PfamSeedTest.java new file mode 100644 index 0000000..355ef0c --- /dev/null +++ b/test/jalview/ws/dbsources/PfamSeedTest.java @@ -0,0 +1,52 @@ +/* + * 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 . + * 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); + } +} diff --git a/test/jalview/ws/dbsources/RfamFullTest.java b/test/jalview/ws/dbsources/RfamFullTest.java new file mode 100644 index 0000000..2d1497f --- /dev/null +++ b/test/jalview/ws/dbsources/RfamFullTest.java @@ -0,0 +1,52 @@ +/* + * 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 . + * 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); + } +} diff --git a/test/jalview/ws/dbsources/RfamSeedTest.java b/test/jalview/ws/dbsources/RfamSeedTest.java new file mode 100644 index 0000000..745ba2e --- /dev/null +++ b/test/jalview/ws/dbsources/RfamSeedTest.java @@ -0,0 +1,52 @@ +/* + * 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 . + * 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); + } +} diff --git a/test/jalview/ws/dbsources/XfamFetcherTest.java b/test/jalview/ws/dbsources/XfamFetcherTest.java index 573022d..51cff6e 100644 --- a/test/jalview/ws/dbsources/XfamFetcherTest.java +++ b/test/jalview/ws/dbsources/XfamFetcherTest.java @@ -58,7 +58,7 @@ public class XfamFetcherTest @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()); diff --git a/test/jalview/ws/sifts/SiftsClientTest.java b/test/jalview/ws/sifts/SiftsClientTest.java index b92766e..75c1413 100644 --- a/test/jalview/ws/sifts/SiftsClientTest.java +++ b/test/jalview/ws/sifts/SiftsClientTest.java @@ -83,103 +83,103 @@ public class SiftsClientTest @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) @@ -311,7 +311,7 @@ public class SiftsClientTest 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); } diff --git a/utils/InstallAnywhere/Jalview.iap_xml b/utils/InstallAnywhere/Jalview.iap_xml index a649cb4..ced9ac0 100755 --- a/utils/InstallAnywhere/Jalview.iap_xml +++ b/utils/InstallAnywhere/Jalview.iap_xml @@ -314,13 +314,13 @@ and any path to a file to save to the file]]> - + - + - + @@ -367,7 +367,7 @@ and any path to a file to save to the file]]> false - + true @@ -419,7 +419,7 @@ and any path to a file to save to the file]]> false - + true @@ -471,7 +471,7 @@ and any path to a file to save to the file]]> false - + true @@ -523,7 +523,7 @@ and any path to a file to save to the file]]> false - + true @@ -575,7 +575,7 @@ and any path to a file to save to the file]]> false - + true @@ -627,7 +627,7 @@ and any path to a file to save to the file]]> false - + true @@ -679,7 +679,7 @@ and any path to a file to save to the file]]> false - + true @@ -731,7 +731,7 @@ and any path to a file to save to the file]]> false - + true @@ -783,7 +783,7 @@ and any path to a file to save to the file]]> false - + true @@ -835,7 +835,7 @@ and any path to a file to save to the file]]> false - + true @@ -887,7 +887,7 @@ and any path to a file to save to the file]]> false - + true @@ -939,7 +939,7 @@ and any path to a file to save to the file]]> false - + true @@ -991,7 +991,7 @@ and any path to a file to save to the file]]> false - + true @@ -1043,7 +1043,7 @@ and any path to a file to save to the file]]> false - + true @@ -1095,7 +1095,7 @@ and any path to a file to save to the file]]> false - + true @@ -1147,7 +1147,7 @@ and any path to a file to save to the file]]> false - + true @@ -1199,7 +1199,7 @@ and any path to a file to save to the file]]> false - + true @@ -1251,7 +1251,7 @@ and any path to a file to save to the file]]> false - + true @@ -1303,7 +1303,7 @@ and any path to a file to save to the file]]> false - + true @@ -1355,7 +1355,7 @@ and any path to a file to save to the file]]> false - + true @@ -1407,7 +1407,7 @@ and any path to a file to save to the file]]> false - + true @@ -1459,7 +1459,7 @@ and any path to a file to save to the file]]> false - + true @@ -1511,7 +1511,7 @@ and any path to a file to save to the file]]> false - + true @@ -1563,7 +1563,7 @@ and any path to a file to save to the file]]> false - + true @@ -1615,7 +1615,7 @@ and any path to a file to save to the file]]> false - + true @@ -1667,7 +1667,7 @@ and any path to a file to save to the file]]> false - + true @@ -1719,7 +1719,7 @@ and any path to a file to save to the file]]> false - + true @@ -1771,7 +1771,7 @@ and any path to a file to save to the file]]> false - + true @@ -1823,7 +1823,7 @@ and any path to a file to save to the file]]> false - + true @@ -1875,7 +1875,7 @@ and any path to a file to save to the file]]> false - + true @@ -1927,7 +1927,7 @@ and any path to a file to save to the file]]> false - + true @@ -1979,7 +1979,7 @@ and any path to a file to save to the file]]> false - + true @@ -2031,7 +2031,7 @@ and any path to a file to save to the file]]> false - + true @@ -2083,7 +2083,7 @@ and any path to a file to save to the file]]> false - + true @@ -2135,7 +2135,7 @@ and any path to a file to save to the file]]> false - + true @@ -2187,7 +2187,7 @@ and any path to a file to save to the file]]> false - + true @@ -2239,7 +2239,7 @@ and any path to a file to save to the file]]> false - + true @@ -2291,7 +2291,7 @@ and any path to a file to save to the file]]> false - + true @@ -2320,6 +2320,58 @@ and any path to a file to save to the file]]> + + + false + + + true + + + true + + + + + + + + + + + + false + + + + + + true + + + true + + + true + + + + + + 1355141 + + + false + + + 0 + + + + + + + false @@ -2343,7 +2395,7 @@ and any path to a file to save to the file]]> false - + true @@ -2395,7 +2447,7 @@ and any path to a file to save to the file]]> false - + true @@ -2447,7 +2499,7 @@ and any path to a file to save to the file]]> false - + true @@ -2499,7 +2551,7 @@ and any path to a file to save to the file]]> false - + true @@ -2551,7 +2603,7 @@ and any path to a file to save to the file]]> false - + true @@ -2603,7 +2655,7 @@ and any path to a file to save to the file]]> false - + true @@ -2655,7 +2707,7 @@ and any path to a file to save to the file]]> false - + true @@ -2707,7 +2759,7 @@ and any path to a file to save to the file]]> false - + true @@ -2759,7 +2811,7 @@ and any path to a file to save to the file]]> false - + true @@ -2811,7 +2863,7 @@ and any path to a file to save to the file]]> false - + true @@ -2863,7 +2915,7 @@ and any path to a file to save to the file]]> false - + true @@ -2915,7 +2967,7 @@ and any path to a file to save to the file]]> false - + true @@ -2949,7 +3001,7 @@ and any path to a file to save to the file]]> - + @@ -4242,7 +4294,7 @@ Press "Done" to quit the installer.]]> true - + @@ -5406,7 +5458,7 @@ Press "Done" to quit the installer.]]> true - + @@ -7230,6 +7282,7 @@ and any path to a file to read from that file]]> + false @@ -7291,7 +7344,7 @@ and any path to a file to read from that file]]> false - + true @@ -7332,7 +7385,7 @@ and any path to a file to read from that file]]> false - + true @@ -7373,7 +7426,7 @@ and any path to a file to read from that file]]> false - + true @@ -7445,7 +7498,7 @@ and any path to a file to read from that file]]> false - + true @@ -7486,7 +7539,7 @@ and any path to a file to read from that file]]> false - + true @@ -7527,7 +7580,7 @@ and any path to a file to read from that file]]> false - + true @@ -7568,7 +7621,7 @@ and any path to a file to read from that file]]> false - + true @@ -7609,7 +7662,7 @@ and any path to a file to read from that file]]> false - + true @@ -7659,7 +7712,7 @@ and any path to a file to read from that file]]> false - + true @@ -7700,7 +7753,7 @@ and any path to a file to read from that file]]> false - + true @@ -7741,7 +7794,7 @@ and any path to a file to read from that file]]> false - + true @@ -7782,7 +7835,7 @@ and any path to a file to read from that file]]> false - + true @@ -7823,7 +7876,7 @@ and any path to a file to read from that file]]> false - + true @@ -7864,7 +7917,7 @@ and any path to a file to read from that file]]> false - + true @@ -7905,7 +7958,7 @@ and any path to a file to read from that file]]> false - + true @@ -7946,7 +7999,7 @@ and any path to a file to read from that file]]> false - + true @@ -7981,6 +8034,7 @@ and any path to a file to read from that file]]> + @@ -8036,7 +8090,7 @@ and any path to a file to read from that file]]> false - + true @@ -8077,7 +8131,7 @@ and any path to a file to read from that file]]> false - + false @@ -8133,7 +8187,7 @@ and any path to a file to read from that file]]> false - + true @@ -8174,7 +8228,7 @@ and any path to a file to read from that file]]> false - + true @@ -8359,7 +8413,7 @@ and any path to a file to read from that file]]> - + diff --git a/utils/InstallAnywhere/jalview_buildinstaller.xml b/utils/InstallAnywhere/jalview_buildinstaller.xml index 6310934..6f0115e 100644 --- a/utils/InstallAnywhere/jalview_buildinstaller.xml +++ b/utils/InstallAnywhere/jalview_buildinstaller.xml @@ -20,7 +20,7 @@ - + diff --git a/utils/proguard.jar b/utils/proguard.jar deleted file mode 100755 index dfb7f29..0000000 Binary files a/utils/proguard.jar and /dev/null differ diff --git a/utils/proguard_5.3.3.jar b/utils/proguard_5.3.3.jar new file mode 100755 index 0000000..08f4a4c Binary files /dev/null and b/utils/proguard_5.3.3.jar differ