Merge branch 'bug/JAL-2046_ds_sharing_features_broken' into develop
authorJim Procter <jprocter@issues.jalview.org>
Wed, 13 Apr 2016 15:46:52 +0000 (16:46 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Wed, 13 Apr 2016 15:46:52 +0000 (16:46 +0100)
30 files changed:
examples/testdata/simpleGff3.gff [new file with mode: 0644]
help/helpTOC.xml
help/html/menus/alwcalculate.html
src/MCview/PDBChain.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/ext/ensembl/EnsemblGene.java
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/ext/ensembl/EnsemblSeqProxy.java
src/jalview/ext/jmol/JmolParser.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/StructureChooser.java
src/jalview/ws/uimodel/PDBRestResponse.java
test/MCview/PDBChainTest.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/datamodel/ColumnSelectionTest.java
test/jalview/ext/jmol/JmolParserTest.java
test/jalview/gui/PDBSearchPanelTest.java
test/jalview/gui/StructureChooserTest.java
test/jalview/structure/Mapping.java
test/jalview/structure/StructureSelectionManagerTest.java

diff --git a/examples/testdata/simpleGff3.gff b/examples/testdata/simpleGff3.gff
new file mode 100644 (file)
index 0000000..34b64ee
--- /dev/null
@@ -0,0 +1,27 @@
+##gff-version 2
+# exonerate output in gff2 format; not gff3 because
+#   - 'similarity' is not a Sequence Ontology term
+#   - attributes' name/values are separated by space ' ' not equals '='
+##source-version exonerate:protein2genome:local 2.2.0
+##date 2015-01-16
+##type DNA
+#
+# exonerate run with --showtargetgff generates 'features on the target' i.e. mappings to the query
+# tab-delimited
+# seqname source feature start end score strand frame attributes
+#
+seq1   exonerate:protein2genome:local  gene    8       11      3652    -       .       gene_id 0 ; sequence seq2 ; gene_orientation .
+seq1   exonerate:protein2genome:local  cds     9       11      .       -       .       
+seq1   exonerate:protein2genome:local  exon    9       11      .       -       .       insertions 3 ; deletions 6
+#seq1  exonerate:protein2genome:local  similarity      8       11      3652    -       .       alignment_id 0 ; Query seq2 ; Align 11 1 3
+seq1   exonerate:protein2genome:local  similarity      9       11      3652    -       .       alignment_id 0 ; Query seq2 ; Align 11 1 3
+#
+# appending FASTA sequences is strictly a GFF3 format feature
+# but Jalview is able to handle this mixture of GFF2 / GFF3 :-)
+#
+##FASTA
+>seq1
+ACTACGACACGACGACGACGACG
+>seq2
+CDEQEATGTQDAQEQAQC
+
index 9ae45b9..2594738 100755 (executable)
                                <tocitem text="Annotations Menu" target="alwAnnotations" />
                                <tocitem text="Format Menu" target="alwFormat" />
                                <tocitem text="Colour Menu" target="alwColour" />
-                               <tocitem text="Calculation Menu" target="alwCalc" />
+                               <tocitem text="Calculate Menu" target="alwCalc" />
                                <tocitem text="Web Service Menu" target="wsMenu" />
                                <tocitem text="Annotation Panel Menu" target="annotPanelMenu" />
                                <tocitem text="Popup Menu" target="popMenu" />
index 2e9ea0c..34e8d75 100755 (executable)
         action on the whole alignment, or selected rows, columns, or
         regions.
     </em> <br></li>
+    <li><strong>Reverse, Reverse Complement</strong> (not applet)<br>
+    <em>These options are visible for nucleotide alignments. Selecting them adds the reverse (or reverse complement)
+    of the sequences (or selected region) as new sequences in the alignment. To try this out, add this sequence and
+    perform 'Reverse Complement' followed by 'Translate as cDNA':
+    <br><small>
+    Seq GTCATTTGCGCGTGTTGATTATTCGGACCGCTCCACTTCCCTTTACTCGTGCGTTCAATTGATTTAATCCTC
+    TGGGGGGGCTCTGGTTTACATAGCTTAAATCTATTCCATTCAAGGAAGCTCATG</small>
+    </em> <br></li>
     <li><strong>Get Cross-References</strong> (not applet)<br>
     <em>This option is visible where sequences have
         cross-references to other standard databases; for example, an
index 108ccf1..3b84ee3 100755 (executable)
@@ -394,9 +394,12 @@ public class PDBChain
                 || ResidueProperties.nucleotideIndex[nucname
                         .charAt((deoxyn ? 1 : 0))] == -1)
         {
-          seq.append("X");
-          // System.err.println("PDBReader:Null aa3Hash for " +
-          // tmpat.resName);
+            char r = ResidueProperties
+                    .getSingleCharacterCode(ResidueProperties
+                            .getCanonicalAminoAcid(tmpat.resName));
+            seq.append(r == '0' ? 'X' : r);
+            // System.err.println("PDBReader:Null aa3Hash for " +
+            // tmpat.resName);
         }
         else
         {
index 14e3907..28062c0 100644 (file)
@@ -1744,35 +1744,40 @@ public class AlignmentUtils
      * /ENSP00000288602?feature=transcript_variation;content-type=text/xml
      * which would be a bit slower but possibly more reliable
      */
-    LinkedHashMap<Integer, String[][]> variants = buildDnaVariantsMap(
+    LinkedHashMap<Integer, List<String[][]>> variants = buildDnaVariantsMap(
             dnaSeq, dnaToProtein);
 
     /*
      * scan codon variations, compute peptide variants and add to peptide sequence
      */
     int count = 0;
-    for (Entry<Integer, String[][]> variant : variants.entrySet())
+    for (Entry<Integer, List<String[][]>> variant : variants.entrySet())
     {
       int peptidePos = variant.getKey();
-      String[][] codonVariants = variant.getValue();
+      List<String[][]> codonVariants = variant.getValue();
       String residue = String.valueOf(peptide.getCharAt(peptidePos - 1)); // 0-based
-      List<String> peptideVariants = computePeptideVariants(codonVariants,
-              residue);
-      if (!peptideVariants.isEmpty())
+      for (String[][] codonVariant : codonVariants)
       {
-        String desc = residue + "," // include canonical residue in description
-                + StringUtils.listToDelimitedString(peptideVariants, ", ");
-        SequenceFeature sf = new SequenceFeature(
-                SequenceOntologyI.SEQUENCE_VARIANT, desc, peptidePos,
-                peptidePos, 0f, null);
-        peptide.addSequenceFeature(sf);
-        count++;
+        List<String> peptideVariants = computePeptideVariants(codonVariant,
+                residue);
+        if (!peptideVariants.isEmpty())
+        {
+          String desc = residue
+                  + "->" // include canonical residue in description
+                  + StringUtils
+                          .listToDelimitedString(peptideVariants, ", ");
+          SequenceFeature sf = new SequenceFeature(
+                  SequenceOntologyI.SEQUENCE_VARIANT, desc, peptidePos,
+                  peptidePos, 0f, null);
+          peptide.addSequenceFeature(sf);
+          count++;
+        }
       }
     }
 
     /*
      * ugly sort to get sequence features in start position order
-     * - would be better to store in Sequence as a TreeSet instead?
+     * - would be better to store in Sequence as a TreeSet or NCList?
      */
     Arrays.sort(peptide.getSequenceFeatures(),
             new Comparator<SequenceFeature>()
@@ -1796,14 +1801,14 @@ public class AlignmentUtils
    * @param dnaToProtein
    * @return
    */
-  static LinkedHashMap<Integer, String[][]> buildDnaVariantsMap(
+  static LinkedHashMap<Integer, List<String[][]>> buildDnaVariantsMap(
           SequenceI dnaSeq, MapList dnaToProtein)
   {
     /*
      * map from peptide position to all variant features of the codon for it
      * LinkedHashMap ensures we add the peptide features in sequence order
      */
-    LinkedHashMap<Integer, String[][]> variants = new LinkedHashMap<Integer, String[][]>();
+    LinkedHashMap<Integer, List<String[][]>> variants = new LinkedHashMap<Integer, List<String[][]>>();
     SequenceOntologyI so = SequenceOntologyFactory.getInstance();
 
     SequenceFeature[] dnaFeatures = dnaSeq.getSequenceFeatures();
@@ -1836,10 +1841,10 @@ public class AlignmentUtils
           continue;
         }
         int peptidePosition = mapsTo[0];
-        String[][] codonVariants = variants.get(peptidePosition);
+        List<String[][]> codonVariants = variants.get(peptidePosition);
         if (codonVariants == null)
         {
-          codonVariants = new String[3][];
+          codonVariants = new ArrayList<String[][]>();
           variants.put(peptidePosition, codonVariants);
         }
 
@@ -1870,31 +1875,33 @@ public class AlignmentUtils
         /*
          * save nucleotide (and this variant) for each codon position
          */
+        String[][] codonVariant = new String[3][];
         for (int codonPos = 0; codonPos < 3; codonPos++)
         {
           String nucleotide = String.valueOf(
                   dnaSeq.getCharAt(codon[codonPos] - dnaStart))
                   .toUpperCase();
-          if (codonVariants[codonPos] == null)
+          if (codonVariant[codonPos] == null)
           {
             /*
              * record current dna base
              */
-            codonVariants[codonPos] = new String[] { nucleotide };
+            codonVariant[codonPos] = new String[] { nucleotide };
           }
           if (codon[codonPos] == dnaCol)
           {
             /*
              * add alleles to dna base (and any previously found alleles)
              */
-            String[] known = codonVariants[codonPos];
+            String[] known = codonVariant[codonPos];
             String[] dnaVariants = new String[alleles.length + known.length];
             System.arraycopy(known, 0, dnaVariants, 0, known.length);
             System.arraycopy(alleles, 0, dnaVariants, known.length,
                     alleles.length);
-            codonVariants[codonPos] = dnaVariants;
+            codonVariant[codonPos] = dnaVariants;
           }
         }
+        codonVariants.add(codonVariant);
       }
     }
     return variants;
index 9106385..71ecb13 100755 (executable)
@@ -428,6 +428,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     gg.setColor(Color.black);
 
     int scalestartx = (startx / 10) * 10;
+    int widthx = 1 + endx - startx;
 
     FontMetrics fm = gg.getFontMetrics(av.getFont());
     int y = avcharHeight - fm.getDescent();
@@ -479,7 +480,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
           res = av.getColumnSelection().findHiddenRegionPosition(i)
                   - startx;
 
-          if (res < 0 || res > endx - scalestartx)
+          if (res < 0 || res > widthx)
           {
             continue;
           }
index ce70597..024fdc7 100755 (executable)
@@ -276,6 +276,7 @@ public class SeqCanvas extends Panel
    * at 0). NOTE 1: The av limits are set in setFont in this class and in the
    * adjustment listener in SeqPanel when the scrollbars move.
    */
+  @Override
   public void update(Graphics g)
   {
     paint(g);
@@ -573,10 +574,17 @@ public class SeqCanvas extends Panel
           g1.translate(-screenY * avcharWidth, 0);
           screenY += blockEnd - blockStart + 1;
           blockStart = hideEnd + 1;
+
+          if (screenY > (endRes - startRes))
+          {
+            // already rendered last block
+            return;
+          }
         }
       }
       if (screenY <= (endRes - startRes))
       {
+        // remaining visible region to render
         blockEnd = blockStart + (endRes - startRes) - screenY;
         g1.translate(screenY * avcharWidth, 0);
         draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
index d1ea70d..a9b0d53 100755 (executable)
@@ -1793,4 +1793,40 @@ public class Alignment implements AlignmentI
     }
     return null;
   }
