Merge branch 'develop' into bug/JAL-2154projectMappings
authorJim Procter <jprocter@issues.jalview.org>
Tue, 23 Aug 2016 10:17:42 +0000 (11:17 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Tue, 23 Aug 2016 10:17:42 +0000 (11:17 +0100)
Conflicts:
 src/jalview/gui/AlignFrame.java
  - pushed raise warning dialog to CrossRefAction
 test/jalview/analysis/AlignmentUtilsTests.java
  - simple merge
 test/jalview/io/Jalview2xmlTests.java
  - pushed updated BeforeClass setup to Jalview2xmlBase

52 files changed:
help/html/features/clarguments.html
help/html/features/dasfeatures.html
help/html/features/varna.html
help/html/io/index.html
help/html/na/index.html
help/html/releases.html
help/html/webServices/index.html
help/html/webServices/newsreader.html
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/MCview/Atom.java
src/MCview/PDBChain.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/Grouping.java
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/bin/Cache.java
src/jalview/bin/Jalview.java
src/jalview/bin/JalviewLite.java
src/jalview/controller/AlignViewController.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/xdb/embl/EmblEntry.java
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/ext/jmol/JmolParser.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/BlogReader.java
src/jalview/gui/CrossRefAction.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqPanel.java
src/jalview/io/FormatAdapter.java
src/jalview/io/JSONFile.java
src/jalview/io/MSFfile.java
src/jalview/io/PfamFile.java
src/jalview/util/Platform.java
test/MCview/AtomTest.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/GroupingTest.java
test/jalview/bin/CacheTest.java [new file with mode: 0644]
test/jalview/controller/AlignViewControllerTest.java [new file with mode: 0644]
test/jalview/datamodel/ColumnSelectionTest.java
test/jalview/datamodel/SequenceTest.java
test/jalview/io/AnnotatedPDBFileInputTest.java
test/jalview/io/FormatAdapterTest.java [new file with mode: 0644]
test/jalview/io/Jalview2xmlBase.java
test/jalview/io/Jalview2xmlTests.java
test/jalview/io/StockholmFileTest.java
test/jalview/structure/StructureSelectionManagerTest.java
test/jalview/ws/jabaws/RNAStructExportImport.java
utils/HelpLinksChecker.java

index 63a14af..1d6f62d 100644 (file)
     </tr>
     <tr>
       <td>
+        <div align="center">-nonews</div>
+      <td>
+        <div align="left">Disable check for <a href="../webServices/newsreader.html">Jalview news</a> on startup (not recommended other than for classroom / demo usage)</div>
+      </td>
+    </tr>
+    <tr>
+      <td>
         <div align="center">-nousagestats</div>
       <td>
         <div align="left">Turn off google analytics usage tracking</div>
index c0c888a..90958ae 100644 (file)
@@ -29,8 +29,7 @@
   </p>
   <p>
     Jalview includes a client for retrieving sequences and their
-    features via the <a href="http://www.biodas.org">Distributed
-      Annotation System</a>.
+    features via the Distributed Annotation System.
   </p>
   <ol>
     <li>Open the Feature Settings panel by selecting &quot;View
   <p>
     <em>DAS support was introduced in Jalview Version 2.1.</em>
   </p>
+  <br/>
+  <p>
+    <em>The DAS registry at http://www.dasregistry.org was decommissioned early in 2015. An unmaintained mirror is currently hosted at http://www.ebi.ac.uk/das-srv/registry/.</em>
+  </p>
   <p>&nbsp;
 </body>
 </html>
index 029edce..ce446f3 100644 (file)
@@ -27,7 +27,7 @@
     <strong>The VARNA RNA Viewer</strong>
   </p>
   <p>
-    <a href="http://varna.lri.fr/index.html">VARNA</a> was integrated
+    <a href="http://varna.lri.fr">VARNA</a> was integrated
     into Jalview 2.8 to allow interactive viewing of RNA secondary
     structure annotation. It is opened by selecting the <strong>&quot;Structure&#8594;View
       Structure:&quot;</strong> option in the <a href="../menus/popupMenu.html">sequence
index c0a89cf..d2196c1 100755 (executable)
       NBRF/PIR (including MODELLER variant), Pfam/Stockholm</em>
   </p>
   <p>
-    The EBI has <a href="http://www.ebi.ac.uk/help/formats.html">examples</a>
-    of these file formats.
-  </p>
-  <p>
     Additionally, whole sets of coloured and annotated alignments and
     trees can be read from a <a href="../features/jalarchive.html">Jalview
       (jar) format</a> file using <strong>Desktop&#8594;Load
index ae4c1c6..de2741b 100644 (file)
@@ -65,7 +65,7 @@ td {
       annotation.</li>
     <li><em>Clustal files</em> - certain RNA alignment programs,
       such as <a
-      href="http://rna.informatik.uni-freiburg.de:8080/LocARNA.jsp"
+      href="http://rna.informatik.uni-freiburg.de/LocARNA"
     >LocaRNA</a> output consensus RNA secondary structure lines in the
       line normally reserved for the Clustal consensus line in a clustal
       file.</li>
index dfb747f..5a5020a 100755 (executable)
                 region export in flat file generation</li>
 
               <li>Export alignment views for display with the <a
-                href="http://biojs.io/d/msa">BioJS MSAViewer</a></li>
+                href="http://msa.biojs.net/">BioJS MSAViewer</a></li>
 
               <li>Export scrollable SVG in HTML page</li>
               <li>Optional embedding of BioJSON data when exporting
index b03bb9d..1463554 100755 (executable)
@@ -90,7 +90,7 @@
     services were maintained by the Barton group at the University of
     Dundee, and ran programs on the Life Sciences High-performance
     Computing Cluster. With the advent of <a
-      href="http://www.compbio.dundee.ac.uk/JABAWS"
+      href="http://www.compbio.dundee.ac.uk/jabaws"
     >JABAWS</a>, however, it is possible for anyone to host Jalview web
     services.
   </p>
index ee69290..5ec088a 100644 (file)
@@ -19,7 +19,7 @@
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  -->
-<head>Jalview Desktop RSS News Reader
+<head>
 </head>
 <body>
   <p>
   <p>The news reader will be launched automatically when you start
     the Desktop if new items are available. Should you want to browse
     older items, however, you can open it manually from the 'Jalview
-    news reader' option in the Desktop's 'Tools' menu.</p>
-  <img src="jalviewrssreader.gif" align="center" width="513"
-    height="337" alt="Snapshot of the Jalview Desktop's RSS reader"
-  />
-  <p>
+    news reader' option in the Desktop's <a href="../menus/desktopMenu.html">'Tools' menu</a>.</p><br/>
+  <div style="text-align: center;"><img src="jalviewrssreader.gif" width="513"
+    height="337" alt="Snapshot of the Jalview Desktop's RSS reader"/></div>
+
+  <br/><p>
     The <em>Jalview news reader</em> was introduced in <a
       href="http://www.jalview.org/releaseHistory.html#Jalview2.7"
     >Jalview version 2.7</a>. Its implementation is based on <a
       href="http://jswingreader.sourceforge.net/"
     >JSwingReader</a>.
   </p>
+  <br/><em>From Jalview 2.10.0, check for news on startup can be disabled with <a href="../features/clarguments.html">command-line parameter</a> &#39;-nonews&#39;. 
+  This is not recommended for normal use, but may be useful to avoid interruptions when teaching, demonstrating, recording etc.</em>
 </body>
 </html>
index 40c311f..ac665e3 100644 (file)
@@ -1028,9 +1028,11 @@ error.implementation_error_need_to_have_httpresponse = Implementation Error: nee
 error.dbrefsource_implementation_exception =DBRefSource Implementation Exception
 error.implementation_error_dbinstance_must_implement_interface = Implmentation Error - getDbInstances must be given a class that implements jalview.ws.seqfetcher.DbSourceProxy (was given{0})
 error.implementation_error_must_init_dbsources =Implementation error. Must initialise dbSources
-label.view_controller_toggled_marked = {0} {1} columns containing features of type {2}  across {3} sequence(s)
+label.view_controller_toggled_marked = {0} {1} columns {2} features of type {3}  across {4} sequence(s)
 label.toggled = Toggled
 label.marked = Marked
+label.containing = containing
+label.not_containing = not containing
 label.not = not
 label.no_feature_of_type_found = No features of type {0} found.
 label.submission_params = Submission {0}
@@ -1308,3 +1310,7 @@ status.fetching_3d_structures_for = Fetching 3D Structure for {0}
 status.obtaining_mapping_with_sifts = Obtaining mapping with SIFTS
 status.obtaining_mapping_with_nw_alignment = Obtaining mapping with NW alignment
 status.exporting_alignment_as_x_file = Exporting alignment as {0} file
+label.column = Column
+label.sequence = Sequence
+label.cant_map_cds = Unable to map CDS to protein\nCDS missing or incomplete
+label.operation_failed = Operation failed
index 618178d..92d4d78 100644 (file)
@@ -468,8 +468,9 @@ label.create_sequence_feature = Crear funci
 label.edit_sequence = Editar secuencia
 label.edit_sequences = Editar secuencias
 label.sequence_details = Detalles de la secuencia
-label.jmol_help = Ayuda de Jmol 
-label.all = Todo
+label.jmol_help = Ayuda de Jmol
+# Todos/Todas is gender-sensitive, but currently only used for feminine (cadena / anotación)! 
+label.all = Todas
 label.sort_by = Ordenar por
 label.sort_by_score = Ordenar por puntuación
 label.sort_by_density = Ordenar por densidad
@@ -961,9 +962,11 @@ error.implementation_error_need_to_have_httpresponse = Error de implementaci
 error.dbrefsource_implementation_exception = Excepción de implementación DBRefSource
 error.implementation_error_dbinstance_must_implement_interface = Error de Implementación- getDbInstances debe recibir una clase que implemente jalview.ws.seqfetcher.DbSourceProxy (recibió {0})
 error.implementation_error_must_init_dbsources =Error de implementación. Debe inicializar dbSources
-label.view_controller_toggled_marked = {0} {1} columnas conteniendo características del tipo {2} en {3} secuencia(s)
+label.view_controller_toggled_marked = {0} {1} columnas {2} características del tipo {3} en {4} secuencia(s)
 label.toggled = Invertida
 label.marked = Marcada
+label.containing = conteniendo
+label.not_containing = no conteniendo
 label.not = no
 label.no_feature_of_type_found = No se han encontrado características del tipo {0}.
 label.submission_params = Envío {0}
@@ -1314,3 +1317,7 @@ status.fetching_3d_structures_for_selected_entries=Buscando las estructuras 3D p
 status.fetching_dbrefs_for_sequences_without_valid_refs=Buscando referencias para {0} secuencia(s) sin referencia válida necesaria para mapeado SIFTS
 status.obtaining_mapping_with_nw_alignment=Obteniendo mapeo por alineamiento Needleman y Wunsch
 status.exporting_alignment_as_x_file = Exportando alineamiento como fichero tipo {0}
+label.column = Columna
+label.sequence = Secuencia
+label.cant_map_cds = No se pudo mapear CDS a proteína\nDatos CDS faltantes o incompletos
+label.operation_failed = Operación fallada
index ab038a0..fe6a0ac 100755 (executable)
@@ -81,7 +81,7 @@ public class Atom
     chain = str.substring(21, 22);
 
     resNumber = Integer.parseInt(str.substring(22, 26).trim());
-    resNumIns = str.substring(22, 27);
+    resNumIns = str.substring(22, 27).trim();
     insCode = str.substring(26, 27).charAt(0);
     this.x = (new Float(str.substring(30, 38).trim()).floatValue());
     this.y = (new Float(str.substring(38, 46).trim()).floatValue());
index 885521b..cf794b6 100755 (executable)
@@ -29,8 +29,8 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ResidueProperties;
-import jalview.structure.StructureMapping;
 import jalview.structure.StructureImportSettings;
+import jalview.structure.StructureMapping;
 
 import java.awt.Color;
 import java.util.List;
@@ -582,12 +582,13 @@ public class PDBChain
         {
           for (AlignmentAnnotation ana : sequence.getAnnotation())
           {
-            List<AlignmentAnnotation> transfer = sq
+            List<AlignmentAnnotation> transfer = dsq
                     .getAlignmentAnnotations(ana.getCalcId(), ana.label);
             if (transfer == null || transfer.size() == 0)
             {
               ana = new AlignmentAnnotation(ana);
               ana.liftOver(dsq, sqmpping);
+              dsq.addAlignmentAnnotation(ana);
               // mapping.transfer(ana);
             }
             else
index 9aaaed2..d93f42f 100644 (file)
@@ -2634,13 +2634,16 @@ public class AlignmentUtils
       return false; // should only pass alignments with datasets here
     }
 
-    // map from dataset sequence to alignment sequence
-    Map<SequenceI, SequenceI> alignedDatasets = new HashMap<SequenceI, SequenceI>();
+    // map from dataset sequence to alignment sequence(s)
+    Map<SequenceI, List<SequenceI>> alignedDatasets = new HashMap<SequenceI, List<SequenceI>>();
     for (SequenceI seq : aligned.getSequences())
     {
-      // JAL-2110: fail if two or more alignment sequences have a common dataset
-      // sequence.
-      alignedDatasets.put(seq.getDatasetSequence(), seq);
+      SequenceI ds = seq.getDatasetSequence();
+      if (alignedDatasets.get(ds) == null)
+      {
+        alignedDatasets.put(ds, new ArrayList<SequenceI>());
+      }
+      alignedDatasets.get(ds).add(seq);
     }
 
     /*
@@ -2656,17 +2659,22 @@ public class AlignmentUtils
     }
 
     /*
-     * second pass - copy aligned sequences
+     * second pass - copy aligned sequences;
+     * heuristic rule: pair off sequences in order for the case where 
+     * more than one shares the same dataset sequence 
      */
     for (SequenceI seq : unaligned.getSequences())
     {
-      SequenceI alignedSequence = alignedDatasets.get(seq
+      List<SequenceI> alignedSequences = alignedDatasets.get(seq
               .getDatasetSequence());
-      // JAL-2110: fail if two or more alignment sequences have common dataset
-      // sequence.
       // TODO: getSequenceAsString() will be deprecated in the future
       // TODO: need to leave to SequenceI implementor to update gaps
-      seq.setSequence(alignedSequence.getSequenceAsString());
+      seq.setSequence(alignedSequences.get(0).getSequenceAsString());
+      if (alignedSequences.size() > 0)
+      {
+        // pop off aligned sequences (except the last one)
+        alignedSequences.remove(0);
+      }
     }
 
     return true;
index 51a818f..2ddd015 100644 (file)
@@ -127,6 +127,11 @@ public class Grouping
         }
       }
     }
+
+    /*
+     * get selected columns (in the order they were selected);
+     * note this could include right-to-left ranges
+     */
     int[] spos = new int[cs.getSelected().size()];
     int width = -1;
     int i = 0;
@@ -134,7 +139,7 @@ public class Grouping
     {
       spos[i++] = pos.intValue();
     }
-    ;
+
     for (i = 0; i < sequences.length; i++)
     {
       int slen = sequences[i].getLength();
index 948c8e5..b6cc7c0 100644 (file)
@@ -70,8 +70,6 @@ import java.util.Vector;
 public class APopupMenu extends java.awt.PopupMenu implements
         ActionListener, ItemListener
 {
-  private static final String ALL_ANNOTATIONS = "All";
-
   Menu groupMenu = new Menu();
 
   MenuItem editGroupName = new MenuItem();
@@ -1326,7 +1324,8 @@ public class APopupMenu extends java.awt.PopupMenu implements
     showMenu.removeAll();
     hideMenu.removeAll();
 
-    final List<String> all = Arrays.asList(ALL_ANNOTATIONS);
+    final List<String> all = Arrays.asList(new String[] { MessageManager
+            .getString("label.all") });
     addAnnotationTypeToShowHide(showMenu, forSequences, "", all, true, true);
     addAnnotationTypeToShowHide(hideMenu, forSequences, "", all, true,
             false);
index 77700d0..e5475f8 100755 (executable)
@@ -22,8 +22,11 @@ package jalview.appletgui;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceI;
 import jalview.renderer.AnnotationRenderer;
 import jalview.renderer.AwtRenderPanelI;
+import jalview.schemes.ResidueProperties;
+import jalview.util.Comparison;
 import jalview.util.MessageManager;
 
 import java.awt.Color;
@@ -158,12 +161,12 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
 
     if (evt.getActionCommand().equals(REMOVE))
     {
-      for (int sel : av.getColumnSelection().getSelected())
+      for (int index : av.getColumnSelection().getSelected())
       {
-        // TODO: JAL-2001 check if applet has faulty 'REMOVE' selected columns
-        // of
-        // annotation if selection includes hidden columns
-        anot[sel] = null;
+        if (av.getColumnSelection().isVisible(index))
+        {
+          anot[index] = null;
+        }
       }
     }
     else if (evt.getActionCommand().equals(LABEL))
@@ -457,21 +460,67 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       }
     }
 
-    int res = evt.getX() / av.getCharWidth() + av.getStartRes();
+    int column = evt.getX() / av.getCharWidth() + av.getStartRes();
 
     if (av.hasHiddenColumns())
     {
-      res = av.getColumnSelection().adjustForHiddenColumns(res);
+      column = av.getColumnSelection().adjustForHiddenColumns(column);
     }
 
-    if (row > -1 && res < aa[row].annotations.length
-            && aa[row].annotations[res] != null)
+    if (row > -1 && column < aa[row].annotations.length
+            && aa[row].annotations[column] != null)
     {
-      StringBuffer text = new StringBuffer("Sequence position " + (res + 1));
-      if (aa[row].annotations[res].description != null)
+      StringBuilder text = new StringBuilder();
+      text.append(MessageManager.getString("label.column")).append(" ")
+              .append(column + 1);
+      String description = aa[row].annotations[column].description;
+      if (description != null && description.length() > 0)
       {
-        text.append("  " + aa[row].annotations[res].description);
+        text.append("  ").append(description);
       }
+
+      /*
+       * if the annotation is sequence-specific, show the sequence number
+       * in the alignment, and (if not a gap) the residue and position
+       */
+      SequenceI seqref = aa[row].sequenceRef;
+      if (seqref != null)
+      {
+        int seqIndex = av.getAlignment().findIndex(seqref);
+        if (seqIndex != -1)
+        {
+          text.append(", ")
+                  .append(MessageManager.getString("label.sequence"))
+                  .append(" ").append(seqIndex + 1);
+          char residue = seqref.getCharAt(column);
+          if (!Comparison.isGap(residue))
+          {
+            text.append(" ");
+            String name;
+            if (av.getAlignment().isNucleotide())
+            {
+              name = ResidueProperties.nucleotideName.get(String
+                      .valueOf(residue));
+              text.append(" Nucleotide: ").append(
+                      name != null ? name : residue);
+            }
+            else
+            {
+              name = 'X' == residue ? "X" : ('*' == residue ? "STOP"
+                      : ResidueProperties.aa2Triplet.get(String
+                              .valueOf(residue)));
+              text.append(" Residue: ").append(
+                      name != null ? name : residue);
+            }
+            int residuePos = seqref.findPosition(column);
+            text.append(" (").append(residuePos).append(")");
+            // int residuePos = seqref.findPosition(column);
+            // text.append(residue).append(" (")
+            // .append(residuePos).append(")");
+          }
+        }
+      }
+
       ap.alignFrame.statusBar.setText(text.toString());
     }
   }
