Merge branch 'develop' into merge/develop_bug/JAL-2154projectMappings
authorJim Procter <jprocter@issues.jalview.org>
Tue, 30 Aug 2016 13:30:34 +0000 (14:30 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Tue, 30 Aug 2016 13:30:34 +0000 (14:30 +0100)
25 files changed:
.checkstyle [new file with mode: 0644]
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/Rna.java
src/jalview/analysis/StructureFrequency.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/datamodel/CigarBase.java
src/jalview/ext/ensembl/EnsemblSeqProxy.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/SplitFrame.java
src/jalview/io/RnamlFile.java
src/jalview/io/StockholmFile.java
src/jalview/jbgui/GStructureChooser.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/schemes/ResidueProperties.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/RnaTest.java
test/jalview/bin/CacheTest.java
test/jalview/datamodel/AlignmentAnnotationTests.java
utils/checkstyle/README.txt [new file with mode: 0644]
utils/checkstyle/checkstyle-suppress.xml [new file with mode: 0644]
utils/checkstyle/checkstyle.xml [new file with mode: 0644]
utils/checkstyle/import-control.xml [new file with mode: 0644]

diff --git a/.checkstyle b/.checkstyle
new file mode 100644 (file)
index 0000000..0329bb7
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
+  <local-check-config name="JalviewCheckstyle" location="utils/checkstyle/checkstyle.xml" type="project" description="">
+    <additional-data name="protect-config-file" value="false"/>
+  </local-check-config>
+  <fileset name="source" enabled="true" check-config-name="JalviewCheckstyle" local="true">
+    <file-match-pattern match-pattern="src/.*.java" include-pattern="true"/>
+    <file-match-pattern match-pattern="resources/.*.properties" include-pattern="true"/>
+  </fileset>
+  <filter name="NonSrcDirs" enabled="false"/>
+</fileset-config>
index 54181fe..b01464a 100644 (file)
@@ -389,7 +389,7 @@ label.ignore_unmatched_dropped_files = Ignore unmatched dropped files?
 label.view_name_original = Original
 label.enter_view_name = Enter View Name
 label.enter_label = Enter label
-label.enter_label_for_the_structure = Enter a label for the structure?
+label.enter_label_for_the_structure = Enter a label for the structure
 label.pdb_entry_is_already_displayed = {0} is already displayed.\nDo you want to re-use this viewer ?
 label.map_sequences_to_visible_window = Map Sequences to Visible Window: {0}
 label.add_pdbentry_to_view = Do you want to add {0} to the view called\n{1}\n
index 45941c2..87538be 100644 (file)
@@ -355,9 +355,9 @@ label.automatically_associate_pdb_files_with_sequences_same_name = Quieres asoci
 label.automatically_associate_pdb_files_by_name = Asociar los ficheros PDB por nombre automáticamente
 label.ignore_unmatched_dropped_files_info = Quieres <em>ignorar</em> los {0} ficheros cuyos nombres no coincidan con ningún IDs de las secuencias ?
 label.ignore_unmatched_dropped_files = Ignorar los ficheros sin coincidencias?
-label.enter_view_name = Introducir nombre visible (¿?)
+label.enter_view_name = Introduzca un nombre para la vista
 label.enter_label = Introducir etiqueta
-label.enter_label_for_the_structure = Introducir una etiqueta para la estructura?
+label.enter_label_for_the_structure = Introducir una etiqueta para la estructura
 label.pdb_entry_is_already_displayed = {0} Ya est\u00E1 mostrado.\nQuieres volver a usar este visor?
 label.map_sequences_to_visible_window = Mapa de secuencias en ventana visible: {0}
 label.add_pdbentry_to_view = Quieres a\u00F1adir {0} a la vista llamada\n{1}\n
index b0a2269..ea330d8 100644 (file)
@@ -72,6 +72,7 @@ import java.util.TreeMap;
 public class AlignmentUtils
 {
 
+  private static final int CODON_LENGTH = 3;
   private static final String SEQUENCE_VARIANT = "sequence_variant:";
   private static final String ID = "ID";
 
@@ -79,15 +80,16 @@ public class AlignmentUtils
    * A data model to hold the 'normal' base value at a position, and an optional
    * sequence variant feature
    */
-  static class DnaVariant
+  static final class DnaVariant
   {
-    String base;
+    final String base;
 
     SequenceFeature variant;
 
     DnaVariant(String nuc)
     {
       base = nuc;
+      variant = null;
     }
 
     DnaVariant(String nuc, SequenceFeature var)
@@ -95,6 +97,11 @@ public class AlignmentUtils
       base = nuc;
       variant = var;
     }
+
+    public String getSource()
+    {
+      return variant == null ? null : variant.getFeatureGroup();
+    }
   }
 
   /**
@@ -427,7 +434,7 @@ public class AlignmentUtils
     /*
      * cdnaStart/End, proteinStartEnd are base 1 (for dataset sequence mapping)
      */
-    final int mappedLength = 3 * aaSeqChars.length;
+    final int mappedLength = CODON_LENGTH * aaSeqChars.length;
     int cdnaLength = cdnaSeqChars.length;
     int cdnaStart = cdnaSeq.getStart();
     int cdnaEnd = cdnaSeq.getEnd();
@@ -439,14 +446,14 @@ public class AlignmentUtils
      */
     if (cdnaLength != mappedLength && cdnaLength > 2)
     {
-      String lastCodon = String.valueOf(cdnaSeqChars, cdnaLength - 3, 3)
+      String lastCodon = String.valueOf(cdnaSeqChars, cdnaLength - CODON_LENGTH, CODON_LENGTH)
               .toUpperCase();
       for (String stop : ResidueProperties.STOP)
       {
         if (lastCodon.equals(stop))
         {
-          cdnaEnd -= 3;
-          cdnaLength -= 3;
+          cdnaEnd -= CODON_LENGTH;
+          cdnaLength -= CODON_LENGTH;
           break;
         }
       }
@@ -458,12 +465,12 @@ public class AlignmentUtils
     int startOffset = 0;
     if (cdnaLength != mappedLength
             && cdnaLength > 2
-            && String.valueOf(cdnaSeqChars, 0, 3).toUpperCase()
+            && String.valueOf(cdnaSeqChars, 0, CODON_LENGTH).toUpperCase()
                     .equals(ResidueProperties.START))
     {
-      startOffset += 3;
-      cdnaStart += 3;
-      cdnaLength -= 3;
+      startOffset += CODON_LENGTH;
+      cdnaStart += CODON_LENGTH;
+      cdnaLength -= CODON_LENGTH;
     }
 
     if (translatesAs(cdnaSeqChars, startOffset, aaSeqChars))
@@ -472,7 +479,7 @@ public class AlignmentUtils
        * protein is translation of dna (+/- start/stop codons)
        */
       MapList map = new MapList(new int[] { cdnaStart, cdnaEnd }, new int[]
-      { proteinStart, proteinEnd }, 3, 1);
+      { proteinStart, proteinEnd }, CODON_LENGTH, 1);
       return map;
     }
 