+
+  @Override
+  public int[] getVisibleStartAndEndIndex(List<int[]> hiddenCols)
+  {
+    int[] alignmentStartEnd = new int[] { 0, getWidth() - 1 };
+    int startPos = alignmentStartEnd[0];
+    int endPos = alignmentStartEnd[1];
+
+    int[] lowestRange = new int[] { -1, -1 };
+    int[] higestRange = new int[] { -1, -1 };
+
+    for (int[] hiddenCol : hiddenCols)
+    {
+      lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange;
+      higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange;
+    }
+
+    if (lowestRange[0] == -1 && lowestRange[1] == -1)
+    {
+      startPos = alignmentStartEnd[0];
+    }
+    else
+    {
+      startPos = lowestRange[1] + 1;
+    }
+
+    if (higestRange[0] == -1 && higestRange[1] == -1)
+    {
+      endPos = alignmentStartEnd[1];
+    }
+    else
+    {
+      endPos = higestRange[0] - 1;
+    }
+    return new int[] { startPos, endPos };
+  }
 }
index 396ef2d..76d1a48 100755 (executable)
@@ -543,4 +543,13 @@ public interface AlignmentI extends AnnotatedCollectionI
    * @return
    */
   AlignedCodonFrame getMapping(SequenceI mapFrom, SequenceI mapTo);