index 4be7830..df71ccc 100755 (executable)
@@ -38,6 +38,7 @@ import java.text.SimpleDateFormat;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
+import java.util.Locale;
 import java.util.Properties;
 import java.util.TreeSet;
 
@@ -237,6 +238,15 @@ public class Cache
   private final static String DEFAULT_PDB_FILE_PARSER = StructureImportSettings.StructureParser.JMOL_PARSER
           .toString();
 
+  /*
+   * a date formatter using a fixed (rather than the user's) locale; 
+   * this ensures that date properties can be written and re-read successfully
+   * even if the user changes their locale setting
+   */
+  private static final DateFormat date_format = SimpleDateFormat
+          .getDateTimeInstance(SimpleDateFormat.MEDIUM,
+                  SimpleDateFormat.MEDIUM, Locale.UK);
+
   /**
    * Initialises the Jalview Application Log
    */
@@ -884,31 +894,32 @@ public class Cache
   {
     setProperty(property, jalview.util.Format.getHexString(colour));
   }
-
-  public static final DateFormat date_format = SimpleDateFormat
-          .getDateTimeInstance();
-
+  
   /**
-   * store a date in a jalview property
+   * Stores a formatted date in a jalview property, using a fixed locale.
    * 
-   * @param string
-   * @param time
+   * @param propertyName
+   * @param date
+   * @return the formatted date string
    */
-  public static void setDateProperty(String property, Date time)
+  public static String setDateProperty(String propertyName, Date date)
   {
-    setProperty(property, date_format.format(time));
+    String formatted = date_format.format(date);
+    setProperty(propertyName, formatted);
+    return formatted;
   }
 
   /**
-   * read a date stored in a jalview property
+   * Reads a date stored in a Jalview property, parses it (using a fixed locale
+   * format) and returns as a Date, or null if parsing fails
    * 
-   * @param property
-   * @return valid date as stored by setDateProperty, or null
+   * @param propertyName
+   * @return
    * 
    */
-  public static Date getDateProperty(String property)
+  public static Date getDateProperty(String propertyName)
   {
-    String val = getProperty(property);
+    String val = getProperty(propertyName);
     if (val != null)
     {
       try
@@ -917,7 +928,7 @@ public class Cache
       } catch (Exception ex)
       {
         System.err.println("Invalid or corrupt date in property '"
-                + property + "' : value was '" + val + "'");
+                + propertyName + "' : value was '" + val + "'");
       }
     }
     return null;
index 76ae3ff..3294c26 100755 (executable)
@@ -328,7 +328,6 @@ public class Jalview
             Cache.log.debug("Starting questionnaire with default url: "
                     + defurl);
             desktop.checkForQuestionnaire(defurl);
-
           }
         }
       }
@@ -336,11 +335,12 @@ public class Jalview
       {
         System.err.println("CMD [-noquestionnaire] executed successfully!");
       }
-      desktop.checkForNews();
-    }
 
-    if (!isHeadlessMode())
-    {
+      if (!aparser.contains("nonews"))
+      {
+        desktop.checkForNews();
+      }
+
       BioJsHTMLOutput.updateBioJS();
     }
 
@@ -782,6 +782,7 @@ public class Jalview
                     + "-eps FILE\tCreate EPS file FILE from alignment.\n"
                     + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
                     + "-noquestionnaire\tTurn off questionnaire check.\n"
+                    + "-nonews\tTurn off check for Jalview news.\n"
                     + "-nousagestats\tTurn off google analytics tracking for this session.\n"
                     + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
                     // +
index 13e4b7e..210a07a 100644 (file)
@@ -466,17 +466,11 @@ public class JalviewLite extends Applet implements
         SequenceI rs = sel.getSequenceAt(0);
         start = rs.findIndex(start);
         end = rs.findIndex(end);
-        if (csel != null)
-        {
-          List<Integer> cs = csel.getSelected();
-          // note - the following actually clears cs as well, since
-          // csel.getSelected returns a reference. Need to check if we need to
-          // have a concurrentModification exception thrown here
-          csel.clear();
-          for (Integer selectedCol : cs)
-          {
-            csel.addElement(rs.findIndex(selectedCol));
-          }
+        List<Integer> cs = csel.getSelected();
+        csel.clear();
+        for (Integer selectedCol : cs)
+        {
+          csel.addElement(rs.findIndex(selectedCol));
         }
       }
       sel.setStartRes(start);
index 24439ca..82c8d38 100644 (file)
@@ -169,157 +169,136 @@ public class AlignViewController implements AlignViewControllerI
     // JBPNote this routine could also mark rows, not just columns.
     // need a decent query structure to allow all types of feature searches
     BitSet bs = new BitSet();