@@ -503,9 +510,9 @@ public class AlignmentUtils
     int aaPos = 0;
     int dnaPos = cdnaStart;
     for (; dnaPos < cdnaSeqChars.length - 2
-            && aaPos < aaSeqChars.length; dnaPos += 3, aaPos++)
+            && aaPos < aaSeqChars.length; dnaPos += CODON_LENGTH, aaPos++)
     {
-      String codon = String.valueOf(cdnaSeqChars, dnaPos, 3);
+      String codon = String.valueOf(cdnaSeqChars, dnaPos, CODON_LENGTH);
       final String translated = ResidueProperties.codonTranslate(codon);
 
       /*
@@ -541,9 +548,9 @@ public class AlignmentUtils
     {
       return true;
     }
-    if (dnaPos == cdnaSeqChars.length - 3)
+    if (dnaPos == cdnaSeqChars.length - CODON_LENGTH)
     {
-      String codon = String.valueOf(cdnaSeqChars, dnaPos, 3);
+      String codon = String.valueOf(cdnaSeqChars, dnaPos, CODON_LENGTH);
       if ("STOP".equals(ResidueProperties.codonTranslate(codon)))
       {
         return true;
@@ -894,7 +901,8 @@ public class AlignmentUtils
       }
       width = Math.max(dnaSeq.getLength(), width);
     }
-    int oldwidth, diff;
+    int oldwidth;
+    int diff;
     for (SequenceI dnaSeq : dna.getSequences())
     {
       oldwidth = dnaSeq.getLength();
@@ -934,9 +942,9 @@ public class AlignmentUtils
     for (AlignedCodonFrame mapping : dnaMappings)
     {
       SequenceI peptide = mapping.findAlignedSequence(cdsSeq, protein);
-      int peptideLength = peptide.getLength();
       if (peptide != null)
       {
+        int peptideLength = peptide.getLength();
         Mapping map = mapping.getMappingBetween(cdsSeq, peptide);
         if (map != null)
         {
@@ -950,7 +958,7 @@ public class AlignmentUtils
                   .getFromRanges());
           int mappedToLength = MappingUtils
                   .getLength(mapList.getToRanges());
-          boolean addStopCodon = (cdsLength == mappedFromLength * 3 + 3)
+          boolean addStopCodon = (cdsLength == mappedFromLength * CODON_LENGTH + CODON_LENGTH)
                   || (peptide.getDatasetSequence().getLength() == mappedFromLength - 1);
           if (cdsLength != mappedToLength && !addStopCodon)
           {
@@ -964,8 +972,8 @@ public class AlignmentUtils
           /*
            * pre-fill the aligned cds sequence with gaps
            */
-          char[] alignedCds = new char[peptideLength * 3
-                  + (addStopCodon ? 3 : 0)];
+          char[] alignedCds = new char[peptideLength * CODON_LENGTH
+                  + (addStopCodon ? CODON_LENGTH : 0)];
           Arrays.fill(alignedCds, gapChar);
 
           /*
@@ -982,7 +990,7 @@ public class AlignmentUtils
           {
             if (Comparison.isGap(residue))
             {
-              cdsCol += 3;
+              cdsCol += CODON_LENGTH;
             }
             else
             {
@@ -991,7 +999,7 @@ public class AlignmentUtils
               if (codon == null)
               {
                 // e.g. incomplete start codon, X in peptide
-                cdsCol += 3;
+                cdsCol += CODON_LENGTH;
               }
               else
               {
@@ -1009,7 +1017,7 @@ public class AlignmentUtils
            * append stop codon if not mapped from protein,
            * closing it up to the end of the mapped sequence
            */
-          if (copiedBases == nucleotides.length - 3)
+          if (copiedBases == nucleotides.length - CODON_LENGTH)
           {
             for (int i = alignedCds.length - 1; i >= 0; i--)
             {
@@ -1019,7 +1027,7 @@ public class AlignmentUtils
                 break;
               }
             }
-            for (int i = nucleotides.length - 3; i < nucleotides.length; i++)
+            for (int i = nucleotides.length - CODON_LENGTH; i < nucleotides.length; i++)
             {
               alignedCds[cdsCol++] = nucleotides[i];
             }
@@ -1825,7 +1833,7 @@ public class AlignmentUtils
     int mappedFromLength = MappingUtils.getLength(aMapping.getMap()
             .getFromRanges());
     int dnaLength = seqDss.getLength();
-    if (mappedFromLength == dnaLength || mappedFromLength == dnaLength - 3)
+    if (mappedFromLength == dnaLength || mappedFromLength == dnaLength - CODON_LENGTH)
     {
       return seqDss;
     }
@@ -1841,7 +1849,7 @@ public class AlignmentUtils
       for (SequenceToSequenceMapping map : acf.getMappings())
       {
         Mapping mapping = map.getMapping();
-        if (mapping != aMapping && mapping.getMap().getFromRatio() == 3
+        if (mapping != aMapping && mapping.getMap().getFromRatio() == CODON_LENGTH
                 && proteinProduct == mapping.getTo()
                 && seqDss != map.getFromSeq())
         {
@@ -2163,7 +2171,7 @@ public class AlignmentUtils
     /*
      * dna length should map to protein (or protein plus stop codon)
      */
-    int codesForResidues = mappedDnaLength / 3;
+    int codesForResidues = mappedDnaLength / CODON_LENGTH;
     if (codesForResidues == (proteinLength + 1))
     {
       // assuming extra codon is for STOP and not in peptide
@@ -2172,7 +2180,7 @@ public class AlignmentUtils
     if (codesForResidues == proteinLength)
     {
       proteinRange.add(new int[] { proteinStart, proteinEnd });
-      return new MapList(ranges, proteinRange, 3, 1);
+      return new MapList(ranges, proteinRange, CODON_LENGTH, 1);
     }
     return null;
   }
@@ -2448,7 +2456,7 @@ public class AlignmentUtils
      * are currently ignored here
      */
     String trans = codon.contains("-") ? "-"
-            : (codon.length() > 3 ? null : ResidueProperties
+            : (codon.length() > CODON_LENGTH ? null : ResidueProperties
                     .codonTranslate(codon));
     if (trans != null && !trans.equals(residue))
     {
@@ -2460,7 +2468,7 @@ public class AlignmentUtils
       // set score to 0f so 'graduated colour' option is offered! JAL-2060
       SequenceFeature sf = new SequenceFeature(
               SequenceOntologyI.SEQUENCE_VARIANT, desc, peptidePos,
-              peptidePos, 0f, "Jalview");
+              peptidePos, 0f, var.getSource());
       StringBuilder attributes = new StringBuilder(32);
       String id = (String) var.variant.getValue(ID);
       if (id != null)
@@ -2471,7 +2479,7 @@ public class AlignmentUtils
         }
         sf.setValue(ID, id);
         attributes.append(ID).append("=").append(id);
-        // TODO handle other species variants
+        // TODO handle other species variants JAL-2064
         StringBuilder link = new StringBuilder(32);
         try
         {
@@ -2510,6 +2518,7 @@ public class AlignmentUtils
    * @param dnaToProtein
    * @return
    */
+  @SuppressWarnings("unchecked")
   static LinkedHashMap<Integer, List<DnaVariant>[]> buildDnaVariantsMap(
           SequenceI dnaSeq, MapList dnaToProtein)
   {
@@ -2553,7 +2562,7 @@ public class AlignmentUtils
         List<DnaVariant>[] codonVariants = variants.get(peptidePosition);
         if (codonVariants == null)
         {
-          codonVariants = new ArrayList[3];
+          codonVariants = new ArrayList[CODON_LENGTH];
           codonVariants[0] = new ArrayList<DnaVariant>();
           codonVariants[1] = new ArrayList<DnaVariant>();
           codonVariants[2] = new ArrayList<DnaVariant>();
@@ -2587,7 +2596,7 @@ public class AlignmentUtils
         /*
          * save nucleotide (and any variant) for each codon position
          */
-        for (int codonPos = 0; codonPos < 3; codonPos++)
+        for (int codonPos = 0; codonPos < CODON_LENGTH; codonPos++)
         {
           String nucleotide = String.valueOf(
                   dnaSeq.getCharAt(codon[codonPos] - dnaStart))
index e752126..e3d999a 100644 (file)
@@ -31,82 +31,108 @@ import jalview.datamodel.SequenceFeature;
 import jalview.util.MessageManager;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Stack;
 import java.util.Vector;
 
 public class Rna
 {
 
-  static Hashtable<Integer, Integer> pairHash = new Hashtable();
-
-  private static final Character[] openingPars = { '(', '[', '{', '<', 'A',
-      'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
-      'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
-
-  private static final Character[] closingPars = { ')', ']', '}', '>', 'a',
-      'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
-      'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
-
-  private static HashSet<Character> openingParsSet = new HashSet<Character>(
-          Arrays.asList(openingPars));
-
-  private static HashSet<Character> closingParsSet = new HashSet<Character>(
-          Arrays.asList(closingPars));
+  /**
+   * Answers true if the character is a valid open pair rna secondary structure
+   * symbol. Currently accepts A-Z, ([{<
+   * 
+   * @param c
+   * @return
+   */
+  public static boolean isOpeningParenthesis(char c)
+  {
+    return ('A' <= c && c <= 'Z' || c == '(' || c == '[' || c == '{' || c == '<');
+  }
 
-  private static Hashtable<Character, Character> closingToOpening = new Hashtable<Character, Character>()
-  // Initializing final data structure
+  /**
+   * Answers true if the string is a valid open pair rna secondary structure
+   * symbol. Currently accepts A-Z, ([{<
+   * 
+   * @param s
+   * @return
+   */
+  public static boolean isOpeningParenthesis(String s)
   {
-    private static final long serialVersionUID = 1L;
-    {
-      for (int i = 0; i < openingPars.length; i++)
-      {
-        // System.out.println(closingPars[i] + "->" + openingPars[i]);
-        put(closingPars[i], openingPars[i]);
-      }
-    }
-  };
+    return s != null && s.length() == 1
+            && isOpeningParenthesis(s.charAt(0));
+  }
 
-  private static boolean isOpeningParenthesis(char c)
+  /**
+   * Answers true if the character is a valid close pair rna secondary structure
+   * symbol. Currently accepts a-z, )]}>
+   * 
+   * @param c
+   * @return
+   */
+  public static boolean isClosingParenthesis(char c)
   {
-    return openingParsSet.contains(c);
+    return ('a' <= c && c <= 'z' || c == ')' || c == ']' || c == '}' || c == '>');
   }
 
-  private static boolean isClosingParenthesis(char c)
+  /**
+   * Answers true if the string is a valid close pair rna secondary structure
+   * symbol. Currently accepts a-z, )]}>
+   * 
+   * @param s
+   * @return
+   */
+  public static boolean isClosingParenthesis(String s)
   {
-    return closingParsSet.contains(c);
+    return s != null && s.length() == 1
+            && isClosingParenthesis(s.charAt(0));
   }
 
-  private static char matchingOpeningParenthesis(char closingParenthesis)
-          throws WUSSParseException
+  /**
+   * Returns the matching open pair symbol for the given closing symbol.
+   * Currently returns A-Z for a-z, or ([{< for )]}>, or the input symbol if it
+   * is not a valid closing symbol.
+   * 
+   * @param c
+   * @return
+   */
+  public static char getMatchingOpeningParenthesis(char c)
   {
-    if (!isClosingParenthesis(closingParenthesis))
+    if ('a' <= c && c <= 'z')
     {
-      throw new WUSSParseException(
-              MessageManager.formatMessage(
-                      "exception.querying_matching_opening_parenthesis_for_non_closing_parenthesis",
-                      new String[] { new StringBuffer(closingParenthesis)
-                              .toString() }), -1);
+      return (char) (c + 'A' - 'a');
+    }
+    switch (c)
+    {
+    case ')':
+      return '(';
+    case ']':
+      return '[';
+    case '}':
+      return '{';
+    case '>':
+      return '<';
+    default:
+      return c;
     }
-
-    return closingToOpening.get(closingParenthesis);
   }
 
   /**
    * Based off of RALEE code ralee-get-base-pairs. Keeps track of open bracket
    * positions in "stack" vector. When a close bracket is reached, pair this
-   * with the last element in the "stack" vector and store in "pairs" vector.
-   * Remove last element in the "stack" vector. Continue in this manner until
-   * the whole string is processed.
+   * with the last matching element in the "stack" vector and store in "pairs"
+   * vector. Remove last element in the "stack" vector. Continue in this manner
+   * until the whole string is processed. Parse errors are thrown as exceptions
+   * wrapping the error location - position of the first unmatched closing
+   * bracket, or string length if there is an unmatched opening bracket.
    * 
    * @param line
    *          Secondary structure line of an RNA Stockholm file
-   * @return Array of SequenceFeature; type = RNA helix, begin is open base
-   *         pair, end is close base pair
+   * @return
+   * @throw {@link WUSSParseException}
    */
-  public static Vector<SimpleBP> GetSimpleBPs(CharSequence line)
+  public static Vector<SimpleBP> getSimpleBPs(CharSequence line)
           throws WUSSParseException
   {
     Hashtable<Character, Stack<Integer>> stacks = new Hashtable<Character, Stack<Integer>>();
@@ -128,13 +154,13 @@ public class Rna
       else if (isClosingParenthesis(base))
       {
 
-        char opening = matchingOpeningParenthesis(base);
+        char opening = getMatchingOpeningParenthesis(base);
 
         if (!stacks.containsKey(opening))
         {
           throw new WUSSParseException(MessageManager.formatMessage(
                   "exception.mismatched_unseen_closing_char",
-                  new String[] { new StringBuffer(base).toString() }), i);
+                  new String[] { String.valueOf(base) }), i);
         }
 
         Stack<Integer> stack = stacks.get(opening);
@@ -143,7 +169,7 @@ public class Rna
           // error whilst parsing i'th position. pass back
           throw new WUSSParseException(MessageManager.formatMessage(
                   "exception.mismatched_closing_char",
-                  new String[] { new StringBuffer(base).toString() }), i);
+                  new String[] { String.valueOf(base) }), i);
         }
         int temp = stack.pop();
 
@@ -156,33 +182,36 @@ public class Rna
       Stack<Integer> stack = stacks.get(opening);
       if (!stack.empty())
       {
+        /*
+         * we have an unmatched opening bracket; report error as at
+         * i (length of input string)
+         */
         throw new WUSSParseException(MessageManager.formatMessage(
                 "exception.mismatched_opening_char",
-                new String[] { new StringBuffer(opening).toString(),
-                    Integer.valueOf(stack.pop()).toString() }), i);
+                new String[] { String.valueOf(opening),
+                    String.valueOf(stack.pop()) }), i);
       }
     }
     return pairs;
   }
 
-  public static SequenceFeature[] GetBasePairs(CharSequence line)
+  public static SequenceFeature[] getBasePairs(List<SimpleBP> bps)
           throws WUSSParseException
   {
-    Vector<SimpleBP> bps = GetSimpleBPs(line);
     SequenceFeature[] outPairs = new SequenceFeature[bps.size()];
     for (int p = 0; p < bps.size(); p++)
     {
-      SimpleBP bp = bps.elementAt(p);
+      SimpleBP bp = bps.get(p);
       outPairs[p] = new SequenceFeature("RNA helix", "", "", bp.getBP5(),
               bp.getBP3(), "");
     }
     return outPairs;
   }
 
-  public static ArrayList<SimpleBP> GetModeleBP(CharSequence line)
+  public static List<SimpleBP> getModeleBP(CharSequence line)
           throws WUSSParseException
   {
-    Vector<SimpleBP> bps = GetSimpleBPs(line);
+    Vector<SimpleBP> bps = getSimpleBPs(line);
     return new ArrayList<SimpleBP>(bps);
   }
 
@@ -220,8 +249,8 @@ public class Rna
     int close; // Position of a close bracket under review
     int j; // Counter
 
-    Hashtable helices = new Hashtable(); // Keep track of helix number for each
-                                         // position
+    Hashtable<Integer, Integer> helices = new Hashtable<Integer, Integer>();
+    // Keep track of helix number for each position
 
     // Go through each base pair and assign positions a helix
     for (i = 0; i < pairs.length; i++)
@@ -255,7 +284,7 @@ public class Rna
         if ((popen < lastopen) && (popen > open))
         {
           if (helices.containsValue(popen)
-                  && (((Integer) helices.get(popen)) == helix))
+                  && ((helices.get(popen)) == helix))
           {
             continue;
           }
@@ -281,4 +310,138 @@ public class Rna
 
     }
   }
+
+  /**
+   * Answers true if the character is a recognised symbol for RNA secondary
+   * structure. Currently accepts a-z, A-Z, ()[]{}<>.
+   * 
+   * @param c
+   * @return
+   */
+  public static boolean isRnaSecondaryStructureSymbol(char c)
+  {
+    return isOpeningParenthesis(c) || isClosingParenthesis(c);
+  }
+
+  /**
+   * Answers true if the string is a recognised symbol for RNA secondary
+   * structure. Currently accepts a-z, A-Z, ()[]{}<>.
+   * 
+   * @param s
+   * @return
+   */
+  public static boolean isRnaSecondaryStructureSymbol(String s)
+  {
+    return isOpeningParenthesis(s) || isClosingParenthesis(s);
+  }
+
+  /**
+   * Translates a string to RNA secondary structure representation. Returns the
+   * string with any non-SS characters changed to spaces. Accepted characters
+   * are a-z, A-Z, and (){}[]<> brackets.
+   * 
+   * @param ssString
+   * @return
+   */
+  public static String getRNASecStrucState(String ssString)
+  {
+    if (ssString == null)
+    {
+      return null;
+    }
+    StringBuilder result = new StringBuilder(ssString.length());
+    for (int i = 0; i < ssString.length(); i++)
+    {
+      char c = ssString.charAt(i);
+      result.append(isRnaSecondaryStructureSymbol(c) ? c : " ");
+    }
+    return result.toString();
+  }
+
+  /**
+   * Answers true if the base-pair is either a canonical (A-T/U, C-G) or a
+   * wobble (G-T/U) pair (either way round), else false
+   * 
+   * @param first
+   * @param second
+   * @return
+   */
+  public static boolean isCanonicalOrWobblePair(char first, char second)
+  {
+    if (first > 'Z')
+    {
+      first -= 32;
+    }
+    if (second > 'Z')
+    {
+      second -= 32;
+    }
+  
+    switch (first)
+    {
+    case 'A':
+      switch (second)
+      {
+      case 'T':
+      case 'U':
+        return true;
+      }
+      break;
+    case 'C':
+      switch (second)
+      {
+      case 'G':
+        return true;
+      }
+      break;
+    case 'T':
+    case 'U':
+      switch (second)
+      {
+      case 'A':
+      case 'G':
+        return true;
+      }
+      break;
+    case 'G':
+      switch (second)
+      {
+      case 'C':
+      case 'T':
+      case 'U':
+        return true;
+      }
+      break;
+    }
+    return false;
+  }
+
+  /**
+   * Returns the matching close pair symbol for the given opening symbol.
+   * Currently returns a-z for A-Z, or )]}> for ([{<, or the input symbol if it
+   * is not a valid opening symbol.
+   * 
+   * @param c
+   * @return
+   */
+  public static char getMatchingClosingParenthesis(char c)
+  {
+    if ('A' <= c && c <= 'Z')
+    {
+      return (char) (c + 'a' - 'A');
+    }
+    switch (c)
+    {
+    case '(':
+      return ')';
+    case '[':
+      return ']';
+    case '{':
+      return '}';
+    case '<':
+      return '>';
+    default:
+      return c;
+    }
+  }
 }
index 88387dd..479c856 100644 (file)
@@ -24,6 +24,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 import jalview.util.Format;
 
 import java.util.ArrayList;
@@ -103,23 +104,23 @@ public class StructureFrequency
 
     SequenceFeature[] rna = rnaStruc._rnasecstr;
     char c, s, cEnd;