+
+  /**
+   * Calculate the visible start and end index of an alignment. The result is
+   * returned an int array where: int[0] = startIndex, and int[1] = endIndex.
+   * 
+   * @param hiddenCols
+   * @return
+   */
+  public int[] getVisibleStartAndEndIndex(List<int[]> hiddenCols);
 }
index c63b6cd..c23b772 100644 (file)
@@ -184,6 +184,26 @@ public class ColumnSelection
     {
       return selected.get(0) ? 0 : selected.nextSetBit(0);
     }
+
+    /**
+     * @return a series of selection intervals along the range
+     */
+    public List<int[]> getRanges()
+    {
+      List<int[]> rlist = new ArrayList<int[]>();
+      if (selected.isEmpty())
+      {
+        return rlist;
+      }
+      int next = selected.nextSetBit(0), clear = -1;
+      while (next != -1)
+      {
+        clear = selected.nextClearBit(next);
+        rlist.add(new int[] { next, clear - 1 });
+        next = selected.nextSetBit(clear);
+      }
+      return rlist;
+    }
   }
 
   IntList selected = new IntList();
@@ -255,6 +275,15 @@ public class ColumnSelection
   }
 
   /**
+   * @return list of int arrays containing start and end column position for
+   *         runs of selected columns ordered from right to left.
+   */
+  public List<int[]> getSelectedRanges()
+  {
+    return selected.getRanges();
+  }
+
+  /**
    * 
    * @param col
    *          index to search for in column selection
@@ -623,6 +652,10 @@ public class ColumnSelection
 
   /**
    * Use this method to determine where the next hiddenRegion starts
+   * 
+   * @param hiddenRegion
+   *          index of hidden region (counts from 0)
+   * @return column number in visible view
    */
   public int findHiddenRegionPosition(int hiddenRegion)
   {
@@ -642,7 +675,7 @@ public class ColumnSelection
         gaps += region[1] + 1 - region[0];
         result = region[1] + 1;
         index++;
-      } while (index < hiddenRegion + 1);
+      } while (index <= hiddenRegion);
 
       result -= gaps;
     }
@@ -708,10 +741,12 @@ public class ColumnSelection
 
   public void hideSelectedColumns()
   {
-    while (!selected.isEmpty())
-    {
-      int column = selected.elementAt(0);
-      hideColumns(column);
+    synchronized (selected) {
+      for (int[] selregions:selected.getRanges())
+      {
+        hideColumns(selregions[0], selregions[1]);
+      }
+      selected.clear();
     }
 
   }
index 0bc6a74..84b5dcf 100644 (file)
@@ -101,23 +101,18 @@ public class EnsemblGene extends EnsemblSeqProxy
    * </ul>
    * 
    * @param query
-   *          one or more identifiers separated by a space
-   * @return an alignment containing one or more genes, and possibly
-   *         transcripts, or null
+   *          a single gene or transcript identifier or gene name
+   * @return an alignment containing a gene, and possibly transcripts, or null
    */
   @Override
   public AlignmentI getSequenceRecords(String query) throws Exception
   {
-    // todo: tidy up handling of one or multiple accession ids
-    String[] queries = query.split(getAccessionSeparator());
-
     /*
      * if given a transcript id, look up its gene parent
      */
     if (isTranscriptIdentifier(query))
     {
-      // we are assuming all transcripts have the same gene parent here
-      query = new EnsemblLookup(getDomain()).getParent(queries[0]);
+      query = new EnsemblLookup(getDomain()).getParent(query);
       if (query == null)
       {
         return null;
@@ -556,4 +551,10 @@ public class EnsemblGene extends EnsemblSeqProxy
     };
   }
 
+  @Override
+  public int getMaximumQueryCount()
+  {
+    return 1;
+  }
+
 }
index 34f8816..441ec7c 100644 (file)
@@ -69,6 +69,12 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     domain = d;
   }
 