-    int alw, alStart;
-    SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null ? viewport
-            .getAlignment() : viewport.getSelectionGroup());
-    alStart = sqcol.getStartRes();
-    alw = sqcol.getEndRes() + 1;
+    SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null || extendCurrent) ? viewport
+            .getAlignment() : viewport.getSelectionGroup();
+
+    int nseq = findColumnsWithFeature(featureType, sqcol, bs);
+
+    ColumnSelection cs = viewport.getColumnSelection();
+    if (cs == null)
+    {
+      cs = new ColumnSelection();
+    }
+
+    if (bs.cardinality() > 0 || invert)
+    {
+      boolean changed = cs.markColumns(bs, sqcol.getStartRes(),
+              sqcol.getEndRes(), invert, extendCurrent, toggle);
+      if (changed)
+      {
+        viewport.setColumnSelection(cs);
+        alignPanel.paintAlignment(true);
+        int columnCount = invert ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
+                - bs.cardinality()
+                : bs.cardinality();
+        avcg.setStatus(MessageManager.formatMessage(
+                "label.view_controller_toggled_marked",
+                new String[] {
+                    MessageManager.getString(toggle ? "label.toggled"
+                            : "label.marked"),
+                    String.valueOf(columnCount),
+                    MessageManager
+                            .getString(invert ? "label.not_containing"
+                                    : "label.containing"), featureType,
+                    Integer.valueOf(nseq).toString() }));
+        return true;
+      }
+    }
+    else
+    {
+      avcg.setStatus(MessageManager.formatMessage(
+              "label.no_feature_of_type_found",
+              new String[] { featureType }));
+      if (!extendCurrent)
+      {
+        cs.clear();
+        alignPanel.paintAlignment(true);
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Sets a bit in the BitSet for each column (base 0) in the sequence
+   * collection which includes the specified feature type. Returns the number of
+   * sequences which have the feature in the selected range.
+   * 
+   * @param featureType
+   * @param sqcol
+   * @param bs
+   * @return
+   */
+  static int findColumnsWithFeature(String featureType,
+          SequenceCollectionI sqcol, BitSet bs)
+  {
+    final int startPosition = sqcol.getStartRes() + 1; // converted to base 1
+    final int endPosition = sqcol.getEndRes() + 1;
     List<SequenceI> seqs = sqcol.getSequences();
     int nseq = 0;
     for (SequenceI sq : seqs)
     {
-      int tfeat = 0;
+      boolean sequenceHasFeature = false;
       if (sq != null)
       {
-        SequenceFeature[] sf = sq.getSequenceFeatures();
-        if (sf != null)
+        SequenceFeature[] sfs = sq.getSequenceFeatures();
+        if (sfs != null)
         {
+          /*
+           * check whether the feature start/end (base 1) 
+           * overlaps the selection start/end
+           */
           int ist = sq.findIndex(sq.getStart());
           int iend = sq.findIndex(sq.getEnd());
-          if (iend < alStart || ist > alw)
+          if (iend < startPosition || ist > endPosition)
           {
             // sequence not in region
             continue;
           }
-          for (SequenceFeature sfpos : sf)
+          for (SequenceFeature sf : sfs)
           {
-            // future functionalty - featureType == null means mark columns
+            // future functionality - featureType == null means mark columns
             // containing all displayed features
-            if (sfpos != null && (featureType.equals(sfpos.getType())))
+            if (sf != null && (featureType.equals(sf.getType())))
             {
-              tfeat++;
               // optimisation - could consider 'spos,apos' like cursor argument
               // - findIndex wastes time by starting from first character and
               // counting
 
-              int i = sq.findIndex(sfpos.getBegin());
-              int j = sq.findIndex(sfpos.getEnd());
-              if (j < alStart || i > alw)
+              int i = sq.findIndex(sf.getBegin());
+              int j = sq.findIndex(sf.getEnd());
+              if (j < startPosition || i > endPosition)
               {
                 // feature is outside selected region
                 continue;
               }
-              if (i < alStart)
+              sequenceHasFeature = true;
+              if (i < startPosition)
               {
-                i = alStart;
+                i = startPosition;
               }
               if (i < ist)
               {
                 i = ist;
               }
-              if (j > alw)
+              if (j > endPosition)
               {
-                j = alw;
+                j = endPosition;
               }
               for (; i <= j; i++)
               {
-                bs.set(i - 1);
+                bs.set(i - 1); // convert to base 0
               }
             }
           }
         }
 
-        if (tfeat > 0)
+        if (sequenceHasFeature)
         {
           nseq++;
         }
       }
     }
-    ColumnSelection cs = viewport.getColumnSelection();
-    if (bs.cardinality() > 0 || invert)
-    {
-      boolean changed = false;
-      if (cs == null)
-      {
-        cs = new ColumnSelection();
-      }
-      else
-      {
-        if (!extendCurrent)
-        {
-          changed = !cs.isEmpty();
-          cs.clear();
-        }
-      }
-      if (invert)
-      {
-        // invert only in the currently selected sequence region
-        for (int i = bs.nextClearBit(alStart), ibs = bs.nextSetBit(alStart); i >= alStart
-                && i < (alw);)
-        {
-          if (ibs < 0 || i < ibs)
-          {
-            changed = true;
-            if (toggle && cs.contains(i))
-            {
-              cs.removeElement(i++);
-            }
-            else
-            {
-              cs.addElement(i++);
-            }
-          }
-          else
-          {
-            i = bs.nextClearBit(ibs);
-            ibs = bs.nextSetBit(i);
-          }
-        }
-      }
-      else
-      {
-        for (int i = bs.nextSetBit(alStart); i >= alStart; i = bs
-                .nextSetBit(i + 1))
-        {
-          changed = true;
-          if (toggle && cs.contains(i))
-          {
-            cs.removeElement(i);
-          }
-          else
-          {
-            cs.addElement(i);
-          }
-        }
-      }
-      if (changed)
-      {
-        viewport.setColumnSelection(cs);
-        alignPanel.paintAlignment(true);
-        avcg.setStatus(MessageManager.formatMessage(
-                "label.view_controller_toggled_marked",
-                new String[] {
-                    (toggle ? MessageManager.getString("label.toggled")
-                            : MessageManager.getString("label.marked")),
-                    (invert ? (Integer.valueOf((alw - alStart)
-                            - bs.cardinality()).toString()) : (Integer
-                            .valueOf(bs.cardinality()).toString())),
-                    featureType, Integer.valueOf(nseq).toString() }));
-        return true;
-      }
-    }
-    else
-    {
-      avcg.setStatus(MessageManager.formatMessage(
-              "label.no_feature_of_type_found",
-              new String[] { featureType }));
-      if (!extendCurrent && cs != null)
-      {
-        cs.clear();
-        alignPanel.paintAlignment(true);
-      }
-    }
-    return false;
+    return nseq;
   }
 
   @Override
index aaf70b8..7ef2a68 100644 (file)
@@ -290,11 +290,12 @@ public class ColumnSelection
   /**
    * Returns a list of selected columns. The list contains no duplicates but is
    * not necessarily ordered. It also may include columns hidden from the
-   * current view
+   * current view. This returns a copy of the actual list, and changes to the
+   * copy will not affect the selection.
    */
   public List<Integer> getSelected()
   {
-    return selection.getList();
+    return new ArrayList<Integer>(selection.getList());
   }
 
   /**
@@ -985,7 +986,7 @@ public class ColumnSelection
           SequenceI[] seqs)
   {
     int i, iSize = seqs.length;
-    String selection[] = new String[iSize];
+    String selections[] = new String[iSize];
     if (hiddenColumns != null && hiddenColumns.size() > 0)
     {
       for (i = 0; i < iSize; i++)
@@ -1027,18 +1028,18 @@ public class ColumnSelection
           visibleSeq.append(seqs[i].getSequence(blockStart, end));
         }
 
-        selection[i] = visibleSeq.toString();
+        selections[i] = visibleSeq.toString();
       }
     }
     else
     {
       for (i = 0; i < iSize; i++)
       {
-        selection[i] = seqs[i].getSequenceAsString(start, end);
+        selections[i] = seqs[i].getSequenceAsString(start, end);
       }
     }
 
-    return selection;
+    return selections;
   }
 
   /**
@@ -1703,4 +1704,78 @@ public class ColumnSelection
     return true;
   }
 
+  /**
+   * Updates the column selection depending on the parameters, and returns true
+   * if any change was made to the selection
+   * 
+   * @param markedColumns
+   *          a set identifying marked columns (base 0)
+   * @param startCol
+   *          the first column of the range to operate over (base 0)
+   * @param endCol
+   *          the last column of the range to operate over (base 0)
+   * @param invert
+   *          if true, deselect marked columns and select unmarked
+   * @param extendCurrent
+   *          if true, extend rather than replacing the current column selection
+   * @param toggle
+   *          if true, toggle the selection state of marked columns
+   * 
+   * @return
+   */
+  public boolean markColumns(BitSet markedColumns, int startCol,
+          int endCol, boolean invert, boolean extendCurrent, boolean toggle)
+  {
+    boolean changed = false;
+    if (!extendCurrent && !toggle)
+    {
+      changed = !this.isEmpty();
+      clear();
+    }
+    if (invert)
+    {
+      // invert only in the currently selected sequence region
+      int i = markedColumns.nextClearBit(startCol);
+      int ibs = markedColumns.nextSetBit(startCol);
+      while (i >= startCol && i <= endCol)
+      {
+        if (ibs < 0 || i < ibs)
+        {
+          changed = true;
+          if (toggle && contains(i))
+          {
+            removeElement(i++);
+          }
+          else
+          {
+            addElement(i++);
+          }
+        }
+        else
+        {
+          i = markedColumns.nextClearBit(ibs);
+          ibs = markedColumns.nextSetBit(i);
+        }
+      }
+    }
+    else
+    {
+      int i = markedColumns.nextSetBit(startCol);
+      while (i >= startCol && i <= endCol)
+      {
+        changed = true;
+        if (toggle && contains(i))
+        {
+          removeElement(i);
+        }
+        else
+        {
+          addElement(i);
+        }
+        i = markedColumns.nextSetBit(i + 1);
+      }
+    }
+    return changed;
+  }
+
 }
index 56b1325..06e929d 100644 (file)
@@ -49,8 +49,7 @@ import java.util.regex.Pattern;
  * Castor binding file
  * 
  * For example:
- * http://www.ebi.ac.uk/Tools/dbfetch/dbfetch?db=ena_sequence&id=J03321
- * &format=emblxml
+ * http://www.ebi.ac.uk/ena/data/view/J03321&display=xml
  * 
  * @see embl_mapping.xml
  */
@@ -188,6 +187,10 @@ public class EmblEntry
   public SequenceI getSequence(String sourceDb, List<SequenceI> peptides)
   {
     SequenceI dna = makeSequence(sourceDb);
+    if (dna == null)
+    {
+      return null;
+    }
     dna.setDescription(description);
     DBRefEntry retrievedref = new DBRefEntry(sourceDb,
             getSequenceVersion(), accession);
@@ -240,6 +243,12 @@ public class EmblEntry
    */
   SequenceI makeSequence(String sourceDb)
   {
+    if (sequence == null)
+    {
+      System.err.println("No sequence was returned for ENA accession "
+              + accession);
+      return null;
+    }
     SequenceI dna = new Sequence(sourceDb + "|" + accession,
             sequence.getSequence());
     return dna;
index f9cfe05..72efdc1 100644 (file)
@@ -35,9 +35,11 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    * changes to Ensembl REST API
    * @see https://github.com/Ensembl/ensembl-rest/wiki/Change-log
    */
-  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "4.4";
+  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "4.6";
 
-  private static final String LATEST_ENSEMBL_REST_VERSION = "4.5";
+  private static final String LATEST_ENSEMBL_REST_VERSION = "4.6";
+
+  private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
 
   private static Map<String, EnsemblInfo> domainData;
 
@@ -453,9 +455,8 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
       if (laterVersion)
       {
         System.err.println(String.format(
-                "Expected %s REST version %s but found %s", getDbSource(),
-                expected,
-                version));
+                "Expected %s REST version %s but found %s, see %s",
+                getDbSource(), expected, version, REST_CHANGE_LOG));
       }
       info.restVersion = version;
     } catch (Throwable t)
index ea969ff..848e7db 100644 (file)
@@ -217,7 +217,8 @@ public class JmolParser extends StructureFile implements JmolStatusListener
         curAtom.resNumber = atom.getResno();
         curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
                 .getIndex()] : Float.valueOf(atom.getOccupancy100());
-        curAtom.resNumIns = "" + curAtom.resNumber + curAtom.insCode;
+        curAtom.resNumIns = ("" + curAtom.resNumber + curAtom.insCode)
+                .trim();
         curAtom.tfactor = atom.getBfactor100() / 100f;
         curAtom.type = 0;
         // significantAtoms.add(curAtom);
index f06ca94..87d5933 100644 (file)
@@ -1269,6 +1269,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   void makeAlignmentImage(jalview.util.ImageMaker.TYPE type, File file)
   {
+    int boarderBottomOffset = 5;
     long pSessionId = System.currentTimeMillis();
     headless = (System.getProperty("java.awt.headless") != null && System
             .getProperty("java.awt.headless").equals("true"));
@@ -1305,14 +1306,15 @@ public class AlignmentPanel extends GAlignmentPanel implements
         }
 
         im = new jalview.util.ImageMaker(this, type, imageAction,
-                aDimension.getWidth(), aDimension.getHeight(), file,
+                aDimension.getWidth(), aDimension.getHeight()
+                        + boarderBottomOffset, file,
                 imageTitle, alignFrame, pSessionId, headless);
         if (av.getWrapAlignment())
         {
           if (im.getGraphics() != null)
           {
             printWrappedAlignment(im.getGraphics(), aDimension.getWidth(),
-                    aDimension.getHeight(), 0);
+                    aDimension.getHeight() + boarderBottomOffset, 0);
             im.writeImage();
           }
         }
index bb311ef..3c9a13e 100755 (executable)
@@ -26,6 +26,8 @@ import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.AnnotationRenderer;
 import jalview.renderer.AwtRenderPanelI;
+import jalview.schemes.ResidueProperties;
+import jalview.util.Comparison;
 import jalview.util.MessageManager;
 
 import java.awt.AlphaComposite;
@@ -47,6 +49,8 @@ import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import java.awt.image.BufferedImage;
+import java.util.Collections;
+import java.util.List;
 
 import javax.swing.JColorChooser;
 import javax.swing.JMenuItem;
