Merge branch 'bug/JAL-2784' into develop
authorJim Procter <jprocter@issues.jalview.org>
Fri, 17 Nov 2017 13:16:10 +0000 (13:16 +0000)
committerJim Procter <jprocter@issues.jalview.org>
Fri, 17 Nov 2017 13:16:10 +0000 (13:16 +0000)
44 files changed:
.classpath
benchmarking/README
benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java
build.xml
help/helpTOC.xml
help/html/features/pdbseqfetcher.png
help/html/features/pdbsequencefetcher.html
help/html/features/uniprotseqfetcher.png
help/html/features/uniprotsequencefetcher.html
help/html/releases.html
help/html/whatsNew.html
lib/groovy-all-2.4.12-indy.jar [moved from lib/groovy-all-2.4.6-indy.jar with 62% similarity]
resources/lang/Messages.properties
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/IdCanvas.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/appletgui/SeqPanel.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/datamodel/SequenceI.java
src/jalview/ext/ensembl/EnsemblGenomes.java
src/jalview/fts/api/GFTSPanelI.java
src/jalview/fts/core/GFTSPanel.java
src/jalview/fts/service/pdb/PDBFTSPanel.java
src/jalview/fts/service/uniprot/UniprotFTSPanel.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/IdCanvas.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/SequenceRenderer.java
src/jalview/io/AlignFile.java
src/jalview/io/cache/JvCacheableInputBox.java
src/jalview/viewmodel/OverviewDimensionsHideHidden.java
src/jalview/viewmodel/OverviewDimensionsShowHidden.java
src/jalview/viewmodel/ViewportRanges.java
src/jalview/ws/dbsources/Uniprot.java
test/jalview/datamodel/SequenceTest.java
test/jalview/viewmodel/ViewportRangesTest.java
test/jalview/ws/dbsources/UniprotTest.java

index c4a2832..d704f10 100644 (file)
@@ -68,6 +68,6 @@
        <classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
        <classpathentry kind="lib" path="lib/biojava-core-4.1.0.jar"/>
        <classpathentry kind="lib" path="lib/biojava-ontology-4.1.0.jar"/>
-       <classpathentry kind="lib" path="lib/groovy-all-2.4.6-indy.jar"/>
+       <classpathentry kind="lib" path="lib/groovy-all-2.4.12-indy.jar"/>
        <classpathentry kind="output" path="classes"/>
 </classpath>
index 60b94a9..fac0bf6 100644 (file)
@@ -1,11 +1,13 @@
 To set up benchmarking:
 
-1. In the jalview directory run 
+You will need to install Maven: https://maven.apache.org/install.html
+
+1. Run the makedist target of build.xml in Eclipse, or in the jalview directory run 
   ant makedist
 
 This builds a jalview.jar file and puts it into dist/
 
-2. Make a lib directory in benchmarking/ if not already present.
+2. Make a lib directory in benchmarking/ if not already present and cd into this directory.
 
 3. Purge any previous maven dependencies:
    mvn dependency:purge-local-repository -DactTransitively=false -DreResolve=false
index eb35e3b..d3c67d7 100644 (file)
@@ -47,126 +47,128 @@ 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()
-               {
-                       rand.setSeed(1234);
-                       int lastcol = 0;
-               while (lastcol < maxcols)
-               {
-                       int count = rand.nextInt(100); 
-                       lastcol += count;
-                       h.hideColumns(lastcol, lastcol+hide);
-                       lastcol+=hide;
-               }
-               
-               // make sure column at start is hidden
-               hiddenColumn = (int)(maxcols * startpcnt/100.0);
-               h.hideColumns(hiddenColumn, hiddenColumn);
-               
-               // and column <hide> after start is visible
-               ColumnSelection sel = new ColumnSelection();
-               h.revealHiddenColumns(hiddenColumn+hide, sel);
-               visibleColumn = hiddenColumn+hide;
-               
-               System.out.println("Maxcols: " + maxcols + " HiddenCol: " + hiddenColumn + " Hide: " + hide);
-               System.out.println("Number of hidden columns: " + h.getSize());
-               }
-       }
-       
-       /* Convention: functions in alphabetical order */
-       
-       @Benchmark
-       @BenchmarkMode({Mode.Throughput})
-       public int benchAdjustForHiddenColumns(HiddenColsAndStartState tstate)
-       {
-               return tstate.h.adjustForHiddenColumns(tstate.visibleColumn);
-       }
-       
-       @Benchmark
-       @BenchmarkMode({Mode.Throughput})
-       public int benchFindColumnPosition(HiddenColsAndStartState tstate)
-       {
-               return tstate.h.findColumnPosition(tstate.visibleColumn);
-       }
-       
-       @Benchmark
-       @BenchmarkMode({Mode.Throughput})
-       public List<Integer> benchFindHiddenRegionPositions(HiddenColsAndStartState tstate)
-       {
-               return tstate.h.findHiddenRegionPositions();
-       }
-       
-       @Benchmark
-       @BenchmarkMode({Mode.Throughput})
-       public ArrayList<int[]> benchGetHiddenColumnsCopy(HiddenColsAndStartState tstate)
-       {
-               return tstate.h.getHiddenColumnsCopy();
-       }
-       
-       
-       @Benchmark
-       @BenchmarkMode({Mode.Throughput})
-    public int benchGetSize(HiddenColsAndStartState tstate)
-    {
-               return tstate.h.getSize();
-    }
+{
+  /*
+   * State with multiple hidden columns and a start position set
+   */
+  @State(Scope.Thread)
+  public static class HiddenColsAndStartState
+  {
+    @Param({ "300", "10000", "100000" })
+    public int maxcols;
 
-   @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) 
+    @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()
     {
-               ColumnSelection sel = new ColumnSelection();
-       tstate.h.revealAllHiddenColumns(sel);
-       return tstate.h;
+      rand.setSeed(1234);
+      int lastcol = 0;
+      while (lastcol < maxcols)
+      {
+        int count = rand.nextInt(100);
+        lastcol += count;
+        h.hideColumns(lastcol, lastcol + hide);
+        lastcol += hide;
+      }
+
+      // make sure column at start is hidden
+      hiddenColumn = (int) (maxcols * startpcnt / 100.0);
+      h.hideColumns(hiddenColumn, hiddenColumn);
+
+      // and column <hide> after start is visible
+      ColumnSelection sel = new ColumnSelection();
+      h.revealHiddenColumns(hiddenColumn + hide, sel);
+      visibleColumn = hiddenColumn + hide;
+
+      System.out.println("Maxcols: " + maxcols + " HiddenCol: "
+              + hiddenColumn + " Hide: " + hide);
+      System.out.println("Number of hidden columns: " + h.getSize());
     }
-       
-       
+  }
+
+  /* Convention: functions in alphabetical order */
+
+  @Benchmark
+  @BenchmarkMode({ Mode.Throughput })
+  public int benchAdjustForHiddenColumns(HiddenColsAndStartState tstate)
+  {
+    return tstate.h.adjustForHiddenColumns(tstate.visibleColumn);
+  }
+
+  @Benchmark
+  @BenchmarkMode({ Mode.Throughput })
+  public int benchFindColumnPosition(HiddenColsAndStartState tstate)
+  {
+    return tstate.h.findColumnPosition(tstate.visibleColumn);
+  }
+
+  @Benchmark
+  @BenchmarkMode({ Mode.Throughput })
+  public List<Integer> benchFindHiddenRegionPositions(
+          HiddenColsAndStartState tstate)
+  {
+    return tstate.h.findHiddenRegionPositions();
+  }
+
+  @Benchmark
+  @BenchmarkMode({ Mode.Throughput })
+  public ArrayList<int[]> benchGetHiddenColumnsCopy(
+          HiddenColsAndStartState tstate)
+  {
+    return tstate.h.getHiddenColumnsCopy();
+  }
+
+  @Benchmark
+  @BenchmarkMode({ Mode.Throughput })
+  public int benchGetSize(HiddenColsAndStartState tstate)
+  {
+    return tstate.h.getSize();
+  }
+
+  @Benchmark
+  @BenchmarkMode({ Mode.Throughput })
+  public HiddenColumns benchHideCols(HiddenColsAndStartState tstate)
+  {
+    tstate.h.hideColumns(tstate.visibleColumn, tstate.visibleColumn + 2000);
+    return tstate.h;
+  }
+
+  @Benchmark
+  @BenchmarkMode({ Mode.Throughput })
+  public boolean benchIsVisible(HiddenColsAndStartState tstate)
+  {
+    return tstate.h.isVisible(tstate.hiddenColumn);
+  }
+
+  @Benchmark
+  @BenchmarkMode({ Mode.Throughput })
+  public HiddenColumns benchReveal(HiddenColsAndStartState tstate)
+  {
+    ColumnSelection sel = new ColumnSelection();
+    tstate.h.revealHiddenColumns(tstate.hiddenColumn, sel);
+    return tstate.h;
+  }
+
+  @Benchmark
+  @BenchmarkMode({ Mode.Throughput })
+  public HiddenColumns benchRevealAll(HiddenColsAndStartState tstate)
+  {
+    ColumnSelection sel = new ColumnSelection();
+    tstate.h.revealAllHiddenColumns(sel);
+    return tstate.h;
+  }
+
 }
\ No newline at end of file
index f39fdf3..4931cfb 100755 (executable)
--- a/build.xml
+++ b/build.xml
 
     <jnlpf toFile="${jnlpFile}" />
     <!-- add the add-modules j2se attribute for java 9 -->
-    <replace file="${jnlpFile}" value="j2se version=&quot;1.7+&quot; initial-heap-size=&quot;${inih}&quot; max-heap-size=&quot;${maxh}&quot; java-vm-args=&quot;--add-modules=java.se.ee&quot;">
+    <replace file="${jnlpFile}" value="j2se version=&quot;1.7+&quot; initial-heap-size=&quot;${inih}&quot; max-heap-size=&quot;${maxh}&quot; java-vm-args=&quot;--add-modules=java.se.ee --illegal-access=warn&quot;">
           <replacetoken>j2se version="1.7+"</replacetoken>
            
         </replace>
index 4636ea3..7ba4ee5 100755 (executable)
        <tocitem text="Jalview Documentation" target="home" expand="true">
                        <tocitem text="What's new" target="new" expand="true">
                                <tocitem text="Latest Release Notes" target="release"/>
-        <tocitem text="Calculations Dialog" target="calcs.dialog"/>
-                               <tocitem text="Groovy Features Counter example" target="groovy.featurescounter"/>
-                               <tocitem text="Custom Colourschemes in Groovy" target="groovy.colours"/>
-                               <tocitem text="Omit hidden regions in Overview" target="overview"/>
-                               <tocitem text="Show gaps as grey in overview" target="overviewprefs"/>
-                               <tocitem text="identifers.org for URL Links" target="linksprefs" />
-                               <tocitem text="New features in Split Frame View" target="splitframe.mirrorfonts" />
+        
                </tocitem>
                
                <tocitem text="Editing Alignments" target="edit" />