+  /**
+   * Returns the domain name to query e.g. http://rest.ensembl.org or
+   * http://rest.ensemblgenomes.org
+   * 
+   * @return
+   */
   String getDomain()
   {
     return domain;
index 0ceb29c..8fb668a 100644 (file)
@@ -36,8 +36,6 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
 {
   private static final String ALLELES = "alleles";
 
-  protected static final String CONSEQUENCE_TYPE = "consequence_type";
-
   protected static final String PARENT = "Parent";
 
   protected static final String ID = "ID";
@@ -57,7 +55,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
     GENOMIC("genomic"),
 
     /**
-     * type=cdna to fetch dna including UTRs
+     * type=cdna to fetch coding dna including UTRs
      */
     CDNA("cdna"),
 
index 3280471..0cbd620 100644 (file)
@@ -277,9 +277,15 @@ public class JmolParser extends StructureFile implements JmolStatusListener
     {
       if (secstr[p] >= 'A' && secstr[p] <= 'z')
       {
+        try
+        {
         asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
                 secstrcode[p], Float.NaN);
         ssFound = true;
+        } catch (Exception e)
+        {
+          // e.printStackTrace();
+        }
       }
     }
 
index d1f3421..cb769bb 100644 (file)
@@ -1276,13 +1276,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     AlignmentI alignmentToExport = null;
     AlignExportSettingI settings = exportSettings;
     String[] omitHidden = null;
-    int[] alignmentStartEnd = new int[2];
 
     HiddenSequences hiddenSeqs = viewport.getAlignment()
             .getHiddenSequences();
 
     alignmentToExport = viewport.getAlignment();
-    alignmentStartEnd = new int[] { 0, alignmentToExport.getWidth() - 1 };
 
     boolean hasHiddenSeqs = hiddenSeqs.getSize() > 0;
     if (settings == null)
@@ -1297,6 +1295,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       omitHidden = viewport.getViewAsString(false);
     }
 