@@ -288,9 +292,12 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
     if (evt.getActionCommand().equals(REMOVE))
     {
-      for (int sel : av.getColumnSelection().getSelected())
+      for (int index : av.getColumnSelection().getSelected())
       {
-        anot[sel] = null;
+        if (av.getColumnSelection().isVisible(index))
+        {
+          anot[index] = null;
+        }
       }
     }
     else if (evt.getActionCommand().equals(LABEL))
@@ -351,7 +358,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       }
     }
     else
-    // HELIX OR SHEET
+    // HELIX, SHEET or STEM
     {
       char type = 0;
       String symbol = "\u03B1";
@@ -412,22 +419,37 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
       }
     }
+
     av.getAlignment().validateAnnotation(aa[activeRow]);
     ap.alignmentChanged();
-
+    ap.alignFrame.setMenusForViewport();
     adjustPanelHeight();
     repaint();
 
     return;
   }
 
-  private String collectAnnotVals(Annotation[] anot, String label2)
+  /**
+   * Returns any existing annotation concatenated as a string. For each
+   * annotation, takes the description, if any, else the secondary structure
+   * character (if type is HELIX, SHEET or STEM), else the display character (if
+   * type is LABEL).
+   * 
+   * @param anots
+   * @param type
+   * @return
+   */
+  private String collectAnnotVals(Annotation[] anots, String type)
   {
-    String collatedInput = "";
+    // TODO is this method wanted? why? 'last' is not used
+
+    StringBuilder collatedInput = new StringBuilder(64);
     String last = "";
     ColumnSelection viscols = av.getColumnSelection();
     // TODO: refactor and save av.getColumnSelection for efficiency
-    for (int index : viscols.getSelected())
+    List<Integer> selected = viscols.getSelected();
+    Collections.sort(selected);
+    for (int index : selected)
     {
       // always check for current display state - just in case
       if (!viscols.isVisible(index))
@@ -435,22 +457,22 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         continue;
       }
       String tlabel = null;
-      if (anot[index] != null)
+      if (anots[index] != null)
       { // LML added stem code
-        if (label2.equals(HELIX) || label2.equals(SHEET)
-                || label2.equals(STEM) || label2.equals(LABEL))
+        if (type.equals(HELIX) || type.equals(SHEET)
+                || type.equals(STEM) || type.equals(LABEL))
         {
-          tlabel = anot[index].description;
+          tlabel = anots[index].description;
           if (tlabel == null || tlabel.length() < 1)
           {
-            if (label2.equals(HELIX) || label2.equals(SHEET)
-                    || label2.equals(STEM))
+            if (type.equals(HELIX) || type.equals(SHEET)
+                    || type.equals(STEM))
             {
-              tlabel = "" + anot[index].secondaryStructure;
+              tlabel = "" + anots[index].secondaryStructure;
             }
             else
             {
-              tlabel = "" + anot[index].displayCharacter;
+              tlabel = "" + anots[index].displayCharacter;
             }
           }
         }
@@ -458,13 +480,13 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         {
           if (last.length() > 0)
           {
-            collatedInput += " ";
+            collatedInput.append(" ");
           }
-          collatedInput += tlabel;
+          collatedInput.append(tlabel);
         }
       }
     }
-    return collatedInput;
+    return collatedInput.toString();
   }
 
   /**
@@ -628,10 +650,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
   }
 
   /**
-   * DOCUMENT ME!
+   * Constructs the tooltip, and constructs and displays a status message, for
+   * the current mouse position
    * 
    * @param evt
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseMoved(MouseEvent evt)
@@ -657,7 +679,6 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       if (evt.getY() < height)
       {
         row = i;
-
         break;
       }
     }
@@ -668,64 +689,140 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       return;
     }
 
-    int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int column = (evt.getX() / av.getCharWidth()) + av.getStartRes();
 
     if (av.hasHiddenColumns())
     {
-      res = av.getColumnSelection().adjustForHiddenColumns(res);
+      column = av.getColumnSelection().adjustForHiddenColumns(column);
     }
 
-    if (row > -1 && aa[row].annotations != null
-            && res < aa[row].annotations.length)
+    AlignmentAnnotation ann = aa[row];
+    if (row > -1 && ann.annotations != null
+            && column < ann.annotations.length)
     {
-      if (aa[row].graphGroup > -1)
+      buildToolTip(ann, column, aa);
+      setStatusMessage(column, ann);
+    }
+    else
+    {
+      this.setToolTipText(null);
+      ap.alignFrame.statusBar.setText(" ");
+    }
+  }
+
+  /**
+   * Builds a tooltip for the annotation at the current mouse position.
+   * 
+   * @param ann
+   * @param column
+   * @param anns
+   */
+  void buildToolTip(AlignmentAnnotation ann, int column,
+          AlignmentAnnotation[] anns)
+  {
+    if (ann.graphGroup > -1)
+    {
+      StringBuilder tip = new StringBuilder(32);
+      tip.append("<html>");
+      for (int i = 0; i < anns.length; i++)
       {
-        StringBuffer tip = new StringBuffer("<html>");
-        for (int gg = 0; gg < aa.length; gg++)
+        if (anns[i].graphGroup == ann.graphGroup
+                && anns[i].annotations[column] != null)
         {
-          if (aa[gg].graphGroup == aa[row].graphGroup
-                  && aa[gg].annotations[res] != null)
+          tip.append(anns[i].label);
+          String description = anns[i].annotations[column].description;
+          if (description != null && description.length() > 0)
           {
-            tip.append(aa[gg].label + " "
-                    + aa[gg].annotations[res].description + "<br>");
+            tip.append(" ").append(description);
           }
-        }
-        if (tip.length() != 6)
-        {
-          tip.setLength(tip.length() - 4);
-          this.setToolTipText(tip.toString() + "</html>");
+          tip.append("<br>");
         }
       }
-      else if (aa[row].annotations[res] != null
-              && aa[row].annotations[res].description != null
-              && aa[row].annotations[res].description.length() > 0)
+      if (tip.length() != 6)
       {
-        this.setToolTipText(JvSwingUtils.wrapTooltip(true,
-                aa[row].annotations[res].description));
+        tip.setLength(tip.length() - 4);
+        this.setToolTipText(tip.toString() + "</html>");
       }
-      else
+    }
+    else if (ann.annotations[column] != null)
+    {
+      String description = ann.annotations[column].description;
+      if (description != null && description.length() > 0)
       {
-        // clear the tooltip.
-        this.setToolTipText(null);
+        this.setToolTipText(JvSwingUtils.wrapTooltip(true, description));
       }
+    }
+    else
+    {
+      // clear the tooltip.
+      this.setToolTipText(null);
+    }
+  }
 
-      if (aa[row].annotations[res] != null)
+  /**
+   * Constructs and displays the status bar message
+   * 
+   * @param column
+   * @param ann
+   */
+  void setStatusMessage(int column, AlignmentAnnotation ann)
+  {
+    /*
+     * show alignment column and annotation description if any
+     */
+    StringBuilder text = new StringBuilder(32);
+    text.append(MessageManager.getString("label.column")).append(" ")
+            .append(column + 1);
+
+    if (ann.annotations[column] != null)
+    {
+      String description = ann.annotations[column].description;
+      if (description != null && description.trim().length() > 0)
       {
-        StringBuffer text = new StringBuffer("Sequence position "
-                + (res + 1));
+        text.append("  ").append(description);
+      }
+    }
 
-        if (aa[row].annotations[res].description != null)
+    /*
+     * if the annotation is sequence-specific, show the sequence number
+     * in the alignment, and (if not a gap) the residue and position
+     */
+    SequenceI seqref = ann.sequenceRef;
+    if (seqref != null)
+    {
+      int seqIndex = av.getAlignment().findIndex(seqref);
+      if (seqIndex != -1)
+      {
+        text.append(", ")
+                .append(MessageManager.getString("label.sequence"))
+                .append(" ")
+                .append(seqIndex + 1);
+        char residue = seqref.getCharAt(column);
+        if (!Comparison.isGap(residue))
         {
-          text.append("  " + aa[row].annotations[res].description);
+          text.append(" ");
+          String name;
+          if (av.getAlignment().isNucleotide())
+          {
+            name = ResidueProperties.nucleotideName.get(String
+                    .valueOf(residue));
+            text.append(" Nucleotide: ").append(
+                    name != null ? name : residue);
+          }
+          else
+          {
+            name = 'X' == residue ? "X" : ('*' == residue ? "STOP"
+                    : ResidueProperties.aa2Triplet.get(String
+                            .valueOf(residue)));
+            text.append(" Residue: ").append(name != null ? name : residue);
+          }
+          int residuePos = seqref.findPosition(column);
+          text.append(" (").append(residuePos).append(")");
         }
-
-        ap.alignFrame.statusBar.setText(text.toString());
       }
     }
-    else
-    {
-      this.setToolTipText(null);
-    }
+
+    ap.alignFrame.statusBar.setText(text.toString());
   }
 
   /**
index 2e72e17..ab9aad7 100644 (file)
@@ -41,6 +41,7 @@ import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -285,6 +286,7 @@ public class BlogReader extends JPanel
   /**
    * check if the news panel's container is visible
    */
+  @Override
   public boolean isVisible()
   {
     if (parent == null)
@@ -312,6 +314,7 @@ public class BlogReader extends JPanel
           xf.setContentPane(me);
           xf.addWindowListener(new WindowAdapter()
           {
+            @Override
             public void windowClosing(WindowEvent e)
             {
               ActionEvent actionEvent = new ActionEvent(this,
@@ -320,6 +323,7 @@ public class BlogReader extends JPanel
               exitAction.actionPerformed(actionEvent);
             }
 
+            @Override
             public void windowOpened(WindowEvent e)
             {
             }
@@ -367,9 +371,9 @@ public class BlogReader extends JPanel
               + " and lastDate is " + lastDate);
       for (Item i : (List<Item>) chan.getItems())
       {
+        Date published = i.getPublishDate();
         boolean isread = lastDate == null ? false
-                : (i.getPublishDate() != null && !lastDate.before(i
-                        .getPublishDate()));
+                : (published != null && !lastDate.before(published));
 
         if (!updating || updateItems)
         {
@@ -379,11 +383,11 @@ public class BlogReader extends JPanel
         {
           i.setRead(isread);
         }
-        if (i.getPublishDate() != null && !i.isRead())
+        if (published != null && !i.isRead())
         {
-          if (earliest == null || earliest.after(i.getPublishDate()))
+          if (earliest == null || earliest.after(published))
           {
-            earliest = i.getPublishDate();
+            earliest = published;
           }
         }
       }
@@ -420,11 +424,9 @@ public class BlogReader extends JPanel
       }
       if (lastDate != null)
       {
-        jalview.bin.Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
-                lastDate);
-        jalview.bin.Cache.log.debug("Saved last read date as "
-                + jalview.bin.Cache.date_format.format(lastDate));
-
+        String formatted = Cache.setDateProperty(
+                "JALVIEW_NEWS_RSS_LASTMODIFIED", lastDate);
+        Cache.log.debug("Saved last read date as " + formatted);
       }
     }
   }