index 97a779a..2081a3d 100644 (file)
Binary files a/help/html/features/pdbseqfetcher.png and b/help/html/features/pdbseqfetcher.png differ
index 2962ba6..bb63bed 100644 (file)
@@ -37,7 +37,7 @@
   <p>
     To open the PDB Sequence Fetcher, select PDB as the database from
     any <a href="seqfetch.html">Sequence Fetcher</a> dialog (opened <em>via</em>
-    <strong>&quot;File &#8594;Fetch Sequences&quot;</strong>).
+    <strong>&quot;File &#8594;Fetch Sequences&quot;</strong>). 
   </p>
   <img src="pdbseqfetcher.png" align="left"
     alt="PDB sequence fetcher (introduced in Jalview 2.9)" />
   <p>
     <strong>Searching the PDB Database</strong>
   </p>
+  <p>To search the PDB, begin typing in the text box. If the
+    'autosearch' checkbox is enabled, then the results of your query
+    will be automatically updated and shown in the search results tab;
+    otherwise, press return to update the results. To access previous
+    searches, press the down-arrow or click the drop down menu icon at
+    the side of the search box. If you just want to paste in a list of
+    IDs, the 'Retrieve IDs' tab provides a batch-retrieval interface.</p>
   <p>
-    To search the PDB, begin typing in the text box. The results of your
-    query are shown in the search results tab, which updates every time
-    you type in the search text box. You can sort results according to
-    the displayed columns, and select entries with the mouse and
-    keyboard. Once you have selected one or more entries, hit the <strong>OK</strong>
-    button to retrieve and view them in Jalview.
+    You can sort results according to the displayed columns, and select
+    entries with the mouse and keyboard. Once you have selected one or
+    more entries, hit the <strong>OK</strong> button to retrieve and
+    view them in Jalview.
   </p>
   <p>
   <ul>
@@ -64,9 +69,8 @@
       1xyz:A</li>
 
     <li><strong>Bulk PDB retrieval</strong><br>Multiple PDB
-      IDs can be specified by separating them with a semi-colon.<br />
-      e.g. 1xyz;2xyz;3xyz<br />Hitting Return or OK will automatically
-      fetch those IDs, like the default Sequence Fetcher interface.</li>
+      IDs can be specified for retrieval via the 
+      <strong>Retrieve IDs</strong> tab.</li>
 
     <li><strong>Wild card searching</strong><br>The following
       wild cards are supported by the EMBL-EBI PDBe query service:
index a592e8e..23b55fa 100644 (file)
Binary files a/help/html/features/uniprotseqfetcher.png and b/help/html/features/uniprotseqfetcher.png differ
index edd8995..4a64f52 100644 (file)
   <p>
     <strong>Searching the UniProt Database</strong>
   </p>
-  <p>
-    To search UniProt, simply begin typing in the text box. After a
-    short delay (about 1.5 seconds), results will be shown in the table
-    below. You can sort results by clicking on the displayed columns,
+  <p>To search UniProt, simply begin typing in the text box. If the
+    'autosearch' check box is enabled, then after a short delay (about
+    1.5 seconds), results will be shown in the table below. Results are
+    also updated whenever you press Enter, and you can access previous
+    searches by pressing the 'Down' arrow or clicking the drop-down menu
+    icon at the side of the search box.</p>
+  <p>You can sort results by clicking on the displayed columns,
     and select entries with the mouse or keyboard. Once you have
     selected one or more entries, hit the <strong>OK</strong> button to
     retrieve the sequences.
 
 
     <li><strong>Bulk UniProt record retrieval</strong><br> To
-      retrieve several uniprot accessions at once, first select <strong>UniProt
-        ID</strong> from the dropdown menu, then paste in the accession IDs as a
-      semi-colon separated list. (e.g. fila_human; mnt_human;
-      mnt_mouse).<br />Hitting Return or OK will automatically fetch
-      those IDs, like the default Sequence Fetcher interface.</li>
+      retrieve sequences for a list of Uniprot accessions, please enter
+      them via the 'Retrieve IDs' tab.</li>
 
     <li><strong><a name="text-search">Complex queries
           with the UniProt query Syntax</a></strong> The text box also allows complex
index 510e477..f1f7c0a 100755 (executable)
@@ -71,7 +71,7 @@ li:before {
       <td width="60" nowrap>
         <div align="center">
           <strong><a name="Jalview.2.10.3">2.10.3</a><br />
-            <em>14/11/2017</em></strong>
+            <em>17/11/2017</em></strong>
         </div>
       </td>
       <td><div align="left">
@@ -95,11 +95,20 @@ li:before {
             
             <li><!-- JAL-2617 -->Stop codons are excluded in CDS/Protein view from Ensembl locus cross-references</li>
             <li><!-- JAL-2685 -->Start/End limits are shown in Pairwise Alignment report</li>
+            <li><!-- JAL-2810 -->Sequence fetcher's Free text 'autosearch' feature can be disabled</li>
+            <li><!-- JAL-2810 -->Retrieve IDs tab added for UniProt and PDB easier retrieval of sequences for lists of IDs</li>
+            <li><!-- JAL-2758 -->Short names for sequences retrieved from Uniprot</li> 
+          </ul>
+          <em>Scripting</em>
+          <ul>
+            <li>Groovy interpreter updated to 2.4.12</li>
+            <li>Example groovy script for generating a matrix of percent identity scores for current alignment.</li>
           </ul>
-          <ul><li>Example groovy script for generating a matrix of percent identity scores for current alignment.</li></ul>
           <em>Testing and Deployment</em>
-          <ul><li><!-- JAL-2727 -->Test to catch memory leaks in Jalview UI</li></ul>
-          </div>
+          <ul>
+            <li><!-- JAL-2727 -->Test to catch memory leaks in Jalview UI</li>
+          </ul>
+        </div>
       </td>
       <td><div align="left">
           <em>General</em>
@@ -108,6 +117,7 @@ li:before {
             <li><!-- JAL-2682 -->Race condition when parsing sequence ID strings in parallel</li>
             <li><!-- JAL-2608 -->Overview windows are also closed when alignment window is closed</li>
             <li><!-- JAL-2548 -->Export of features doesn't always respect group visibility</li> 
+            <li><!-- JAL-2831 -->Jumping from column 1 to column 100,000 takes a long time in Cursor mode</li>            
           </ul>
           <em>Desktop</em>
           <ul>
@@ -129,12 +139,14 @@ li:before {
             <li><!-- JAL-1900,JAL-1625 -->Unable to minimise windows within the Jalview desktop on OSX</li>
             <li><!-- JAL-2667 -->Mouse wheel doesn't scroll vertically when in wrapped alignment mode</li>
             <li><!-- JAL-2636 -->Scale mark not shown when close to right hand end of alignment</li>
-            <li><!-- JAL-2684 -->Pairwise alignment only aligns selected regions of each selected sequence</li>
+            <li><!-- JAL-2684 -->Pairwise alignment of selected regions of each selected sequence do not have correct start/end positions</li>
             <li><!-- JAL-2973 -->Alignment ruler height set incorrectly after canceling the Alignment Window's Font dialog</li>
             <li><!-- JAL-2036 -->Show cross-references not enabled after restoring project until a new view is created</li>
             <li><!-- JAL-2756 -->Warning popup about use of SEQUENCE_ID in URL links appears when only default EMBL-EBI link is configured (since 2.10.2b2)</li>            
             <li><!-- JAL-2775 -->Overview redraws whole window when box position is adjusted</li>
-            <li><!-- JAL-2225 -->Structure viewer doesn't map all chains in a multi-chain structure when viewing alignment involving more than one chain (since 2.10)</li>            
+            <li><!-- JAL-2225 -->Structure viewer doesn't map all chains in a multi-chain structure when viewing alignment involving more than one chain (since 2.10)</li>
+            <li><!-- JAL-2811 -->Double residue highlights in cursor mode if new selection moves alignment window</li>
+            <li><!-- JAL-2837,JAL-2840 -->Alignment vanishes when using arrow key in cursor mode to pass hidden column marker</li>          
            </ul>
           <strong><em>Applet</em></strong><br/>
            <ul>
@@ -146,6 +158,19 @@ li:before {
             <!-- JAL-2546 -->BioJSON export does not preserve non-positional features
           </li>
           </ul>
+          <strong>Known Java 9 Issues</strong>
+          <ul>
+            <li><!-- JAL-2902 -->Groovy Console very slow to open and is 
+            not responsive when entering characters (Webstart, Java 9.01, 
+            OSX 10.10)
+            </li>
+          </ul>
+          <strong>New Known Issues</strong>
+          <ul>
+          <li><!-- JAL-2541 -->Delete/Cut selection doesn't relocate sequence features correctly (for many previous versions of Jalview)</li>
+          <li><!-- JAL-2841 -->Cursor mode unexpectedly scrolls when using cursor in wrapped panel other than top</li>
+          <li><!-- JAL-2791 -->Select columns containing feature ignores graduated colour threshold</li>
+          </ul>
           </div>
       </td>
     </tr>
index 3475012..d92f26b 100755 (executable)
     <strong>What's new in Jalview 2.10.3 ?</strong>
   </p>
   <p>
-    Version 2.10.3 is due for release in October 2017. The full list of
+    Version 2.10.3 was released in November 2017. The full list of
     bug fixes and new features can be found in the <a
       href="releases.html#Jalview.2.10.3"> 2.10.3 Release Notes</a>, but
     the highlights are below.
   </p>
+  <ul>
+    <li>Faster import and more responsive UI when working with wide alignments and handling hundreds and thousands of sequence features</li>
+    <li> 
+    <li>Improved usability with <a href="features/pdbsequencefetcher.html">PDB</a> and 
+    <a href="features/uniprotsequencefetcher.html">UniProt</a> Free Text Search
+      dialog, and new tab for retrieval of sequences for lists of IDs.</li>
+      <li>Short names assigned to sequences retrieved from UniProt</li> 
+  </ul>
   <p>
     <strong><a name="experimental">Experimental Features</a></strong>
   </p>
similarity index 62%
rename from lib/groovy-all-2.4.6-indy.jar
rename to lib/groovy-all-2.4.12-indy.jar
index 5f3d51c..bb246a3 100644 (file)
Binary files a/lib/groovy-all-2.4.6-indy.jar and b/lib/groovy-all-2.4.12-indy.jar differ
index 5d9bdff..94f7eff 100644 (file)
@@ -1319,3 +1319,6 @@ label.select_hidden_colour = Select hidden colour
 label.overview = Overview
 label.reset_to_defaults = Reset to defaults
 label.oview_calc = Recalculating overview...
+option.enable_disable_autosearch = When ticked, search is performed automatically.
+option.autosearch = Autosearch
+label.retrieve_ids = Retrieve IDs
\ No newline at end of file
index c06f7b1..50a9e33 100755 (executable)
@@ -778,5 +778,14 @@ public class AnnotationPanel extends Panel
     {
       fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
     }
+    else if (evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ))
+    {
+      fastPaint(((int[]) evt.getNewValue())[0]
+              - ((int[]) evt.getOldValue())[0]);
+    }
+    else if (evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT))
+    {
+      repaint();
+    }
   }
 }
index 5eddc4f..f5ea12e 100755 (executable)
@@ -448,5 +448,14 @@ public class IdCanvas extends Panel implements ViewportListenerI
     {
       fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
     }
+    else if (propertyName.equals(ViewportRanges.STARTRESANDSEQ))
+    {
+      fastPaint(((int[]) evt.getNewValue())[1]
+              - ((int[]) evt.getOldValue())[1]);
+    }
+    else if (propertyName.equals(ViewportRanges.MOVE_VIEWPORT))
+    {
+      repaint();
+    }
   }
 }
index 7d4150d..04fb22b 100755 (executable)
@@ -468,7 +468,9 @@ public class ScalePanel extends Panel
     // 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 (evt.getPropertyName().equals(ViewportRanges.STARTRES))
+    if (evt.getPropertyName().equals(ViewportRanges.STARTRES)
+            || evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ)
+            || evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT))
     {
       // scroll event, repaint panel
       repaint();
index f59967d..2420cf7 100755 (executable)
@@ -889,15 +889,37 @@ public class SeqCanvas extends Panel implements ViewportListenerI
   {
     String eventName = evt.getPropertyName();
 
+    if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED))
+    {
+      fastPaint = true;
+      repaint();
+      return;
+    }
+    else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT))
+    {
+      fastPaint = false;
+      repaint();
+      return;
+    }
+
     if (!av.getWrapAlignment())
     {
       int scrollX = 0;
-      if (eventName.equals(ViewportRanges.STARTRES))
+      if (eventName.equals(ViewportRanges.STARTRES)
+              || eventName.equals(ViewportRanges.STARTRESANDSEQ))
       {
         // Make sure we're not trying to draw a panel
         // larger than the visible window
+        if (eventName.equals(ViewportRanges.STARTRES))
+        {
+          scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+        }
+        else
+        {
+          scrollX = ((int[]) evt.getNewValue())[0]
+                  - ((int[]) evt.getOldValue())[0];
+        }
         ViewportRanges vpRanges = av.getRanges();
-        scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
         int range = vpRanges.getEndRes() - vpRanges.getStartRes();
         if (scrollX > range)
         {
@@ -924,6 +946,10 @@ public class SeqCanvas extends Panel implements ViewportListenerI
         // scroll
         fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
       }
+      else if (eventName.equals(ViewportRanges.STARTRESANDSEQ))
+      {
+        fastPaint(scrollX, 0);
+      }
     }
   }
 
index 9a61f5f..d74bbb7 100644 (file)
@@ -43,7 +43,6 @@ import jalview.util.Comparison;
 import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
-import jalview.viewmodel.ViewportRanges;
 
 import java.awt.BorderLayout;
 import java.awt.Font;
@@ -148,13 +147,13 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   void setCursorRow()
   {
     seqCanvas.cursorY = getKeyboardNo1() - 1;
-    scrollToVisible();
+    scrollToVisible(true);
   }
 
   void setCursorColumn()
   {
     seqCanvas.cursorX = getKeyboardNo1() - 1;
-    scrollToVisible();
+    scrollToVisible(true);
   }
 
   void setCursorRowAndColumn()
@@ -167,7 +166,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     {
       seqCanvas.cursorX = getKeyboardNo1() - 1;
       seqCanvas.cursorY = getKeyboardNo2() - 1;
-      scrollToVisible();
+      scrollToVisible(true);
     }
   }
 