-    int count = 0, nonGap = 0, i, bpEnd = -1, j, jSize = sequences.length;
+    int bpEnd = -1;
+    int jSize = sequences.length;
     int[] values;
     int[][] pairs;
     float percentage;
-    boolean wooble = true;
-    for (i = start; i < end; i++) // foreach column
+
+    for (int i = start; i < end; i++) // foreach column
     {
-      residueHash = new Hashtable();
+      int canonicalOrWobblePairCount = 0;
+      int otherPairCount = 0;
       maxResidue = "-";
       values = new int[255];
       pairs = new int[255][255];
       bpEnd = -1;
-      // System.out.println("s="+struc[i]);
       if (i < struc.length)
       {
         s = struc[i];
-
       }
       else
       {
@@ -130,7 +131,7 @@ public class StructureFrequency
         s = '-';
       }
 
-      if (s != '(' && s != '[')
+      if (!Rna.isOpeningParenthesis(s))
       {
         if (s == '-')
         {
@@ -139,12 +140,11 @@ public class StructureFrequency
       }
       else
       {
-
         bpEnd = findPair(rna, i);
 
         if (bpEnd > -1)
         {
-          for (j = 0; j < jSize; j++) // foreach row
+          for (int j = 0; j < jSize; j++) // foreach row
           {
             if (sequences[j] == null)
             {
@@ -152,45 +152,46 @@ public class StructureFrequency
                       .println("WARNING: Consensus skipping null sequence - possible race condition.");
               continue;
             }
-            c = sequences[j].getCharAt(i);
-            // System.out.println("c="+c);
 
-            // standard representation for gaps in sequence and structure
-            if (c == '.' || c == ' ')
-            {
-              c = '-';
-            }
+            c = sequences[j].getCharAt(i);
+            cEnd = sequences[j].getCharAt(bpEnd);
 
-            if (c == '-')
+            if (Comparison.isGap(c) || Comparison.isGap(cEnd))
             {
               values['-']++;
               continue;
             }
-            cEnd = sequences[j].getCharAt(bpEnd);
 
-            // System.out.println("pairs ="+c+","+cEnd);
-            if (checkBpType(c, cEnd) == true)
+            /*
+             * ensure upper-case for counting purposes
+             */
+            if ('a' <= c && 'z' >= c)
+            {
+              c += 'A' - 'a';
+            }
+            if ('a' <= cEnd && 'z' >= cEnd)
+            {
+              cEnd += 'A' - 'a';
+            }
+            if (Rna.isCanonicalOrWobblePair(c, cEnd))
             {
-              values['(']++; // H means it's a helix (structured)
+              values['(']++;
               maxResidue = "(";
-              wooble = true;
-              // System.out.println("It's a pair wc");
-
+              canonicalOrWobblePairCount++;
             }
-            if (checkBpType(c, cEnd) == false)
+            else
             {
-              wooble = false;
-              values['[']++; // H means it's a helix (structured)
+              values['[']++;
               maxResidue = "[";
-
+              otherPairCount++;
             }
             pairs[c][cEnd]++;
-
           }
         }
         // nonGap++;
       }
-      // UPDATE this for new values
+
+      residueHash = new Hashtable();
       if (profile)
       {
         // TODO 1-dim array with jsize in [0], nongapped in [1]; or Pojo
@@ -199,13 +200,21 @@ public class StructureFrequency
 
         residueHash.put(PAIRPROFILE, pairs);
       }
-      if (wooble == true)
-      {
-        count = values['('];
-      }
-      if (wooble == false)
+
+      /*
+       * the count is the number of valid pairs (as a percentage, determines
+       * the relative size of the profile logo)
+       */
+      int count = canonicalOrWobblePairCount;
+
+      /*
+       * currently displaying as '(' if most pairs are valid, or as
+       * '[' if there are more invalid than valid pairs 
+       */
+      if (!maxResidue.equals("-"))
       {
-        count = values['['];
+        maxResidue = canonicalOrWobblePairCount >= otherPairCount ? "("
+                : "[";
       }
       residueHash.put(MAXCOUNT, new Integer(count));
       residueHash.put(MAXRESIDUE, maxResidue);
@@ -225,17 +234,9 @@ public class StructureFrequency
         values[']'] = values['['];
         values['('] = 0;
         values['['] = 0;
+        maxResidue = maxResidue.equals("(") ? ")" : "]";
+
         residueHash = new Hashtable();
-        if (wooble == true)
-        {
-          // System.out.println(maxResidue+","+wooble);
-          maxResidue = ")";
-        }
-        if (wooble == false)
-        {
-          // System.out.println(maxResidue+","+wooble);
-          maxResidue = "]";
-        }
         if (profile)
         {
           residueHash.put(PROFILE, new int[][] { values,
@@ -251,80 +252,8 @@ public class StructureFrequency
         residueHash.put(PID_GAPS, new Float(percentage));
 
         result[bpEnd] = residueHash;
-
-      }
-    }
-  }
-
-  /**
-   * Method to check if a base-pair is a canonical or a wobble bp
-   * 
-   * @param up
-   *          5' base
-   * @param down
-   *          3' base
-   * @return True if it is a canonical/wobble bp
-   */
-  public static boolean checkBpType(char up, char down)
-  {
-    if (up > 'Z')
-    {
-      up -= 32;
-    }
-    if (down > 'Z')
-    {
-      down -= 32;
-    }
-
-    switch (up)
-    {
-    case 'A':
-      switch (down)
-      {
-      case 'T':
-        return true;
-      case 'U':
-        return true;
-      }
-      break;
-    case 'C':
-      switch (down)
-      {
-      case 'G':
-        return true;
-      }
-      break;
-    case 'T':
-      switch (down)
-      {
-      case 'A':
-        return true;
-      case 'G':
-        return true;
-      }
-      break;
-    case 'G':
-      switch (down)
-      {
-      case 'C':
-        return true;
-      case 'T':
-        return true;
-      case 'U':
-        return true;
-      }
-      break;
-    case 'U':
-      switch (down)
-      {
-      case 'A':
-        return true;
-      case 'G':
-        return true;
       }
-      break;
     }
-    return false;
   }
 
   /**
@@ -534,7 +463,7 @@ public class StructureFrequency
       for (String j : test)
       {
         System.out.println(i + "-" + j + ": "
-                + StructureFrequency.checkBpType(i.charAt(0), j.charAt(0)));
+                + Rna.isCanonicalOrWobblePair(i.charAt(0), j.charAt(0)));
       }
     }
   }
index e5475f8..6012c1a 100755 (executable)
@@ -28,6 +28,7 @@ import jalview.renderer.AwtRenderPanelI;
 import jalview.schemes.ResidueProperties;
 import jalview.util.Comparison;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 
 import java.awt.Color;
 import java.awt.Dimension;
@@ -101,7 +102,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
 
   public AnnotationPanel(AlignmentPanel ap)
   {
-    MAC = new jalview.util.Platform().isAMac();
+    new jalview.util.Platform();
+    MAC = Platform.isAMac();
     this.ap = ap;
     av = ap.av;
     setLayout(null);
@@ -242,7 +244,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       else if (evt.getActionCommand().equals(STEM))
       {
         type = 'S';
-        symbol = "\u03C3";
+        int column = av.getColumnSelection().getSelectedRanges().get(0)[0];
+        symbol = aa[activeRow].getDefaultRnaHelixSymbol(column);
       }
 
       if (!aa[activeRow].hasIcons)
@@ -347,7 +350,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
     if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK
             && activeRow != -1)
     {
-      if (av.getColumnSelection() == null)
+      if (av.getColumnSelection() == null
+              || av.getColumnSelection().isEmpty())
       {
         return;
       }
@@ -355,10 +359,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       PopupMenu pop = new PopupMenu(
               MessageManager.getString("label.structure_type"));
       MenuItem item;
-      /*
-       * Just display the needed structure options
-       */
-      if (av.getAlignment().isNucleotide() == true)
+
+      if (av.getAlignment().isNucleotide())
       {
         item = new MenuItem(STEM);
         item.addActionListener(this);
index 7990a5c..2a89fa1 100755 (executable)
@@ -24,11 +24,11 @@ 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;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -79,7 +79,7 @@ public class AlignmentAnnotation
   /** Array of annotations placed in the current coordinate system */
   public Annotation[] annotations;
 
-  public ArrayList<SimpleBP> bps = null;
+  public List<SimpleBP> bps = null;
 
   /**
    * RNA secondary structure contact positions
@@ -102,8 +102,8 @@ public class AlignmentAnnotation
   {
     try
     {
-      _rnasecstr = Rna.GetBasePairs(RNAannot);
-      bps = Rna.GetModeleBP(RNAannot);
+      bps = Rna.getModeleBP(RNAannot);
+      _rnasecstr = Rna.getBasePairs(bps);
       invalidrnastruc = -1;
     } catch (WUSSParseException px)
     {
@@ -272,7 +272,7 @@ public class AlignmentAnnotation
   // JBPNote: what does this do ?
   public void ConcenStru(CharSequence RNAannot) throws WUSSParseException
   {
-    bps = Rna.GetModeleBP(RNAannot);
+    bps = Rna.getModeleBP(RNAannot);
   }
 
   /**
@@ -485,7 +485,7 @@ public class AlignmentAnnotation
       this(0, annotations.length);
     }
 
-    public AnnotCharSequence(int start, int end)
+    AnnotCharSequence(int start, int end)
     {
       offset = start;
       max = end;
@@ -593,6 +593,7 @@ public class AlignmentAnnotation
     if (annotations == null)
     {
       visible = false; // try to prevent renderer from displaying.
+      invalidrnastruc = -1;
       return; // this is a non-annotation row annotation - ie a sequence score.
     }
 
@@ -1411,6 +1412,77 @@ public class AlignmentAnnotation
     this.annotationId = ANNOTATION_ID_PREFIX + Long.toString(nextId());
   }
 
+  /**
+   * Returns the match for the last unmatched opening RNA helix pair symbol
+   * preceding the given column, or '(' if nothing found to match.
+   * 
+   * @param column
+   * @return
+   */
+  public String getDefaultRnaHelixSymbol(int column)
+  {
+    String result = "(";
+    if (annotations == null)
+    {
+      return result;
+    }
+
+    /*
+     * for each preceding column, if it contains an open bracket, 
+     * count whether it is still unmatched at column, if so return its pair
+     * (likely faster than the fancy alternative using stacks)
+     */
+    for (int col = column - 1; col >= 0; col--)
+    {
+      Annotation annotation = annotations[col];
+      if (annotation == null)
+      {
+        continue;
+      }
+      String displayed = annotation.displayCharacter;
+      if (displayed == null || displayed.length() != 1)
+      {
+        continue;
+      }
+      char symbol = displayed.charAt(0);
+      if (!Rna.isOpeningParenthesis(symbol))
+      {
+        continue;
+      }
+
+      /*
+       * found an opening bracket symbol
+       * count (closing-opening) symbols of this type that follow it,
+       * up to and excluding the target column; if the count is less
+       * than 1, the opening bracket is unmatched, so return its match
+       */
+      String closer = String.valueOf(Rna
+              .getMatchingClosingParenthesis(symbol));
+      String opener = String.valueOf(symbol);
+      int count = 0;
+      for (int j = col + 1; j < column; j++)
+      {
+        if (annotations[j] != null)
+        {
+          String s = annotations[j].displayCharacter;
+          if (closer.equals(s))
+          {
+            count++;
+          }
+          else if (opener.equals(s))
+          {
+            count--;
+          }
+        }
+      }
+      if (count < 1)
+      {
+        return closer;
+      }
+    }
+    return result;
+  }
+
   protected static synchronized long nextId()
   {
     return counter++;
index bcf8596..5fb507a 100644 (file)
@@ -533,6 +533,7 @@ public abstract class CigarBase
       {
       case M:
         cursor += range[i];
+        break;
       case I:
         vcursor += range[i];
         break;
index 5a32736..5fccedd 100644 (file)
@@ -612,6 +612,10 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
       SequenceFeature copy = new SequenceFeature(sf);
       copy.setBegin(Math.min(mappedRange[0], mappedRange[1]));
       copy.setEnd(Math.max(mappedRange[0], mappedRange[1]));
+      if (".".equals(copy.getFeatureGroup()))
+      {
+        copy.setFeatureGroup(getDbSource());
+      }
       targetSequence.addSequenceFeature(copy);
 
       /*
index 3c9a13e..6a621ff 100755 (executable)
@@ -290,7 +290,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       aa[activeRow].annotations = anot;
     }
 
-    if (evt.getActionCommand().equals(REMOVE))
+    String action = evt.getActionCommand();
+    if (action.equals(REMOVE))
     {
       for (int index : av.getColumnSelection().getSelected())
       {
@@ -300,7 +301,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         }
       }
     }
-    else if (evt.getActionCommand().equals(LABEL))
+    else if (action.equals(LABEL))
     {
       String exMesg = collectAnnotVals(anot, LABEL);
       String label = JOptionPane.showInputDialog(this,
@@ -325,10 +326,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
         if (anot[index] == null)
         {
-          anot[index] = new Annotation(label, "", ' ', 0); // TODO: verify that
-          // null exceptions
-          // aren't raised
-          // elsewhere.
+          anot[index] = new Annotation(label, "", ' ', 0);
         }
         else
         {
@@ -336,7 +334,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         }
       }
     }
-    else if (evt.getActionCommand().equals(COLOUR))
+    else if (action.equals(COLOUR))
     {
       Color col = JColorChooser.showDialog(this,
               MessageManager.getString("label.select_foreground_colour"),
@@ -361,23 +359,24 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     // HELIX, SHEET or STEM
     {
       char type = 0;
-      String symbol = "\u03B1";
+      String symbol = "\u03B1"; // alpha
 
-      if (evt.getActionCommand().equals(HELIX))
+      if (action.equals(HELIX))
       {
         type = 'H';
       }
-      else if (evt.getActionCommand().equals(SHEET))
+      else if (action.equals(SHEET))
       {
         type = 'E';
-        symbol = "\u03B2";
+        symbol = "\u03B2"; // beta
       }
 
       // Added by LML to color stems
-      else if (evt.getActionCommand().equals(STEM))
+      else if (action.equals(STEM))
       {
         type = 'S';
-        symbol = "\u03C3";
+        int column = av.getColumnSelection().getSelectedRanges().get(0)[0];
+        symbol = aa[activeRow].getDefaultRnaHelixSymbol(column);
       }
 
       if (!aa[activeRow].hasIcons)
@@ -396,7 +395,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       if ((label.length() > 0) && !aa[activeRow].hasText)
       {
         aa[activeRow].hasText = true;
-        if (evt.getActionCommand().equals(STEM))
+        if (action.equals(STEM))
         {
           aa[activeRow].showAllColLabels = true;
         }
@@ -534,7 +533,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
     if (evt.isPopupTrigger() && activeRow != -1)
     {
-      if (av.getColumnSelection() == null)
+      if (av.getColumnSelection() == null
+              || av.getColumnSelection().isEmpty())
       {
         return;
       }
@@ -545,7 +545,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       /*
        * Just display the needed structure options
        */
-      if (av.getAlignment().isNucleotide() == true)
+      if (av.getAlignment().isNucleotide())
       {
         item = new JMenuItem(STEM);
         item.addActionListener(this);
@@ -574,11 +574,6 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       return;
     }
 
-    if (aa == null)
-    {
-      return;
-    }
-
     ap.getScalePanel().mousePressed(evt);
 
   }
index c1039ee..1bc85d2 100644 (file)
@@ -336,6 +336,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
         actioned = true;
         e.consume();
       }
+      break;
     default:
     }
     return actioned;
index 0941a6f..f48f825 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.io;
 
-import jalview.analysis.SecStrConsensus.SimpleBP;
+import jalview.analysis.Rna;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.Sequence;
@@ -32,6 +32,7 @@ import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.List;
 
 import com.stevesoft.pat.Regex;
 
@@ -79,6 +80,7 @@ public class RnamlFile extends AlignFile
    * 
    * @see jalview.io.AlignFile#parse()
    */
+  @Override
   public void parse() throws IOException
   {
     if (System.getProperty("java.version").indexOf("1.6") > -1
@@ -134,10 +136,10 @@ public class RnamlFile extends AlignFile
 
     result = RNAFactory.loadSecStrRNAML(getReader());
 
-    ArrayList<ArrayList> allarray = new ArrayList();
-    ArrayList<ArrayList<SimpleBP>> BP = new ArrayList();
-    ArrayList strucinarray = new ArrayList();
-    SequenceI[] seqs = new SequenceI[result.size()];
+    // ArrayList<ArrayList> allarray = new ArrayList();
+    // ArrayList<ArrayList<SimpleBP>> BP = new ArrayList();
+    // ArrayList strucinarray = new ArrayList();
+    SequenceI[] sqs = new SequenceI[result.size()];
 
     for (int i = 0; i < result.size(); i++)
     {
@@ -157,9 +159,9 @@ public class RnamlFile extends AlignFile
           id += "." + i;
         }
       }
-      seqs[i] = new Sequence(id, seq, begin, end);
+      sqs[i] = new Sequence(id, seq, begin, end);
 
-      seqs[i].setEnd(seqs[i].findPosition(seqs[i].getLength()));
+      sqs[i].setEnd(sqs[i].findPosition(sqs[i].getLength()));
       String[] annot = new String[rna.length()];
       Annotation[] ann = new Annotation[rna.length()];
 
@@ -170,9 +172,8 @@ public class RnamlFile extends AlignFile
       }
       for (int k = 0; k < rna.length(); k++)
       {
-        ann[k] = new Annotation(annot[k], "",
-                jalview.schemes.ResidueProperties.getRNASecStrucState(
-                        annot[k]).charAt(0), 0f);
+        ann[k] = new Annotation(annot[k], "", Rna.getRNASecStrucState(
+                annot[k]).charAt(0), 0f);
       }
 
       AlignmentAnnotation align = new AlignmentAnnotation(
@@ -181,17 +182,17 @@ public class RnamlFile extends AlignFile
                       + current.getID()
                       : "", ann);
 
-      seqs[i].addAlignmentAnnotation(align);
-      seqs[i].setRNA(result.get(i));
+      sqs[i].addAlignmentAnnotation(align);
+      sqs[i].setRNA(result.get(i));
 
-      allarray.add(strucinarray);
+      // allarray.add(strucinarray);
 
       annotations.addElement(align);
-      BP.add(align.bps);
+      // BP.add(align.bps);
 
     }
 
-    setSeqs(seqs);
+    setSeqs(sqs);
   }
 
   public static String print(SequenceI[] s)