+    int[] alignmentStartEnd = new int[2];
     if (hasHiddenSeqs && settings.isExportHiddenSequences())
     {
       alignmentToExport = hiddenSeqs.getFullAlignment();
@@ -1304,7 +1303,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     else
     {
       alignmentToExport = viewport.getAlignment();
-      alignmentStartEnd = getStartEnd(alignmentStartEnd, viewport
+      alignmentStartEnd = viewport.getAlignment()
+              .getVisibleStartAndEndIndex(
+                      viewport
               .getColumnSelection().getHiddenColumns());
     }
     AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
@@ -1312,55 +1313,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return ed;
   }
 
-  public static int[] getStartEnd(int[] aligmentStartEnd,
-          List<int[]> hiddenCols)
-  {
-    int startPos = aligmentStartEnd[0];
-    int endPos = aligmentStartEnd[1];
-
-    int[] lowestRange = new int[] { -1, -1 };
-    int[] higestRange = new int[] { -1, -1 };
-
-    for (int[] hiddenCol : hiddenCols)
-    {
-      lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange;
-      higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange;
-    }
-
-    if (lowestRange[0] == -1 && lowestRange[1] == -1)
-    {
-      startPos = aligmentStartEnd[0];
-    }
-    else
-    {
-      startPos = lowestRange[1] + 1;
-    }
-
-    if (higestRange[0] == -1 && higestRange[1] == -1)
-    {
-      endPos = aligmentStartEnd[1];
-    }
-    else
-    {
-      endPos = higestRange[0] - 1;
-    }
-
-    // System.out.println("Export range : " + startPos + " - " + endPos);
-    return new int[] { startPos, endPos };
-  }
-
-  public static void main(String[] args)
-  {
-    ArrayList<int[]> hiddenCols = new ArrayList<int[]>();
-    hiddenCols.add(new int[] { 0, 0 });
-    hiddenCols.add(new int[] { 6, 9 });
-    hiddenCols.add(new int[] { 11, 12 });
-    hiddenCols.add(new int[] { 33, 33 });
-    hiddenCols.add(new int[] { 50, 50 });
-
-    int[] x = getStartEnd(new int[] { 0, 50 }, hiddenCols);
-    // System.out.println("Export range : " + x[0] + " - " + x[1]);
-  }
 
   /**
    * DOCUMENT ME!
index d4300e4..3105ab9 100755 (executable)
@@ -213,6 +213,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     AlignmentAnnotation[] aa = ap.av.getAlignment()
@@ -331,6 +332,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mousePressed(MouseEvent evt)
   {
     getSelectedRow(evt.getY() - getScrollOffset());
@@ -343,6 +345,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseReleased(MouseEvent evt)
   {
     int start = selectedRow;
@@ -377,6 +380,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseEntered(MouseEvent evt)
   {
     if (evt.getY() < 10)
@@ -392,6 +396,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseExited(MouseEvent evt)
   {
     if (dragEvent == null)
@@ -407,6 +412,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseDragged(MouseEvent evt)
   {
     dragEvent = evt;
@@ -443,6 +449,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseMoved(MouseEvent evt)
   {
     resizePanel = evt.getY() < 10;
@@ -527,6 +534,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void mouseClicked(MouseEvent evt)
   {
     final AlignmentAnnotation[] aa = ap.av.getAlignment()
@@ -711,6 +719,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
         final AlignmentAnnotation aaa = aa[selectedRow];
         cbmi.addActionListener(new ActionListener()
         {
+          @Override
           public void actionPerformed(ActionEvent e)
           {
             if (aaa.groupRef != null)
@@ -735,6 +744,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
                   aa[selectedRow].groupRef.isShowConsensusHistogram());
           chist.addActionListener(new ActionListener()
           {
+            @Override
             public void actionPerformed(ActionEvent e)
             {
               // TODO: pass on reference
@@ -754,6 +764,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
                   aa[selectedRow].groupRef.isShowSequenceLogo());
           cprofl.addActionListener(new ActionListener()
           {
+            @Override
             public void actionPerformed(ActionEvent e)
             {
               // TODO: pass on reference
@@ -773,6 +784,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
                   aa[selectedRow].groupRef.isNormaliseSequenceLogo());
           cproflnorm.addActionListener(new ActionListener()
           {
+            @Override
             public void actionPerformed(ActionEvent e)
             {
 
@@ -798,6 +810,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
                   av.isShowConsensusHistogram());
           chist.addActionListener(new ActionListener()
           {
+            @Override
             public void actionPerformed(ActionEvent e)
             {
               // TODO: pass on reference
@@ -818,6 +831,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
                   av.isShowSequenceLogo());
           cprof.addActionListener(new ActionListener()
           {
+            @Override
             public void actionPerformed(ActionEvent e)
             {
               // TODO: pass on reference
@@ -838,6 +852,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
                   av.isNormaliseSequenceLogo());
           cprofnorm.addActionListener(new ActionListener()
           {
+            @Override
             public void actionPerformed(ActionEvent e)
             {
               // TODO: pass on reference
@@ -893,7 +908,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     List<int[]> hiddenCols = av.getColumnSelection().getHiddenColumns();
     if (hiddenCols != null)
     {
-      alignmentStartEnd = AlignFrame.getStartEnd(alignmentStartEnd,
+      alignmentStartEnd = av.getAlignment().getVisibleStartAndEndIndex(
               hiddenCols);
     }
     String output = new FormatAdapter().formatSequences("Fasta", seqs,
@@ -926,6 +941,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    * @param g1
    *          DOCUMENT ME!
    */
+  @Override
   public void paintComponent(Graphics g)
   {
 
index 7e17f46..41de58f 100755 (executable)
@@ -493,6 +493,7 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     gg.setColor(Color.black);
 
     int scalestartx = (startx / 10) * 10;
+    int widthx = 1 + endx - startx;
 
     FontMetrics fm = gg.getFontMetrics(av.getFont());
     int y = avCharHeight - fm.getDescent();
@@ -540,11 +541,10 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
         for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
                 .size(); i++)
         {
-
           res = av.getColumnSelection().findHiddenRegionPosition(i)
                   - startx;
 
-          if (res < 0 || res > endx - scalestartx)
+          if (res < 0 || res > widthx)
           {
             continue;
           }
index 5706fe7..0f24b4b 100755 (executable)
@@ -335,6 +335,7 @@ public class SeqCanvas extends JComponent
    */
 
   // Set this to false to force a full panel paint
+  @Override
   public void paintComponent(Graphics g)
   {
     updateViewport();
@@ -682,10 +683,17 @@ public class SeqCanvas extends JComponent
         g1.translate(-screenY * charWidth, 0);
         screenY += blockEnd - blockStart + 1;
         blockStart = hideEnd + 1;
+
+        if (screenY > (endRes - startRes))
+        {
+          // already rendered last block
+          return;
+        }
       }
 
       if (screenY <= (endRes - startRes))
       {
+        // remaining visible region to render
         blockEnd = blockStart + (endRes - startRes) - screenY;
         g1.translate(screenY * charWidth, 0);
         draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
index 784474e..eb33ce7 100755 (executable)
 package jalview.gui;
 
 import jalview.api.FeatureSettingsModelI;
+import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.io.gff.SequenceOntologyI;
 import jalview.util.DBRefUtils;
 import jalview.util.MessageManager;
 import jalview.ws.dbsources.das.api.DasSourceRegistryI;
@@ -156,9 +158,9 @@ public class SequenceFetcher extends JPanel implements Runnable
       }
     }
     if (sfetch == null
-            || dasRegistry != jalview.bin.Cache.getDasSourceRegistry()
-            || lastDasSourceRegistry != (jalview.bin.Cache
-                    .getDasSourceRegistry().getDasRegistryURL() + jalview.bin.Cache
+            || dasRegistry != Cache.getDasSourceRegistry()
+            || lastDasSourceRegistry != (Cache.getDasSourceRegistry()
+                    .getDasRegistryURL() + Cache
                     .getDasSourceRegistry().getLocalSourceString())
                     .hashCode())
     {
@@ -173,7 +175,7 @@ public class SequenceFetcher extends JPanel implements Runnable
                 .getString("status.init_sequence_database_fetchers"),
                 Thread.currentThread().hashCode());
       }
-      dasRegistry = jalview.bin.Cache.getDasSourceRegistry();
+      dasRegistry = Cache.getDasSourceRegistry();
       dasRegistry.refreshSources();
 
       jalview.ws.SequenceFetcher sf = new jalview.ws.SequenceFetcher();
@@ -552,7 +554,7 @@ public class SequenceFetcher extends JPanel implements Runnable
                             proxy.getDbName() }), Thread.currentThread()
                         .hashCode());
         isAliSource = proxy.isAlignmentSource();