@@ -176,7 +175,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     SequenceI sequence = av.getAlignment().getSequenceAt(seqCanvas.cursorY);
 
     seqCanvas.cursorX = sequence.findIndex(getKeyboardNo1()) - 1;
-    scrollToVisible();
+    scrollToVisible(true);
   }
 
   void moveCursor(int dx, int dy)
@@ -202,10 +201,16 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         seqCanvas.cursorX = original;
       }
     }
-    scrollToVisible();
+    scrollToVisible(false);
   }
 
-  void scrollToVisible()
+  /**
+   * Scroll to make the cursor visible in the viewport.
+   * 
+   * @param jump
+   *          just jump to the location rather than scrolling
+   */
+  void scrollToVisible(boolean jump)
   {
     if (seqCanvas.cursorX < 0)
     {
@@ -226,44 +231,34 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
 
     endEditing();
-    if (av.getWrapAlignment())
+
+    boolean repaintNeeded = true;
+    if (jump)
     {
-      av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
+      // only need to repaint if the viewport did not move, as otherwise it will
+      // get a repaint
+      repaintNeeded = !av.getRanges().setViewportLocation(seqCanvas.cursorX,
+              seqCanvas.cursorY);
     }
     else
     {
-      ViewportRanges ranges = av.getRanges();
-      HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-      while (seqCanvas.cursorY < ranges.getStartSeq())
+      if (av.getWrapAlignment())
       {
-        ranges.scrollUp(true);
+        av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
       }
-      while (seqCanvas.cursorY > ranges.getEndSeq())
-      {
-        ranges.scrollUp(false);
-      }
-      while (seqCanvas.cursorX < hidden
-              .adjustForHiddenColumns(ranges.getStartRes()))
-      {
-
-        if (!ranges.scrollRight(false))
-        {
-          break;
-        }
-      }
-      while (seqCanvas.cursorX > hidden
-              .adjustForHiddenColumns(ranges.getEndRes()))
+      else
       {
-        if (!ranges.scrollRight(true))
-        {
-          break;
-        }
+        av.getRanges().scrollToVisible(seqCanvas.cursorX,
+                seqCanvas.cursorY);
       }
     }
     setStatusMessage(av.getAlignment().getSequenceAt(seqCanvas.cursorY),
             seqCanvas.cursorX, seqCanvas.cursorY);
 
-    seqCanvas.repaint();
+    if (repaintNeeded)
+    {
+      seqCanvas.repaint();
+    }
   }
 
   void setSelectionAreaAtCursor(boolean topLeft)
index 8c5e4ac..f268d37 100755 (executable)
@@ -28,6 +28,7 @@ import jalview.util.LinkedIdentityHashSet;
 import jalview.util.MessageManager;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
@@ -1617,40 +1618,21 @@ public class Alignment implements AlignmentI
   @Override
   public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
   {
-    List<AlignmentAnnotation> aa = new ArrayList<>();
     AlignmentAnnotation[] alignmentAnnotation = getAlignmentAnnotation();
     if (alignmentAnnotation != null)
     {
-      for (AlignmentAnnotation a : alignmentAnnotation)
-      {
-        if (a.getCalcId() == calcId || (a.getCalcId() != null
-                && calcId != null && a.getCalcId().equals(calcId)))
-        {
-          aa.add(a);
-        }
-      }
+      return AlignmentAnnotation.findAnnotation(
+              Arrays.asList(getAlignmentAnnotation()), calcId);
     }
-    return aa;
+    return Arrays.asList(new AlignmentAnnotation[] {});
   }
 
   @Override
   public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
           String calcId, String label)
   {
-    ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
-    for (AlignmentAnnotation ann : getAlignmentAnnotation())
-    {
-      if ((calcId == null || (ann.getCalcId() != null
-              && ann.getCalcId().equals(calcId)))
-              && (seq == null || (ann.sequenceRef != null
-                      && ann.sequenceRef == seq))
-              && (label == null
-                      || (ann.label != null && ann.label.equals(label))))
-      {
-        aa.add(ann);
-      }
-    }
-    return aa;
+    return AlignmentAnnotation.findAnnotations(
+            Arrays.asList(getAlignmentAnnotation()), seq, calcId, label);
   }
 
   @Override
index 09facbf..f7bf4d8 100755 (executable)
@@ -24,6 +24,7 @@ import jalview.analysis.Rna;
 import jalview.analysis.SecStrConsensus.SimpleBP;
 import jalview.analysis.WUSSParseException;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -1471,4 +1472,71 @@ public class AlignmentAnnotation
   {
     return graphMin < graphMax;
   }
+
+  public static Iterable<AlignmentAnnotation> findAnnotations(
+          Iterable<AlignmentAnnotation> list, SequenceI seq, String calcId,
+          String label)
+  {
+
+    ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
+    for (AlignmentAnnotation ann : list)
+    {
+      if ((calcId == null || (ann.getCalcId() != null
+              && ann.getCalcId().equals(calcId)))
+              && (seq == null || (ann.sequenceRef != null
+                      && ann.sequenceRef == seq))
+              && (label == null
+                      || (ann.label != null && ann.label.equals(label))))
+      {
+        aa.add(ann);
+      }
+    }
+    return aa;
+  }
+
+  /**
+   * Answer true if any annotation matches the calcId passed in (if not null).
+   * 
+   * @param list
+   *          annotation to search
+   * @param calcId
+   * @return
+   */
+  public static boolean hasAnnotation(List<AlignmentAnnotation> list,
+          String calcId)
+  {
+
+    if (calcId != null && !"".equals(calcId))
+    {
+      for (AlignmentAnnotation a : list)
+      {
+        if (a.getCalcId() == calcId)
+        {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  public static Iterable<AlignmentAnnotation> findAnnotation(
+          List<AlignmentAnnotation> list, String calcId)
+  {
+
+    List<AlignmentAnnotation> aa = new ArrayList<>();
+    if (calcId == null)
+    {
+      return aa;
+    }
+    for (AlignmentAnnotation a : list)
+    {
+
+      if (a.getCalcId() == calcId || (a.getCalcId() != null
+              && calcId != null && a.getCalcId().equals(calcId)))
+      {
+        aa.add(a);
+      }
+    }
+    return aa;
+  }
 }
index 96b0757..15d1378 100755 (executable)
@@ -77,11 +77,6 @@ public class Sequence extends ASequence implements SequenceI
    */
   Vector<AlignmentAnnotation> annotation;
 
-  /**
-   * The index of the sequence in a MSA
-   */
-  int index = -1;
-
   private SequenceFeaturesI sequenceFeatureStore;
 
   /*
@@ -1165,7 +1160,7 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   @Override
-  public void deleteChars(int i, int j)
+  public void deleteChars(final int i, final int j)
   {
     int newstart = start, newend = end;
     if (i >= sequence.length || i < 0)
@@ -1177,62 +1172,75 @@ public class Sequence extends ASequence implements SequenceI
     boolean createNewDs = false;
     // TODO: take a (second look) at the dataset creation validation method for
     // the very large sequence case
-    int eindex = -1, sindex = -1;
-    boolean ecalc = false, scalc = false;
+    int startIndex = findIndex(start) - 1;
+    int endIndex = findIndex(end) - 1;
+    int startDeleteColumn = -1; // for dataset sequence deletions
+    int deleteCount = 0;
+
     for (int s = i; s < j; s++)
     {
-      if (jalview.schemes.ResidueProperties.aaIndex[sequence[s]] != 23)
+      if (Comparison.isGap(sequence[s]))
+      {
+        continue;
+      }
+      deleteCount++;
+      if (startDeleteColumn == -1)
+      {
+        startDeleteColumn = findPosition(s) - start;
+      }
+      if (createNewDs)
+      {
+        newend--;
+      }
+      else
       {
-        if (createNewDs)
+        if (startIndex == s)
         {
-          newend--;
+          /*
+           * deleting characters from start of sequence; new start is the
+           * sequence position of the next column (position to the right
+           * if the column position is gapped)
+           */
+          newstart = findPosition(j);
+          break;
         }
         else
         {
-          if (!scalc)
+          if (endIndex < j)
           {
-            sindex = findIndex(start) - 1;
-            scalc = true;
-          }
-          if (sindex == s)
-          {
-            // delete characters including start of sequence
-            newstart = findPosition(j);
-            break; // don't need to search for any more residue characters.
+            /*
+             * deleting characters at end of sequence; new end is the sequence
+             * position of the column before the deletion; subtract 1 if this is
+             * gapped since findPosition returns the next sequence position
+             */
+            newend = findPosition(i - 1);
+            if (Comparison.isGap(sequence[i - 1]))
+            {
+              newend--;
+            }
+            break;
           }
           else
           {
-            // delete characters after start.
-            if (!ecalc)
-            {
-              eindex = findIndex(end) - 1;
-              ecalc = true;
-            }
-            if (eindex < j)
-            {
-              // delete characters at end of sequence
-              newend = findPosition(i - 1);
-              break; // don't need to search for any more residue characters.
-            }
-            else
-            {
-              createNewDs = true;
-              newend--; // decrease end position by one for the deleted residue
-              // and search further
-            }
+            createNewDs = true;
+            newend--;
           }
         }
       }
     }
-    // deletion occured in the middle of the sequence
+
     if (createNewDs && this.datasetSequence != null)
     {
-      // construct a new sequence
+      /*
+       * if deletion occured in the middle of the sequence,
+       * construct a new dataset sequence and delete the residues
+       * that were deleted from the aligned sequence
+       */
       Sequence ds = new Sequence(datasetSequence);
+      ds.deleteChars(startDeleteColumn, startDeleteColumn + deleteCount);
+      datasetSequence = ds;
       // TODO: remove any non-inheritable properties ?
       // TODO: create a sequence mapping (since there is a relation here ?)
-      ds.deleteChars(i, j);
-      datasetSequence = ds;
     }
     start = newstart;
     end = newend;
@@ -1682,30 +1690,6 @@ public class Sequence extends ASequence implements SequenceI
     }
   }
 
-  /**
-   * @return The index (zero-based) on this sequence in the MSA. It returns
-   *         {@code -1} if this information is not available.
-   */
-  @Override
-  public int getIndex()
-  {
-    return index;
-  }
-
-  /**
-   * Defines the position of this sequence in the MSA. Use the value {@code -1}
-   * if this information is undefined.
-   * 
-   * @param The
-   *          position for this sequence. This value is zero-based (zero for
-   *          this first sequence)
-   */
-  @Override
-  public void setIndex(int value)
-  {
-    index = value;
-  }
-
   @Override
   public void setRNA(RNA r)
   {
index e2f15e1..6b797d7 100755 (executable)
@@ -30,6 +30,7 @@ import java.awt.Color;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -1316,39 +1317,16 @@ public class SequenceGroup implements AnnotatedCollectionI
   @Override
   public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
   {
-    List<AlignmentAnnotation> aa = new ArrayList<>();
-    if (calcId == null)
-    {
-      return aa;
-    }
-    for (AlignmentAnnotation a : getAlignmentAnnotation())
-    {
-      if (calcId.equals(a.getCalcId()))
-      {
-        aa.add(a);
-      }
-    }
-    return aa;
+    return AlignmentAnnotation.findAnnotation(
+            Arrays.asList(getAlignmentAnnotation()), calcId);
   }
 
   @Override
   public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
           String calcId, String label)
   {
-    ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
-    for (AlignmentAnnotation ann : getAlignmentAnnotation())
-    {
-      if ((calcId == null || (ann.getCalcId() != null
-              && ann.getCalcId().equals(calcId)))
-              && (seq == null || (ann.sequenceRef != null
-                      && ann.sequenceRef == seq))
-              && (label == null
-                      || (ann.label != null && ann.label.equals(label))))
-      {
-        aa.add(ann);
-      }
-    }
-    return aa;
+    return AlignmentAnnotation.findAnnotations(
+            Arrays.asList(getAlignmentAnnotation()), seq, calcId, label);
   }
 
   /**
@@ -1359,17 +1337,8 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   public boolean hasAnnotation(String calcId)
   {
-    if (calcId != null && !"".equals(calcId))
-    {
-      for (AlignmentAnnotation a : getAlignmentAnnotation())
-      {
-        if (a.getCalcId() == calcId)
-        {
-          return true;
-        }
-      }
-    }
-    return false;
+    return AlignmentAnnotation
+            .hasAnnotation(Arrays.asList(getAlignmentAnnotation()), calcId);
   }
 
   /**
index 6e6d1aa..2f3e925 100755 (executable)
@@ -192,13 +192,14 @@ public interface SequenceI extends ASequenceI
   public int findIndex(int pos);
 
   /**
-   * Returns the sequence position for an alignment position.
+   * Returns the sequence position for an alignment (column) position. If at a
+   * gap, returns the position of the next residue to the right. If beyond the
+   * end of the sequence, returns 1 more than the last residue position.
    * 
    * @param i
    *          column index in alignment (from 0..<length)
    * 
-   * @return TODO: JAL-2562 - residue number for residue (left of and) nearest
-   *         ith column
+   * @return
    */
   public int findPosition(int i);
 