@@ -199,13 +200,14 @@ public class RnamlFile extends AlignFile
     return "not yet implemented";
   }
 
+  @Override
   public String print()
   {
     System.out.print("print :");
     return print(getSeqsAsArray());
   }
 
-  public ArrayList getRNA()
+  public List<RNA> getRNA()
   {
     return result;
   }
index ab80ffa..bec7d82 100644 (file)
@@ -23,6 +23,7 @@
  */
 package jalview.io;
 
+import jalview.analysis.Rna;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
@@ -31,6 +32,7 @@ import jalview.datamodel.Mapping;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.schemes.ResidueProperties;
 import jalview.util.Format;
 import jalview.util.MessageManager;
 
@@ -72,8 +74,12 @@ import fr.orsay.lri.varna.models.rna.RNA;
  */
 public class StockholmFile extends AlignFile
 {
-  // static Logger logger = Logger.getLogger("jalview.io.StockholmFile");
-  protected ArrayList<RNA> result;
+  private static final Regex OPEN_PAREN = new Regex("(<|\\[)", "(");
+
+  private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")");
+
+  private static final Regex DETECT_BRACKETS = new Regex(
+          "(<|>|\\[|\\]|\\(|\\))");
 
   StringBuffer out; // output buffer
 
@@ -119,7 +125,7 @@ public class StockholmFile extends AlignFile
     fr = new FileReader(inFile);
 
     BufferedReader r = new BufferedReader(fr);
-    result = null;
+    List<RNA> result = null;
     try
     {
       result = RNAFactory.loadSecStrStockholm(r);
@@ -156,9 +162,8 @@ public class StockholmFile extends AlignFile
 
       for (int k = 0; k < rna.length(); k++)
       {
-        ann[k] = new Annotation(annot[k], "",
-                jalview.schemes.ResidueProperties.getRNASecStrucState(
-                        annot[k]).charAt(0), 0f);
+        ann[k] = new Annotation(annot[k], "", Rna.getRNASecStrucState(
+                annot[k]).charAt(0), 0f);
 
       }
       AlignmentAnnotation align = new AlignmentAnnotation("Sec. str.",
@@ -789,19 +794,13 @@ public class StockholmFile extends AlignFile
   }
 
   protected static AlignmentAnnotation parseAnnotationRow(
-          Vector annotation, String label, String annots)
+          Vector<AlignmentAnnotation> annotation, String label,
+          String annots)
   {
     String convert1, convert2 = null;
 
-    // Convert all bracket types to parentheses
-    Regex openparen = new Regex("(<|\\[)", "(");
-    Regex closeparen = new Regex("(>|\\])", ")");
-
-    // Detect if file is RNA by looking for bracket types
-    Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))");
-
-    convert1 = openparen.replaceAll(annots);
-    convert2 = closeparen.replaceAll(convert1);
+    convert1 = OPEN_PAREN.replaceAll(annots);
+    convert2 = CLOSE_PAREN.replaceAll(convert1);
     annots = convert2;
 
     String type = label;
@@ -828,15 +827,15 @@ public class StockholmFile extends AlignFile
       {
         // if (" .-_".indexOf(pos) == -1)
         {
-          if (detectbrackets.search(pos))
+          if (DETECT_BRACKETS.search(pos))
           {
-            ann.secondaryStructure = jalview.schemes.ResidueProperties
-                    .getRNASecStrucState(pos).charAt(0);
+            ann.secondaryStructure = Rna.getRNASecStrucState(
+                    pos).charAt(0);
           }
           else
           {
-            ann.secondaryStructure = jalview.schemes.ResidueProperties
-                    .getDssp3state(pos).charAt(0);
+            ann.secondaryStructure = ResidueProperties.getDssp3state(pos)
+                    .charAt(0);
           }
 
           if (ann.secondaryStructure == pos.charAt(0))
@@ -854,10 +853,10 @@ public class StockholmFile extends AlignFile
       els[i] = ann;
     }
     AlignmentAnnotation annot = null;
-    Enumeration e = annotation.elements();
+    Enumeration<AlignmentAnnotation> e = annotation.elements();
     while (e.hasMoreElements())
     {
-      annot = (AlignmentAnnotation) e.nextElement();
+      annot = e.nextElement();
       if (annot.label.equals(type))
       {
         break;
@@ -1121,6 +1120,7 @@ public class StockholmFile extends AlignFile
   }
 
   private static Hashtable typeIds = null;
+
   static
   {
     if (typeIds == null)
index e571064..1348e59 100644 (file)
@@ -379,6 +379,7 @@ public abstract class GStructureChooser extends JPanel implements
             }
           }
           evt.consume();
+          break;
         default:
           return;
         }
index 75099c2..82f6ffb 100644 (file)
@@ -22,6 +22,7 @@ package jalview.renderer;
 
 import jalview.analysis.AAFrequency;
 import jalview.analysis.CodingUtils;
+import jalview.analysis.Rna;
 import jalview.analysis.StructureFrequency;
 import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentAnnotation;
@@ -43,8 +44,6 @@ import java.awt.image.ImageObserver;
 import java.util.BitSet;
 import java.util.Hashtable;
 
-import com.stevesoft.pat.Regex;
-
 public class AnnotationRenderer
 {
   private static final int UPPER_TO_LOWER = 'a' - 'A'; // 32
@@ -75,7 +74,7 @@ public class AnnotationRenderer
     this.debugRedraw = debugRedraw;
   }
 
