Merge branch 'develop' into bug/JAL-1841rnaSecStr
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 18 Aug 2016 15:33:06 +0000 (16:33 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 18 Aug 2016 15:33:06 +0000 (16:33 +0100)
16 files changed:
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/analysis/Grouping.java
src/jalview/appletgui/AnnotationPanel.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/gui/AlignFrame.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/ScalePanel.java
src/jalview/util/Platform.java
test/jalview/analysis/GroupingTest.java
test/jalview/datamodel/ColumnSelectionTest.java

index 04566fe..9480d9d 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}
@@ -1310,3 +1312,5 @@ 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 61563b3..8e94146 100644 (file)
@@ -962,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}
@@ -1317,3 +1319,5 @@ status.obtaining_mapping_with_nw_alignment=Obteniendo mapeo por alineamiento Nee
 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 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 ee8c9ca..6012c1a 100755 (executable)
@@ -25,6 +25,7 @@ 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 jalview.util.Platform;
@@ -162,12 +163,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))
@@ -474,9 +475,10 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       StringBuilder text = new StringBuilder();
       text.append(MessageManager.getString("label.column")).append(" ")
               .append(column + 1);
-      if (aa[row].annotations[column].description != null)
+      String description = aa[row].annotations[column].description;
+      if (description != null && description.length() > 0)
       {
-        text.append("  ").append(aa[row].annotations[column].description);
+        text.append("  ").append(description);
       }
 
       /*
@@ -495,9 +497,28 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
           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(residue).append(" (")
-                    .append(residuePos).append(")");
+            text.append(" (").append(residuePos).append(")");
+            // int residuePos = seqref.findPosition(column);
+            // text.append(residue).append(" (")
+            // .append(residuePos).append(")");
           }
         }
       }
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..74a5235 100644 (file)
@@ -299,11 +299,13 @@ public class AlignViewController implements AlignViewControllerI
         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())),
+                    MessageManager.getString(toggle ? "label.toggled"
+                            : "label.marked"),
+                    String.valueOf(invert ? alw - alStart
+                            - bs.cardinality() : bs.cardinality()),
+                    MessageManager
+                            .getString(invert ? "label.not_containing"
+                                    : "label.containing"),
                     featureType, Integer.valueOf(nseq).toString() }));
         return true;
       }
index aaf70b8..47acbd0 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());
   }
 
   /**
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 b0debf8..21f4aac 100644 (file)
@@ -4765,6 +4765,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                       xrefsAlignment.getSequencesArray());
               if (copyAlignment.getHeight() == 0)
               {
+                JOptionPane.showMessageDialog(AlignFrame.this,
+                        MessageManager.getString("label.cant_map_cds"),
+                        MessageManager.getString("label.operation_failed"),
+                        JOptionPane.OK_OPTION);
                 System.err.println("Failed to make CDS alignment");
               }
 
index 61a3f8c..6a621ff 100755 (executable)
@@ -26,6 +26,7 @@ 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;
 
@@ -48,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;
@@ -290,9 +293,12 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     String action = evt.getActionCommand();
     if (action.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 (action.equals(LABEL))
@@ -422,13 +428,27 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     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))
@@ -436,22 +456,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;
             }
           }
         }
@@ -459,13 +479,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();
   }
 
   /**
@@ -775,9 +795,24 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         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(residue).append(" (")
-                  .append(residuePos).append(")");
+          text.append(" (").append(residuePos).append(")");
         }
       }
     }
index 7d9e937..742ff8d 100644 (file)
@@ -182,9 +182,12 @@ public class FeatureSettings extends JPanel implements
         }
         else if (evt.getClickCount() == 2)
         {
+          boolean invertSelection = evt.isAltDown();
+          boolean ctrlDown = Platform.isControlDown(evt);
+          boolean toggleSelection = ctrlDown;
+          boolean extendSelection = evt.isShiftDown() || ctrlDown;
           fr.ap.alignFrame.avc.markColumnsContainingFeatures(
-                  evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
-                  evt.isMetaDown(),
+                  invertSelection, extendSelection, toggleSelection,
                   (String) table.getValueAt(selectedRow, 0));
         }
       }
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 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 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++)
index 04af3ce..2deb1a7 100644 (file)
@@ -22,6 +22,7 @@ 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;
 
@@ -66,6 +67,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));
   }
@@ -545,21 +549,32 @@ public class ColumnSelectionTest
     {
       cs.addElement(col);
     }
-    List<Integer> selected = cs.getSelected();
-    assertEquals(4, selected.size());
+
+    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, selected.get(i++).intValue());
+      assertEquals(col, selected2.get(i++).intValue());
     }
 
     cs.removeElement(7);
     cs.addElement(1);
     cs.removeElement(4);
-    selected = cs.getSelected();
-    assertEquals(3, selected.size());
-    assertEquals(3, selected.get(0).intValue());
-    assertEquals(21, selected.get(1).intValue());
-    assertEquals(1, selected.get(2).intValue());
+
+    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());
   }
 }