@@ -449,17 +450,6 @@ public interface SequenceI extends ASequenceI
   public void transferAnnotation(SequenceI entry, Mapping mp);
 
   /**
-   * @param index
-   *          The sequence index in the MSA
-   */
-  public void setIndex(int index);
-
-  /**
-   * @return The index of the sequence in the alignment
-   */
-  public int getIndex();
-
-  /**
    * @return The RNA of the sequence in the alignment
    */
 
index b40df50..bbd1f26 100644 (file)
@@ -44,11 +44,13 @@ public class EnsemblGenomes extends EnsemblGene
     return "EnsemblGenomes";
   }
 
-  private String Wrong[];
   @Override
   public String getTestQuery()
   {
-    return "DDB_G0283883";
+    /*
+     * Salmonella gene, Uniprot Q8Z9G6, EMBLCDS CAD01290
+     */
+    return "CAD01290";
   }
 
   @Override
index 99c0c51..974cc88 100644 (file)
@@ -145,4 +145,11 @@ public interface GFTSPanelI
    * @return
    */
   public String getCacheKey();
+
+  /**
+   * 
+   * @return user preference name for configuring this FTS search's autosearch
+   *         checkbox
+   */
+  public String getAutosearchPreference();
 }
index c0d005f..9802d4b 100644 (file)
@@ -56,6 +56,7 @@ import java.util.List;
 
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JFrame;
 import javax.swing.JInternalFrame;
@@ -88,6 +89,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
   protected JInternalFrame mainFrame = new JInternalFrame(
           getFTSFrameTitle());
 
+  protected JTabbedPane tabs = new JTabbedPane();
   protected IProgressIndicator progressIndicator;
 
   protected JComboBox<FTSDataColumnI> cmb_searchTarget = new JComboBox<FTSDataColumnI>();
@@ -98,6 +100,8 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
 
   protected JButton btn_cancel = new JButton();
 
+  protected JCheckBox btn_autosearch = new JCheckBox();
+
   protected JvCacheableInputBox<String> txt_search;
 
   protected SequenceFetcher seqFetcher;
@@ -239,16 +243,38 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
 
   public GFTSPanel()
   {
+    this(null);
+  }
+
+  public GFTSPanel(SequenceFetcher fetcher)
+  {
     try
     {
+      if (fetcher == null)
+      {
+        tabs = null;
+      }
       jbInit();
+      if (fetcher != null)
+      {
+        tabs.addTab(MessageManager.getString("label.retrieve_ids"),
+                fetcher);
+        fetcher.setDatabaseChooserVisible(false);
+        fetcher.embedWithFTSPanel(this);
+      }
       mainFrame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
+      final JPanel ftsPanel = this;
       mainFrame.addFocusListener(new FocusAdapter()
       {
         @Override
         public void focusGained(FocusEvent e)
         {
-          txt_search.requestFocusInWindow();
+          // TODO: make selected tab gain focus in correct widget
+          if (tabs != null
+                  && tabs.getSelectedComponent() == ftsPanel)
+          {
+            txt_search.requestFocusInWindow();
+          }
         }
       });
       mainFrame.invalidate();
@@ -331,6 +357,20 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       }
     });
 
+    btn_autosearch.setText(MessageManager.getString("option.autosearch"));
+    btn_autosearch.setToolTipText(
+            MessageManager.getString("option.enable_disable_autosearch"));
+    btn_autosearch.setSelected(
+            jalview.bin.Cache.getDefault(getAutosearchPreference(), true));
+    btn_autosearch.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        jalview.bin.Cache.setProperty(getAutosearchPreference(),
+                Boolean.toString(btn_autosearch.isSelected()));
+      }
+    });
     btn_back.setFont(new java.awt.Font("Verdana", 0, 12));
     btn_back.setText(MessageManager.getString("action.back"));
     btn_back.addActionListener(new java.awt.event.ActionListener()
@@ -511,8 +551,14 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
                   if (primaryKeyName.equalsIgnoreCase(getCmbSearchTarget()
                           .getSelectedItem().toString()))
                   {
+                    // TODO: nicer to show the list in the result set before
+                    // viewing in Jalview perhaps ?
                     transferToSequenceFetcher(getTypedText());
                   }
+                  else
+                  {
+                    performSearchAction();
+                  }
                 }
               }
             });
@@ -522,12 +568,10 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
               @Override
               public void actionPerformed(ActionEvent e)
               {
-                String typed = getTypedText();
-                if (!typed.equalsIgnoreCase(lastSearchTerm))
+                if (btn_autosearch.isSelected()
+                        || txt_search.wasEnterPressed())
                 {
-                  searchAction(true);
-                  paginatorCart.clear();
-                  lastSearchTerm = typed;
+                  performSearchAction();
                 }
               }
             }, false);
@@ -549,6 +593,15 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       }
     });
 
+    txt_search.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        performSearchAction();
+      }
+    });
     final String searchTabTitle = MessageManager
             .getString("label.search_result");
     final String configureCols = MessageManager
@@ -613,6 +666,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     pnl_results.add(tabbedPane);
     pnl_inputs.add(cmb_searchTarget);
     pnl_inputs.add(txt_search);
+    pnl_inputs.add(btn_autosearch);
     pnl_inputs.add(lbl_loading);
     pnl_inputs.add(lbl_warning);
     pnl_inputs.add(lbl_blank);
@@ -624,7 +678,17 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     this.add(pnl_results, java.awt.BorderLayout.CENTER);
     this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
     mainFrame.setVisible(true);
-    mainFrame.setContentPane(this);
+    if (tabs != null)
+    {
+      tabs.setOpaque(true);
+      tabs.insertTab("Free Text Search", null, this, "", 0);
+      mainFrame.setContentPane(tabs);
+      tabs.setVisible(true);
+    }
+    else
+    {
+      mainFrame.setContentPane(this);
+    }
     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
     mainFrame.addInternalFrameListener(
             new javax.swing.event.InternalFrameAdapter()
@@ -635,8 +699,6 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
                 closeAction();
               }
             });
-    mainFrame.setVisible(true);
-    mainFrame.setContentPane(this);
     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
     Integer x = getTempUserPrefs().get("FTSPanel.x");
     Integer y = getTempUserPrefs().get("FTSPanel.y");
@@ -698,6 +760,18 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
 
   }
 
+  void performSearchAction()
+  {
+    String typed = getTypedText();
+    if (typed != null && typed.length() > 0
+            && !typed.equalsIgnoreCase(lastSearchTerm))
+    {
+      searchAction(true);
+      paginatorCart.clear();
+      lastSearchTerm = typed;
+    }
+  }
+
   public boolean wantedFieldsUpdated()
   {
     if (previousWantedFields == null)
@@ -774,7 +848,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     }
   }
 
-  protected void btn_back_ActionPerformed()
+  public void btn_back_ActionPerformed()
   {
     closeAction();
     new SequenceFetcher(progressIndicator);
@@ -787,7 +861,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     btn_cancel.setEnabled(false);
   }
 
-  protected void btn_cancel_ActionPerformed()
+  public void btn_cancel_ActionPerformed()
   {
     closeAction();
   }
index 19f7db4..053d91b 100644 (file)
@@ -43,9 +43,11 @@ public class PDBFTSPanel extends GFTSPanel
 
   private static final String PDB_FTS_CACHE_KEY = "CACHE.PDB_FTS";
 
+  private static final String PDB_AUTOSEARCH = "FTS.PDB.AUTOSEARCH";
+
   public PDBFTSPanel(SequenceFetcher fetcher)
   {
-    super();
+    super(fetcher);
     pageLimit = PDBFTSRestClient.getInstance().getDefaultResponsePageSize();
     this.seqFetcher = fetcher;
     this.progressIndicator = (fetcher == null) ? null
@@ -281,4 +283,9 @@ public class PDBFTSPanel extends GFTSPanel
     return PDB_FTS_CACHE_KEY;
   }
 
-}
+  @Override
+  public String getAutosearchPreference()
+  {
+    return PDB_AUTOSEARCH;
+  }
+}
\ No newline at end of file
index 020331a..df54dea 100644 (file)
@@ -44,9 +44,11 @@ public class UniprotFTSPanel extends GFTSPanel
 
   private static final String UNIPROT_FTS_CACHE_KEY = "CACHE.UNIPROT_FTS";
 
+  private static final String UNIPROT_AUTOSEARCH = "FTS.UNIPROT.AUTOSEARCH";
+
   public UniprotFTSPanel(SequenceFetcher fetcher)
   {
-    super();
+    super(fetcher);
     pageLimit = UniProtFTSRestClient.getInstance()
             .getDefaultResponsePageSize();
     this.seqFetcher = fetcher;
@@ -237,4 +239,10 @@ public class UniprotFTSPanel extends GFTSPanel
   {
     return UNIPROT_FTS_CACHE_KEY;
   }
+
+  @Override
+  public String getAutosearchPreference()
+  {
+    return UNIPROT_AUTOSEARCH;
+  }
 }
index 12d1369..438e81b 100755 (executable)
@@ -1185,5 +1185,14 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     {
       fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
     }
+    else if (evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ))
+    {
+      fastPaint(((int[]) evt.getNewValue())[0]
+              - ((int[]) evt.getOldValue())[0]);
+    }
+    else if (evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT))
+    {
+      repaint();
+    }
   }
 }
index a7dff86..085b259 100755 (executable)
@@ -564,5 +564,14 @@ public class IdCanvas extends JPanel implements ViewportListenerI
     {
       fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
     }
+    else if (propertyName.equals(ViewportRanges.STARTRESANDSEQ))
+    {
+      fastPaint(((int[]) evt.getNewValue())[1]
+              - ((int[]) evt.getOldValue())[1]);
+    }
+    else if (propertyName.equals(ViewportRanges.MOVE_VIEWPORT))
+    {
+      repaint();
+    }
   }
 }
index e677769..798c833 100755 (executable)
@@ -549,7 +549,9 @@ public class ScalePanel extends JPanel
     // 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 (evt.getPropertyName().equals(ViewportRanges.STARTRES))
+    if (evt.getPropertyName().equals(ViewportRanges.STARTRES)
+            || evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ)
+            || evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT))
     {
       // scroll event, repaint panel
       repaint();
index 2987404..433d2ec 100755 (executable)
@@ -296,47 +296,48 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       int transX = 0;
       int transY = 0;
 
-    gg.copyArea(horizontal * charWidth, vertical * charHeight,
-            img.getWidth(), img.getHeight(), -horizontal * charWidth,
-            -vertical * charHeight);
+      gg.copyArea(horizontal * charWidth, vertical * charHeight,
+              img.getWidth(), img.getHeight(), -horizontal * charWidth,
+              -vertical * charHeight);
 
-    if (horizontal > 0) // scrollbar pulled right, image to the left
-    {
-      transX = (endRes - startRes - horizontal) * charWidth;
-      startRes = endRes - horizontal;
-    }
-    else if (horizontal < 0)
-    {
-      endRes = startRes - horizontal;
-    }
-    else if (vertical > 0) // scroll down
-    {
-      startSeq = endSeq - vertical;
-
-      if (startSeq < ranges.getStartSeq())
-      { // ie scrolling too fast, more than a page at a time
-        startSeq = ranges.getStartSeq();
+      if (horizontal > 0) // scrollbar pulled right, image to the left
+      {
+        transX = (endRes - startRes - horizontal) * charWidth;
+        startRes = endRes - horizontal;
       }
-      else
+      else if (horizontal < 0)
       {
-        transY = img.getHeight() - ((vertical + 1) * charHeight);
+        endRes = startRes - horizontal;
       }
-    }
-    else if (vertical < 0)
-    {
-      endSeq = startSeq - vertical;
 
-      if (endSeq > ranges.getEndSeq())
+      if (vertical > 0) // scroll down
       {
-        endSeq = ranges.getEndSeq();
+        startSeq = endSeq - vertical;
+
+        if (startSeq < ranges.getStartSeq())
+        { // ie scrolling too fast, more than a page at a time
+          startSeq = ranges.getStartSeq();
+        }
+        else
+        {
+          transY = img.getHeight() - ((vertical + 1) * charHeight);
+        }
       }
-    }
+      else if (vertical < 0)
+      {
+        endSeq = startSeq - vertical;
 
-    gg.translate(transX, transY);
-    drawPanel(gg, startRes, endRes, startSeq, endSeq, 0);
-    gg.translate(-transX, -transY);
+        if (endSeq > ranges.getEndSeq())
+        {
+          endSeq = ranges.getEndSeq();
+        }
+      }
 
-    repaint();
+      gg.translate(transX, transY);
+      drawPanel(gg, startRes, endRes, startSeq, endSeq, 0);
+      gg.translate(-transX, -transY);
+
+      repaint();
     } finally
     {
       fastpainting = false;
@@ -410,6 +411,13 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       // 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);
+
+    }
+
+    if (av.cursorMode)
+    {
+      drawCursor(g, ranges.getStartRes(), ranges.getEndRes(),
+              ranges.getStartSeq(), ranges.getEndSeq());
     }
   }
   