-  public void drawStemAnnot(Graphics g, Annotation[] row_annotations,
+  void drawStemAnnot(Graphics g, Annotation[] row_annotations,
           int lastSSX, int x, int y, int iconOffset, int startRes,
           int column, boolean validRes, boolean validEnd)
   {
@@ -83,7 +82,6 @@ public class AnnotationRenderer
     int sCol = (lastSSX / charWidth) + startRes;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
-    Regex closeparen = new Regex("(\\))");
 
     char dc = (column == 0 || row_annotations[column - 1] == null) ? ' '
             : row_annotations[column - 1].secondaryStructure;
@@ -93,15 +91,17 @@ public class AnnotationRenderer
     boolean diffdownstream = !validRes || !validEnd
             || row_annotations[column] == null
             || dc != row_annotations[column].secondaryStructure;
-    // System.out.println("Column "+column+" diff up: "+diffupstream+" down:"+diffdownstream);
-    // If a closing base pair half of the stem, display a backward arrow
-    if (column > 0 && ResidueProperties.isCloseParenRNA(dc))
-    {
 
+    if (column > 0 && Rna.isClosingParenthesis(dc))
+    {
       if (diffupstream)
       // if (validRes && column>1 && row_annotations[column-2]!=null &&
       // dc.equals(row_annotations[column-2].displayCharacter))
       {
+        /*
+         * if new annotation with a closing base pair half of the stem, 
+         * display a backward arrow
+         */
         g.fillPolygon(new int[] { lastSSX + 5, lastSSX + 5, lastSSX },
                 new int[] { y + iconOffset, y + 14 + iconOffset,
                     y + 8 + iconOffset }, 3);
@@ -114,10 +114,13 @@ public class AnnotationRenderer
     }
     else
     {
-
       // display a forward arrow
       if (diffdownstream)
       {
+        /*
+         * if annotation ending with an opeing base pair half of the stem, 
+         * display a forward arrow
+         */
         g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 }, new int[] {
             y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, 3);
         x2 -= 5;
@@ -195,7 +198,7 @@ public class AnnotationRenderer
    */
   private boolean canClip = false;
 
-  public void drawNotCanonicalAnnot(Graphics g, Color nonCanColor,
+  void drawNotCanonicalAnnot(Graphics g, Color nonCanColor,
           Annotation[] row_annotations, int lastSSX, int x, int y,
           int iconOffset, int startRes, int column, boolean validRes,
           boolean validEnd)
@@ -206,7 +209,6 @@ public class AnnotationRenderer
     int sCol = (lastSSX / charWidth) + startRes;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
-    Regex closeparen = new Regex("}|]|<|[a-z]");
 
     String dc = (column == 0 || row_annotations[column - 1] == null) ? ""
             : row_annotations[column - 1].displayCharacter;
@@ -218,8 +220,7 @@ public class AnnotationRenderer
             || !dc.equals(row_annotations[column].displayCharacter);
     // System.out.println("Column "+column+" diff up: "+diffupstream+" down:"+diffdownstream);
     // If a closing base pair half of the stem, display a backward arrow
-    if (column > 0 && closeparen.search(dc))// closeletter_b.search(dc)||closeletter_c.search(dc)||closeletter_d.search(dc)||closecrochet.search(dc))
-                                            // )
+    if (column > 0 && Rna.isClosingParenthesis(dc))
     {
 
       if (diffupstream)
@@ -321,7 +322,7 @@ public class AnnotationRenderer
    * @param column
    * @return
    */
-  public int[] getProfileFor(AlignmentAnnotation aa, int column)
+  int[] getProfileFor(AlignmentAnnotation aa, int column)
   {
     // TODO : consider refactoring the global alignment calculation
     // properties/rendering attributes as a global 'alignment group' which holds
@@ -750,7 +751,7 @@ public class AnnotationRenderer
                             validEnd);
                     break;
                   }
-
+                  // no break if isRNA - falls through to drawNotCanonicalAnnot!
                 case 'E':
                   if (!isRNA)
                   {
@@ -759,6 +760,7 @@ public class AnnotationRenderer
                             validEnd);
                     break;
                   }
+                  // no break if isRNA - fall through to drawNotCanonicalAnnot!
 
                 case '{':
                 case '}':
@@ -866,7 +868,6 @@ public class AnnotationRenderer
         {
           validRes = true;
         }
-
         // x ++;
 
         if (row.hasIcons)
@@ -881,6 +882,7 @@ public class AnnotationRenderer
                       startRes, column, validRes, validEnd);
               break;
             }
+            // no break if isRNA - fall through to drawNotCanonicalAnnot!
 
           case 'E':
             if (!isRNA)
@@ -889,6 +891,7 @@ public class AnnotationRenderer
                       startRes, column, validRes, validEnd);
               break;
             }
+            // no break if isRNA - fall through to drawNotCanonicalAnnot!
 
           case '(':
           case ')': // Stem case for RNA secondary structure
@@ -1069,7 +1072,7 @@ public class AnnotationRenderer
 
   private Color sdNOTCANONICAL_COLOUR;
 
-  public void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX,
+  void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX,
           int x, int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
   {
@@ -1077,7 +1080,7 @@ public class AnnotationRenderer
     g.fillRect(lastSSX, y + 6 + iconOffset, (x * charWidth) - lastSSX, 2);
   }
 
-  public void drawSheetAnnot(Graphics g, Annotation[] row,
+  void drawSheetAnnot(Graphics g, Annotation[] row,
 
   int lastSSX, int x, int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
@@ -1101,7 +1104,7 @@ public class AnnotationRenderer
 
   }
 
-  public void drawHelixAnnot(Graphics g, Annotation[] row, int lastSSX,
+  void drawHelixAnnot(Graphics g, Annotation[] row, int lastSSX,
           int x, int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
   {
@@ -1161,7 +1164,7 @@ public class AnnotationRenderer
     g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
   }
 
-  public void drawLineGraph(Graphics g, AlignmentAnnotation _aa,
+  void drawLineGraph(Graphics g, AlignmentAnnotation _aa,
           Annotation[] aa_annotations, int sRes, int eRes, int y,
           float min, float max, int graphHeight)
   {
@@ -1254,7 +1257,7 @@ public class AnnotationRenderer
     }
   }
 
-  public void drawBarGraph(Graphics g, AlignmentAnnotation _aa,
+  void drawBarGraph(Graphics g, AlignmentAnnotation _aa,
           Annotation[] aa_annotations, int sRes, int eRes, float min,
           float max, int y, boolean renderHistogram, boolean renderProfile,
           boolean normaliseProfile)
@@ -1385,8 +1388,9 @@ public class AnnotationRenderer
             scl = htn * scale * profl[c++];
             lm = ofont.getLineMetrics(dc, 0, 1, g.getFontMetrics()
                     .getFontRenderContext());
-            g.setFont(ofont.deriveFont(AffineTransform.getScaleInstance(
-                    wdth, scl / lm.getAscent())));
+            Font font = ofont.deriveFont(AffineTransform.getScaleInstance(
+                    wdth, scl / lm.getAscent()));
+            g.setFont(font);
             lm = g.getFontMetrics().getLineMetrics(dc, 0, 1, g);
 
             // Debug - render boxes around characters
index 2aa24a1..d0d26b0 100755 (executable)
@@ -1603,87 +1603,6 @@ public class ResidueProperties
     return ss.toString();
   }
 
-  /**
-   * Used by getRNASecStrucState
-   * 
-   */
-  public static Hashtable<String, String> toRNAssState;
-
-  public static boolean RNAcloseParen[] = new boolean[255];
-  static
-  {
-    toRNAssState = new Hashtable<String, String>();
-    toRNAssState.put(")", "(");
-    toRNAssState.put("(", "(");
-    toRNAssState.put("]", "[");
-    toRNAssState.put("[", "[");
-    toRNAssState.put("{", "{");
-    toRNAssState.put("}", "{");
-    toRNAssState.put(">", ">");
-    toRNAssState.put("<", ">");
-    toRNAssState.put("A", "A");
-    toRNAssState.put("a", "A");
-    toRNAssState.put("B", "B");
-    toRNAssState.put("b", "B");
-    toRNAssState.put("C", "C");
-    toRNAssState.put("c", "C");
-    toRNAssState.put("D", "D");
-    toRNAssState.put("d", "D");
-    toRNAssState.put("E", "E");
-    toRNAssState.put("e", "E");
-    toRNAssState.put("F", "F");
-    toRNAssState.put("f", "F");
-    toRNAssState.put("G", "G");
-    toRNAssState.put("g", "G");
-    toRNAssState.put("H", "H");
-    toRNAssState.put("h", "H");
-    toRNAssState.put("I", "I");
-    toRNAssState.put("i", "I");
-    toRNAssState.put("J", "J");
-    toRNAssState.put("j", "J");
-    toRNAssState.put("K", "K");
-    toRNAssState.put("k", "K");
-    toRNAssState.put("L", "L");
-    toRNAssState.put("l", "L");
-    toRNAssState.put("M", "M");
-    toRNAssState.put("m", "M");
-    toRNAssState.put("N", "N");
-    toRNAssState.put("n", "N");
-    toRNAssState.put("O", "O");
-    toRNAssState.put("o", "O");
-    toRNAssState.put("P", "P");
-    toRNAssState.put("p", "P");
-    toRNAssState.put("Q", "Q");
-    toRNAssState.put("q", "Q");
-    toRNAssState.put("R", "R");
-    toRNAssState.put("r", "R");
-    toRNAssState.put("S", "S");
-    toRNAssState.put("s", "S");
-    toRNAssState.put("T", "T");
-    toRNAssState.put("t", "T");
-    toRNAssState.put("U", "U");
-    toRNAssState.put("u", "U");
-    toRNAssState.put("V", "V");
-    toRNAssState.put("v", "V");
-    toRNAssState.put("W", "W");
-    toRNAssState.put("w", "W");
-    toRNAssState.put("X", "X");
-    toRNAssState.put("x", "X");
-    toRNAssState.put("Y", "Y");
-    toRNAssState.put("y", "Y");
-    toRNAssState.put("Z", "Z");
-    toRNAssState.put("z", "Z");
-    for (int p = 0; p < RNAcloseParen.length; p++)
-    {
-      RNAcloseParen[p] = false;
-    }
-    for (String k : toRNAssState.keySet())
-    {
-      RNAcloseParen[k.charAt(0)] = k.charAt(0) != toRNAssState.get(k)
-              .charAt(0);
-    }
-  }
-
   static
   {
     modifications.put("MSE", "MET"); // Selenomethionine
@@ -3008,40 +2927,6 @@ public class ResidueProperties
     return canonical == null ? aa : canonical;
   }
 
-  /**
-   * translate to RNA secondary structure representation
-   * 
-   * @param ssstring
-   * @return ssstring as a RNA-state secondary structure assignment.
-   */
-  public static String getRNASecStrucState(String ssstring)
-  {
-    if (ssstring == null)
-    {
-      return null;
-    }
-    StringBuffer ss = new StringBuffer();
-    for (int i = 0; i < ssstring.length(); i++)
-    {
-      String ssc = ssstring.substring(i, i + 1);
-      if (toRNAssState.containsKey(ssc))
-      {
-        // valid ss character - so return it
-        ss.append(ssc); // (String) toRNAssState.get(ssc));
-      }
-      else
-      {
-        ss.append(" ");
-      }
-    }
-    return ss.toString();
-  }
-
-  public static boolean isCloseParenRNA(char dc)
-  {
-    return RNAcloseParen[dc];
-  }
-
   // main method generates perl representation of residue property hash
   // / cut here
   public static void main(String[] args)
index 7e8442d..ddd38e7 100644 (file)
@@ -1954,13 +1954,15 @@ public class AlignmentUtilsTests
   public void testComputePeptideVariants()
   {
     /*
-     * scenario: AAATTTCCC codes for KFP, with variants
-     *           GAA -> E
-     *           CAA -> Q
-     *           AAG synonymous
-     *           AAT -> N
-     *              TTC synonymous
-     *                 CAC,CGC -> H,R (as one variant)
+     * scenario: AAATTTCCC codes for KFP
+     * variants:
+     *           GAA -> E             source: Ensembl
+     *           CAA -> Q             source: dbSNP
+     *           AAG synonymous       source: COSMIC
+     *           AAT -> N             source: Ensembl
+     *           ...TTC synonymous    source: dbSNP
+     *           ......CAC,CGC -> H,R source: COSMIC
+     *                 (one variant with two alleles)
      */
     SequenceI peptide = new Sequence("pep/10-12", "KFP");
 
@@ -1968,32 +1970,35 @@ public class AlignmentUtilsTests
      * two distinct variants for codon 1 position 1
      * second one has clinical significance
      */
+    String ensembl = "Ensembl";
+    String dbSnp = "dbSNP";
+    String cosmic = "COSMIC";
     SequenceFeature sf1 = new SequenceFeature("sequence_variant", "", 1, 1,
-            0f, null);
+            0f, ensembl);
     sf1.setValue("alleles", "A,G"); // GAA -> E
     sf1.setValue("ID", "var1.125A>G");
     SequenceFeature sf2 = new SequenceFeature("sequence_variant", "", 1, 1,
-            0f, null);
+            0f, dbSnp);
     sf2.setValue("alleles", "A,C"); // CAA -> Q
     sf2.setValue("ID", "var2");
     sf2.setValue("clinical_significance", "Dodgy");
     SequenceFeature sf3 = new SequenceFeature("sequence_variant", "", 3, 3,
-            0f, null);
+            0f, cosmic);
     sf3.setValue("alleles", "A,G"); // synonymous
     sf3.setValue("ID", "var3");
     sf3.setValue("clinical_significance", "None");
     SequenceFeature sf4 = new SequenceFeature("sequence_variant", "", 3, 3,
-            0f, null);
+            0f, ensembl);
     sf4.setValue("alleles", "A,T"); // AAT -> N
     sf4.setValue("ID", "sequence_variant:var4"); // prefix gets stripped off
     sf4.setValue("clinical_significance", "Benign");
     SequenceFeature sf5 = new SequenceFeature("sequence_variant", "", 6, 6,
-            0f, null);
+            0f, dbSnp);
     sf5.setValue("alleles", "T,C"); // synonymous
     sf5.setValue("ID", "var5");
     sf5.setValue("clinical_significance", "Bad");
     SequenceFeature sf6 = new SequenceFeature("sequence_variant", "", 8, 8,
-            0f, null);
+            0f, cosmic);
     sf6.setValue("alleles", "C,A,G"); // CAC,CGC -> H,R
     sf6.setValue("ID", "var6");
     sf6.setValue("clinical_significance", "Good");
@@ -2041,14 +2046,15 @@ public class AlignmentUtilsTests
 
     /*
      * verify added sequence features for
-     * var1 K -> E
-     * var2 K -> Q
-     * var4 K -> N
-     * var6 P -> H
-     * var6 P -> R
+     * var1 K -> E Ensembl
+     * var2 K -> Q dbSNP
+     * var4 K -> N Ensembl
+     * var6 P -> H COSMIC
+     * var6 P -> R COSMIC
      */
     SequenceFeature[] sfs = peptide.getSequenceFeatures();
     assertEquals(5, sfs.length);
+
     SequenceFeature sf = sfs[0];
     assertEquals(1, sf.getBegin());
     assertEquals(1, sf.getEnd());
@@ -2061,7 +2067,8 @@ public class AlignmentUtilsTests
     assertEquals(
             "p.Lys1Glu var1.125A>G|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var1.125A%3EG",
             sf.links.get(0));
-    assertEquals("Jalview", sf.getFeatureGroup());
+    assertEquals(ensembl, sf.getFeatureGroup());
+
     sf = sfs[1];
     assertEquals(1, sf.getBegin());
     assertEquals(1, sf.getEnd());
@@ -2073,7 +2080,8 @@ public class AlignmentUtilsTests
     assertEquals(
             "p.Lys1Gln var2|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var2",
             sf.links.get(0));
-    assertEquals("Jalview", sf.getFeatureGroup());
+    assertEquals(dbSnp, sf.getFeatureGroup());
+
     sf = sfs[2];
     assertEquals(1, sf.getBegin());
     assertEquals(1, sf.getEnd());
@@ -2085,7 +2093,9 @@ public class AlignmentUtilsTests
     assertEquals(
             "p.Lys1Asn var4|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var4",
             sf.links.get(0));
-    assertEquals("Jalview", sf.getFeatureGroup());
+    assertEquals(ensembl, sf.getFeatureGroup());
+
+    // var5 generates two distinct protein variant features
     sf = sfs[3];
     assertEquals(3, sf.getBegin());
     assertEquals(3, sf.getEnd());