-        if (proxy.getAccessionSeparator() == null)
+        if (proxy.getMaximumQueryCount() == 1)
         {
           while (en.hasNext())
           {
@@ -592,7 +594,8 @@ public class SequenceFetcher extends JPanel implements Runnable
               }
             } catch (Exception e)
             {
-              jalview.bin.Cache.log.info("Error retrieving " + item
+              Cache.log.info(
+                      "Error retrieving " + item
                       + " from " + proxy.getDbName(), e);
               nextfetch.add(item);
             }
@@ -833,8 +836,13 @@ public class SequenceFetcher extends JPanel implements Runnable
 
         if (preferredFeatureColours != null)
         {
-          af.viewport.applyFeaturesStyle(preferredFeatureColours);
+          af.getViewport().applyFeaturesStyle(preferredFeatureColours);
         }
+        if (Cache.getDefault("HIDE_INTRONS", true))
+        {
+          hideIntronsIfPresent(af);
+        }
+
         Desktop.addInternalFrame(af, title, AlignFrame.DEFAULT_WIDTH,
                 AlignFrame.DEFAULT_HEIGHT);
 
@@ -843,7 +851,7 @@ public class SequenceFetcher extends JPanel implements Runnable
 
         try
         {
-          af.setMaximum(jalview.bin.Cache.getDefault("SHOW_FULLSCREEN",
+          af.setMaximum(Cache.getDefault("SHOW_FULLSCREEN",
                   false));
         } catch (Exception ex)
         {
@@ -857,6 +865,25 @@ public class SequenceFetcher extends JPanel implements Runnable
     return al;
   }
 
+  /**
+   * Hide columns not containing 'exon' features, provided there are exon
+   * features on the alignment
+   * 
+   * @param af
+   */
+  public void hideIntronsIfPresent(AlignFrame af)
+  {
+    boolean hasExons = af.avc.markColumnsContainingFeatures(false, false,
+            false,
+            SequenceOntologyI.EXON);
+    if (hasExons)
+    {
+      af.avc.markColumnsContainingFeatures(true, false, true,
+              SequenceOntologyI.EXON);
+      af.getViewport().hideSelectedColumns();
+    }
+  }
+
   void showErrorMessage(final String error)
   {
     resetDialog();
index f38f267..5709ac9 100644 (file)
@@ -341,7 +341,7 @@ public class StructureChooser extends GStructureChooser implements
   {
     Objects.requireNonNull(seqName);
     return seqName.replaceAll("\\[\\d*\\]", "")
-            .replaceAll("[^\\dA-Za-z ]", "").replaceAll("\\s+", "+");
+            .replaceAll("[^\\dA-Za-z|]", "").replaceAll("\\s+", "+");
   }
 
 
index 2a38b39..3471fab 100644 (file)
@@ -198,7 +198,8 @@ public class PDBRestResponse
               summaryRowData[colCounter++] = 0.0;
             }
           }else{
-            summaryRowData[colCounter++] = fieldData;
+            summaryRowData[colCounter++] = (fieldData == null || fieldData
+                    .isEmpty()) ? null : fieldData;
           }
         }
       }
@@ -268,8 +269,18 @@ public class PDBRestResponse
   public static void configureTableColumn(JTable tbl_summary,
           Collection<PDBDocField> wantedFields)
   {
+    try
+    {
+      // wait for table model initialisation to complete
+      Thread.sleep(1200);
+    } catch (InterruptedException e1)
+    {
+      e1.printStackTrace();
+    }
     for (PDBDocField wantedField : wantedFields)
     {
+      try
+      {
       if (wantedField.equals(PDBDocField.PDB_ID))
       {
         tbl_summary.getColumn(wantedField.getName()).setMinWidth(40);
@@ -294,6 +305,10 @@ public class PDBRestResponse
         tbl_summary.getColumn(wantedField.getName()).setMaxWidth(400);
         tbl_summary.getColumn(wantedField.getName()).setPreferredWidth(95);
       }
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+      }
     }
   }
 }
index 9255e5a..ff745ac 100644 (file)
@@ -32,6 +32,7 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.TaylorColourScheme;
+import jalview.structure.StructureViewSettings;
 
 import java.awt.Color;
 import java.util.Vector;
@@ -55,6 +56,7 @@ public class PDBChainTest
   public void setUp()
   {
     System.out.println("setup");
+    StructureViewSettings.setShowSeqFeatures(true);
     c = new PDBChain("1GAQ", "A");
   }
 
index 7ccbf97..810ef5f 100644 (file)
@@ -1733,52 +1733,97 @@ public class AlignmentUtilsTests
     /*
      * first with no variants on dna
      */
-    LinkedHashMap<Integer, String[][]> variantsMap = AlignmentUtils
+    LinkedHashMap<Integer, List<String[][]>> variantsMap = AlignmentUtils
             .buildDnaVariantsMap(dna, map);
     assertTrue(variantsMap.isEmpty());
 
-    // single allele codon 1, on base 1
+    /*
+     * single allele codon 1, on base 1
+     */
     SequenceFeature sf = new SequenceFeature("sequence_variant", "", 1, 1,
             0f, null);
     sf.setValue("alleles", "T");
+    sf.setValue("ID", "sequence_variant:rs758803211");
     dna.addSequenceFeature(sf);
 