@@ -472,6 +474,7 @@ public class BlogReader extends JPanel
 
     listItems.addMouseListener(new java.awt.event.MouseAdapter()
     {
+      @Override
       public void mouseClicked(MouseEvent e)
       {
         listItems_mouseClicked(e);
@@ -497,6 +500,7 @@ public class BlogReader extends JPanel
     }
     textDescription.addHyperlinkListener(new HyperlinkListener()
     {
+      @Override
       public void hyperlinkUpdate(HyperlinkEvent e)
       {
         if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
@@ -508,6 +512,7 @@ public class BlogReader extends JPanel
 
     listItems.addListSelectionListener(new ListSelectionListener()
     {
+      @Override
       public void valueChanged(ListSelectionEvent e)
       {
         if (e.getValueIsAdjusting() == false)
@@ -537,6 +542,7 @@ public class BlogReader extends JPanel
       _listItems = listItems;
     }
 
+    @Override
     public void actionPerformed(ActionEvent e)
     {
       Object o = _listItems.getSelectedValue();
@@ -550,6 +556,7 @@ public class BlogReader extends JPanel
       }
     }
 
+    @Override
     public void update(Object o)
     {
       setEnabled(true);
@@ -754,11 +761,10 @@ public class BlogReader extends JPanel
     lastread.set(1983, 01, 01);
     while (lastread.before(today))
     {
-      Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
-              lastread.getTime());
+      String formattedDate = Cache.setDateProperty(
+              "JALVIEW_NEWS_RSS_LASTMODIFIED", lastread.getTime());
       BlogReader me = new BlogReader();
-      System.out.println("Set last date to "
-              + jalview.bin.Cache.date_format.format(lastread.getTime()));
+      System.out.println("Set last date to " + formattedDate);
       if (me.isNewsNew())
       {
         Cache.log.debug("There is news to read.");
@@ -810,6 +816,7 @@ class ChannelsRenderer extends DefaultListCellRenderer
   private final static Icon _icon = new ImageIcon(
           Main.class.getResource("image/ComposeMail16.gif"));
 
+  @Override
   public Component getListCellRendererComponent(JList list, Object value,
           int index, boolean isSelected, boolean cellHasFocus)
   {
@@ -837,6 +844,7 @@ class ItemsRenderer extends DefaultListCellRenderer
   private final static Icon _icon = new ImageIcon(
           Main.class.getResource("image/ComposeMail16.gif"));
 
+  @Override
   public Component getListCellRendererComponent(JList list, Object value,
           int index, boolean isSelected, boolean cellHasFocus)
   {
index cb315d6..f0b0891 100644 (file)
@@ -37,6 +37,8 @@ import jalview.ws.SequenceFetcher;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.swing.JOptionPane;
+
 /**
  * Factory constructor and runnable for discovering and displaying
  * cross-references for a set of aligned sequences
@@ -119,6 +121,10 @@ public class CrossRefAction implements Runnable
                   xrefsAlignment.getSequencesArray());
           if (copyAlignment.getHeight() == 0)
           {
+            JOptionPane.showMessageDialog(alignFrame,
+                    MessageManager.getString("label.cant_map_cds"),
+                    MessageManager.getString("label.operation_failed"),
+                    JOptionPane.OK_OPTION);
             System.err.println("Failed to make CDS alignment");
           }
 
index 7d9e937..3b8ce37 100644 (file)
@@ -174,7 +174,8 @@ public class FeatureSettings extends JPanel implements
       public void mousePressed(MouseEvent evt)
       {
         selectedRow = table.rowAtPoint(evt.getPoint());
-        if (SwingUtilities.isRightMouseButton(evt))
+        boolean ctrlDown = Platform.isControlDown(evt);
+        if (SwingUtilities.isRightMouseButton(evt) && !ctrlDown)
         {
           popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
                   table.getValueAt(selectedRow, 1), fr.getMinMax(),
@@ -182,9 +183,11 @@ public class FeatureSettings extends JPanel implements
         }
         else if (evt.getClickCount() == 2)
         {
+          boolean invertSelection = evt.isAltDown();
+          boolean toggleSelection = ctrlDown;
+          boolean extendSelection = evt.isShiftDown();
           fr.ap.alignFrame.avc.markColumnsContainingFeatures(
-                  evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
-                  evt.isMetaDown(),
+                  invertSelection, extendSelection, toggleSelection,
                   (String) table.getValueAt(selectedRow, 0));
         }
       }
index 497f3ba..569fcec 100644 (file)
@@ -91,8 +91,6 @@ import javax.swing.JRadioButtonMenuItem;
  */
 public class PopupMenu extends JPopupMenu
 {
-  private static final String ALL_ANNOTATIONS = "All";
-
   JMenu groupMenu = new JMenu();
 
   JMenuItem groupName = new JMenuItem();
@@ -756,7 +754,8 @@ public class PopupMenu extends JPopupMenu
     showMenu.removeAll();
     hideMenu.removeAll();
 
-    final List<String> all = Arrays.asList(ALL_ANNOTATIONS);
+    final List<String> all = Arrays.asList(new String[] { MessageManager
+            .getString("label.all") });
     addAnnotationTypeToShowHide(showMenu, forSequences, "", all, true, true);
     addAnnotationTypeToShowHide(hideMenu, forSequences, "", all, true,
             false);
index e231c6f..316b6be 100755 (executable)
@@ -26,6 +26,7 @@ import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
@@ -221,7 +222,7 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
    */
   protected void leftMouseButtonPressed(MouseEvent evt, final int res)
   {
-    if (!evt.isControlDown() && !evt.isShiftDown())
+    if (!Platform.isControlDown(evt) && !evt.isShiftDown())
     {
       av.getColumnSelection().clear();
     }
index 8ebcc87..f476d41 100644 (file)
@@ -857,7 +857,8 @@ public class SeqPanel extends JPanel implements MouseListener,
      * Sequence number (if known), and sequence name.
      */
     String seqno = seq == -1 ? "" : " " + (seq + 1);
-    text.append("Sequence" + seqno + " ID: " + sequence.getName());
+    text.append("Sequence").append(seqno).append(" ID: ")
+            .append(sequence.getName());
 
     String residue = null;
     /*
index 4ec077f..6d94616 100755 (executable)
@@ -305,20 +305,6 @@ public class FormatAdapter extends AppletFormatAdapter
     return this.formatSequences(format, alignment, suffix);
   }
 
-  public AlignmentI readFile(String inFile, String type, String format)
-          throws java.io.IOException
-  {
-    AlignmentI al = super.readFile(inFile, type, format);
-    return al;
-  }
-
-  public AlignmentI readFromFile(FileParse source, String format)
-          throws java.io.IOException
-  {
-    AlignmentI al = super.readFromFile(source, format);
-    return al;
-  }
-
   /**
    * validate format is valid for IO in Application. This is basically the
    * AppletFormatAdapter.isValidFormat call with additional checks for
index 3cda444..653c071 100644 (file)
@@ -735,6 +735,10 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
   @Override
   public void configureForView(AlignmentViewPanel avpanel)
   {
+    if (avpanel == null)
+    {
+      return;
+    }
     super.configureForView(avpanel);
     AlignViewportI viewport = avpanel.getAlignViewport();
     AlignmentI alignment = viewport.getAlignment();
index f62ad81..ab510d5 100755 (executable)
@@ -22,12 +22,14 @@ package jalview.io;
 
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 import jalview.util.Format;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.StringTokenizer;
-import java.util.Vector;
 
 /**
  * DOCUMENT ME!
@@ -67,24 +69,23 @@ public class MSFfile extends AlignFile
   }
 
   /**
-   * DOCUMENT ME!
+   * Read and parse MSF sequence data
    */
   @Override
   public void parse() throws IOException
   {
-    int i = 0;
     boolean seqFlag = false;
-    String key = new String();
-    Vector headers = new Vector();
-    Hashtable seqhash = new Hashtable();
-    String line;
+    List<String> headers = new ArrayList<String>();
+    Hashtable<String, StringBuilder> seqhash = new Hashtable<String, StringBuilder>();
 
     try
     {
+      String line;
       while ((line = nextLine()) != null)
       {
         StringTokenizer str = new StringTokenizer(line);
 
+        String key = null;
         while (str.hasMoreTokens())
         {
           String inStr = str.nextToken();
@@ -93,31 +94,31 @@ public class MSFfile extends AlignFile
           if (inStr.indexOf("Name:") != -1)
           {
             key = str.nextToken();
-            headers.addElement(key);
+            headers.add(key);
           }
 
-          // if line has // set SeqFlag to 1 so we know sequences are coming
+          // if line has // set SeqFlag so we know sequences are coming
           if (inStr.indexOf("//") != -1)
           {
             seqFlag = true;
           }
 
           // Process lines as sequence lines if seqFlag is set
-          if ((inStr.indexOf("//") == -1) && (seqFlag == true))
+          if ((inStr.indexOf("//") == -1) && seqFlag)
           {
-            // seqeunce id is the first field
+            // sequence id is the first field
             key = inStr;
 
-            StringBuffer tempseq;
+            StringBuilder tempseq;
 
             // Get sequence from hash if it exists
             if (seqhash.containsKey(key))
             {
-              tempseq = (StringBuffer) seqhash.get(key);
+              tempseq = seqhash.get(key);
             }
             else
             {
-              tempseq = new StringBuffer();
+              tempseq = new StringBuilder(64);
               seqhash.put(key, tempseq);
             }
 
@@ -125,7 +126,8 @@ public class MSFfile extends AlignFile
             while (str.hasMoreTokens())
             {
               // append the word to the sequence
-              tempseq.append(str.nextToken());
+              String sequenceBlock = str.nextToken();
+              tempseq.append(sequenceBlock);
             }
           }
         }
@@ -139,11 +141,11 @@ public class MSFfile extends AlignFile
     this.noSeqs = headers.size();
 
     // Add sequences to the hash
-    for (i = 0; i < headers.size(); i++)
+    for (int i = 0; i < headers.size(); i++)
     {
-      if (seqhash.get(headers.elementAt(i)) != null)
+      if (seqhash.get(headers.get(i)) != null)
       {
-        String head = headers.elementAt(i).toString();
+        String head = headers.get(i);
         String seq = seqhash.get(head).toString();
 
         if (maxLength < head.length())
@@ -151,8 +153,11 @@ public class MSFfile extends AlignFile
           maxLength = head.length();
         }
 
-        // Replace ~ with a sensible gap character
-        seq = seq.replace('~', '-');
+        /*
+         * replace ~ (leading/trailing positions) with the gap character;
+         * use '.' as this is the internal gap character required by MSF
+         */
+        seq = seq.replace('~', '.');
 
         Sequence newSeq = parseId(head);
 
@@ -163,7 +168,7 @@ public class MSFfile extends AlignFile
       else
       {
         System.err.println("MSFFile Parser: Can't find sequence for "
-                + headers.elementAt(i));
+                + headers.get(i));
       }
     }
   }
@@ -211,15 +216,16 @@ public class MSFfile extends AlignFile
    * 
    * @return DOCUMENT ME!
    */
-  public String print(SequenceI[] seqs)
+  public String print(SequenceI[] sqs)
   {
 
-    boolean is_NA = jalview.util.Comparison.isNucleotide(seqs);
+    boolean is_NA = Comparison.isNucleotide(sqs);
 
-    SequenceI[] s = new SequenceI[seqs.length];
+    SequenceI[] s = new SequenceI[sqs.length];
 
-    StringBuffer out = new StringBuffer("!!" + (is_NA ? "NA" : "AA")
-            + "_MULTIPLE_ALIGNMENT 1.0");
+    StringBuilder out = new StringBuilder(256);
+    out.append("!!").append(is_NA ? "NA" : "AA")
+            .append("_MULTIPLE_ALIGNMENT 1.0");
     // TODO: JBPNote : Jalview doesn't remember NA or AA yet.
     out.append(newline);
     out.append(newline);
@@ -227,14 +233,16 @@ public class MSFfile extends AlignFile
     int maxid = 0;
     int i = 0;
 
-    while ((i < seqs.length) && (seqs[i] != null))
+    while ((i < sqs.length) && (sqs[i] != null))
     {
-      // Replace all internal gaps with . and external spaces with ~
-      s[i] = new Sequence(seqs[i].getName(), seqs[i].getSequenceAsString()
-              .replace('-', '.'), seqs[i].getStart(), seqs[i].getEnd());
+      /*
+       * modify to MSF format: uses '.' for internal gaps, 
+       * and '~' for leading or trailing gaps
+       */
+      String seqString = sqs[i].getSequenceAsString()
+              .replace('-', '.');
 
-      StringBuffer sb = new StringBuffer();
-      sb.append(s[i].getSequence());
+      StringBuilder sb = new StringBuilder(seqString);
 
       for (int ii = 0; ii < sb.length(); ii++)
       {
@@ -259,12 +267,12 @@ public class MSFfile extends AlignFile
           break;
         }
       }
+      s[i] = new Sequence(sqs[i].getName(), sb.toString(),
+              sqs[i].getStart(), sqs[i].getEnd());
 
-      s[i].setSequence(sb.toString());
-
-      if (s[i].getSequence().length > max)
+      if (sb.length() > max)
       {
-        max = s[i].getSequence().length;
+        max = sb.length();
       }
 
       i++;
index 71cc7f0..667da9f 100755 (executable)
@@ -108,7 +108,7 @@ public class PfamFile extends AlignFile
       }
       if (spces + 1 < line.length())
       {
-        tempseq.append(line.substring(spces + 1));
+        tempseq.append(line.substring(spces + 1).trim());
       }
     }
 
index 786f5bf..85a27f6 100644 (file)
@@ -78,10 +78,21 @@ public class Platform
     return f.toString();
   }
 
+  /**
+   * Answers true if the mouse event has Meta-down (on Mac) or Ctrl-down (on
+   * other o/s)
+   * 
+   * @param e
+   * @return
+   */
   public static boolean isControlDown(MouseEvent e)
   {
-    return (jalview.util.Platform.isAMac() ? (Toolkit.getDefaultToolkit()
-            .getMenuShortcutKeyMask() & e.getModifiers()) != 0 : e
-            .isControlDown());
+    if (isAMac())
+    {
+      return (Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() & e
+              .getModifiers()) != 0;
+      // could we use e.isMetaDown() here?
+    }
+    return e.isControlDown();
   }
 }
index 33d332a..21a79fe 100644 (file)
@@ -42,7 +42,7 @@ public class AtomTest
     assertEquals("GLN", a.resName);
     assertEquals("A", a.chain);
     assertEquals(48, a.resNumber);
-    assertEquals("  48 ", a.resNumIns);
+    assertEquals("48", a.resNumIns);
     assertEquals(' ', a.insCode);
     assertEquals(22.290, a.x, 0.00001);
     assertEquals(8.595, a.y, 0.00001);
index 237aaac..22bb680 100644 (file)
@@ -2449,10 +2449,9 @@ public class AlignmentUtilsTests
   {
     SequenceI dna1 = new Sequence("dna1", "cccGGGTTTaaa");
     SequenceI dna2 = new Sequence("dna2", "CCCgggtttAAA");
-    // See JAL-2110 - this test will fail due to alignAs not coping with
-    // distinct sequences sharing the same dataset sequence reference
-    SequenceI as1 = dna1.deriveSequence(), as2 = dna1.deriveSequence()
-            .getSubSequence(3, 7), as3 = dna2.deriveSequence();
+    SequenceI as1 = dna1.deriveSequence();
+    SequenceI as2 = dna1.deriveSequence().getSubSequence(3, 7);
+    SequenceI as3 = dna2.deriveSequence();
     as1.insertCharAt(6, 5, '-');
     String s_as1 = as1.getSequenceAsString();
     as2.insertCharAt(6, 5, '-');
@@ -2463,8 +2462,9 @@ public class AlignmentUtilsTests
 
     // why do we need to cast this still ?
     ((Alignment) aligned).createDatasetAlignment();
-    SequenceI uas1 = dna1.deriveSequence(), uas2 = dna1.deriveSequence()
-            .getSubSequence(3, 7), uas3 = dna2.deriveSequence();
+    SequenceI uas1 = dna1.deriveSequence();
+    SequenceI uas2 = dna1.deriveSequence().getSubSequence(3, 7);
+    SequenceI uas3 = dna2.deriveSequence();
     AlignmentI tobealigned = new Alignment(new SequenceI[] { uas1, uas2,
         uas3 });
     ((Alignment) tobealigned).createDatasetAlignment();
index 55823e4..df39b81 100644 (file)
@@ -27,7 +27,6 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 
 import org.testng.AssertJUnit;
@@ -45,21 +44,26 @@ public class GroupingTest
 
   Sequence s5 = new Sequence("s5", "AAAADDEDTTEE");
 
-  SequenceGroup sg1 = new SequenceGroup(Arrays.asList(new SequenceI[] { s1,
+  SequenceGroup sg_12 = new SequenceGroup(Arrays.asList(new SequenceI[] { s1,
       s2 }), "Group1", null, false, false, false, 0, 5);
 
-  SequenceGroup sg2 = new SequenceGroup(Arrays.asList(new SequenceI[] { s3,
+  SequenceGroup sg_345 = new SequenceGroup(Arrays.asList(new SequenceI[] { s3,
       s4, s5 }), "Group2", null, false, false, false, 0, 5);
 
   AlignmentI alignment = new Alignment(
           new SequenceI[] { s1, s2, s3, s4, s5 });
 
-  int[] positions = new int[] { 1, 7, 9 };
+  /*
+   * test for the case where column selections are not added in
+   * left to right order
+   */
+  int[] positions = new int[] { 7, 9, 1 };
 
   @Test(groups = { "Functional" })
   public void testMakeGroupsWithBoth()
   {
-    ArrayList<String> str = new ArrayList<String>();
+    String[] str = new String[alignment.getHeight()];
+    int seq = 0;
     for (SequenceI s : alignment.getSequences())
     {
       StringBuilder sb = new StringBuilder();
@@ -67,12 +71,12 @@ public class GroupingTest
       {
         sb.append(s.getCharAt(p));
       }
-      str.add(sb.toString());
+      str[seq++] = sb.toString();
     }
     SequenceGroup[] seqgroupsString = Grouping.makeGroupsFrom(
-            alignment.getSequencesArray(),
-            str.toArray(new String[str.size()]),
-            Arrays.asList(new SequenceGroup[] { sg1, sg2 }));
+            alignment.getSequencesArray(), str,
+            Arrays.asList(new SequenceGroup[] { sg_12, sg_345 }));
+
     ColumnSelection cs = new ColumnSelection();
     for (int p : positions)
     {
@@ -80,7 +84,7 @@ public class GroupingTest
     }
     SequenceGroup[] seqgroupsColSel = Grouping.makeGroupsFromCols(
             alignment.getSequencesArray(), cs,
-            Arrays.asList(new SequenceGroup[] { sg1, sg2 }));
+            Arrays.asList(new SequenceGroup[] { sg_12, sg_345 }));
     AssertJUnit
             .assertEquals(seqgroupsString.length, seqgroupsColSel.length);
     for (int p = 0; p < seqgroupsString.length; p++)
diff --git a/test/jalview/bin/CacheTest.java b/test/jalview/bin/CacheTest.java
new file mode 100644 (file)
index 0000000..ac58aa9
--- /dev/null
@@ -0,0 +1,48 @@
+package jalview.bin;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class CacheTest
+{
+  private Locale locale;
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpBeforeClass()
+  {
+    locale = Locale.getDefault();
+  }
+
+  @AfterClass(alwaysRun = true)
+  public void tearDownAfterClass()
+  {
+    Locale.setDefault(locale);
+  }
+
+  /**
+   * Test that saved date format does not vary with current locale
+   */
+  @Test(groups = "Functional")
+  public void testSetDateProperty()
+  {
+    Date now = new Date();
+    Locale.setDefault(Locale.FRENCH);
+    String formattedDate = Cache.setDateProperty("test", now);
+    Locale.setDefault(Locale.UK);
+    String formattedDate2 = Cache.setDateProperty("test", now);
+    assertEquals(formattedDate, formattedDate2);
+
+    // currently using Locale.UK to format dates:
+    assertEquals(
+            formattedDate2,
+            SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.LONG,
+                    SimpleDateFormat.LONG, Locale.UK).format(now));
+  }
+}
diff --git a/test/jalview/controller/AlignViewControllerTest.java b/test/jalview/controller/AlignViewControllerTest.java
new file mode 100644 (file)
index 0000000..3eefada
--- /dev/null
@@ -0,0 +1,100 @@
+package jalview.controller;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.util.BitSet;
+
+import org.testng.annotations.Test;
+
+public class AlignViewControllerTest
+{
+  @Test(groups = "Functional")
+  public void testFindColumnsWithFeature()
+  {
+    SequenceI seq1 = new Sequence("seq1", "aMMMaaaaaaaaaaaaaaaa");
+    SequenceI seq2 = new Sequence("seq2", "aaaMMMMMMMaaaaaaaaaa");
+    SequenceI seq3 = new Sequence("seq3", "aaaaaaaaaaMMMMMaaaaa");
+    SequenceI seq4 = new Sequence("seq3", "aaaaaaaaaaaaaaaaaaaa");
+
+    /*
+     * features start/end are base 1
+     */
+    seq1.addSequenceFeature(new SequenceFeature("Metal", "desc", 2, 4, 0f,
+            null));
+    seq1.addSequenceFeature(new SequenceFeature("Helix", "desc", 1, 15, 0f,
+            null));
+    seq2.addSequenceFeature(new SequenceFeature("Metal", "desc", 4, 10, 0f,
+            null));
+    seq3.addSequenceFeature(new SequenceFeature("Metal", "desc", 11, 15,
+            0f, null));
+
+    /*
+     * select the first three columns --> Metal in seq1 2-3
+     */
+    SequenceGroup sg = new SequenceGroup();
+    sg.setStartRes(0); // base 0
+    sg.setEndRes(2);
+    sg.addSequence(seq1, false);
+    sg.addSequence(seq2, false);
+    sg.addSequence(seq3, false);
+    sg.addSequence(seq4, false);
+
+    BitSet bs = new BitSet();
+    int seqCount = AlignViewController.findColumnsWithFeature("Metal", sg,
+            bs);
+    assertEquals(1, seqCount);
+    assertEquals(2, bs.cardinality());
+    assertTrue(bs.get(1));
+    assertTrue(bs.get(2));
+    
+    /*
+     * select the first four columns: Metal in seq1 2:4, seq2 4:4
+     */
+    sg.setEndRes(3);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("Metal", sg,
+            bs);
+    assertEquals(2, seqCount);
+    assertEquals(3, bs.cardinality());
+    assertTrue(bs.get(1));
+    assertTrue(bs.get(2));
+    assertTrue(bs.get(3));
+
+    /*
+     * select column 11: Metal in seq3 only
+     */
+    sg.setStartRes(10);
+    sg.setEndRes(10);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
+    assertEquals(1, seqCount);
+    assertEquals(1, bs.cardinality());
+    assertTrue(bs.get(10));
+
+    /*
+     * select columns 16-20: no Metal feature
+     */
+    sg.setStartRes(15);
+    sg.setEndRes(19);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
+    assertEquals(0, seqCount);
+    assertEquals(0, bs.cardinality());
+
+    /*
+     * look for a feature that isn't there
+     */
+    sg.setStartRes(0);
+    sg.setEndRes(19);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("Pfam", sg, bs);
+    assertEquals(0, seqCount);
+    assertEquals(0, bs.cardinality());
+  }
+}
index 1a7ae32..e59719c 100644 (file)
@@ -22,10 +22,12 @@ package jalview.datamodel;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotSame;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.List;
 
 import org.testng.annotations.Test;
@@ -66,6 +68,9 @@ public class ColumnSelectionTest
 
     // removing an element in the list removes it
     cs.removeElement(2);
+    // ...but not from the copy list!
+    assertEquals(2, sel.size());
+    sel = cs.getSelected();
     assertEquals(1, sel.size());
     assertEquals(new Integer(5), sel.get(0));
   }
@@ -325,10 +330,14 @@ public class ColumnSelectionTest
    * this fails, HideSelectedColumns may also fail
    */
   @Test(groups = { "Functional" })
-  public void testgetSelectedRanges()
+  public void testGetSelectedRanges()
   {
+    /*
+     * getSelectedRanges returns ordered columns regardless
+     * of the order in which they are added
+     */
     ColumnSelection cs = new ColumnSelection();
-    int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 };
+    int[] sel = { 4, 3, 7, 21, 9, 20, 8, 22, 2 };
     for (int col : sel)
     {
       cs.addElement(col);
@@ -527,4 +536,137 @@ public class ColumnSelectionTest
     cs.addElement(88);
     assertTrue(cs.equals(cs2));
   }
+
+  /**
+   * Test the method that returns selected columns, in the order in which they
+   * were added
+   */
+  @Test(groups = { "Functional" })
+  public void testGetSelection()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    int[] sel = { 4, 3, 7, 21 };
+    for (int col : sel)
+    {
+      cs.addElement(col);
+    }
+
+    List<Integer> selected1 = cs.getSelected();
+    assertEquals(4, selected1.size());
+
+    /*
+     * getSelected returns a copy, verify the list
+     * is externally immutable
+     */
+    selected1.clear();
+    List<Integer> selected2 = cs.getSelected();
+    assertNotSame(selected1, selected2);
+    assertEquals(4, selected2.size());
+    int i = 0;
+    for (int col : sel)
+    {
+      assertEquals(col, selected2.get(i++).intValue());
+    }
+
+    cs.removeElement(7);
+    cs.addElement(1);
+    cs.removeElement(4);
+
+    List<Integer> selected3 = cs.getSelected();
+    assertEquals(3, selected3.size());
+    assertEquals(3, selected3.get(0).intValue());
+    assertEquals(21, selected3.get(1).intValue());
+    assertEquals(1, selected3.get(2).intValue());
+  }
+
+  @Test(groups = "Functional")
+  public void testMarkColumns()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(5); // this will be cleared
+    BitSet toMark = new BitSet();
+    toMark.set(1);
+    toMark.set(3);
+    toMark.set(6);
+    toMark.set(9);
+
+    assertTrue(cs.markColumns(toMark, 3, 8, false, false, false));
+    List<Integer> selected = cs.getSelected();
+    assertEquals(2, selected.size());
+    assertTrue(selected.contains(3));
+    assertTrue(selected.contains(6));
+  }
+
+  @Test(groups = "Functional")
+  public void testMarkColumns_extend()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(1);
+    cs.addElement(5);
+    BitSet toMark = new BitSet();
+    toMark.set(1);
+    toMark.set(3);
+    toMark.set(6);
+    toMark.set(9);
+
+    /*
+     * extending selection of {3, 6} should leave {1, 3, 5, 6} selected
+     */
+    assertTrue(cs.markColumns(toMark, 3, 8, false, true, false));
+    List<Integer> selected = cs.getSelected();
+    assertEquals(4, selected.size());
+    assertTrue(selected.contains(1));
+    assertTrue(selected.contains(3));
+    assertTrue(selected.contains(5));
+    assertTrue(selected.contains(6));
+  }
+
+  @Test(groups = "Functional")
+  public void testMarkColumns_invert()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(5); // this will be cleared
+    BitSet toMark = new BitSet();
+    toMark.set(1);
+    toMark.set(3);
+    toMark.set(6);
+    toMark.set(9);
+
+    /*
+     * inverted selection of {3, 6} should select {4, 5, 7, 8}
+     */
+    assertTrue(cs.markColumns(toMark, 3, 8, true, false, false));
+    List<Integer> selected = cs.getSelected();
+    assertEquals(4, selected.size());
+    assertTrue(selected.contains(4));
+    assertTrue(selected.contains(5));
+    assertTrue(selected.contains(7));
+    assertTrue(selected.contains(8));
+  }
+
+  @Test(groups = "Functional")
+  public void testMarkColumns_toggle()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(1); // outside change range
+    cs.addElement(3);
+    cs.addElement(4);
+    cs.addElement(10); // outside change range
+    BitSet toMark = new BitSet();
+    toMark.set(1);
+    toMark.set(3);
+    toMark.set(6);
+    toMark.set(9);
+
+    /*
+     * toggling state of {3, 6} should leave {1, 4, 6, 10} selected
+     */
+    assertTrue(cs.markColumns(toMark, 3, 8, false, false, true));
+    List<Integer> selected = cs.getSelected();
+    assertEquals(4, selected.size());
+    assertTrue(selected.contains(1));
+    assertTrue(selected.contains(4));
+    assertTrue(selected.contains(6));
+    assertTrue(selected.contains(10));
+  }
 }
index 71719dd..cfc4cbb 100644 (file)
@@ -110,8 +110,7 @@ public class SequenceTest
   {
     AlignmentAnnotation ann1 = addAnnotation("label1", "desc1", "calcId1",
             1f);
-    AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
-            1f);
+    addAnnotation("label2", "desc2", "calcId2", 1f);
     AlignmentAnnotation ann3 = addAnnotation("label1", "desc3", "calcId3",
             1f);
     AlignmentAnnotation[] anns = seq.getAnnotation("label1");
@@ -133,16 +132,15 @@ public class SequenceTest
   @Test(groups = { "Functional" })
   public void testGetAlignmentAnnotations_forCalcIdAndLabel()
   {
-    AlignmentAnnotation ann1 = addAnnotation("label1", "desc1", "calcId1",
-            1f);
+    addAnnotation("label1", "desc1", "calcId1", 1f);
     AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
             1f);
-    AlignmentAnnotation ann3 = addAnnotation("label2", "desc3", "calcId3",
-            1f);
+    addAnnotation("label2", "desc3", "calcId3", 1f);
     AlignmentAnnotation ann4 = addAnnotation("label2", "desc3", "calcId2",
             1f);
-    AlignmentAnnotation ann5 = addAnnotation("label5", "desc3", null, 1f);
-    AlignmentAnnotation ann6 = addAnnotation(null, "desc3", "calcId3", 1f);
+    addAnnotation("label5", "desc3", null, 1f);
+    addAnnotation(null, "desc3", "calcId3", 1f);
+
     List<AlignmentAnnotation> anns = seq.getAlignmentAnnotations("calcId2",
             "label2");
     assertEquals(2, anns.size());
index e6019aa..d3d9ff8 100644 (file)
@@ -68,8 +68,8 @@ public class AnnotatedPDBFileInputTest
     pdbId = al.getSequenceAt(0).getDatasetSequence().getAllPDBEntries()
             .get(0).getId();
     StructureImportSettings.setDefaultStructureFileFormat("PDB");
-    StructureImportSettings
-            .setDefaultPDBFileParser(StructureParser.JALVIEW_PARSER);
+    // StructureImportSettings
+    // .setDefaultPDBFileParser(StructureParser.JALVIEW_PARSER);
   }
 
   @Test(groups = { "Functional" })
@@ -101,7 +101,11 @@ public class AnnotatedPDBFileInputTest
       {
 
         System.out.println("CalcId: " + aa.getCalcId());
+        if (StructureImportSettings.getDefaultPDBFileParser().equals(
+                StructureParser.JALVIEW_PARSER))
+        {
         assertTrue(MCview.PDBfile.isCalcIdForFile(aa, pdbId));
+        }
       }
     }
   }
@@ -118,9 +122,9 @@ public class AnnotatedPDBFileInputTest
     SequenceFeature[] sf = al.getSequenceAt(0).getSequenceFeatures();
     assertEquals(296, sf.length);
     assertEquals("RESNUM", sf[0].getType());
-    assertEquals("GLU:  19  1gaqA", sf[0].getDescription());
+    assertEquals("GLU:19 1gaqA", sf[0].getDescription());
     assertEquals("RESNUM", sf[295].getType());
-    assertEquals("TYR: 314  1gaqA", sf[295].getDescription());
+    assertEquals("TYR:314 1gaqA", sf[295].getDescription());
 
     /*
      * 1GAQ/B
@@ -128,9 +132,9 @@ public class AnnotatedPDBFileInputTest
     sf = al.getSequenceAt(1).getSequenceFeatures();
     assertEquals(98, sf.length);
     assertEquals("RESNUM", sf[0].getType());
-    assertEquals("ALA:   1  1gaqB", sf[0].getDescription());
+    assertEquals("ALA:1 1gaqB", sf[0].getDescription());
     assertEquals("RESNUM", sf[97].getType());
-    assertEquals("ALA:  98  1gaqB", sf[97].getDescription());
+    assertEquals("ALA:98 1gaqB", sf[97].getDescription());
 
     /*
      * 1GAQ/C
@@ -138,9 +142,9 @@ public class AnnotatedPDBFileInputTest
     sf = al.getSequenceAt(2).getSequenceFeatures();
     assertEquals(296, sf.length);
     assertEquals("RESNUM", sf[0].getType());
-    assertEquals("GLU:  19  1gaqC", sf[0].getDescription());
+    assertEquals("GLU:19 1gaqC", sf[0].getDescription());
     assertEquals("RESNUM", sf[295].getType());
-    assertEquals("TYR: 314  1gaqC", sf[295].getDescription());
+    assertEquals("TYR:314 1gaqC", sf[295].getDescription());
   }
 
   @Test(groups = { "Functional" })
diff --git a/test/jalview/io/FormatAdapterTest.java b/test/jalview/io/FormatAdapterTest.java
new file mode 100644 (file)
index 0000000..81e336e
--- /dev/null
@@ -0,0 +1,138 @@
+package jalview.io;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.fail;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class FormatAdapterTest
+{
+
+  /**
+   * Test saving and re-reading in a specified format
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" }, dataProvider = "formats")
+  public void testRoundTrip(String format) throws IOException
+  {
+    try
+    {
+      AlignmentI al = new FormatAdapter().readFile("examples/uniref50.fa",
+              FormatAdapter.FILE, "FASTA");
+
+      /*
+       * 'gap' is the gap character used in the alignment data file here,
+       * not the user preferred gap character
+       */
+      char gap = al.getGapCharacter();
+      assertNotNull(al);
+
+      SequenceI[] seqs = al.getSequencesArray();
+      String formatted = new FormatAdapter().formatSequences(format, al,
+              false);
+
+      AlignmentI reloaded = new FormatAdapter().readFile(formatted,
+              FormatAdapter.PASTE, format);
+      List<SequenceI> reread = reloaded.getSequences();
+      assertEquals("Wrong number of reloaded sequences", seqs.length,
+              reread.size());
+
+      int i = 0;
+      for (SequenceI seq : reread)
+      {
+        String sequenceString = seq.getSequenceAsString();
+
+        /*
+         * special case: MSF always uses '.' as gap character
+         */
+        sequenceString = adjustForGapTreatment(sequenceString, gap, format);
+        assertEquals(
+                String.format("Sequence %d: %s", i,
+                        seqs[i].getName()), seqs[i].getSequenceAsString(),
+                sequenceString);
+        i++;
+      }
+    } catch (IOException e)
+    {
+      fail(String
+              .format("Format %s failed with %s", format, e.getMessage()));
+    }
+  }
+
+  /**
+   * Optionally change the gap character in the string to the given character,
+   * depending on the sequence file format
+   * 
+   * @param sequenceString
+   *          a sequence (as written in 'format' format)
+   * @param gap
+   *          the sequence's original gap character
+   * @param format
+   * @return
+   */
+  String adjustForGapTreatment(String sequenceString, char gap,
+          String format)
+  {
+    if ("MSF".equals(format))
+    {
+      /*
+       * MSF forces gap character to '.', so change it back
+       * for comparison purposes
+       */
+      sequenceString = sequenceString.replace('.', gap);
+    }
+    return sequenceString;
+  }
+
+  /**
+   * Data provider that serves alignment formats that are both readable and
+   * writable
+   * 
+   * @return
+   */
+  @DataProvider(name = "formats")
+  static Object[][] getFormats()
+  {
+    List<String> both = new ArrayList<String>();
+    String[] readable = FormatAdapter.READABLE_FORMATS;
+    List<String> writeable = Arrays.asList(FormatAdapter.WRITEABLE_FORMATS);
+    for (String r : readable)
+    {
+      if (writeable.contains(r))
+      {
+        both.add(r);
+      }
+    }
+
+    Object[][] formats = new Object[both.size()][];
+    int i = 0;
+    for (String format : both)
+    {
+      formats[i] = new Object[] { format };
+      i++;
+    }
+    return formats;
+  }
+
+  /**
+   * Enable this to isolate testing to a single file format
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" }, enabled = false)
+  public void testOneFormatRoundTrip() throws IOException
+  {
+    testRoundTrip("JSON");
+  }
+}
index 3ce5c4f..379fd68 100644 (file)
@@ -1,11 +1,11 @@
 package jalview.io;
 
 import jalview.bin.Cache;
+import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.SequenceI;
 import jalview.gui.Desktop;
 
-import java.time.Instant;
 import java.util.Date;
 
 import org.testng.annotations.AfterClass;
@@ -21,12 +21,19 @@ public class Jalview2xmlBase
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
-    jalview.bin.Jalview.main(new String[] { "-props",
-        "test/jalview/io/testProps_nodas.jvprops" });
-    jalview.bin.Cache.setProperty(
-            "JALVIEW_NEWS_RSS_LASTMODIFIED",
-            Cache.date_format.format(Date.from(Instant.now().plusSeconds(
-                    3600))));
+    /*
+     * use read-only test properties file
+     */
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+
+    /*
+     * set news feed last read to a future time to ensure no
+     * 'unread' news item is displayed
+     */
+    Date oneHourFromNow = new Date(System.currentTimeMillis() + 3600 * 1000);
+    Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED", oneHourFromNow);
+
+    Jalview.main(new String[] {});
   }
 
   /**
index a54d190..f7853ff 100644 (file)
@@ -32,10 +32,12 @@ import jalview.api.ViewStyleI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.HiddenSequences;
+import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
+import jalview.gui.AlignmentPanel;
 import jalview.gui.Desktop;
 import jalview.gui.Jalview2XML;
 import jalview.schemes.AnnotationColourGradient;
@@ -632,4 +634,92 @@ public class Jalview2xmlTests extends Jalview2xmlBase
               hidden.size(), hs.getSize());
     }
   }
+
+  /**
+   * Test save and reload of PDBEntry in Jalview project
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverPDBEntry() throws Exception
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    String exampleFile = "examples/3W5V.pdb";
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
+            FormatAdapter.FILE);
+    assertTrue("Didn't read in the example file correctly.", af != null);
+    String afid = af.getViewport().getSequenceSetId();
+
+    AlignmentPanel[] alignPanels = Desktop.getAlignmentPanels(afid);
+    System.out.println();
+    AlignmentViewPanel ap = alignPanels[0];
+    String tfileBase = new File(".").getAbsolutePath().replace(".", "");
+    String testFile = tfileBase + exampleFile;
+    AlignmentI alignment = ap.getAlignment();
+    System.out.println("blah");
+    SequenceI[] seqs = alignment.getSequencesArray();
+    Assert.assertNotNull(seqs[0]);
+    Assert.assertNotNull(seqs[1]);
+    Assert.assertNotNull(seqs[2]);
+    Assert.assertNotNull(seqs[3]);
+    Assert.assertNotNull(seqs[0].getDatasetSequence());
+    Assert.assertNotNull(seqs[1].getDatasetSequence());
+    Assert.assertNotNull(seqs[2].getDatasetSequence());
+    Assert.assertNotNull(seqs[3].getDatasetSequence());
+    PDBEntry[] pdbEntries = new PDBEntry[4];
+    pdbEntries[0] = new PDBEntry("3W5V", "A", null, testFile);
+    pdbEntries[1] = new PDBEntry("3W5V", "B", null, testFile);
+    pdbEntries[2] = new PDBEntry("3W5V", "C", null, testFile);
+    pdbEntries[3] = new PDBEntry("3W5V", "D", null, testFile);
+    Assert.assertTrue(seqs[0].getDatasetSequence().getAllPDBEntries()
+            .get(0).equals(pdbEntries[0]));
+    Assert.assertTrue(seqs[1].getDatasetSequence().getAllPDBEntries()
+            .get(0).equals(pdbEntries[1]));
+    Assert.assertTrue(seqs[2].getDatasetSequence().getAllPDBEntries()
+            .get(0).equals(pdbEntries[2]));
+    Assert.assertTrue(seqs[3].getDatasetSequence().getAllPDBEntries()
+            .get(0).equals(pdbEntries[3]));
+
+    File tfile = File.createTempFile("testStoreAndRecoverPDBEntry", ".jvp");
+    try
+    {
+      new Jalview2XML(false).saveState(tfile);
+    } catch (Throwable e)
+    {
+      Assert.fail("Didn't save the state", e);
+    }
+    Desktop.instance.closeAll_actionPerformed(null);
+    if (Desktop.getAlignFrames() != null)
+    {
+      Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+    }
+
+    AlignFrame restoredFrame = new FileLoader().LoadFileWaitTillLoaded(
+            tfile.getAbsolutePath(), FormatAdapter.FILE);
+    String rfid = restoredFrame.getViewport().getSequenceSetId();
+    AlignmentPanel[] rAlignPanels = Desktop.getAlignmentPanels(rfid);
+    AlignmentViewPanel rap = rAlignPanels[0];
+    AlignmentI rAlignment = rap.getAlignment();
+    System.out.println("blah");
+    SequenceI[] rseqs = rAlignment.getSequencesArray();
+    Assert.assertNotNull(rseqs[0]);
+    Assert.assertNotNull(rseqs[1]);
+    Assert.assertNotNull(rseqs[2]);
+    Assert.assertNotNull(rseqs[3]);
+    Assert.assertNotNull(rseqs[0].getDatasetSequence());
+    Assert.assertNotNull(rseqs[1].getDatasetSequence());
+    Assert.assertNotNull(rseqs[2].getDatasetSequence());
+    Assert.assertNotNull(rseqs[3].getDatasetSequence());
+
+    // The Asserts below are expected to fail until the PDB chainCode is
+    // recoverable from a Jalview projects
+    Assert.assertTrue(rseqs[0].getDatasetSequence().getAllPDBEntries()
+            .get(0).equals(pdbEntries[0]));
+    Assert.assertTrue(rseqs[1].getDatasetSequence().getAllPDBEntries()
+            .get(0).equals(pdbEntries[1]));
+    Assert.assertTrue(rseqs[2].getDatasetSequence().getAllPDBEntries()
+            .get(0).equals(pdbEntries[2]));
+    Assert.assertTrue(rseqs[3].getDatasetSequence().getAllPDBEntries()
+            .get(0).equals(pdbEntries[3]));
+  }
 }
index d7a9166..b034fb0 100644 (file)
@@ -23,6 +23,7 @@ package jalview.io;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -159,7 +160,7 @@ public class StockholmFileTest
    *          'secondary' or generated alignment from some datapreserving
    *          transformation
    * @param ignoreFeatures
-   *          when true, differences in seuqence feature annotation are ignored.
+   *          when true, differences in sequence feature annotation are ignored
    */
   public static void testAlignmentEquivalence(AlignmentI al,
           AlignmentI al_input, boolean ignoreFeatures)
@@ -167,12 +168,9 @@ public class StockholmFileTest
     assertNotNull("Original alignment was null", al);
     assertNotNull("Generated alignment was null", al_input);
 
-    assertTrue(
-            "Alignment dimension mismatch: originl contains "
-                    + al.getHeight() + " and generated has "
-                    + al_input.getHeight() + " sequences; original has "
-                    + al.getWidth() + " and generated has "
-                    + al_input.getWidth() + " columns.",
+    assertTrue("Alignment dimension mismatch: original: " + al.getHeight()
+            + "x" + al.getWidth() + ", generated: " + al_input.getHeight()
+            + "x" + al_input.getWidth(),
             al.getHeight() == al_input.getHeight()
                     && al.getWidth() == al_input.getWidth());
 
@@ -183,9 +181,10 @@ public class StockholmFileTest
     // note - at moment we do not distinguish between alignment without any
     // annotation rows and alignment with no annotation row vector
     // we might want to revise this in future
-    int aa_new_size = (aa_new == null ? 0 : aa_new.length), aa_original_size = (aa_original == null ? 0
-            : aa_original.length);
-    Map<Integer, java.util.BitSet> orig_groups = new HashMap<Integer, java.util.BitSet>(), new_groups = new HashMap<Integer, java.util.BitSet>();
+    int aa_new_size = (aa_new == null ? 0 : aa_new.length);
+    int aa_original_size = (aa_original == null ? 0 : aa_original.length);
+    Map<Integer, BitSet> orig_groups = new HashMap<Integer, BitSet>();
+    Map<Integer, BitSet> new_groups = new HashMap<Integer, BitSet>();
 
     if (aa_new != null && aa_original != null)
     {
@@ -196,20 +195,17 @@ public class StockholmFileTest
           assertTrue("Different alignment annotation at position " + i,
                   equalss(aa_original[i], aa_new[i]));
           // compare graphGroup or graph properties - needed to verify JAL-1299
-          assertTrue("Graph type not identical.",
-                  aa_original[i].graph == aa_new[i].graph);
-          assertTrue("Visibility not identical.",
-                  aa_original[i].visible == aa_new[i].visible);
-          assertTrue(
-                  "Threshold line not identical.",
-                  aa_original[i].threshold == null ? aa_new[i].threshold == null
-                          : aa_original[i].threshold
-                                  .equals(aa_new[i].threshold));
+          assertEquals("Graph type not identical.", aa_original[i].graph,
+                  aa_new[i].graph);
+          assertEquals("Visibility not identical.", aa_original[i].visible,
+                  aa_new[i].visible);
+          assertEquals("Threshold line not identical.",
+                  aa_original[i].threshold, aa_new[i].threshold);
           // graphGroup may differ, but pattern should be the same
-          Integer o_ggrp = new Integer(aa_original[i].graphGroup + 2), n_ggrp = new Integer(
-                  aa_new[i].graphGroup + 2);
-          BitSet orig_g = orig_groups.get(o_ggrp), new_g = new_groups
-                  .get(n_ggrp);
+          Integer o_ggrp = new Integer(aa_original[i].graphGroup + 2);
+          Integer n_ggrp = new Integer(aa_new[i].graphGroup + 2);
+          BitSet orig_g = orig_groups.get(o_ggrp);
+          BitSet new_g = new_groups.get(n_ggrp);
           if (orig_g == null)
           {
             orig_groups.put(o_ggrp, orig_g = new BitSet());
@@ -218,8 +214,8 @@ public class StockholmFileTest
           {
             new_groups.put(n_ggrp, new_g = new BitSet());
           }
-          assertTrue("Graph Group pattern differs at annotation " + i,
-                  orig_g.equals(new_g));
+          assertEquals("Graph Group pattern differs at annotation " + i,
+                  orig_g, new_g);
           orig_g.set(i);
           new_g.set(i);
         }
@@ -230,10 +226,9 @@ public class StockholmFileTest
         }
       }
     }
-    assertTrue(
-            "Generated and imported alignment have different annotation sets ("
-                    + aa_new_size + " != " + aa_original_size + ")",
-            aa_new_size == aa_original_size);
+    assertEquals(
+            "Generated and imported alignment have different annotation sets",
+            aa_new_size, aa_original_size);
 
     // check sequences, annotation and features
     SequenceI[] seq_original = new SequenceI[al.getSequencesArray().length];
@@ -260,8 +255,8 @@ public class StockholmFileTest
         {
           String ss_original = seq_original[i].getSequenceAsString();
           String ss_new = seq_new[in].getSequenceAsString();
-          assertTrue("The sequences " + name + "/" + start + "-" + end
-                  + " are not equal", ss_original.equals(ss_new));
+          assertEquals("The sequences " + name + "/" + start + "-" + end
+                  + " are not equal", ss_original, ss_new);
 
           assertTrue(
                   "Sequence Features were not equivalent"
@@ -284,15 +279,16 @@ public class StockholmFileTest
                     .getSequenceFeatures().length];
             sequenceFeatures_new = seq_new[in].getSequenceFeatures();
 
-            assertTrue("different number of features", seq_original[i]
-                    .getSequenceFeatures().length == seq_new[in]
+            assertEquals("different number of features",
+                    seq_original[i].getSequenceFeatures().length,
+                    seq_new[in]
                     .getSequenceFeatures().length);
 
             for (int feat = 0; feat < seq_original[i].getSequenceFeatures().length; feat++)
             {
-              assertTrue("Different features",
-                      sequenceFeatures_original[feat]
-                              .equals(sequenceFeatures_new[feat]));
+              assertEquals("Different features",
+                      sequenceFeatures_original[feat],
+                      sequenceFeatures_new[feat]);
             }
           }
           // compare alignment annotation
@@ -319,9 +315,9 @@ public class StockholmFileTest
           else if (al.getSequenceAt(i).getAnnotation() != null
                   && al_input.getSequenceAt(in).getAnnotation() == null)
           {
-            assertTrue("Annotations differed between sequences ("
+            fail("Annotations differed between sequences ("
                     + al.getSequenceAt(i).getName() + ") and ("
-                    + al_input.getSequenceAt(i).getName() + ")", false);
+                    + al_input.getSequenceAt(i).getName() + ")");
           }
           break;
         }
index 2074fb4..baaa96b 100644 (file)
@@ -138,7 +138,7 @@ public class StructureSelectionManagerTest
     SequenceFeature sf = pmap.getSeqs().get(0).getSequenceFeatures()[0];
     assertEquals("RESNUM", sf.getType());
     assertEquals("1gaq", sf.getFeatureGroup());
-    assertEquals("GLU:  19  1gaqA", sf.getDescription());
+    assertEquals("GLU:19 1gaqA", sf.getDescription());
 
     /*
      * Verify a RESNUM sequence feature in the StructureSelectionManager mapped
@@ -148,6 +148,6 @@ public class StructureSelectionManagerTest
     sf = map.sequence.getSequenceFeatures()[0];
     assertEquals("RESNUM", sf.getType());
     assertEquals("1gaq", sf.getFeatureGroup());
-    assertEquals("ALA:   1  1gaqB", sf.getDescription());
+    assertEquals("ALA:1 1gaqB", sf.getDescription());
   }
 }
index dbe1258..2a111ee 100644 (file)
@@ -28,6 +28,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.gui.Jalview2XML;
 import jalview.io.AnnotationFile;
+import jalview.io.FileLoader;
 import jalview.io.FormatAdapter;
 import jalview.io.StockholmFileTest;
 import jalview.ws.jws2.Jws2Discoverer;
@@ -49,6 +50,7 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import compbio.metadata.Argument;
 import compbio.metadata.WrongParameterException;
 
 public class RNAStructExportImport
@@ -88,9 +90,9 @@ public class RNAStructExportImport
       Assert.fail("no web service");
     }
 
-    jalview.io.FileLoader fl = new jalview.io.FileLoader(false);
+    FileLoader fl = new FileLoader(false);
 
-    af = fl.LoadFileWaitTillLoaded(testseqs, jalview.io.FormatAdapter.FILE);
+    af = fl.LoadFileWaitTillLoaded(testseqs, FormatAdapter.FILE);
 
     assertNotNull("Couldn't load test data ('" + testseqs + "')", af);
 
@@ -143,7 +145,6 @@ public class RNAStructExportImport
       } catch (InterruptedException x)
       {
       }
-      ;
     } while (af.getViewport().getCalcManager().isWorking());
 
     AlignmentI orig_alig = af.getViewport().getAlignment();
@@ -177,7 +178,6 @@ public class RNAStructExportImport
       } catch (InterruptedException x)
       {
       }
-      ;
     } while (af.getViewport().getCalcManager().isWorking());
 
     AlignmentI orig_alig = af.getViewport().getAlignment();
@@ -196,11 +196,11 @@ public class RNAStructExportImport
 
       String anfileout = new AnnotationFile()
               .printAnnotationsForAlignment(al);
-      assertTrue(
+      assertNotNull(
               "Test "
                       + testname
                       + "\nAlignment annotation file was not regenerated. Null string",
-              anfileout != null);
+              anfileout);
       assertTrue(
               "Test "
                       + testname
@@ -235,8 +235,8 @@ public class RNAStructExportImport
   @Test(groups = { "Functional" })
   public void testRnaalifoldSettingsRecovery()
   {
-    List<compbio.metadata.Argument> opts = new ArrayList<compbio.metadata.Argument>();
-    for (compbio.metadata.Argument rg : (List<compbio.metadata.Argument>) rnaalifoldws
+    List<Argument> opts = new ArrayList<Argument>();
+    for (Argument rg : (List<Argument>) rnaalifoldws
             .getRunnerConfig().getArguments())
     {
       if (rg.getDescription().contains("emperature"))
index 1f666a4..1ad5322 100644 (file)
@@ -90,7 +90,7 @@ public class HelpLinksChecker
       return;
     }
 
-    internetAvailable &= connectToUrl("http://www.example.com");
+    internetAvailable &= connectToUrl("http://www.example.org");
 
     Map<String, String> tocTargets = checkHelpMappings(helpFolder);