@@ -2097,8 +2107,8 @@ public class AlignmentUtilsTests
     assertEquals(
             "p.Pro3His var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
             sf.links.get(0));
-    // var5 generates two distinct protein variant features
-    assertEquals("Jalview", sf.getFeatureGroup());
+    assertEquals(cosmic, sf.getFeatureGroup());
+
     sf = sfs[4];
     assertEquals(3, sf.getBegin());
     assertEquals(3, sf.getEnd());
@@ -2110,7 +2120,7 @@ public class AlignmentUtilsTests
     assertEquals(
             "p.Pro3Arg var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
             sf.links.get(0));
-    assertEquals("Jalview", sf.getFeatureGroup());
+    assertEquals(cosmic, sf.getFeatureGroup());
   }
 
   /**
index 5801437..f33525f 100644 (file)
@@ -21,6 +21,9 @@
 package jalview.analysis;
 
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
 import jalview.analysis.SecStrConsensus.SimpleBP;
@@ -35,11 +38,12 @@ public class RnaTest
   public void testGetSimpleBPs() throws WUSSParseException
   {
     String rna = "([{})]"; // JAL-1081 example
-    Vector<SimpleBP> bps = Rna.GetSimpleBPs(rna);
+    Vector<SimpleBP> bps = Rna.getSimpleBPs(rna);
     assertEquals(3, bps.size());
 
     /*
      * the base pairs are added in the order in which the matching base is found
+     * (popping the stack of unmatched opening brackets)
      */
     assertEquals(2, bps.get(0).bp5); // {
     assertEquals(3, bps.get(0).bp3); // }