-    // two alleles codon 2, on bases 2 and 3
+    /*
+     * two alleles codon 2, on bases 2 and 3 (distinct variants)
+     */
     sf = new SequenceFeature("sequence_variant", "", 5, 5, 0f, null);
     sf.setValue("alleles", "T");
+    sf.setValue("ID", "sequence_variant:rs758803212");
     dna.addSequenceFeature(sf);
     sf = new SequenceFeature("sequence_variant", "", 6, 6, 0f, null);
     sf.setValue("alleles", "G");
+    sf.setValue("ID", "sequence_variant:rs758803213");
     dna.addSequenceFeature(sf);
 
-    // two alleles codon 3, both on base 2
+    /*
+     * two alleles codon 3, both on base 2 (one variant)
+     */
     sf = new SequenceFeature("sequence_variant", "", 8, 8, 0f, null);
     sf.setValue("alleles", "C, G");
+    sf.setValue("ID", "sequence_variant:rs758803214");
     dna.addSequenceFeature(sf);
 
     // no alleles on codon 4
-    // alleles on codon 5 on all 3 bases
+
+    /*
+     * alleles on codon 5 on all 3 bases (distinct variants)
+     */
     sf = new SequenceFeature("sequence_variant", "", 13, 13, 0f, null);
     sf.setValue("alleles", "C, G"); // (C duplicates given base value)
+    sf.setValue("ID", "sequence_variant:rs758803215");
     dna.addSequenceFeature(sf);
     sf = new SequenceFeature("sequence_variant", "", 14, 14, 0f, null);
     sf.setValue("alleles", "g, a"); // should force to upper-case
+    sf.setValue("ID", "sequence_variant:rs758803216");
     dna.addSequenceFeature(sf);
     sf = new SequenceFeature("sequence_variant", "", 15, 15, 0f, null);
     sf.setValue("alleles", "A, T");
+    sf.setValue("ID", "sequence_variant:rs758803217");
     dna.addSequenceFeature(sf);
 
+    /*
+     * build map - expect variants on positions 1, 2, 3, 5
+     */
     variantsMap = AlignmentUtils.buildDnaVariantsMap(dna, map);
     assertEquals(4, variantsMap.size());
+
+    /*
+     * one variant on protein position 1
+     */
+    assertEquals(1, variantsMap.get(1).size());
     assertTrue(Arrays.deepEquals(new String[][] { { "A", "T" }, { "T" },
-        { "G" } }, variantsMap.get(1)));
+        { "G" } }, variantsMap.get(1).get(0)));
+
+    /*
+     * two variants on protein position 2
+     */
+    assertEquals(2, variantsMap.get(2).size());
     assertTrue(Arrays.deepEquals(new String[][] { { "A" }, { "A", "T" },
-        { "A", "G" } }, variantsMap.get(2)));
+        { "A" } }, variantsMap.get(2).get(0)));
+    assertTrue(Arrays.deepEquals(new String[][] { { "A" }, { "A" },
+        { "A", "G" } }, variantsMap.get(2).get(1)));
+
+    /*
+     * one variant on protein position 3
+     */
+    assertEquals(1, variantsMap.get(3).size());
     assertTrue(Arrays.deepEquals(new String[][] { { "T" },
-        { "T", "C", "G" }, { "T" } }, variantsMap.get(3)));
-    // duplicated bases are not removed here, handled in computePeptideVariants
+        { "T", "C", "G" }, { "T" } }, variantsMap.get(3).get(0)));
+
+    /*
+     * three variants on protein position 5
+     * duplicated bases are not removed here, handled in computePeptideVariants
+     */
+    assertEquals(3, variantsMap.get(5).size());
     assertTrue(Arrays.deepEquals(new String[][] { { "C", "C", "G" },
-        { "C", "G", "A" }, { "C", "A", "T" } }, variantsMap.get(5)));
+        { "C" }, { "C" } }, variantsMap.get(5).get(0)));
+    assertTrue(Arrays.deepEquals(new String[][] { { "C" },
+        { "C", "G", "A" }, { "C" } }, variantsMap.get(5).get(1)));
+    assertTrue(Arrays.deepEquals(new String[][] { { "C" }, { "C" },
+        { "C", "A", "T" } }, variantsMap.get(5).get(2)));
   }
 
   /**
index bd445c4..5a45176 100644 (file)
@@ -32,6 +32,7 @@ import jalview.io.FormatAdapter;
 import jalview.util.MapList;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
@@ -474,4 +475,33 @@ public class AlignmentTest
     align.addCodonFrame(acf2);
     assertTrue(align.getDataset().getCodonFrames().contains(acf));
   }
+
+  @Test(groups = "Functional")
+  public void getVisibleStartAndEndIndexTest()
+  {
+    Sequence seq = new Sequence("testSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    AlignmentI align = new Alignment(new SequenceI[] { seq });
+    ArrayList<int[]> hiddenCols = new ArrayList<int[]>();
+
+    int[] startEnd = align.getVisibleStartAndEndIndex(hiddenCols);
+    assertEquals(0, startEnd[0]);
+    assertEquals(25, startEnd[1]);
+
+    hiddenCols.add(new int[] { 0, 0 });
+    startEnd = align.getVisibleStartAndEndIndex(hiddenCols);
+    assertEquals(1, startEnd[0]);
+    assertEquals(25, startEnd[1]);
+
+    hiddenCols.add(new int[] { 6, 9 });
+    hiddenCols.add(new int[] { 11, 12 });
+    startEnd = align.getVisibleStartAndEndIndex(hiddenCols);
+    assertEquals(1, startEnd[0]);
+    assertEquals(25, startEnd[1]);
+
+    hiddenCols.add(new int[] { 24, 25 });
+    startEnd = align.getVisibleStartAndEndIndex(hiddenCols);
+    System.out.println(startEnd[0] + " : " + startEnd[1]);
+    assertEquals(1, startEnd[0]);
+    assertEquals(23, startEnd[1]);
+  }
 }
index 0f08ceb..0245b15 100644 (file)
@@ -244,6 +244,32 @@ public class ColumnSelectionTest
   }
 
   /**
+   * Test the method that gets runs of selected columns ordered by column. If
+   * this fails, HideSelectedColumns may also fail
+   */
+  @Test(groups = { "Functional" })
+  public void testgetSelectedRanges()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 };
+    for (int col : sel)
+    {
+      cs.addElement(col);
+    }
+    List<int[]> range;
+    range = cs.getSelectedRanges();
+    assertEquals(3, range.size());
+    assertEquals("[2, 4]", Arrays.toString(range.get(0)));
+    assertEquals("[7, 9]", Arrays.toString(range.get(1)));
+    assertEquals("[20, 22]", Arrays.toString(range.get(2)));
+    cs.addElement(0);
+    cs.addElement(1);
+    range = cs.getSelectedRanges();
+    assertEquals(3, range.size());
+    assertEquals("[0, 4]", Arrays.toString(range.get(0)));
+  }
+
+  /**
    * Test the method that reveals a range of hidden columns given the start
    * column of the range
    */