@@ -508,6 +516,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
               AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
       g2d.drawImage(selectImage, 0, 0, this);
     }
+
     g2d.dispose();
 
     return lcimg;
@@ -912,9 +921,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
           int canvasWidth,
           int canvasHeight, int startRes)
   {
-       int charHeight = av.getCharHeight();
-       int charWidth = av.getCharWidth();
-         
+    int charHeight = av.getCharHeight();
+    int charWidth = av.getCharWidth();
+      
     // height gap above each panel
     int hgap = charHeight;
     if (av.getScaleAboveWrapped())
@@ -1141,13 +1150,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
           }
         }
       }
-
-      if (av.cursorMode && cursorY == i && cursorX >= startRes
-              && cursorX <= endRes)
-      {
-        seqRdr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * charWidth,
-                offset + ((i - startSeq) * charHeight));
-      }
     }
 
     if (av.getSelectionGroup() != null
@@ -1245,6 +1247,94 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     return selectionImage;
   }
 
+  /**
+   * Draw the cursor as a separate image and overlay
+   * 
+   * @param startRes
+   *          start residue of area to draw cursor in
+   * @param endRes
+   *          end residue of area to draw cursor in
+   * @param startSeq
+   *          start sequence of area to draw cursor in
+   * @param endSeq
+   *          end sequence of are to draw cursor in
+   * @return a transparent image of the same size as the sequence canvas, with
+   *         the cursor drawn on it, if any
+   */
+  private void drawCursor(Graphics g, int startRes, int endRes,
+          int startSeq,
+          int endSeq)
+  {
+    // convert the cursorY into a position on the visible alignment
+    int cursor_ypos = cursorY;
+
+    // don't do work unless we have to
+    if (cursor_ypos >= startSeq && cursor_ypos <= endSeq)
+    {
+      int yoffset = 0;
+      int xoffset = 0;
+      int startx = startRes;
+      int endx = endRes;
+
+      // convert the cursorX into a position on the visible alignment
+      int cursor_xpos = av.getAlignment().getHiddenColumns()
+              .findColumnPosition(cursorX);
+
+      if (av.getAlignment().getHiddenColumns().isVisible(cursorX))
+      {
+
+        if (av.getWrapAlignment())
+        {
+          // work out the correct offsets for the cursor
+          int charHeight = av.getCharHeight();
+          int charWidth = av.getCharWidth();
+          int canvasWidth = getWidth();
+          int canvasHeight = getHeight();
+
+          // height gap above each panel
+          int hgap = charHeight;
+          if (av.getScaleAboveWrapped())
+          {
+            hgap += charHeight;
+          }
+
+          int cWidth = (canvasWidth - labelWidthEast - labelWidthWest)
+                  / charWidth;
+          int cHeight = av.getAlignment().getHeight() * charHeight;
+
+          endx = startx + cWidth - 1;
+          int ypos = hgap; // vertical offset
+
+          // iterate down the wrapped panels
+          while ((ypos <= canvasHeight) && (endx < cursor_xpos))
+          {
+            // update vertical offset
+            ypos += cHeight + getAnnotationHeight() + hgap;
+
+            // update horizontal offset
+            startx += cWidth;
+            endx = startx + cWidth - 1;
+          }
+          yoffset = ypos;
+          xoffset = labelWidthWest;
+        }
+
+        // now check if cursor is within range for x values
+        if (cursor_xpos >= startx && cursor_xpos <= endx)
+        {
+          // get the character the cursor is drawn at
+          SequenceI seq = av.getAlignment().getSequenceAt(cursorY);
+          char s = seq.getCharAt(cursorX);
+
+          seqRdr.drawCursor(g, s,
+                  xoffset + (cursor_xpos - startx) * av.getCharWidth(),
+                  yoffset + (cursor_ypos - startSeq) * av.getCharHeight());
+        }
+      }
+    }
+  }
+
+
   /*
    * Set up graphics for selection group
    */
@@ -1276,8 +1366,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   private void drawUnwrappedSelection(Graphics2D g, SequenceGroup group,
           int startRes, int endRes, int startSeq, int endSeq, int offset)
   {
-       int charWidth = av.getCharWidth();
-         
+    int charWidth = av.getCharWidth();
+          
     if (!av.hasHiddenColumns())
     {
       drawPartialGroupOutline(g, group, startRes, endRes, startSeq, endSeq,
@@ -1339,9 +1429,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
           int startRes, int endRes, int startSeq, int endSeq,
           int verticalOffset)
   {
-       int charHeight = av.getCharHeight();
-       int charWidth = av.getCharWidth();
-         
+    int charHeight = av.getCharHeight();
+    int charWidth = av.getCharWidth();
     int visWidth = (endRes - startRes + 1) * charWidth;
 
     int oldY = -1;
@@ -1349,140 +1438,141 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     boolean inGroup = false;
     int top = -1;
     int bottom = -1;
-
-    int sx = -1;
     int sy = -1;
-    int xwidth = -1;
 
-    for (i = startSeq; i <= endSeq; i++)
-    {
-      // position of start residue of group relative to startRes, in pixels
-      sx = (group.getStartRes() - startRes) * charWidth;
+    List<SequenceI> seqs = group.getSequences(null);
 
-      // width of group in pixels
-      xwidth = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth)
-              - 1;
+    // position of start residue of group relative to startRes, in pixels
+    int sx = (group.getStartRes() - startRes) * charWidth;
 
-      sy = verticalOffset + (i - startSeq) * charHeight;
+    // width of group in pixels
+    int xwidth = (((group.getEndRes() + 1) - group.getStartRes())
+            * charWidth) - 1;
 
-      if (sx + xwidth < 0 || sx > visWidth)
-      {
-        continue;
-      }
-
-      if ((sx <= (endRes - startRes) * charWidth)
-              && group.getSequences(null)
-                      .contains(av.getAlignment().getSequenceAt(i)))
+    if (!(sx + xwidth < 0 || sx > visWidth))
+    {
+      for (i = startSeq; i <= endSeq; i++)
       {
-        if ((bottom == -1) && !group.getSequences(null)
-                .contains(av.getAlignment().getSequenceAt(i + 1)))
-        {
-          bottom = sy + charHeight;
-        }
+        sy = verticalOffset + (i - startSeq) * charHeight;
 
-        if (!inGroup)
-        {
-          if (((top == -1) && (i == 0)) || !group.getSequences(null)
-                  .contains(av.getAlignment().getSequenceAt(i - 1)))
-          {
-            top = sy;
-          }
-
-          oldY = sy;
-          inGroup = true;
-        }
-      }
-      else
-      {
-        if (inGroup)
+        if ((sx <= (endRes - startRes) * charWidth)
+                && seqs.contains(av.getAlignment().getSequenceAt(i)))
         {
-          // if start position is visible, draw vertical line to left of
-          // group
-          if (sx >= 0 && sx < visWidth)
-          {
-            g.drawLine(sx, oldY, sx, sy);
-          }
-
-          // if end position is visible, draw vertical line to right of
-          // group
-          if (sx + xwidth < visWidth)
+          if ((bottom == -1)
+                  && !seqs.contains(av.getAlignment().getSequenceAt(i + 1)))
           {
-            g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
+            bottom = sy + charHeight;
           }
 
-          if (sx < 0)
-          {
-            xwidth += sx;
-            sx = 0;
-          }
-
-          // don't let width extend beyond current block, or group extent
-          // fixes JAL-2672
-          if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
-          {
-            xwidth = (endRes - startRes + 1) * charWidth - sx;
-          }
-          
-          // draw horizontal line at top of group
-          if (top != -1)
+          if (!inGroup)
           {
-            g.drawLine(sx, top, sx + xwidth, top);
-            top = -1;
-          }
+            if (((top == -1) && (i == 0)) || !seqs
+                    .contains(av.getAlignment().getSequenceAt(i - 1)))
+            {
+              top = sy;
+            }
 
-          // draw horizontal line at bottom of group
-          if (bottom != -1)
-          {
-            g.drawLine(sx, bottom, sx + xwidth, bottom);
-            bottom = -1;
+            oldY = sy;
+            inGroup = true;
           }
+        }
+        else if (inGroup)
+        {
+          drawVerticals(g, sx, xwidth, visWidth, oldY, sy);
+          drawHorizontals(g, sx, xwidth, visWidth, top, bottom);
 
+          // reset top and bottom
+          top = -1;
+          bottom = -1;
           inGroup = false;
         }
       }
-    }
-
-    if (inGroup)
-    {
-      sy = verticalOffset + ((i - startSeq) * charHeight);
-      if (sx >= 0 && sx < visWidth)
+      if (inGroup)
       {
-        g.drawLine(sx, oldY, sx, sy);
+        sy = verticalOffset + ((i - startSeq) * charHeight);
+        drawVerticals(g, sx, xwidth, visWidth, oldY, sy);
+        drawHorizontals(g, sx, xwidth, visWidth, top, bottom);
       }
+    }
+  }
 
-      if (sx + xwidth < visWidth)
-      {
-        g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
-      }
+  /**
+   * Draw horizontal selection group boundaries at top and bottom positions
+   * 
+   * @param g
+   *          graphics object to draw on
+   * @param sx
+   *          start x position
+   * @param xwidth
+   *          width of gap
+   * @param visWidth
+   *          visWidth maximum available width
+   * @param top
+   *          position to draw top of group at
+   * @param bottom
+   *          position to draw bottom of group at
+   */
+  private void drawHorizontals(Graphics2D g, int sx, int xwidth,
+          int visWidth, int top, int bottom)
+  {
+    int width = xwidth;
+    int startx = sx;
+    if (startx < 0)
+    {
+      width += startx;
+      startx = 0;
+    }
 
-      if (sx < 0)
-      {
-        xwidth += sx;
-        sx = 0;
-      }
+    // don't let width extend beyond current block, or group extent
+    // fixes JAL-2672
+    if (startx + width >= visWidth)
+    {
+      width = visWidth - startx;
+    }
 
-      if (sx + xwidth > visWidth)
-      {
-        xwidth = visWidth;
-      }
-      else if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
-      {
-        xwidth = (endRes - startRes + 1) * charWidth;
-      }
+    if (top != -1)
+    {
+      g.drawLine(startx, top, startx + width, top);
+    }
 
-      if (top != -1)
-      {
-        g.drawLine(sx, top, sx + xwidth, top);
-        top = -1;
-      }
+    if (bottom != -1)
+    {
+      g.drawLine(startx, bottom - 1, startx + width, bottom - 1);
+    }
+  }
 
-      if (bottom != -1)
-      {
-        g.drawLine(sx, bottom - 1, sx + xwidth, bottom - 1);
-        bottom = -1;
-      }
+  /**
+   * Draw vertical lines at sx and sx+xwidth providing they lie within
+   * [0,visWidth)
+   * 
+   * @param g
+   *          graphics object to draw on
+   * @param sx
+   *          start x position
+   * @param xwidth
+   *          width of gap
+   * @param visWidth
+   *          visWidth maximum available width
+   * @param oldY
+   *          top y value
+   * @param sy
+   *          bottom y value
+   */
+  private void drawVerticals(Graphics2D g, int sx, int xwidth, int visWidth,
+          int oldY, int sy)
+  {
+    // if start position is visible, draw vertical line to left of
+    // group
+    if (sx >= 0 && sx < visWidth)
+    {
+      g.drawLine(sx, oldY, sx, sy);
+    }
 
-      inGroup = false;
+    // if end position is visible, draw vertical line to right of
+    // group
+    if (sx + xwidth < visWidth)
+    {
+      g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
     }
   }
   
@@ -1660,15 +1750,31 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       repaint();
       return;
     }
+    else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT))
+    {
+      fastPaint = false;
+      repaint();
+      return;
+    }
 
     int scrollX = 0;