@@ -55,25 +59,221 @@ public class RnaTest
     String rna = "(([{})]";
     try
     {
-      Rna.GetSimpleBPs(rna);
+      Rna.getSimpleBPs(rna);
       fail("expected exception");
     } catch (WUSSParseException e)
     {
-      // expected
+      // error reported as after end of input string
+      assertEquals(rna.length(), e.getProblemPos());
     }
   }
 
   @Test(groups = { "Functional" })
   public void testGetSimpleBPs_unmatchedCloser()
   {
-    String rna = "([{})]]";
+    String rna = "([{})]]]";
     try
     {
-      Rna.GetSimpleBPs(rna);
+      Rna.getSimpleBPs(rna);
       fail("expected exception");
     } catch (WUSSParseException e)
     {
-      // expected
+      // error reported as at first unmatched close
+      assertEquals(6, e.getProblemPos());
+    }
+
+    /*
+     * a variant where we have no opening bracket of the same type
+     * as the unmatched closing bracket (no stack rather than empty stack)
+     */
+    rna = "((()])";
+    try
+    {
+      Rna.getSimpleBPs(rna);
+      fail("expected exception");
+    } catch (WUSSParseException e)
+    {
+      assertEquals(4, e.getProblemPos());
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetRNASecStrucState()
+  {
+    assertNull(Rna.getRNASecStrucState(null));
+    for (int i = 0; i <= 255; i++)
+    {
+      String s = String.valueOf((char) i);
+      String ss = Rna.getRNASecStrucState(s);
+  
+      /*
+       * valid SS chars are a-z, A-Z, and various brackets;
+       * anything else is returned as a space
+       */
+      if ((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z')
+              || "()[]{}<>".indexOf(s) > -1)
+      {
+        assertEquals("" + i, s, ss);
+      }
+      else
+      {
+        assertEquals(" ", ss);
+      }
+    }
+  
+    /*
+     * a string is processed character by character
+     */
+    assertEquals("a [K ]z} {Q b(w)p><i",
+            Rna.getRNASecStrucState("a.[K-]z}?{Q b(w)p><i"));
+  }
+
+  /**
+   * Tests for isClosingParenthesis with char or String argument
+   */
+  @Test(groups = { "Functional" })
+  public void testIsClosingParenthesis()
+  {
+    assertFalse(Rna.isClosingParenthesis(null));
+
+    /*
+     * only a-z, )]}> are closing bracket symbols
+     */
+    for (int i = 0; i <= 255; i++)
+    {
+      boolean isClosingChar = Rna.isClosingParenthesis((char) i);
+      boolean isClosingString = Rna.isClosingParenthesis(String
+              .valueOf((char) i));
+      if ((i >= 'a' && i <= 'z') || i == ')' || i == '}' || i == ']'
+              || i == '>')
+      {
+        assertTrue(String.format("close base pair %c", i), isClosingChar);
+        assertTrue(String.format("close base pair %c", i), isClosingString);
+      }
+      else
+      {
+        assertFalse(String.format("close base pair %c", i), isClosingChar);
+        assertFalse(String.format("close base pair %c", i), isClosingString);
+      }
+      assertFalse(Rna.isClosingParenthesis(String.valueOf((char) i) + " "));
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsCanonicalOrWobblePair()
+  {
+    String bases = "acgtuACGTU";
+    for (int i = 0; i < bases.length(); i++)
+    {
+      for (int j = 0; j < bases.length(); j++)
+      {
+        char first = bases.charAt(i);
+        char second = bases.charAt(j);
+        boolean result = Rna.isCanonicalOrWobblePair(first, second);
+        String pair = new String(new char[] { first, second })
+                .toUpperCase();
+        if (pair.equals("AT") || pair.equals("TA") || pair.equals("AU")
+                || pair.equals("UA") || pair.equals("GC")
+                || pair.equals("CG") || pair.equals("GT")
+                || pair.equals("TG") || pair.equals("GU")
+                || pair.equals("UG"))
+        {
+          assertTrue(pair + " should be valid", result);
+        }
+        else
+        {
+          assertFalse(pair + " should be invalid", result);
+        }
+      }
+    }
+  }
+
+  /**
+   * Tests for isOpeningParenthesis with char or String argument
+   */
+  @Test(groups = { "Functional" })
+  public void testIsOpeningParenthesis()
+  {
+    /*
+     * only A-Z, ([{< are opening bracket symbols
+     */
+    for (int i = 0; i <= 255; i++)
+    {
+      boolean isOpeningChar = Rna.isOpeningParenthesis((char) i);
+      boolean isOpeningString = Rna.isOpeningParenthesis(String
+              .valueOf((char) i));
+      if ((i >= 'A' && i <= 'Z') || i == '(' || i == '{' || i == '['
+              || i == '<')
+      {
+        assertTrue(String.format("Open base pair %c", i), isOpeningChar);
+        assertTrue(String.format("Open base pair %c", i), isOpeningString);
+      }
+      else
+      {
+        assertFalse(String.format("Open base pair %c", i), isOpeningChar);
+        assertFalse(String.format("Open base pair %c", i), isOpeningString);
+      }
+      assertFalse(Rna.isOpeningParenthesis(String.valueOf((char) i) + " "));
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetMatchingOpeningParenthesis() throws WUSSParseException
+  {
+    for (int i = 0; i <= 255; i++)
+    {
+      boolean isClosing = Rna.isClosingParenthesis((char) i);
+      if (isClosing)
+      {
+        char opening = Rna.getMatchingOpeningParenthesis((char) i);
+        if (i >= 'a' && i <= 'z')
+        {
+          assertEquals(i + 'A' - 'a', opening);
+        }
+        else if (i == ')' && opening == '(' || i == ']' && opening == '['
+                || i == '}' && opening == '{' || i == '>' && opening == '<')
+        {
+          // ok
+        }
+        else
+        {
+          fail("Got " + opening + " as opening bracket pair for "
+                  + ((char) i));
+        }
+      }
+    }
+  }
+
+  /**
+   * Tests for isRnaSecondaryStructureSymbol with char or String argument
+   */
+  @Test(groups = { "Functional" })
+  public void testIsRnaSecondaryStructureSymbol()
+  {
+    assertFalse(Rna.isRnaSecondaryStructureSymbol(null));
+  
+    /*
+     * only A-Z,  a-z, ()[]{}<> are valid symbols
+     */
+    for (int i = 0; i <= 255; i++)
+    {
+      boolean isValidChar = Rna.isRnaSecondaryStructureSymbol((char) i);
+      boolean isValidString = Rna.isRnaSecondaryStructureSymbol(String
+              .valueOf((char) i));
+      if ((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || i == '('
+              || i == ')' || i == '{' || i == '}' || i == '[' || i == ']'
+              || i == '<' || i == '>')
+      {
+        assertTrue(String.format("close base pair %c", i), isValidChar);
+        assertTrue(String.format("close base pair %c", i), isValidString);
+      }
+      else
+      {
+        assertFalse(String.format("close base pair %c", i), isValidChar);
+        assertFalse(String.format("close base pair %c", i), isValidString);
+      }
+      assertFalse(Rna.isRnaSecondaryStructureSymbol(String
+              .valueOf((char) i) + " "));
     }
   }
 }
index ac58aa9..a37370f 100644 (file)
@@ -42,7 +42,7 @@ public class CacheTest
     // currently using Locale.UK to format dates:
     assertEquals(
             formattedDate2,
-            SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.LONG,
-                    SimpleDateFormat.LONG, Locale.UK).format(now));
+            SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.MEDIUM,
+                    SimpleDateFormat.MEDIUM, Locale.UK).format(now));
   }
 }
index 271162b..1aff519 100644 (file)
@@ -219,4 +219,65 @@ public class AlignmentAnnotationTests
     assertEquals(1, ann.annotations[1].value, 0.001);
     assertEquals(2, ann.annotations[2].value, 0.001);
   }
-}
+
+  /**
+   * Test the method that defaults rna symbol to the one matching the preceding
+   * unmatched opening bracket (if any)
+   */
+  @Test(groups = { "Functional" })
+  public void testGetDefaultRnaHelixSymbol()
+  {
+    AlignmentAnnotation ann = new AlignmentAnnotation("SS",
+            "secondary structure", null);
+    assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
+
+    Annotation[] anns = new Annotation[20];
+    ann.annotations = anns;
+    assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
+
+    anns[1] = new Annotation("(", "S", '(', 0f);
+    assertEquals("(", ann.getDefaultRnaHelixSymbol(0));
+    assertEquals("(", ann.getDefaultRnaHelixSymbol(1));
+    assertEquals(")", ann.getDefaultRnaHelixSymbol(2));
+    assertEquals(")", ann.getDefaultRnaHelixSymbol(3));
+
+    /*
+     * .(.[.{.<.}.>.).].
+     */
+    anns[1] = new Annotation("(", "S", '(', 0f);
+    anns[3] = new Annotation("[", "S", '[', 0f);
+    anns[5] = new Annotation("{", "S", '{', 0f);
+    anns[7] = new Annotation("<", "S", '<', 0f);
+    anns[9] = new Annotation("}", "S", '}', 0f);
+    anns[11] = new Annotation(">", "S", '>', 0f);
+    anns[13] = new Annotation(")", "S", ')', 0f);
+    anns[15] = new Annotation("]", "S", ']', 0f);
+
+    String expected = "(())]]}}>>>>]]]](";
+    for (int i = 0; i < expected.length(); i++)
+    {
+      assertEquals("column " + i, String.valueOf(expected.charAt(i)),
+              ann.getDefaultRnaHelixSymbol(i));
+    }
+
+    /*
+     * .(.[.(.).{.}.<.].D.
+     */
+    anns[1] = new Annotation("(", "S", '(', 0f);
+    anns[3] = new Annotation("[", "S", '[', 0f);
+    anns[5] = new Annotation("(", "S", '(', 0f);
+    anns[7] = new Annotation(")", "S", ')', 0f);
+    anns[9] = new Annotation("{", "S", '{', 0f);
+    anns[11] = new Annotation("}", "S", '}', 0f);
+    anns[13] = new Annotation("<", "S", '>', 0f);
+    anns[15] = new Annotation("]", "S", ']', 0f);
+    anns[17] = new Annotation("D", "S", 'D', 0f);
+
+    expected = "(())]]))]]}}]]>>>>dd";
+    for (int i = 0; i < expected.length(); i++)
+    {
+      assertEquals("column " + i, String.valueOf(expected.charAt(i)),
+              ann.getDefaultRnaHelixSymbol(i));
+    }
+  }
+}
\ No newline at end of file
diff --git a/utils/checkstyle/README.txt b/utils/checkstyle/README.txt
new file mode 100644 (file)
index 0000000..e38064e
--- /dev/null
@@ -0,0 +1,85 @@
+Checkstyle for Jalview
+----------------------
+
+http://checkstyle.sourceforge.net/
+GNU LGPL
+
+To get the Eclipse Checkstyle plugin
+------------------------------------
+       - Help | Eclipse Marketplace
+       - search for checkstyle
+       - install eclipse-cs checkstyle plugin
+The current version is 6.19.1 (August 2016).
+
+Config
+------
+
+       File Jalview/.checkstyle holds configuration for the "JalviewCheckstyle" ruleset.
+       This includes confining its scope to src/*.java and resources/*.properties.
+       This can be modified interactively through the checkstyle properties editor.
+       
+       Checkstyle config files in utils/checkstyle:
+               checkstyle.xml          : main configuration file with selected checkstyle modules
+               checkstyle-suppress.xml : rules to exclude certain checks / files
+               import-control.xml      : package import rules
+       
+       Checkstyle error messages can be customised. See TypeName for an example.
+
+How to use checkstyle
+---------------------
+
+       Option 1: enable it for the Jalview project
+               - right-click on project | Checkstyle | Activate Checkstyle
+               - notice CheckstyleNature gets added to the .project file
+               - don't commit this file unless we all agree to!
+               - Checkstyle will run as you recompile changed code
+
+       Option 2: on demand on selected code
+               - right-click on a class or package and Checkstyle | Check code with checkstyle
+               - (or Clear Checkstyle violations to remove checkstyle warnings)
+
+Checkstyle rules
+----------------
+       Documented at http://checkstyle.sourceforge.net/checks.html
+       Should be self-documenting in checkstyle.xml
+       Open for discussion:
+       - which rules to use
+       - what naming and layout standards to apply
+       - settings for complexity metrics
+       - whether any rules should report an error instead of a warning  
+       
+Suppressing findings
+--------------------
+       If there are warnings you judge it ok to suppress (false positives), 
+       your options are (from most global to most local impact):
+       - remove the rule entirely
+       - adjust its properties
+       - add an entry in checkstyle-suppress.xml to skip the file for the rule
+       - add comments around the reported source lines
+               // CHECKSTYLE.OFF: RuleName 'a comment to justify suppression'
+               source code here
+               // CHECKSTYLE.ON: RuleName
+       The suppression should be as localised as possible, to avoid false negatives.
+       
+Tips
+----
+       Sometimes checkstyle needs a kick before it will refresh its findings.
+       A whitespace edit in checkstyle.xml usually does this. There may be better ways.
+       
+       Invalid configuration files may result in checkstyle failing with an error reported
+       in the Eclipse log file. 
+       Help | Installation Details | Configuration takes you to a screen with a 
+       'View Error Log' button.
+       
+       Sometimes checkstyle can fail silently. Try 'touching' (editing) config files, failing
+       that, carefully check / back out / redo any recent changes to its config.
+       
+       Putting <!-- XML comments --> inside a checkstyle <module> causes it to be ignored!
+       
+       If a rule doesn't behave as you expected, read its documentation carefully, including
+       the use and default value of any properties.
+       
+       To highlight a single rule's findings, you can 'Configure Contents' of the Problems view
+       and filter on Text Contains <rule name> (case-sensitive). 
+       Here you should select 'Use item limits' with a value of, say, 500,     or Eclipse may 
+       labour to display all warnings.
diff --git a/utils/checkstyle/checkstyle-suppress.xml b/utils/checkstyle/checkstyle-suppress.xml
new file mode 100644 (file)
index 0000000..ac9e260
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+       <!-- 
+               Do not put individual file-level suppressions here.
+               Instead use embedded comments to switch checks on and off.
+    -->
+        
+    <!-- 
+        Suppress check of XML binding generated code packages 
+    --> 
+    <suppress checks="[a-zA-Z0-9]*" files="jalview[\\/]schemabinding[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="jalview[\\/]binding[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="jalview[\\/]json[\\/]binding[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="jalview[\\/]xml[\\/]binding[\\/]*"/>
+        
+    <!-- 
+       Suppress check of externally sourced code 
+    --> 
+    <suppress checks="[a-zA-Z0-9]*" files="com[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="ext[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="org[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="uk[\\/]*"/>
+    
+    <!-- 
+       ImportControl can only handle one top level package
+    -->
+    <suppress checks="ImportControl" files="MCview[\\/]*" />
+    <suppress checks="ImportControl" files="vamsas[\\/]*" />
+    
+    <!--  
+       Suppress checks by name 
+    -->
+       <suppress checks="FinalLocalVariable" files=".*\.java"/>
+    
+    <!--  
+       Suppress checks by id 
+    -->
+       <suppress id="InterfaceNaming" files=".*\.java"/>
+       <suppress id="NoStaticInitialization" files=".*\.java"/>
+         
+</suppressions>
\ No newline at end of file
diff --git a/utils/checkstyle/checkstyle.xml b/utils/checkstyle/checkstyle.xml
new file mode 100644 (file)
index 0000000..8a5f14f
--- /dev/null
@@ -0,0 +1,601 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+<!--
+       Jalview Checkstyle configuration file
+-->
+<module name="Checker">
+       <!-- Default severity is warning -->
+       <property name="severity" value="warning"/>
+       <property name="fileExtensions" value="java,properties"/>
+
+       <!-- 
+               Add any metrics that you wish to suppress to the following file.
+       -->
+       <module name="SuppressionFilter">
+               <property name="file" value="${basedir}/utils/checkstyle/checkstyle-suppress.xml"/>
+       </module>
+
+       <!-- 
+               Allow suppression of rules by comments, e.g.:
+               // CHECKSTYLE.OFF: ParameterNumber
+               ..method declaration
+               // CHECKSTYLE.ON: ParameterNumber
+       -->
+       <module name="SuppressionCommentFilter">
+               <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
+               <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
+               <property name="checkFormat" value="$1"/>
+       </module>
+
+       <!-- 
+               Check language bundles have the same keys and no duplicates
+               (ensure Checkstyle is configured to scan non-source files)
+        -->
+       <module name="Translation">
+               <property name="fileExtensions" value="properties"/>
+               <property name="baseName" value="^Messages.*$"/>
+       </module>
+       <module name="UniqueProperties">
+           <property name="fileExtensions" value="properties" />
+               <property name="severity" value="error"/>
+       </module>
+
+       <!--
+               Maximum line count for source files
+               (note this can't be inside TreeWalker)
+       -->
+       <module name="FileLength">
+               <property name="max" value="1200"/>
+               <property name="fileExtensions" value="java"/>
+       </module>
+       
+       <module name="TreeWalker">
+
+               <property name="tabWidth" value="4"/>
+
+               <!-- 
+                       Enables parsing of suppressions comments
+                       see http://checkstyle.sourceforge.net/config_filters.html#SuppressionCommentFilter 
+               -->
+               <module name="FileContentsHolder"/>
+
+       <!-- ****************************** -->
+       <!--         NAMING STANDARDS       -->
+       <!-- ****************************** -->
+               
+               <!--
+                       Naming convention for member fields. Start with (optional) underscore, then
+                       lower case, then camel case; no internal underscores
+               -->
+               <module name="MemberName">
+                       <property name="format" value="^_?[a-z][a-zA-Z0-9]*$"/>
+               </module>
+
+               <!-- 
+                       Naming convention for methods. Start with (optional) underscore, then
+                       lower case, then camel case; no internal underscores
+               -->
+               <module name="MethodName">
+                       <property name="format" value="^_?[a-z]([a-zA-Z0-9]+)*$"/>
+               </module>
+
+               <!--
+                       Name pattern for local final variables.
+               -->
+               <module name="LocalFinalVariableName">
+                       <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+               </module>
+
+               <!--
+                       Name pattern for local variables
+               -->
+               <module name="LocalVariableName">
+                       <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+               </module>
+               
+               <!--
+                       Name pattern for constants (static final fields)
+               -->
+               <module name="ConstantName">
+                       <property name="format" value="^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"/>
+               </module>
+
+               <!--
+                       Name pattern for parameters (note no underscores allowed)
+               -->
+               <module name="ParameterName">
+                       <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+               </module>
+               
+               <!--
+                       Name pattern for static (non-final) fields
+               -->
+               <module name="StaticVariableName">
+                       <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
+               </module>
+               
+               <!--
+                       Name pattern for classes
+               -->
+               <module name="TypeName">
+                       <property name="format" value="[A-Z][a-zA-Z0-9]*$"/>
+                       <property name="tokens" value="CLASS_DEF"/>
+               </module>
+               
+               <!--
+                       Name pattern for interfaces. All interfaces names must end with 'I'.
+                       ** currently suppressed in checkstyle-suppress.xml **
+               -->
+               <module name="TypeName">
+                       <property name="id" value="InterfaceNaming"/>
+                       <property name="format" value="^[A-Z][a-zA-Z0-9]*I$"/>
+                       <property name="tokens" value="INTERFACE_DEF"/>
+                       <message key="name.invalidPattern" value="Interface names should end in a I"/>
+               </module>
+
+               <!--
+                       Java package name pattern 
+               -->
+               <module name="PackageName">
+                       <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
+               </module>
+
+       <!-- ****************************** -->
+       <!--         LAYOUT AND STYLE       -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Only one top level type per source file
+               -->
+               <module name="OuterTypeNumber"/>
+               
+               <!-- 
+                       Ensure a class has a package declaration
+                -->
+               <module name="PackageDeclaration"/>
+               
+               <!--
+                       see http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-141855.html#1852
+                       1. Class (static) variables: public, protected, package, private
+                       2. Instance variables: public, protected, package, private
+                       3. Constructors
+                       4. Methods
+                -->
+               <module name="DeclarationOrder"/>
+               
+               <!-- 
+                       Modifier order should conform to JLS
+                       see http://checkstyle.sourceforge.net/config_modifier.html#ModifierOrder 
+                       public protected private abstract static final transient volatile synchronized native strictfp          
+               -->
+               <module name="ModifierOrder"/>
+               
+               <!-- 
+                       Declare variables in separate statements, for readability and bug avoidance
+                -->
+               <module name="MultipleVariableDeclarations"/>
+               
+               <!-- 
+                       Don't have more than one statement on a line
+                       (code formatting on save may enforce this anyway)
+                -->
+               <module name="OneStatementPerLine"/>
+
+               <!-- 
+                       Declare variables close to their point of first use 
+                       (doesn't handle variables used inside loops very well) 
+               -->
+               <module name="VariableDeclarationUsageDistance">
+                       <property name="allowedDistance" value="5" />
+                       <message key="variable.declaration.usage.distance.extend"
+                               value="Distance between declaration of ''{0}'' and its first use is {1}, suggested maximum is {2}. Consider moving, or make final if it may not be modified." />
+               </module>
+       
+               <!-- 
+                       Only use blocks within control statements 
+               -->
+               <module name="AvoidNestedBlocks" />
+
+               <!-- 
+                       Require at least a comment within a block. 
+                       Note this will accept auto-generated // TODO comments, 
+                       (but they should be flagged up by the TodoComment rule) 
+               -->
+               <module name="EmptyBlock">
+                       <property name="option" value="text"/>
+               </module>
+               
+               <!-- 
+                       Require braces round all code blocks within if/else/for/do/while 
+               -->
+               <module name="NeedBraces"/>
+               
+               <!--
+                       Disallow empty ';' statements
+               -->
+               <module name="EmptyStatement"/>
+
+               <!-- 
+                       Maximum number of return statements for a method
+               -->
+               <module name="ReturnCount">
+                       <property name="max" value="4"/>
+               </module>
+
+               <!-- 
+                       Don't use modifiers in contexts where their value is not optional,
+                       for example all interface methods are always public
+                       see http://checkstyle.sourceforge.net/config_modifier.html#RedundantModifier
+               -->
+               <module name="RedundantModifier"/>
+               
+               <!-- 
+                       Variables whose value is not modified should be declared final, both to show the
+                   program's intent, and to  allow compiler optimisation
+                   ** currently suppressed in checkstyle-suppress.xml **
+                -->            
+               <module name="FinalLocalVariable">
+                       <property name="tokens" value="VARIABLE_DEF" />
+               </module>
+
+               <!-- 
+                       Disallows shorthand of assigning values within an expression 
+               -->
+               <module name="InnerAssignment"/>
+
+               <!-- 
+                       Use Java style array declarations to assist in readability 
+               -->
+               <module name="ArrayTypeStyle"/>
+
+               <!-- 
+                       Use L not l to define a long constant 
+               -->
+               <module name="UpperEll"/>
+
+       <!-- ****************************** -->
+       <!--           SIZE LIMITS          -->
+       <!-- ****************************** -->
+
+               <!--
+                       Maximum line count for methods
+               -->
+               <module name="MethodLength">
+                       <property name="tokens" value="METHOD_DEF"/>
+                       <property name="max" value="50"/>
+                       <property name="countEmpty" value="false"/>
+               </module>
+
+               <!--
+                       Maximum statement count for methods, constructors,
+                       instance initialisation and static initialisation blocks
+               -->
+               <module name="ExecutableStatementCount">
+                       <property name="max" value="30"/>
+                       <property name="tokens" value="METHOD_DEF"/>
+               </module>
+               <module name="ExecutableStatementCount">
+                       <property name="max" value="30"/>
+                       <property name="tokens" value="CTOR_DEF"/>
+               </module>
+               <module name="ExecutableStatementCount">
+                       <property name="max" value="4"/>
+                       <property name="tokens" value="INSTANCE_INIT"/>
+               </module>
+               <module name="ExecutableStatementCount">
+                       <property name="id" value="NoStaticInitialization"/>
+                       <property name="max" value="0"/>
+                       <property name="tokens" value="STATIC_INIT"/>
+               </module>
+
+               <!--
+                       Maximum parameter count for methods 
+               -->
+               <module name="ParameterNumber">
+                       <property name="max" value="5"/>
+               </module>
+
+               <!--
+                       Maximum line length for anonymous inner classes
+               -->
+               <module name="AnonInnerLength">
+                       <property name="max" value="40"/>
+               </module>
+
+       <!-- ****************************** -->
+       <!--            IMPORTS             -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Ensures that there are no redundant or unused imports.
+                    Should be handled by Save actions if using Eclipse 
+               -->
+               <module name="RedundantImport"/>
+               <module name="UnusedImports"/>
+
+               <!--
+                       Disallow * imports; may also be enforced by IDE Save Actions
+               -->
+               <module name="AvoidStarImport"/>
+
+               <!-- 
+                       Disallow import of sun.* packages as they are not portable 
+               -->
+               <module name="IllegalImport"/>
+
+               <!--
+                       rules as to what packages each package may (not) import
+                       see http://checkstyle.sourceforge.net/config_imports.html#ImportControl 
+               -->
+               <module name="ImportControl">
+                   <property name="file" value="${basedir}/utils/checkstyle/import-control.xml"/>
+                       <property name="severity" value="error"/>
+               </module>
+               
+       <!-- ****************************** -->
+       <!--         CATCH and THROW        -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Disallow catch of Exception, RunTimeException or Error 
+               -->
+               <module name="IllegalCatch"/>
+
+               <!-- 
+                       Disallow throw of Exception, RunTimeException or Error 
+               -->
+               <module name="IllegalThrows"/>
+
+       <!-- ****************************** -->
+       <!--          CODING CHECKS         -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Check for use of factory method rather than constructor for specified classes
+                       e.g. Boolean.valueOf(true) rather than new Boolean(true)
+               -->
+               <module name="IllegalInstantiation">
+                       <property name="classes" value="java.lang.Boolean"/>
+               </module>
+               
+               <!--
+                       Check that "string".equals(value) is used rather than value.equals("string")
+               -->
+               <module name="EqualsAvoidNull"/>
+
+               <!--
+                       Check that equals() and hashCode() are always overridden together
+               -->
+               <module name="EqualsHashCode"/>
+               
+               <!-- 
+                       Require switch statements to include a default 
+               -->
+               <module name="MissingSwitchDefault"/>
+               
+               <!-- 
+                       Check that switch default follows all case statements
+                -->
+               <module name="DefaultComesLast">
+                       <property name="severity" value="error"/>
+               </module>
+               
+               <!-- 
+                       Disallows fall-through in switch statements 
+                       i.e. a case without a break, return, throw or continue 
+                       NB a comment with the words "fall[s] through" suppresses this message
+                -->
+               <module name="FallThrough">
+                       <property name="severity" value="error" />
+               </module>
+               
+               <!-- 
+                       Warn if boolean expressions can be simplified 
+               -->
+               <module name="SimplifyBooleanExpression"/>
+
+               <!-- 
+                       Warn if boolean return expressions can be simplified 
+               -->
+               <module name="SimplifyBooleanReturn"/>
+
+               <!--
+                       Classes with only private constructors should be declared final
+               -->
+               <module name="FinalClass"/>
+               
+               <!-- 
+                       Classes with only static methods should not be instantiable,
+                       so should declare a private default constructor.
+               -->
+               <module name="HideUtilityClassConstructor"/>
+               
+               <!-- 
+                       An Interface should declare methods (do not use to define constants only) 
+               -->
+               <module name="InterfaceIsType"/>
+               
+               <!-- 
+                       Disallow public fields in classes (other than constants) 
+               -->
+               <module name="VisibilityModifier">
+                       <property name="packageAllowed" value="true"/>
+                       <property name="allowPublicImmutableFields" value="true"/>
+               </module>
+               
+               <!-- 
+                       Checks that a local variable or a parameter does not shadow a field that is defined in the same class.
+                       Note this should also be configured as a compiler warning in the IDE. 
+               -->
+               <module name="HiddenField"/> 
+
+               <!-- 
+                       Check that proper logging is used.
+                       This may be suppressed in the class that provides logging functions.
+               -->
+               <module name="RegexpSinglelineJava">
+                       <property name="id" value="NoSysout" />
+                       <property name="format" value="System\.out\.println"/>
+                       <property name="ignoreComments" value="true"/>
+                       <message key="regexp.exceeded" value="Should use jalview.bin.Cache.log for logging"/>
+               </module>
+               <module name="RegexpSinglelineJava">
+                       <property name="id" value="NoSyserr" />
+                       <property name="format" value="System\.err\.println"/>
+                       <property name="ignoreComments" value="true"/>
+                       <message key="regexp.exceeded" value="Should use jalview.bin.Cache.log for logging"/>
+               </module>
+
+               <!--
+                       Checks that classes that define a covariant equals() method also override 
+                       method equals(java.lang.Object).
+                -->
+               <module name="CovariantEquals"/>
+               
+               <!-- 
+                       Checks that there are no "magic numbers" (numeric literals) 
+               -->
+               <module name="MagicNumber">
+                       <property name="ignoreNumbers" value="-1,0,1,2"/>
+               </module>
+               
+               <!-- 
+                       Check that  loop control variables are not modified inside the for block
+                -->
+               <module name="ModifiedControlVariable">
+               </module>
+               
+               <!-- 
+                       Checks that string literals are not used with == or !=.
+                -->
+               <module name="StringLiteralEquality">
+               </module>
+               
+               <!-- 
+                       Don't override clone - it never works! 
+                -->
+               <module name="NoClone"/>
+               
+               <!-- 
+                       Checks that clone() invokes super.clone()
+                       (for classes that break the NoClone rule)
+                -->
+               <module name="SuperClone"/>
+               
+               <!-- 
+                       Checks that finalize() invokes super.finalize()
+                -->
+               <module name="SuperFinalize"/>
+               
+               <!-- 
+                       Disallow assignment of parameters.
+                -->
+               <module name="ParameterAssignment"/>
+
+               <!-- 
+                       Checks for multiple occurrences of the same string literal within a single file.
+                       NB - does not check for the same string in different files.
+                -->
+               <module name="MultipleStringLiterals">
+                       <property name="allowedDuplicates" value="1"/>
+               </module>
+               
+               <!-- 
+                       Checks that exceptions are immutable (have only final fields)
+                -->
+               <module name="MutableException"/>
+               
+               <!-- 
+                       A general rule to check for source text tokens that shouldn't be there
+                       see http://checkstyle.sourceforge.net/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html
+                -->
+               <module name="IllegalToken">
+                  <property name="tokens" value="LITERAL_ASSERT"/>
+               </module>
+
+       <!-- ****************************** -->
+       <!--           COMPLEXITY           -->
+       <!-- ****************************** -->
+               
+               <!-- 
+                       Restrict the number of number of &&, ||, &, |  and ^ in an expression.
+                       Note that the operators & and | are not only integer bitwise operators, they are also the 
+                       non-shortcut versions of the boolean operators && and ||.
+                -->
+               <module name="BooleanExpressionComplexity">
+                       <property name="max" value="3"/>
+               </module>
+               
+               <!-- 
+                       This metric measures the number of instantiations of other classes within the given class. 
+                       The higher the DAC, the more complex the data structure of the system.
+                -->
+               <module name="ClassDataAbstractionCoupling">
+                       <property name="max" value="7"/>
+               </module>
+               
+               <!-- 
+                       The number of other classes a class relies on. A high number indicates over-complex
+                       class interdependencies that might benefit from refactoring.
+                -->
+               <module name="ClassFanOutComplexity">
+               <property name="max" value="10"/>
+       </module>
+               
+               <!-- 
+                       Checks cyclomatic complexity against a specified limit. The complexity is a measure 
+                       of the minimum number of possible paths through the source and therefore the number of required 
+                       tests. Consider re-factoring if at or above 10.
+                -->
+               <module name="CyclomaticComplexity">
+                       <property name="max" value="15"/>
+               </module>
+               
+               <!-- 
+                       The NPATH metric computes the number of possible execution paths through a function. It takes 
+                       into account the nesting of conditional statements and multi-part boolean expressions 
+                       (e.g., A && B, C || D, etc.).
+                -->
+               <module name="NPathComplexity">
+                       <property name="max" value="200"/>
+               </module>
+
+               <!-- 
+                       Maximum number of throws statements in a method
+                -->
+               <module name="ThrowsCount">
+                       <property name="max" value="2"/>
+               </module>
+               
+               <!-- 
+                       Maximum if-else depth
+                -->
+               <module name="NestedIfDepth">
+                       <property name="max" value="4"/>
+               </module>
+
+               <!-- 
+                       Restricts nested try blocks to a specified depth. 
+                -->
+               <module name="NestedTryDepth">
+                       <property name="max" value="2"/>
+               </module>
+
+       <!-- ****************************** -->
+       <!--              TODO              -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Checks for uncommented main() methods (debugging leftovers)
+                -->
+               <module name="UncommentedMain"/>
+
+               <!-- 
+                       Check for TODO and similar comments 
+               -->
+               <module name="TodoComment">
+                       <property name="format" value="(TODO)|(FIXME)|(DOCUMENT ME)"/>
+               </module>
+
+       </module>
+</module>
diff --git a/utils/checkstyle/import-control.xml b/utils/checkstyle/import-control.xml
new file mode 100644 (file)
index 0000000..b11b567
--- /dev/null
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE import-control PUBLIC
+    "-//Puppy Crawl//DTD Import Control 1.1//EN"
+    "http://www.puppycrawl.com/dtds/import_control_1_1.dtd">
+    
+    <!--
+       see http://checkstyle.sourceforge.net/config_imports.html#ImportControl
+       allow/disallow rules propagate to sub-packages 
+       unless local-only="true" is specified
+       
+       note this can handle only one top-level package, so ImportControl is
+       suppressed for MCview and vamsas in checkstyle-suppress.xml
+       (all rules are suppressed for com/ext/org/uk)
+    -->
+   <import-control pkg="jalview">
+   
+               <allow pkg="java"/>
+               <allow pkg="jalview"/>
+               <allow pkg="com.stevesoft.pat"/>
+               
+               <subpackage name="appletgui">
+               <disallow pkg="jalview.gui"/>
+               <disallow pkg="jalview.ws"/>
+               <allow pkg="org.jmol"/>
+               <allow pkg="javajs.awt" class="jalview.appletgui.AppletJmolBinding"/>
+           </subpackage>
+               
+               <subpackage name="bin">
+               <allow pkg="groovy"/>
+               <allow pkg="org.apache.log4j" class="jalview.bin.Cache"/>
+               <allow pkg="javax.swing" class="jalview.bin.Jalview"/>
+               <allow pkg="netscape.javascript" class="jalview.bin.JalviewLite"/>
+           </subpackage>
+               
+               <subpackage name="datamodel">
+               <disallow pkg="jalview.gui"/>
+               <allow pkg="fr.orsay.lri.varna"/>
+                       <subpackage name="xdb">
+                               <subpackage name="embl">
+                               <allow pkg="org.exolab.castor"/>
+                           </subpackage>
+                   </subpackage>
+           </subpackage>
+               
+               <subpackage name="fts">
+               <allow pkg="javax.swing"/>
+               <allow pkg="javax.ws"/>
+               <allow pkg="org.json"/>
+               <allow pkg="com.sun.jersey"/>
+           </subpackage>
+               
+               <subpackage name="gui">
+               <allow pkg="javax.swing"/>
+               <allow pkg="javax.help"/>
+               <allow pkg="javax.imageio"/>
+               <allow pkg="ext.edu.ucsf"/>
+               <allow pkg="net.miginfocom"/>
+               <allow pkg="org.jibble"/>
+               <allow pkg="org.jmol"/>
+               <allow pkg="org.openscience"/>
+               <allow pkg="org.exolab.castor" class="jalview.gui.Jalview2XML"/>
+               <allow pkg="org.robsite" class="jalview.gui.BlogReader"/>
+               <allow pkg="org.apache.log4j" class="jalview.gui.Console"/>
+               <allow pkg="org.apache.log4j" class="jalview.gui.JalviewAppender"/>
+               <allow pkg="org.biodas" class="jalview.gui.DasSourceBrowser"/>
+               <allow pkg="compbio.metadata" class="jalview.gui.WsJobParameters"/>
+               <allow pkg="fr.orsay.lri.varna" class="jalview.gui.AppVarna"/>
+               <allow pkg="fr.orsay.lri.varna" class="jalview.gui.AppVarnaBinding"/>
+               <allow pkg="uk.ac.vamsas" class="jalview.gui.VamsasApplication"/>
+           </subpackage>
+               
+               <subpackage name="jbgui">
+               <allow pkg="javax.swing"/>
+               <allow pkg="net.miginfocom"/>
+           </subpackage>
+
+               <subpackage name="httpserver">
+               <allow pkg="javax.servlet"/>
+               <allow pkg="org.eclipse.jetty"/>
+           </subpackage>
+
+               <subpackage name="io">
+               <allow pkg="javax.swing"/>
+               <allow pkg="org.jfree"/>
+               <allow pkg="org.json"/>
+               <allow pkg="org.jsoup"/>
+               <allow pkg="uk.ac.ebi"/>
+               <allow pkg="uk.ac.vamsas"/>
+               <allow pkg="fr.orsay.lri.varna"/>
+               <allow pkg="MCview"/>
+               </subpackage>       
+                               
+               <subpackage name="javascript">
+               <allow pkg="netscape.javascript"/>
+           </subpackage>
+
+               <subpackage name="rest">
+               <allow pkg="javax.servlet"/>
+               </subpackage>
+
+               <subpackage name="structure">
+               <allow pkg="MCview"/>
+               </subpackage>
+
+               <subpackage name="util">
+               <allow pkg="javax.swing"/>
+               <allow pkg="javax.imageio"/>
+               <allow pkg="org.jfree"/>
+               <allow pkg="org.jibble"/>
+               </subpackage>
+
+               <subpackage name="ws">
+               <allow pkg="javax.swing"/>
+               <allow pkg="javax.xml"/>
+               <allow pkg="ext.vamsas"/>
+               <allow pkg="compbio"/>
+               <allow pkg="MCview"/>
+               <allow pkg="org.apache.http"/>
+               <allow pkg="org.apache.james"/>
+               <allow pkg="org.apache.axis"/>
+               <allow pkg="org.biodas.jdas"/>
+               <allow pkg="org.exolab.castor"/>
+               <allow pkg="uk.ac.ebi"/>
+               <allow pkg="vamsas.objects"/>
+               </subpackage>
+
+   </import-control>
\ No newline at end of file