index a68f7c8..7ac1579 100644 (file)
@@ -50,7 +50,8 @@ public class JmolParserTest
    * 1QCF is the full PDB file including headers, HETATM etc
    */
   String[] testFile = new String[] { "./examples/1GAQ.txt",
-      "./test/jalview/ext/jmol/1xyz.pdb" };
+      "./test/jalview/ext/jmol/1xyz.pdb",
+      "./test/jalview/ext/jmol/1qcf.pdb" };
 
   //@formatter:off
   // a modified and very cut-down extract of 4UJ4
index 5e31bef..2310373 100644 (file)
@@ -88,7 +88,7 @@ public class PDBSearchPanelTest
     assertEquals(expectedString, outcome);
   }
 
-  @Test(groups = { "Network", "External" }, timeOut = 5000)
+  @Test(groups = { "Network", "External" }, timeOut = 7000)
   public void txt_search_ActionPerformedTest()
   {
     PDBSearchPanel searchPanel = new PDBSearchPanel(null);
@@ -98,9 +98,15 @@ public class PDBSearchPanelTest
     assertTrue(mainFrame.getTitle().length() == 20);
     assertTrue(mainFrame.getTitle()
             .equalsIgnoreCase("PDB Sequence Fetcher"));
-
     txt_search.setText("ABC");
-
+    try
+    {
+      // wait for web-service to handle response
+      Thread.sleep(3000);
+    } catch (InterruptedException e)
+    {
+      e.printStackTrace();
+    }
     assertTrue(mainFrame.getTitle().length() > 20);
     assertTrue(!mainFrame.getTitle().equalsIgnoreCase(
             "PDB Sequence Fetcher"));
index 1b00c4a..6b726de 100644 (file)
@@ -70,10 +70,16 @@ public class StructureChooserTest
   public void buildQueryTest()
   {
     String query = StructureChooser.buildQuery(seq);
-    System.out.println(">>>>>>>>>> query : " + query);
+    assertEquals("pdb_id:1tim", query);
+    System.out.println("seq >>>> " + seq);
+    seq.getAllPDBEntries().clear();
+    query = StructureChooser.buildQuery(seq);
     assertEquals(
-            "4kqy OR text:1tim OR text:XYZ_1 OR text:XYZ_2 OR text:XYZ_3 OR text:XYZ_4",
+            "text:XYZ_1 OR text:XYZ_2 OR text:XYZ_3 OR text:XYZ_4 OR text:4kqy",
             query);
+    seq.setDBRefs(null);
+    query = StructureChooser.buildQuery(seq);
+    assertEquals("text:4kqy", query);
   }
 
   @Test(groups = { "Functional" })
@@ -88,6 +94,13 @@ public class StructureChooserTest
 
     sc.setStructuresDiscovered(true);
     sc.populateFilterComboBox();
+    try
+    {
+      Thread.sleep(1000);
+    } catch (InterruptedException e)
+    {
+      e.printStackTrace();
+    }
     optionsSize = sc.getCmbFilterOption().getItemCount();
     assertTrue(optionsSize > 3); // if structures are found, filter options
                                  // should be populated
index 1630110..8674ed8 100644 (file)
@@ -250,6 +250,7 @@ public class Mapping
   @Test(groups = { "Functional" })
   public void compareTransferredToRefPDBAnnot() throws Exception
   {
+    StructureViewSettings.setShowSeqFeatures(true);
     AlignFrame ref = new FileLoader(false)
             .LoadFileWaitTillLoaded("test/jalview/ext/jmol/1QCF.pdb",
                     jalview.io.FormatAdapter.FILE);
index 3529375..999d158 100644 (file)
@@ -43,6 +43,7 @@ public class StructureSelectionManagerTest
   @BeforeMethod(alwaysRun = true)
   public void setUp()
   {
+    StructureViewSettings.setShowSeqFeatures(true);
     ssm = new StructureSelectionManager();
   }