-    if (eventName.equals(ViewportRanges.STARTRES))
+    if (eventName.equals(ViewportRanges.STARTRES)
+            || eventName.equals(ViewportRanges.STARTRESANDSEQ))
     {
       // Make sure we're not trying to draw a panel
       // larger than the visible window
+      if (eventName.equals(ViewportRanges.STARTRES))
+      {
+        scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+      }
+      else
+      {
+        scrollX = ((int[]) evt.getNewValue())[0]
+                - ((int[]) evt.getOldValue())[0];
+      }
       ViewportRanges vpRanges = av.getRanges();
-      scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
-      int range = vpRanges.getViewportWidth();
+
+      int range = vpRanges.getEndRes() - vpRanges.getStartRes();
       if (scrollX > range)
       {
         scrollX = range;
@@ -1677,30 +1783,43 @@ 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.
 
-    // scroll - startres and endres both change
-    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))
       {
-        fastPaintWrapped(scrollX);
+         if (av.getWrapAlignment())
+          {
+            fastPaintWrapped(scrollX);
+          }
+          else
+          {
+            fastPaint(scrollX, 0);
+          }
       }
-      else
+      else if (eventName.equals(ViewportRanges.STARTSEQ))
       {
-        fastPaint(scrollX, 0);
+        // scroll
+        fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+      }
+      else if (eventName.equals(ViewportRanges.STARTRESANDSEQ))
+      {
+        if (av.getWrapAlignment())
+        {
+          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.
       }
-    }
-    else if (eventName.equals(ViewportRanges.STARTSEQ))
-    {
-      // scroll
-      fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
     }
   }
 
@@ -1717,7 +1836,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   {
     ViewportRanges ranges = av.getRanges();
 
-    if (Math.abs(scrollX) > ranges.getViewportWidth())
+    // if (Math.abs(scrollX) > ranges.getViewportWidth())
+    // JAL-2836, 2836 temporarily removed wrapped fastpaint for release 2.10.3
+    if (true)
     {
       /*
        * shift of more than one view width is 
index 2223ee5..2cdb1d8 100644 (file)
@@ -320,13 +320,13 @@ public class SeqPanel extends JPanel
   void setCursorRow()
   {
     seqCanvas.cursorY = getKeyboardNo1() - 1;
-    scrollToVisible();
+    scrollToVisible(true);
   }
 
   void setCursorColumn()
   {
     seqCanvas.cursorX = getKeyboardNo1() - 1;
-    scrollToVisible();
+    scrollToVisible(true);
   }
 
   void setCursorRowAndColumn()
@@ -339,7 +339,7 @@ public class SeqPanel extends JPanel
     {
       seqCanvas.cursorX = getKeyboardNo1() - 1;
       seqCanvas.cursorY = getKeyboardNo2() - 1;
-      scrollToVisible();
+      scrollToVisible(true);
     }
   }
 
@@ -348,7 +348,7 @@ public class SeqPanel extends JPanel
     SequenceI sequence = av.getAlignment().getSequenceAt(seqCanvas.cursorY);
 
     seqCanvas.cursorX = sequence.findIndex(getKeyboardNo1()) - 1;
-    scrollToVisible();
+    scrollToVisible(true);
   }
 
   void moveCursor(int dx, int dy)
@@ -376,10 +376,16 @@ public class SeqPanel extends JPanel
       }
     }
 
-    scrollToVisible();
+    scrollToVisible(false);
   }
 
-  void scrollToVisible()
+  /**
+   * Scroll to make the cursor visible in the viewport.
+   * 
+   * @param jump
+   *          just jump to the location rather than scrolling
+   */
+  void scrollToVisible(boolean jump)
   {
     if (seqCanvas.cursorX < 0)
     {
@@ -400,20 +406,44 @@ public class SeqPanel extends JPanel
     }
 
     endEditing();
-    if (av.getWrapAlignment())
+
+    boolean repaintNeeded = true;
+    if (jump)
     {
-      av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
+      // only need to repaint if the viewport did not move, as otherwise it will
+      // get a repaint
+      repaintNeeded = !av.getRanges().setViewportLocation(seqCanvas.cursorX,
+              seqCanvas.cursorY);
     }
     else
     {
-      av.getRanges().scrollToVisible(seqCanvas.cursorX, seqCanvas.cursorY);
+      if (av.getWrapAlignment())
+      {
+        // scrollToWrappedVisible expects x-value to have hidden cols subtracted
+        int x = av.getAlignment().getHiddenColumns()
+                .findColumnPosition(seqCanvas.cursorX);
+        av.getRanges().scrollToWrappedVisible(x);
+      }
+      else
+      {
+        av.getRanges().scrollToVisible(seqCanvas.cursorX,
+                seqCanvas.cursorY);
+      }
     }
-    setStatusMessage(av.getAlignment().getSequenceAt(seqCanvas.cursorY),
+
+    if (av.getAlignment().getHiddenColumns().isVisible(seqCanvas.cursorX))
+    {
+      setStatusMessage(av.getAlignment().getSequenceAt(seqCanvas.cursorY),
             seqCanvas.cursorX, seqCanvas.cursorY);
+    }
 
-    seqCanvas.repaint();
+    if (repaintNeeded)
+    {
+      seqCanvas.repaint();
+    }
   }
 
+
   void setSelectionAreaAtCursor(boolean topLeft)
   {
     SequenceI sequence = av.getAlignment().getSequenceAt(seqCanvas.cursorY);
index e05230b..8d46792 100755 (executable)
@@ -26,6 +26,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.fts.core.GFTSPanel;
 import jalview.fts.service.pdb.PDBFTSPanel;
 import jalview.fts.service.uniprot.UniprotFTSPanel;
 import jalview.io.FileFormatI;
@@ -78,6 +79,8 @@ public class SequenceFetcher extends JPanel implements Runnable
 
   JButton close = new JButton();
 
+  JButton back = new JButton();
+
   JPanel jPanel1 = new JPanel();
 
   JTextArea textArea = new JTextArea();
@@ -383,6 +386,15 @@ public class SequenceFetcher extends JPanel implements Runnable
                     .getString("label.additional_sequence_fetcher"));
   }
 
+  GFTSPanel parentFTSframe = null;
+  /**
+   * change the buttons so they fit with the FTS panel.
+   */
+  public void embedWithFTSPanel(GFTSPanel toClose)
+  {
+    back.setVisible(true);
+    parentFTSframe = toClose;
+  }
   private void jbInit() throws Exception
   {
     this.setLayout(borderLayout2);
@@ -427,7 +439,7 @@ public class SequenceFetcher extends JPanel implements Runnable
         example_actionPerformed();
       }
     });
-    close.setText(MessageManager.getString("action.close"));
+    close.setText(MessageManager.getString("action.cancel"));
     close.addActionListener(new ActionListener()
     {
       @Override
@@ -436,6 +448,17 @@ public class SequenceFetcher extends JPanel implements Runnable
         close_actionPerformed(e);
       }
     });
+    back.setText(MessageManager.getString("action.back"));
+    back.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        parentFTSframe.btn_back_ActionPerformed();
+      }
+    });
+    // back not visible unless embedded
+    back.setVisible(false);
     textArea.setFont(JvSwingUtils.getLabelFont());
     textArea.setLineWrap(true);
     textArea.addKeyListener(new KeyAdapter()
@@ -451,9 +474,10 @@ public class SequenceFetcher extends JPanel implements Runnable
     });
     jPanel3.setLayout(borderLayout1);
     borderLayout1.setVgap(5);
-    jPanel1.add(ok);
+    jPanel1.add(back);
     jPanel1.add(example);
     jPanel1.add(clear);
+    jPanel1.add(ok);
     jPanel1.add(close);
     jPanel2.setLayout(borderLayout3);
     databaseButt = /*database.getDatabaseSelectorButton();
@@ -582,6 +606,10 @@ public class SequenceFetcher extends JPanel implements Runnable
     try
     {
       frame.setClosed(true);
+      if (parentFTSframe!=null)
+      {
+        parentFTSframe.btn_cancel_ActionPerformed();
+      }
     } catch (Exception ex)
     {
     }
@@ -594,7 +622,7 @@ public class SequenceFetcher extends JPanel implements Runnable
     textArea.setEnabled(false);
     ok.setEnabled(false);
     close.setEnabled(false);
-
+    back.setEnabled(false);
     Thread worker = new Thread(this);
     worker.start();
   }
@@ -606,6 +634,7 @@ public class SequenceFetcher extends JPanel implements Runnable
     textArea.setEnabled(true);
     ok.setEnabled(true);
     close.setEnabled(true);
+    back.setEnabled(parentFTSframe != null);
   }
 
   @Override
@@ -1087,4 +1116,9 @@ public class SequenceFetcher extends JPanel implements Runnable
   {
     frame.setVisible(false);
   }
+
+  public void setDatabaseChooserVisible(boolean b)
+  {
+    databaseButt.setVisible(b);
+  }
 }
index 0a1e8ef..81b394b 100755 (executable)
@@ -481,21 +481,30 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     }
   }
 
-  public void drawCursor(SequenceI seq, int res, int x1, int y1)
+  /**
+   * Draw a sequence canvas cursor
+   * 
+   * @param g
+   *          graphics context to draw on
+   * @param s
+   *          character to draw at cursor
+   * @param x1
+   *          x position of cursor in graphics context
+   * @param y1
+   *          y position of cursor in graphics context
+   */
+  public void drawCursor(Graphics g, char s, int x1, int y1)
   {
     int pady = av.getCharHeight() / 5;
     int charOffset = 0;
-    graphics.setColor(Color.black);
-    graphics.fillRect(x1, y1, av.getCharWidth(), av.getCharHeight());
+    g.setColor(Color.black);
+    g.fillRect(x1, y1, av.getCharWidth(), av.getCharHeight());
 
     if (av.isValidCharWidth())
     {
-      graphics.setColor(Color.white);
-
-      char s = seq.getCharAt(res);
-
+      g.setColor(Color.white);
       charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
-      graphics.drawString(String.valueOf(s), charOffset + x1,
+      g.drawString(String.valueOf(s), charOffset + x1,
               (y1 + av.getCharHeight()) - pady);
     }
 
index a603cca..2340283 100755 (executable)
@@ -174,11 +174,6 @@ public abstract class AlignFile extends FileParse
     }
     parseCalled = true;
     parse();
-    // sets the index of each sequence in the alignment
-    for (int i = 0, c = seqs.size(); i < c; i++)
-    {
-      seqs.get(i).setIndex(i);
-    }
   }
 
   /**
index 3d0daed..a837512 100644 (file)
@@ -28,6 +28,7 @@ import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -70,11 +71,49 @@ public class JvCacheableInputBox<E> extends JComboBox<String>
 
   private JMenuItem menuItemClearCache = new JMenuItem();
 
+  volatile boolean enterWasPressed = false;
+
+  /**
+   * @return flag indicating if the most recent keypress was enter
+   */
+  public boolean wasEnterPressed()
+  {
+    return enterWasPressed;
+  }
+
   public JvCacheableInputBox(String newCacheKey)
   {
     super();
     this.cacheKey = newCacheKey;
     setEditable(true);
+    addKeyListener(new KeyListener()
+    {
+
+      @Override
+      public void keyTyped(KeyEvent e)
+      {
+        enterWasPressed = false;
+        if (e.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          enterWasPressed = true;
+        }
+        // let event bubble up
+      }
+
+      @Override
+      public void keyReleased(KeyEvent e)
+      {
+        // TODO Auto-generated method stub
+
+      }
+
+      @Override
+      public void keyPressed(KeyEvent e)
+      {
+        // TODO Auto-generated method stub
+
+      }
+    });
     setPrototypeDisplayValue(
             "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
     appCache = AppCache.getInstance();
index c525bc6..c158ce7 100644 (file)
@@ -132,9 +132,7 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions
       }
     }
 
-    // update viewport
-    ranges.setStartRes(xAsRes);
-    ranges.setStartSeq(yAsSeq);
+    ranges.setStartResAndSeq(xAsRes, yAsSeq);
   }
 
   @Override
index 0bda56e..9dde16e 100644 (file)
@@ -176,8 +176,7 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions
     }
 
     // update viewport
-    ranges.setStartRes(visXAsRes);
-    ranges.setStartSeq(visYAsSeq);
+    ranges.setStartResAndSeq(visXAsRes, visYAsSeq);
   }
 
   /**
index 24ff57f..c7a3fa1 100644 (file)
@@ -24,11 +24,10 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.HiddenColumns;
 
 /**
- * Slightly less embryonic class which: Supplies and updates viewport properties
- * relating to position such as: start and end residues and sequences; ideally
- * will serve hidden columns/rows too. Intention also to support calculations
- * for positioning, scrolling etc. such as finding the middle of the viewport,
- * checking for scrolls off screen
+ * Supplies and updates viewport properties relating to position such as: start
+ * and end residues and sequences; ideally will serve hidden columns/rows too.
+ * Intention also to support calculations for positioning, scrolling etc. such
+ * as finding the middle of the viewport, checking for scrolls off screen
  */
 public class ViewportRanges extends ViewportProperties
 {
@@ -40,6 +39,10 @@ public class ViewportRanges extends ViewportProperties
 
   public static final String ENDSEQ = "endseq";
 
+  public static final String STARTRESANDSEQ = "startresandseq";
+
+  public static final String MOVE_VIEWPORT = "move_viewport";
+
   private boolean wrappedMode = false;
 
   // start residue of viewport
@@ -130,6 +133,31 @@ public class ViewportRanges extends ViewportProperties
    */
   public void setStartEndRes(int start, int end)
   {
+    int[] oldvalues = updateStartEndRes(start, end);
+    int oldstartres = oldvalues[0];
+    int oldendres = oldvalues[1];
+
+    changeSupport.firePropertyChange(STARTRES, oldstartres, startRes);
+    if (oldstartres == startRes)
+    {
+      // event won't be fired if start positions are same
+      // fire an event for the end positions in case they changed
+      changeSupport.firePropertyChange(ENDRES, oldendres, endRes);
+    }
+  }
+
+  /**
+   * Update start and end residue values, adjusting for width constraints if
+   * necessary
+   * 
+   * @param start
+   *          start residue
+   * @param end
+   *          end residue
+   * @return array containing old start and end residue values
+   */
+  private int[] updateStartEndRes(int start, int end)
+  {
     int oldstartres = this.startRes;
 
     /*
@@ -162,14 +190,7 @@ public class ViewportRanges extends ViewportProperties
     {
       endRes = end;
     }
-
-    changeSupport.firePropertyChange(STARTRES, oldstartres, startRes);
-    if (oldstartres == startRes)
-    {
-      // event won't be fired if start positions are same
-      // fire an event for the end positions in case they changed
-      changeSupport.firePropertyChange(ENDRES, oldendres, endRes);
-    }
+    return new int[] { oldstartres, oldendres };
   }
 
   /**
@@ -203,6 +224,31 @@ public class ViewportRanges extends ViewportProperties
    */
   public void setStartEndSeq(int start, int end)
   {
+    int[] oldvalues = updateStartEndSeq(start, end);
+    int oldstartseq = oldvalues[0];
+    int oldendseq = oldvalues[1];
+
+    changeSupport.firePropertyChange(STARTSEQ, oldstartseq, startSeq);
+    if (oldstartseq == startSeq)
+    {
+      // event won't be fired if start positions are the same
+      // fire in case the end positions changed
+      changeSupport.firePropertyChange(ENDSEQ, oldendseq, endSeq);
+    }
+  }
+
+  /**
+   * Update start and end sequence values, adjusting for height constraints if
+   * necessary
+   * 
+   * @param start
+   *          start sequence
+   * @param end
+   *          end sequence
+   * @return array containing old start and end sequence values
+   */
+  private int[] updateStartEndSeq(int start, int end)
+  {
     int oldstartseq = this.startSeq;
     int visibleHeight = getVisibleAlignmentHeight();
     if (start > visibleHeight - 1)
@@ -231,14 +277,7 @@ public class ViewportRanges extends ViewportProperties
     {
       endSeq = end;
     }
-
-    changeSupport.firePropertyChange(STARTSEQ, oldstartseq, startSeq);
-    if (oldstartseq == startSeq)
-    {
-      // event won't be fired if start positions are the same
-      // fire in case the end positions changed
-      changeSupport.firePropertyChange(ENDSEQ, oldendseq, endSeq);
-    }
+    return new int[] { oldstartseq, oldendseq };
   }
 
   /**
@@ -255,6 +294,34 @@ public class ViewportRanges extends ViewportProperties
   }
 
   /**
+   * Set start residue and start sequence together (fires single event). The
+   * event supplies a pair of old values and a pair of new values: [old start
+   * residue, old start sequence] and [new start residue, new start sequence]
+   * 
+   * @param res
+   *          the start residue
+   * @param seq
+   *          the start sequence
+   */
+  public void setStartResAndSeq(int res, int seq)
+  {
+    int width = getViewportWidth();
+    int[] oldresvalues = updateStartEndRes(res, res + width - 1);
+
+    int startseq = seq;
+    int height = getViewportHeight();
+    if (startseq + height - 1 > getVisibleAlignmentHeight() - 1)
+    {
+      startseq = getVisibleAlignmentHeight() - height;
+    }
+    int[] oldseqvalues = updateStartEndSeq(startseq, startseq + height - 1);
+
+    int[] old = new int[] { oldresvalues[0], oldseqvalues[0] };
+    int[] newresseq = new int[] { startRes, startSeq };
+    changeSupport.firePropertyChange(STARTRESANDSEQ, old, newresseq);
+  }
+
+  /**
    * Get start residue of viewport
    */
   public int getStartRes()
@@ -477,18 +544,33 @@ public class ViewportRanges extends ViewportProperties
    * the startRes changed, else false.
    * 
    * @param res
-   *          residue position to scroll to
+   *          residue position to scroll to NB visible position not absolute
+   *          alignment position
    * @return
    */
   public boolean scrollToWrappedVisible(int res)
   {
-    int oldStartRes = startRes;
-    int width = getViewportWidth();
-
-    if (res >= oldStartRes && res < oldStartRes + width)
+    int newStartRes = calcWrappedStartResidue(res);
+    if (newStartRes == startRes)
     {
       return false;
     }
+    setStartRes(newStartRes);
+
+    return true;
+  }
+
+  /**
+   * Calculate wrapped start residue from visible start residue
+   * 
+   * @param res
+   *          visible start residue
+   * @return left column of panel res will be located in
+   */
+  private int calcWrappedStartResidue(int res)
+  {
+    int oldStartRes = startRes;
+    int width = getViewportWidth();
 
     boolean up = res < oldStartRes;
     int widthsToScroll = Math.abs((res - oldStartRes) / width);
@@ -504,19 +586,16 @@ public class ViewportRanges extends ViewportProperties
     {
       newStartRes = 0;
     }
-
-    setStartRes(newStartRes);
-
-    return true;
+    return newStartRes;
   }
 
   /**
    * Scroll so that (x,y) is visible. Fires a property change event.
    * 
    * @param x
-   *          x position in alignment
+   *          x position in alignment (absolute position)
    * @param y
-   *          y position in alignment
+   *          y position in alignment (absolute position)
    */
   public void scrollToVisible(int x, int y)
   {
@@ -528,7 +607,7 @@ public class ViewportRanges extends ViewportProperties
     {
       scrollUp(false);
     }
-
+    
     HiddenColumns hidden = al.getHiddenColumns();
     while (x < hidden.adjustForHiddenColumns(startRes))
     {
@@ -547,6 +626,62 @@ public class ViewportRanges extends ViewportProperties
   }
 
   /**
+   * Set the viewport location so that a position is visible
+   * 
+   * @param x
+   *          column to be visible: absolute position in alignment
+   * @param y
+   *          row to be visible: absolute position in alignment
+   */
+  public boolean setViewportLocation(int x, int y)
+  {
+    boolean changedLocation = false;
+
+    // convert the x,y location to visible coordinates
+    int visX = al.getHiddenColumns().findColumnPosition(x);
+    int visY = al.getHiddenSequences().findIndexWithoutHiddenSeqs(y);
+
+    // if (vis_x,vis_y) is already visible don't do anything
+    if (startRes > visX || visX > endRes
+            || startSeq > visY && visY > endSeq)
+    {
+      int[] old = new int[] { startRes, startSeq };
+      int[] newresseq;
+      if (wrappedMode)
+      {
+        int newstartres = calcWrappedStartResidue(visX);
+        setStartRes(newstartres);
+        newresseq = new int[] { startRes, startSeq };
+      }
+      else
+      {
+        // set the viewport x location to contain vis_x
+        int newstartres = visX;
+        int width = getViewportWidth();
+        if (newstartres + width - 1 > getVisibleAlignmentWidth() - 1)
+        {
+          newstartres = getVisibleAlignmentWidth() - width;
+        }
+        updateStartEndRes(newstartres, newstartres + width - 1);
+
+        // set the viewport y location to contain vis_y
+        int newstartseq = visY;
+        int height = getViewportHeight();
+        if (newstartseq + height - 1 > getVisibleAlignmentHeight() - 1)
+        {
+          newstartseq = getVisibleAlignmentHeight() - height;
+        }
+        updateStartEndSeq(newstartseq, newstartseq + height - 1);
+
+        newresseq = new int[] { startRes, startSeq };
+      }
+      changedLocation = true;
+      changeSupport.firePropertyChange(MOVE_VIEWPORT, old, newresseq);
+    }
+    return changedLocation;
+  }
+
+  /**
    * Adjust sequence position for page up. Fires a property change event.
    */
   public void pageUp()
index c9beb8e..73775cf 100644 (file)
@@ -310,23 +310,18 @@ public class Uniprot extends DbSourceProxyImpl
   /**
    *
    * @param entry
-   *          UniportEntry
+   *          UniprotEntry
    * @return The accession id(s) and name(s) delimited by '|'.
    */
   public static String getUniprotEntryId(UniprotEntry entry)
   {
     StringBuilder name = new StringBuilder(32);
-    // name.append("UniProt/Swiss-Prot");
-    // use 'canonicalised' name for optimal id matching
-    name.append(DBRefSource.UNIPROT);
-    for (String accessionId : entry.getAccession())
-    {
-      name.append(BAR_DELIMITER);
-      name.append(accessionId);
-    }
     for (String n : entry.getName())
     {
-      name.append(BAR_DELIMITER);
+      if (name.length() > 0)
+      {
+        name.append(BAR_DELIMITER);
+      }
       name.append(n);
     }
     return name.toString();
index c0cb09c..a084a8e 100644 (file)
@@ -1803,4 +1803,82 @@ public class SequenceTest
     sq.checkValidRange();
     assertEquals(22, sq.getEnd());
   }
+
+  @Test(groups = { "Functional" })
+  public void testDeleteChars_withGaps()
+  {
+    /*
+     * delete gaps only
+     */
+    SequenceI sq = new Sequence("test/8-10", "A-B-C");
+    sq.createDatasetSequence();
+    assertEquals("ABC", sq.getDatasetSequence().getSequenceAsString());
+    sq.deleteChars(1, 2); // delete first gap
+    assertEquals("AB-C", sq.getSequenceAsString());
+    assertEquals(8, sq.getStart());
+    assertEquals(10, sq.getEnd());
+    assertEquals("ABC", sq.getDatasetSequence().getSequenceAsString());
+
+    /*
+     * delete gaps and residues at start (no new dataset sequence)
+     */
+    sq = new Sequence("test/8-10", "A-B-C");
+    sq.createDatasetSequence();
+    sq.deleteChars(0, 3); // delete A-B
+    assertEquals("-C", sq.getSequenceAsString());
+    assertEquals(10, sq.getStart());
+    assertEquals(10, sq.getEnd());
+    assertEquals("ABC", sq.getDatasetSequence().getSequenceAsString());
+
+    /*
+     * delete gaps and residues at end (no new dataset sequence)
+     */
+    sq = new Sequence("test/8-10", "A-B-C");
+    sq.createDatasetSequence();
+    sq.deleteChars(2, 5); // delete B-C
+    assertEquals("A-", sq.getSequenceAsString());
+    assertEquals(8, sq.getStart());
+    assertEquals(8, sq.getEnd());
+    assertEquals("ABC", sq.getDatasetSequence().getSequenceAsString());
+
+    /*
+     * delete gaps and residues internally (new dataset sequence)
+     * first delete from gap to residue
+     */
+    sq = new Sequence("test/8-10", "A-B-C");
+    sq.createDatasetSequence();
+    sq.deleteChars(1, 3); // delete -B
+    assertEquals("A-C", sq.getSequenceAsString());
+    assertEquals(8, sq.getStart());
+    assertEquals(9, sq.getEnd());
+    assertEquals("AC", sq.getDatasetSequence().getSequenceAsString());
+    assertEquals(8, sq.getDatasetSequence().getStart());
+    assertEquals(9, sq.getDatasetSequence().getEnd());
+
+    /*
+     * internal delete from gap to gap
+     */
+    sq = new Sequence("test/8-10", "A-B-C");
+    sq.createDatasetSequence();
+    sq.deleteChars(1, 4); // delete -B-
+    assertEquals("AC", sq.getSequenceAsString());
+    assertEquals(8, sq.getStart());
+    assertEquals(9, sq.getEnd());
+    assertEquals("AC", sq.getDatasetSequence().getSequenceAsString());
+    assertEquals(8, sq.getDatasetSequence().getStart());
+    assertEquals(9, sq.getDatasetSequence().getEnd());
+
+    /*
+     * internal delete from residue to residue
+     */
+    sq = new Sequence("test/8-10", "A-B-C");
+    sq.createDatasetSequence();
+    sq.deleteChars(2, 3); // delete B
+    assertEquals("A--C", sq.getSequenceAsString());
+    assertEquals(8, sq.getStart());
+    assertEquals(9, sq.getEnd());
+    assertEquals("AC", sq.getDatasetSequence().getSequenceAsString());
+    assertEquals(8, sq.getDatasetSequence().getStart());
+    assertEquals(9, sq.getDatasetSequence().getEnd());
+  }
 }
index c0cb4ba..41a313f 100644 (file)
@@ -85,7 +85,6 @@ public class ViewportRangesTest {
     vr.setEndSeq(al.getHeight());
     assertEquals(vr.getEndSeq(), al.getHeight() - 1);
 
-    // vr.setEndRes(al.getHeight() - 1);
     vr.setEndSeq(al.getHeight() - 1);
     assertEquals(vr.getEndSeq(), al.getHeight() - 1);
   }
@@ -169,6 +168,24 @@ public class ViewportRangesTest {
   }
 
   @Test(groups = { "Functional" })
+  public void testSetStartResAndSeq()
+  {
+    ViewportRanges vr = new ViewportRanges(al);
+    vr.setViewportHeight(10);
+    vr.setStartResAndSeq(3, 6);
+    assertEquals(vr.getStartRes(), 3);
+    assertEquals(vr.getStartSeq(), 6);
+    assertEquals(vr.getEndRes(), 3 + vr.getViewportWidth() - 1);
+    assertEquals(vr.getEndSeq(), 6 + vr.getViewportHeight() - 1);
+
+    vr.setStartResAndSeq(10, 25);
+    assertEquals(vr.getStartRes(), 10);
+    assertEquals(vr.getStartSeq(), 19);
+    assertEquals(vr.getEndRes(), 10 + vr.getViewportWidth() - 1);
+    assertEquals(vr.getEndSeq(), 19 + vr.getViewportHeight() - 1);
+  }
+
+  @Test(groups = { "Functional" })
   public void testSetViewportHeight()
   {
     ViewportRanges vr = new ViewportRanges(al);
@@ -385,14 +402,13 @@ public class ViewportRangesTest {
     assertEquals(vr.getEndRes(), 52);
   }
 
-  // leave until JAL-2388 is merged and we can do without viewport
-  /*@Test(groups = { "Functional" })
+  @Test(groups = { "Functional" })
   public void testScrollToVisible()
   {
     ViewportRanges vr = new ViewportRanges(al);
     vr.setViewportStartAndWidth(12,5);
     vr.setViewportStartAndHeight(10,6);
-    vr.scrollToVisible(13,14)
+    vr.scrollToVisible(13, 14);
     
     // no change
     assertEquals(vr.getStartRes(), 12);
@@ -403,7 +419,15 @@ public class ViewportRangesTest {
     assertEquals(vr.getStartSeq(), 6);
     
     // test for hidden columns too
-  }*/
+    al.getHiddenColumns().hideColumns(1, 3);
+    vr.scrollToVisible(13, 3);
+    assertEquals(vr.getStartRes(), 6);
+    assertEquals(vr.getStartSeq(), 3);
+
+    vr.scrollToVisible(2, 9);
+    assertEquals(vr.getStartRes(), 0);
+    assertEquals(vr.getStartSeq(), 4);
+  }
 
   @Test(groups = { "Functional" })
   public void testEventFiring()
@@ -418,7 +442,7 @@ public class ViewportRangesTest {
 
     // one event fired when startRes is called with new value
     vr.setStartRes(4);
-    assertTrue(l.verify(1, Arrays.asList("startres")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTRES)));
     l.reset();
 
     // no event fired for same value
@@ -427,7 +451,7 @@ public class ViewportRangesTest {
     l.reset();
 
     vr.setStartSeq(4);
-    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTSEQ)));
     l.reset();
 
     vr.setStartSeq(4);
@@ -435,7 +459,7 @@ public class ViewportRangesTest {
     l.reset();
 
     vr.setEndSeq(10);
-    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTSEQ)));
     l.reset();
 
     vr.setEndSeq(10);
@@ -443,7 +467,7 @@ public class ViewportRangesTest {
     l.reset();
 
     vr.setStartEndRes(2, 15);
-    assertTrue(l.verify(1, Arrays.asList("startres")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTRES)));
     l.reset();
 
     vr.setStartEndRes(2, 15);
@@ -452,16 +476,18 @@ public class ViewportRangesTest {
 
     // check new value fired by event is corrected startres
     vr.setStartEndRes(-1, 5);
-    assertTrue(l.verify(1, Arrays.asList("startres"), Arrays.asList(0)));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTRES),
+            Arrays.asList(0)));
     l.reset();
 
     // check new value fired by event is corrected endres
     vr.setStartEndRes(0, -1);
-    assertTrue(l.verify(1, Arrays.asList("endres"), Arrays.asList(0)));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.ENDRES),
+            Arrays.asList(0)));
     l.reset();
 
     vr.setStartEndSeq(2, 15);
-    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTSEQ)));
     l.reset();
 
     vr.setStartEndSeq(2, 15);
@@ -474,12 +500,14 @@ public class ViewportRangesTest {
 
     // check new value fired by event is corrected startseq
     vr.setStartEndSeq(-1, 5);
-    assertTrue(l.verify(1, Arrays.asList("startseq"), Arrays.asList(0)));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTSEQ),
+            Arrays.asList(0)));
     l.reset();
 
     // check new value fired by event is corrected endseq
     vr.setStartEndSeq(0, -1);
-    assertTrue(l.verify(1, Arrays.asList("endseq"), Arrays.asList(0)));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.ENDSEQ),
+            Arrays.asList(0)));
     l.reset();
 
     // reset for later tests
@@ -488,51 +516,52 @@ public class ViewportRangesTest {
 
     // test viewport height and width setting triggers event
     vr.setViewportHeight(10);
-    assertTrue(l.verify(1, Arrays.asList("endseq")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.ENDSEQ)));
     l.reset();
 
     vr.setViewportWidth(18);
-    assertTrue(l.verify(1, Arrays.asList("endres")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.ENDRES)));
     l.reset();
 
     // already has seq start set to 2, so triggers endseq
     vr.setViewportStartAndHeight(2, 16);
-    assertTrue(l.verify(1, Arrays.asList("endseq")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.ENDSEQ)));
     l.reset();
 
     vr.setViewportStartAndWidth(1, 14);
-    assertTrue(l.verify(1, Arrays.asList("startres")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTRES)));
     l.reset();
 
     // test page up/down triggers event
     vr.pageUp();
-    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTSEQ)));
     l.reset();
 
     vr.pageDown();
-    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTSEQ)));
     l.reset();
 
     // test scrolling triggers event
     vr.scrollUp(true);
-    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTSEQ)));
     l.reset();
 
     vr.scrollUp(false);
-    assertTrue(l.verify(1, Arrays.asList("startseq")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTSEQ)));
     l.reset();
 
     vr.scrollRight(true);
-    assertTrue(l.verify(1, Arrays.asList("startres")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTRES)));
     l.reset();
 
     vr.scrollRight(false);
-    assertTrue(l.verify(1, Arrays.asList("startres")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTRES)));
     l.reset();
 
     vr.scrollToVisible(10, 10);
     assertTrue(l.verify(4,
-            Arrays.asList("startseq", "startseq", "startseq", "startseq")));
+            Arrays.asList(ViewportRanges.STARTSEQ, ViewportRanges.STARTSEQ,
+                    ViewportRanges.STARTSEQ, ViewportRanges.STARTSEQ)));
     l.reset();
 
     /*
@@ -544,7 +573,15 @@ public class ViewportRangesTest {
     l.reset();
 
     vr.scrollToWrappedVisible(25);
-    assertTrue(l.verify(1, Arrays.asList("startres")));
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTRES)));
+    l.reset();
+
+    // test setStartResAndSeq triggers one event
+    vr.setStartResAndSeq(5, 7);
+    assertTrue(l.verify(1, Arrays.asList(ViewportRanges.STARTRESANDSEQ),
+            Arrays.asList(5, 7)));
+
+    l.reset();
   }
 
   @Test(groups = { "Functional" })
@@ -823,6 +860,76 @@ public class ViewportRangesTest {
     assertEquals(vr.getStartSeq(), 1);
     assertEquals(vr.getStartRes(), 43);
   }
+
+  @Test(groups = { "Functional" })
+  public void testSetViewportLocation()
+  {
+    AlignmentI al2 = gen.generate(60, 80, 1, 0, 0);
+
+    ViewportRanges vr = new ViewportRanges(al2);
+
+    // start with viewport on 5-14
+    vr.setViewportStartAndWidth(5, 10);
+    assertEquals(vr.getStartRes(), 5);
+    assertEquals(vr.getEndRes(), 14);
+
+    vr.setViewportStartAndHeight(3, 13);
+    assertEquals(vr.getStartSeq(), 3);
+    assertEquals(vr.getEndSeq(), 15);
+
+    // set location to (8,5) - no change
+    vr.setViewportLocation(8, 5);
+    assertEquals(vr.getStartRes(), 5);
+    assertEquals(vr.getEndRes(), 14);
+    assertEquals(vr.getStartSeq(), 3);
+    assertEquals(vr.getEndSeq(), 15);
+
+    // set location to (40,50) - change to top left (40,50)
+    vr.setViewportLocation(40, 50);
+    assertEquals(vr.getStartRes(), 40);
+    assertEquals(vr.getEndRes(), 49);
+    assertEquals(vr.getStartSeq(), 50);
+    assertEquals(vr.getEndSeq(), 62);
+
+    // set location past end of alignment - resets to leftmost pos
+    vr.setViewportLocation(63, 85);
+    assertEquals(vr.getStartRes(), 50);
+    assertEquals(vr.getEndRes(), 59);
+    assertEquals(vr.getStartSeq(), 67);
+    assertEquals(vr.getEndSeq(), 79);
+
+    // hide some columns
+    al2.getHiddenColumns().hideColumns(20, 50);
+    vr.setViewportLocation(55, 4);
+    assertEquals(vr.getStartRes(), 19);
+    assertEquals(vr.getEndRes(), 28);
+    assertEquals(vr.getStartSeq(), 4);
+    assertEquals(vr.getEndSeq(), 16);
+
+    // hide some sequences
+    al2.getHiddenSequences().hideSequence(al2.getSequenceAt(3));
+    al2.getHiddenSequences().hideSequence(al2.getSequenceAt(4));
+    vr.setViewportLocation(17, 5);
+    assertEquals(vr.getStartRes(), 17);
+    assertEquals(vr.getEndRes(), 26);
+    assertEquals(vr.getStartSeq(), 3);
+    assertEquals(vr.getEndSeq(), 15);
+
+    // set wrapped mode
+    vr.setWrappedMode(true);
+    vr.setViewportLocation(1, 8);
+    assertEquals(vr.getStartRes(), 0);
+    assertEquals(vr.getEndRes(), 9);
+    assertEquals(vr.getStartSeq(), 3);
+    assertEquals(vr.getEndSeq(), 15);
+
+    // try further down the alignment
+    vr.setViewportLocation(57, 5);
+    assertEquals(vr.getStartRes(), 20);
+    assertEquals(vr.getEndRes(), 29);
+    assertEquals(vr.getStartSeq(), 3);
+    assertEquals(vr.getEndSeq(), 15);
+  }
 }
 
 // mock listener for property change events
@@ -844,7 +951,15 @@ class MockPropChangeListener implements ViewportListenerI
   {
     firecount++;
     events.add(evt.getPropertyName());
-    newvalues.add((Integer) evt.getNewValue());
+    if (evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ))
+    {
+      newvalues.add(((int[]) evt.getNewValue())[0]);
+      newvalues.add(((int[]) evt.getNewValue())[1]);
+    }
+    else
+    {
+      newvalues.add((Integer) evt.getNewValue());
+    }
   }
 
   public boolean verify(int count, List<String> eventslist,
index 2d4be71..f98ef85 100644 (file)
@@ -163,11 +163,11 @@ public class UniprotTest
             new StringReader(UNIPROT_XML)).get(0);
 
     /*
-     * name formatted as source | accession ids | names
-     * source database converted to Jalview canonical name
+     * name formatted with Uniprot Entry name
      */
-    String expectedName = "UNIPROT|A9CKP4|A9CKP5|A9CKP4_AGRT5|A9CKP4_AGRT6";
-    assertEquals(expectedName, Uniprot.getUniprotEntryId(entry));
+    String expectedName = "A9CKP4_AGRT5|A9CKP4_AGRT6";
+    assertEquals(expectedName,
+            Uniprot.getUniprotEntryId(entry));
   }
 
   /**