Merge branch 'JAL-2571' into develop
authorJim Procter <jprocter@issues.jalview.org>
Wed, 31 May 2017 20:23:52 +0000 (21:23 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Wed, 31 May 2017 20:23:52 +0000 (21:23 +0100)
13 files changed:
help/html/releases.html
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/Finder.java
src/jalview/appletgui/SeqPanel.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/gui/SeqPanel.java
src/jalview/io/AppletFormatAdapter.java
test/jalview/datamodel/SequenceGroupTest.java
test/jalview/ext/jmol/JmolParserTest.java
test/jalview/ext/jmol/JmolViewerTest.java
test/jalview/gui/StructureChooserTest.java
test/jalview/io/FileLoaderTest.java

index 18f8f43..b8bcfc7 100755 (executable)
@@ -81,6 +81,7 @@ li:before {
           <li><!--  JAL-384 -->Custom shading schemes created via groovy scripts</li>
           <li><!--  JAL-2491 -->linked scrolling of CDS/Protein views via Overview or sequence motif search operations</li>
           <li><!--  JAL-2526 -->Efficiency improvements for interacting with alignment and overview windows</li>
+          <li><!-- JAL-2388 -->Hidden columns and sequences can be omitted in Overview</li>
             <li>
               <!-- JAL-2535 -->Posterior probability annotation from
               Stockholm files imported as sequence associated annotation
@@ -116,7 +117,7 @@ li:before {
           <li><!--  --></li>
           </ul>
           <em>Test Suite</em>
-          <li><!--  JAL-2474 -->Added PrivelegedAccessor to test suite</li>
+          <li><!--  JAL-2474 -->Added PrivilegedAccessor to test suite</li>
           <li><!-- JAL-2326 -->Prevent or clear modal dialogs raised during tests</li>
           <li><!--  -->  
           </ul>
@@ -126,7 +127,7 @@ li:before {
             <li>
               <!-- JAL-2398, -->Fixed incorrect value in BLOSUM 62 score
               matrix - C->R should be '3'<br />Old matrix restored with
-              this one-line groovy script:<br />jalview.schemes.ResidueProperties.BLOSUM62[4][1]=3
+              this one-line groovy script:<br />jalview.analysis.scoremodels.ScoreModels.instance.BLOSUM62.@matrix[4][1]=3
             </li>
             <li>
               <!-- JAL-2397 -->Fixed Jalview's treatment of gaps in PCA
@@ -159,7 +160,8 @@ li:before {
           <li><!-- JAL-2385 -->Colour threshold slider doesn't update to reflect currently selected view or group's shading thresholds</li>
           <li><!-- JAL-2373 -->Percentage identity and conservation menu items do not show a tick or allow shading to be disabled</li>
           <li><!-- JAL-2385 -->Conservation shading or PID threshold lost when base colourscheme changed if slider not visible</li>
-          <li><!-- JAL-2547 -->Sequence features shown in tooltip for gaps before start of features</li> 
+          <li><!-- JAL-2547 -->Sequence features shown in tooltip for gaps before start of features</li>
+          <li><!-- JAL-2563 -->Sequence position for ambiguous codon not shown in status bar</li> 
           </ul>
           <em>Application</em>
           <ul>
index 8fd317a..77ec373 100644 (file)
@@ -65,6 +65,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -819,9 +820,9 @@ public class APopupMenu extends java.awt.PopupMenu implements
         return;
       }
 
-      int rsize = 0, gSize = sg.getSize();
-      SequenceI[] rseqs, seqs = new SequenceI[gSize];
-      SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
+      int gSize = sg.getSize();
+      List<SequenceI> seqs = new ArrayList<SequenceI>();
+      List<SequenceFeature> features = new ArrayList<SequenceFeature>();
 
       for (int i = 0; i < gSize; i++)
       {
@@ -829,25 +830,17 @@ public class APopupMenu extends java.awt.PopupMenu implements
         int end = sg.findEndRes(sg.getSequenceAt(i));
         if (start <= end)
         {
-          seqs[rsize] = sg.getSequenceAt(i);
-          features[rsize] = new SequenceFeature(null, null, null, start,
-                  end, "Jalview");
-          rsize++;
+          seqs.add(sg.getSequenceAt(i));
+          features.add(new SequenceFeature(null, null, null, start, end,
+                  "Jalview"));
         }
       }
-      rseqs = new SequenceI[rsize];
-      tfeatures = new SequenceFeature[rsize];
-      System.arraycopy(seqs, 0, rseqs, 0, rsize);
-      System.arraycopy(features, 0, tfeatures, 0, rsize);
-      features = tfeatures;
-      seqs = rseqs;
 
       if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
               features, true, ap))
       {
         ap.alignFrame.sequenceFeatures.setState(true);
         ap.av.setShowSequenceFeatures(true);
-        ;
         ap.highlightSearchResults(null);
       }
     }
index 38ecf76..3c2715f 100644 (file)
@@ -53,6 +53,7 @@ import java.awt.event.MouseEvent;
 import java.awt.event.TextEvent;
 import java.awt.event.TextListener;
 import java.util.Hashtable;
+import java.util.List;
 
 /**
  * DOCUMENT ME!
@@ -182,8 +183,8 @@ public class FeatureRenderer extends
    * @param ap
    * @return
    */
-  boolean amendFeatures(final SequenceI[] sequences,
-          final SequenceFeature[] features, boolean create,
+  boolean amendFeatures(final List<SequenceI> sequences,
+          final List<SequenceFeature> features, boolean create,
           final AlignmentPanel ap)
   {
     final Panel bigPanel = new Panel(new BorderLayout());
@@ -223,22 +224,20 @@ public class FeatureRenderer extends
 
     // /////////////////////////////////////
     // /MULTIPLE FEATURES AT SELECTED RESIDUE
-    if (!create && features.length > 1)
+    if (!create && features.size() > 1)
     {
       panel = new Panel(new GridLayout(4, 1));
       tmp = new Panel();
       tmp.add(new Label("Select Feature: "));
       overlaps = new Choice();
-      for (int i = 0; i < features.length; i++)
+      for (SequenceFeature sf : features)
       {
-        String item = features[i].getType() + "/" + features[i].getBegin()
-                + "-" + features[i].getEnd();
-
-        if (features[i].getFeatureGroup() != null)
+        String item = sf.getType() + "/" + sf.getBegin() + "-"
+                + sf.getEnd();
+        if (sf.getFeatureGroup() != null)
         {
-          item += " (" + features[i].getFeatureGroup() + ")";
+          item += " (" + sf.getFeatureGroup() + ")";
         }
-
         overlaps.addItem(item);
       }
 
@@ -253,15 +252,16 @@ public class FeatureRenderer extends
           if (index != -1)
           {
             featureIndex = index;
-            name.setText(features[index].getType());
-            description.setText(features[index].getDescription());
-            group.setText(features[index].getFeatureGroup());
-            start.setText(features[index].getBegin() + "");
-            end.setText(features[index].getEnd() + "");
+            SequenceFeature sf = features.get(index);
+            name.setText(sf.getType());
+            description.setText(sf.getDescription());
+            group.setText(sf.getFeatureGroup());
+            start.setText(sf.getBegin() + "");
+            end.setText(sf.getEnd() + "");
 
             SearchResultsI highlight = new SearchResults();
-            highlight.addResult(sequences[0], features[index].getBegin(),
-                    features[index].getEnd());
+            highlight.addResult(sequences.get(0), sf.getBegin(),
+                    sf.getEnd());
 
             ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
 
@@ -269,8 +269,8 @@ public class FeatureRenderer extends
           FeatureColourI col = getFeatureStyle(name.getText());
           if (col == null)
           {
-            Color generatedColour = ColorUtils
-                    .createColourFromName(name.getText());
+            Color generatedColour = ColorUtils.createColourFromName(name
+                    .getText());
             col = new FeatureColour(generatedColour);
           }
 
@@ -328,16 +328,17 @@ public class FeatureRenderer extends
      * if feature type has not been supplied by the caller
      * (e.g. for Amend, or create features from Find) 
      */
-    boolean useLastDefaults = features[0].getType() == null;
-    String featureType = useLastDefaults ? lastFeatureAdded : features[0]
+    SequenceFeature firstFeature = features.get(0);
+    boolean useLastDefaults = firstFeature.getType() == null;
+    String featureType = useLastDefaults ? lastFeatureAdded : firstFeature
             .getType();
     String featureGroup = useLastDefaults ? lastFeatureGroupAdded
-            : features[0].getFeatureGroup();
+            : firstFeature.getFeatureGroup();
 
     String title = create ? MessageManager
             .getString("label.create_new_sequence_features")
             : MessageManager.formatMessage("label.amend_delete_features",
-                    new String[] { sequences[0].getName() });
+                    new String[] { sequences.get(0).getName() });
 
     final JVDialog dialog = new JVDialog(ap.alignFrame, title, true, 385,
             240);
@@ -362,9 +363,9 @@ public class FeatureRenderer extends
       });
     }
 
-    start.setText(features[0].getBegin() + "");
-    end.setText(features[0].getEnd() + "");
-    description.setText(features[0].getDescription());
+    start.setText(firstFeature.getBegin() + "");
+    end.setText(firstFeature.getEnd() + "");
+    description.setText(firstFeature.getDescription());
     // lookup (or generate) the feature colour
     FeatureColourI fcol = getFeatureStyle(name.getText());
     // simply display the feature color in a box
@@ -403,7 +404,7 @@ public class FeatureRenderer extends
 
     if (!create)
     {
-      SequenceFeature sf = features[featureIndex];
+      SequenceFeature sf = features.get(featureIndex);
       if (dialog.accept)
       {
         sf.type = enteredType;
@@ -437,7 +438,7 @@ public class FeatureRenderer extends
       }
       if (deleteFeature)
       {
-        sequences[0].deleteFeature(sf);
+        sequences.get(0).deleteFeature(sf);
         // ensure Feature Settings reflects removal of feature / group
         featuresAdded();
       }
@@ -449,14 +450,14 @@ public class FeatureRenderer extends
        */
       if (dialog.accept && name.getText().length() > 0)
       {
-        for (int i = 0; i < sequences.length; i++)
+        for (int i = 0; i < sequences.size(); i++)
         {
-          features[i].type = enteredType;
-          features[i].featureGroup = group.getText().trim();
-          features[i].description = description.getText()
+          features.get(i).type = enteredType;
+          features.get(i).featureGroup = group.getText().trim();
+          features.get(i).description = description.getText()
                   .replace('\n', ' ');
-          sequences[i].addSequenceFeature(features[i]);
-          ffile.parseDescriptionHTML(features[i], false);
+          sequences.get(i).addSequenceFeature(features.get(i));
+          ffile.parseDescriptionHTML(features.get(i), false);
         }
 
         Color newColour = colourPanel.getBackground();
index a342736..f7ebab6 100644 (file)
@@ -41,6 +41,8 @@ import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Vector;
 
 public class Finder extends Panel implements ActionListener
@@ -113,20 +115,16 @@ public class Finder extends Panel implements ActionListener
 
   public void createNewGroup_actionPerformed()
   {
-    SequenceI[] seqs = new SequenceI[searchResults.getSize()];
-    SequenceFeature[] features = new SequenceFeature[searchResults
-            .getSize()];
+    List<SequenceI> seqs = new ArrayList<SequenceI>();
+    List<SequenceFeature> features = new ArrayList<SequenceFeature>();
     String searchString = textfield.getText().trim();
 
-    int i = 0;
     for (SearchResultMatchI match : searchResults.getResults())
     {
-      seqs[i] = match.getSequence().getDatasetSequence();
-
-      features[i] = new SequenceFeature(searchString,
+      seqs.add(match.getSequence().getDatasetSequence());
+      features.add(new SequenceFeature(searchString,
               "Search Results", null, match.getStart(), match.getEnd(),
-              "Search Results");
-      i++;
+ "Search Results"));
     }
 
     if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
index 0a833b3..4aa205e 100644 (file)
@@ -54,6 +54,10 @@ import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
 import java.util.Vector;
 
 public class SeqPanel extends Panel implements MouseMotionListener,
@@ -563,20 +567,23 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         av.setSelectionGroup(null);
       }
 
-      SequenceFeature[] features = findFeaturesAtRes(sequence,
-              sequence.findPosition(findRes(evt)));
+      int column = findRes(evt);
+      boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+      List<SequenceFeature> features = findFeaturesAtRes(sequence,
+              sequence.findPosition(column));
+      if (isGapped)
+      {
+        removeAdjacentFeatures(features, column + 1, sequence);
+      }
 
-      if (features != null && features.length > 0)
+      if (!features.isEmpty())
       {
         SearchResultsI highlight = new SearchResults();
-        highlight.addResult(sequence, features[0].getBegin(),
-                features[0].getEnd());
+        highlight.addResult(sequence, features.get(0).getBegin(), features
+                .get(0).getEnd());
         seqCanvas.highlightSearchResults(highlight);
-      }
-      if (features != null && features.length > 0)
-      {
         seqCanvas.getFeatureRenderer().amendFeatures(
-                new SequenceI[] { sequence }, features, false, ap);
+                Collections.singletonList(sequence), features, false, ap);
 
         seqCanvas.highlightSearchResults(null);
       }
@@ -802,9 +809,11 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
 
     final char ch = sequence.getCharAt(column);
-    int respos = Comparison.isGap(ch) ? -1 : sequence.findPosition(column);
+    boolean isGapped = Comparison.isGap(ch);
+    // find residue at column (or nearest if at a gap)
+    int respos = sequence.findPosition(column);
 
-    if (ssm != null && respos != -1)
+    if (ssm != null && !isGapped)
     {
       mouseOverSequence(sequence, column, respos);
     }
@@ -813,30 +822,21 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     text.append("Sequence ").append(Integer.toString(seq + 1))
             .append(" ID: ").append(sequence.getName());
 
-    String obj = null;
-    if (respos != -1)
+    if (!isGapped)
     {
       if (av.getAlignment().isNucleotide())
       {
-        obj = ResidueProperties.nucleotideName.get(ch);
-        if (obj != null)
-        {
-          text.append(" Nucleotide: ").append(obj);
-        }
+        String base = ResidueProperties.nucleotideName.get(ch);
+        text.append(" Nucleotide: ").append(base == null ? ch : base);
       }
       else
       {
-        obj = (ch == 'x' || ch == 'X') ? "X" : ResidueProperties.aa2Triplet
+        String residue = (ch == 'x' || ch == 'X') ? "X"
+                : ResidueProperties.aa2Triplet
                 .get(String.valueOf(ch));
-        if (obj != null)
-        {
-          text.append(" Residue: ").append(obj);
-        }
-      }
-      if (obj != null)
-      {
-        text.append(" (").append(Integer.toString(respos)).append(")");
+        text.append(" Residue: ").append(residue == null ? ch : residue);
       }
+      text.append(" (").append(Integer.toString(respos)).append(")");
     }
 
     ap.alignFrame.statusBar.setText(text.toString());
@@ -864,18 +864,19 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
 
     /*
-     * add feature details to tooltip if over one or more features
+     * add feature details to tooltip, including any that straddle
+     * a gapped position
      */
-    if (respos != -1)
+    if (av.isShowSequenceFeatures())
     {
-      SequenceFeature[] allFeatures = findFeaturesAtRes(sequence,
+      List<SequenceFeature> allFeatures = findFeaturesAtRes(sequence,
               sequence.findPosition(column));
-
-      int index = 0;
-      while (index < allFeatures.length)
+      if (isGapped)
+      {
+        removeAdjacentFeatures(allFeatures, column + 1, sequence);
+      }
+      for (SequenceFeature sf : allFeatures)
       {
-        SequenceFeature sf = allFeatures[index];
-
         tooltipText.append(sf.getType() + " " + sf.begin + ":" + sf.end);
 
         if (sf.getDescription() != null)
@@ -892,8 +893,6 @@ public class SeqPanel extends Panel implements MouseMotionListener,
           }
         }
         tooltipText.append("\n");
-
-        index++;
       }
     }
 
@@ -907,9 +906,38 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
   }
 
-  SequenceFeature[] findFeaturesAtRes(SequenceI sequence, int res)
+  /**
+   * Removes from the list of features any that start after, or end before, the
+   * given column position. This allows us to retain only those features
+   * adjacent to a gapped position that straddle the position. Contact features
+   * that 'straddle' the position are also removed, since they are not 'at' the
+   * position.
+   * 
+   * @param features
+   * @param column
+   *          alignment column (1..)
+   * @param sequence
+   */
+  protected void removeAdjacentFeatures(List<SequenceFeature> features,
+          int column, SequenceI sequence)
   {
-    Vector tmp = new Vector();
+    // TODO should this be an AlignViewController method (shared by gui)?
+    ListIterator<SequenceFeature> it = features.listIterator();
+    while (it.hasNext())
+    {
+      SequenceFeature sf = it.next();
+      if (sf.isContactFeature()
+              || sequence.findIndex(sf.getBegin()) > column
+              || sequence.findIndex(sf.getEnd()) < column)
+      {
+        it.remove();
+      }
+    }
+  }
+
+  List<SequenceFeature> findFeaturesAtRes(SequenceI sequence, int res)
+  {
+    List<SequenceFeature> result = new ArrayList<SequenceFeature>();
     SequenceFeature[] features = sequence.getSequenceFeatures();
     if (features != null)
     {
@@ -932,15 +960,12 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         if ((features[i].getBegin() <= res)
                 && (features[i].getEnd() >= res))
         {
-          tmp.addElement(features[i]);
+          result.add(features[i]);
         }
       }
     }
 
-    features = new SequenceFeature[tmp.size()];
-    tmp.copyInto(features);
-
-    return features;
+    return result;
   }
 
   Tooltip tooltip;
@@ -1466,24 +1491,21 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     // DETECT RIGHT MOUSE BUTTON IN AWT
     if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
     {
-      SequenceFeature[] allFeatures = findFeaturesAtRes(sequence,
+      List<SequenceFeature> allFeatures = findFeaturesAtRes(sequence,
               sequence.findPosition(res));
 
       Vector<String> links = null;
-      if (allFeatures != null)
+      for (SequenceFeature sf : allFeatures)
       {
-        for (int i = 0; i < allFeatures.length; i++)
+        if (sf.links != null)
         {
-          if (allFeatures[i].links != null)
+          if (links == null)
           {
-            if (links == null)
-            {
-              links = new Vector<>();
-            }
-            for (int j = 0; j < allFeatures[i].links.size(); j++)
-            {
-              links.addElement(allFeatures[i].links.elementAt(j));
-            }
+            links = new Vector<String>();
+          }
+          for (int j = 0; j < sf.links.size(); j++)
+          {
+            links.addElement(sf.links.elementAt(j));
           }
         }
       }
index 8c29ca5..463b909 100755 (executable)
@@ -110,13 +110,23 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   private boolean normaliseSequenceLogo;
 
-  /**
-   * @return the includeAllConsSymbols
+  /*
+   * visibility of rows or represented rows covered by group
    */
-  public boolean isShowSequenceLogo()
-  {
-    return showSequenceLogo;
-  }
+  private boolean hidereps = false;
+
+  /*
+   * visibility of columns intersecting this group
+   */
+  private boolean hidecols = false;
+
+  AlignmentAnnotation consensus = null;
+
+  AlignmentAnnotation conservation = null;
+
+  private boolean showConsensusHistogram;
+
+  private AnnotatedCollectionI context;
 
   /**
    * Creates a new SequenceGroup object.
@@ -178,13 +188,17 @@ public class SequenceGroup implements AnnotatedCollectionI
       colourText = seqsel.colourText;
       startRes = seqsel.startRes;
       endRes = seqsel.endRes;
-      cs = seqsel.cs;
+      cs = new ResidueShader(seqsel.getColourScheme());
       if (seqsel.description != null)
       {
         description = new String(seqsel.description);
       }
       hidecols = seqsel.hidecols;
       hidereps = seqsel.hidereps;
+      showNonconserved = seqsel.showNonconserved;
+      showSequenceLogo = seqsel.showSequenceLogo;
+      normaliseSequenceLogo = seqsel.normaliseSequenceLogo;
+      showConsensusHistogram = seqsel.showConsensusHistogram;
       idColour = seqsel.idColour;
       outlineColour = seqsel.outlineColour;
       seqrep = seqsel.seqrep;
@@ -201,6 +215,11 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
   }
 
+  public boolean isShowSequenceLogo()
+  {
+    return showSequenceLogo;
+  }
+
   public SequenceI[] getSelectionAsNewSequences(AlignmentI align)
   {
     int iSize = sequences.size();
@@ -957,11 +976,6 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   /**
-   * visibility of rows or represented rows covered by group
-   */
-  private boolean hidereps = false;
-
-  /**
    * set visibility of sequences covered by (if no sequence representative is
    * defined) or represented by this group.
    * 
@@ -983,11 +997,6 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   /**
-   * visibility of columns intersecting this group
-   */
-  private boolean hidecols = false;
-
-  /**
    * set intended visibility of columns covered by this group
    * 
    * @param visibility
@@ -1049,13 +1058,6 @@ public class SequenceGroup implements AnnotatedCollectionI
     this.showNonconserved = displayNonconserved;
   }
 
-  AlignmentAnnotation consensus = null, conservation = null;
-
-  /**
-   * flag indicating if consensus histogram should be rendered
-   */
-  private boolean showConsensusHistogram;
-
   /**
    * set this alignmentAnnotation object as the one used to render consensus
    * annotation
@@ -1346,8 +1348,6 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
   }
 
-  private AnnotatedCollectionI context;
-
   /**
    * Sets the alignment or group context for this group, and whether it is
    * defined as a group
index 012ac94..c6c2deb 100644 (file)
@@ -62,6 +62,7 @@ import java.awt.event.MouseWheelListener;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.ListIterator;
 
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
@@ -731,8 +732,9 @@ public class SeqPanel extends JPanel implements MouseListener,
     /*
      * set status bar message, returning residue position in sequence
      */
+    boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
     final int pos = setStatusMessage(sequence, column, seq);
-    if (ssm != null && pos > -1)
+    if (ssm != null && !isGapped)
     {
       mouseOverSequence(sequence, column, pos);
     }
@@ -761,10 +763,19 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
     }
 
-    if (av.isShowSequenceFeatures() && pos != -1)
+    /*
+     * add any features at the position to the tooltip; if over a gap, only
+     * add features that straddle the gap (pos may be the residue before or
+     * after the gap)
+     */
+    if (av.isShowSequenceFeatures())
     {
       List<SequenceFeature> features = ap.getFeatureRenderer()
               .findFeaturesAtRes(sequence.getDatasetSequence(), pos);
+      if (isGapped)
+      {
+        removeAdjacentFeatures(features, column + 1, sequence);
+      }
       seqARep.appendFeatures(tooltipText, pos, features,
               this.ap.getSeqPanel().seqCanvas.fr.getMinMax());
     }
@@ -789,6 +800,35 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   }
 
+  /**
+   * Removes from the list of features any that start after, or end before, the
+   * given column position. This allows us to retain only those features
+   * adjacent to a gapped position that straddle the position. Contact features
+   * that 'straddle' the position are also removed, since they are not 'at' the
+   * position.
+   * 
+   * @param features
+   * @param column
+   *          alignment column (1..)
+   * @param sequence
+   */
+  protected void removeAdjacentFeatures(List<SequenceFeature> features,
+          final int column, SequenceI sequence)
+  {
+    // TODO should this be an AlignViewController method (and reused by applet)?
+    ListIterator<SequenceFeature> it = features.listIterator();
+    while (it.hasNext())
+    {
+      SequenceFeature sf = it.next();
+      if (sf.isContactFeature()
+              || sequence.findIndex(sf.getBegin()) > column
+              || sequence.findIndex(sf.getEnd()) < column)
+      {
+        it.remove();
+      }
+    }
+  }
+
   private Point lastp = null;
 
   /*
@@ -833,9 +873,10 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   /**
    * Sets the status message in alignment panel, showing the sequence number
-   * (index) and id, residue and residue position for the given sequence and
-   * column position. Returns the calculated residue position in the sequence,
-   * or -1 for a gapped column position.
+   * (index) and id, and residue and residue position if not at a gap, for the
+   * given sequence and column position. Returns the residue position returned
+   * by Sequence.findPosition. Note this may be for the nearest adjacent residue
+   * if at a gapped position.
    * 
    * @param sequence
    *          aligned sequence object
@@ -843,7 +884,8 @@ public class SeqPanel extends JPanel implements MouseListener,
    *          alignment column
    * @param seq
    *          index of sequence in alignment
-   * @return position of column in sequence or -1 if at a gap
+   * @return sequence position of residue at column, or adjacent residue if at a
+   *         gap
    */
   int setStatusMessage(SequenceI sequence, final int column, int seq)
   {
@@ -857,36 +899,34 @@ public class SeqPanel extends JPanel implements MouseListener,
             .append(sequence.getName());
 
     String residue = null;
+
     /*
      * Try to translate the display character to residue name (null for gap).
      */
     final String displayChar = String.valueOf(sequence.getCharAt(column));
-    if (av.getAlignment().isNucleotide())
+    boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+    int pos = sequence.findPosition(column);
+
+    if (!isGapped)
     {
-      residue = ResidueProperties.nucleotideName.get(displayChar);
-      if (residue != null)
+      boolean nucleotide = av.getAlignment().isNucleotide();
+      if (nucleotide)
       {
-        text.append(" Nucleotide: ").append(residue);
+        residue = ResidueProperties.nucleotideName.get(displayChar);
       }
-    }
-    else
-    {
-      residue = "X".equalsIgnoreCase(displayChar) ? "X" : ("*"
-              .equals(displayChar) ? "STOP" : ResidueProperties.aa2Triplet
-              .get(displayChar));
-      if (residue != null)
+      else
       {
-        text.append(" Residue: ").append(residue);
+        residue = "X".equalsIgnoreCase(displayChar) ? "X" : ("*"
+                .equals(displayChar) ? "STOP"
+                : ResidueProperties.aa2Triplet.get(displayChar));
       }
-    }
+      text.append(" ").append(nucleotide ? "Nucleotide" : "Residue")
+              .append(": ").append(residue == null ? displayChar : residue);
 
-    int pos = -1;
-    if (residue != null)
-    {
-      pos = sequence.findPosition(column);
       text.append(" (").append(Integer.toString(pos)).append(")");
     }
     ap.alignFrame.statusBar.setText(text.toString());
+
     return pos;
   }
 
@@ -1526,9 +1566,20 @@ public class SeqPanel extends JPanel implements MouseListener,
         av.setSelectionGroup(null);
       }
 
+      int column = findColumn(evt);
+      boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+
+      /*
+       * find features at the position (if not gapped), or straddling
+       * the position (if at a gap)
+       */
       List<SequenceFeature> features = seqCanvas.getFeatureRenderer()
               .findFeaturesAtRes(sequence.getDatasetSequence(),
-                      sequence.findPosition(findColumn(evt)));
+                      sequence.findPosition(column));
+      if (isGapped)
+      {
+        removeAdjacentFeatures(features, column, sequence);
+      }
 
       if (!features.isEmpty())
       {
index c5a80e3..907ff46 100755 (executable)
@@ -407,15 +407,26 @@ public class AppletFormatAdapter
     return null;
   }
 
-  public static DataSourceType checkProtocol(String file)
+  /**
+   * Determines the protocol (i.e DataSourceType.{FILE|PASTE|URL}) for the input
+   * data
+   *
+   * @param data
+   * @return the protocol for the input data
+   */
+  public static DataSourceType checkProtocol(String data)
   {
-    DataSourceType protocol = DataSourceType.FILE;
-    String ft = file.toLowerCase().trim();
+    DataSourceType protocol = DataSourceType.PASTE;
+    String ft = data.toLowerCase().trim();
     if (ft.indexOf("http:") == 0 || ft.indexOf("https:") == 0
             || ft.indexOf("file:") == 0)
     {
       protocol = DataSourceType.URL;
     }
+    else if (new File(data).exists())
+    {
+      protocol = DataSourceType.FILE;
+    }
     return protocol;
   }
 
index 7837b49..f6d4028 100644 (file)
@@ -3,17 +3,21 @@ package jalview.datamodel;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotSame;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
 import jalview.schemes.NucleotideColourScheme;
+import jalview.schemes.PIDColourScheme;
 
-import org.testng.annotations.Test;
+import java.awt.Color;
 
 import junit.extensions.PA;
 
+import org.testng.annotations.Test;
+
 public class SequenceGroupTest
 {
   @Test(groups={"Functional"})
@@ -217,6 +221,73 @@ public class SequenceGroupTest
     assertTrue(sg2.contains(seq2, 8));
     sg2.deleteSequence(seq2, false);
     assertFalse(sg2.contains(seq2));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testCopyConstructor()
+  {
+    SequenceI seq = new Sequence("seq", "ABC");
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seq, false);
+    sg.setName("g1");
+    sg.setDescription("desc");
+    sg.setColourScheme(new PIDColourScheme());
+    sg.setDisplayBoxes(false);
+    sg.setDisplayText(false);
+    sg.setColourText(true);
+    sg.isDefined = true;
+    sg.setShowNonconserved(true);
+    sg.setOutlineColour(Color.red);
+    sg.setIdColour(Color.blue);
+    sg.thresholdTextColour = 1;
+    sg.textColour = Color.orange;
+    sg.textColour2 = Color.yellow;
+    sg.setIgnoreGapsConsensus(false);
+    sg.setshowSequenceLogo(true);
+    sg.setNormaliseSequenceLogo(true);
+    sg.setHidereps(true);
+    sg.setHideCols(true);
+    sg.setShowConsensusHistogram(true);
+    sg.setContext(new SequenceGroup());
+
+    SequenceGroup sg2 = new SequenceGroup(sg);
+    assertEquals(sg2.getName(), sg.getName());
+    assertEquals(sg2.getDescription(), sg.getDescription());
+    assertNotSame(sg2.getGroupColourScheme(), sg.getGroupColourScheme());
+    assertSame(sg2.getColourScheme(), sg.getColourScheme());
+    assertEquals(sg2.getDisplayBoxes(), sg.getDisplayBoxes());
+    assertEquals(sg2.getDisplayText(), sg.getDisplayText());
+    assertEquals(sg2.getColourText(), sg.getColourText());
+    assertEquals(sg2.getShowNonconserved(), sg.getShowNonconserved());
+    assertEquals(sg2.getOutlineColour(), sg.getOutlineColour());
+    assertEquals(sg2.getIdColour(), sg.getIdColour());
+    assertEquals(sg2.thresholdTextColour, sg.thresholdTextColour);
+    assertEquals(sg2.textColour, sg.textColour);
+    assertEquals(sg2.textColour2, sg.textColour2);
+    assertEquals(sg2.getIgnoreGapsConsensus(), sg.getIgnoreGapsConsensus());
+    assertEquals(sg2.isShowSequenceLogo(), sg.isShowSequenceLogo());
+    assertEquals(sg2.isNormaliseSequenceLogo(),
+            sg.isNormaliseSequenceLogo());
+    assertEquals(sg2.isHidereps(), sg.isHidereps());
+    assertEquals(sg2.isHideCols(), sg.isHideCols());
+    assertEquals(sg2.isShowConsensusHistogram(),
+            sg.isShowConsensusHistogram());
 
+    /*
+     * copy of sequences
+     */
+    assertNotSame(sg2.getSequences(), sg.getSequences());
+    assertEquals(sg2.getSequences(), sg.getSequences());
+
+    /*
+     * isDefined should only be set true when a new group is added to
+     * an alignment, not in the copy constructor
+     */
+    assertFalse(sg2.isDefined());
+
+    /*
+     * context should be set explicitly, not by copy
+     */
+    assertNull(sg2.getContext());
   }
 }
index 131ef41..36e9b20 100644 (file)
@@ -272,7 +272,7 @@ public class JmolParserTest
      * local structure files should yield a false ID based on the filename
      */
     assertNotNull(structureData.getId());
-    assertEquals(structureData.getId(), "localstruct.pdb");
+    assertEquals(structureData.getId(), "localstruct");
     assertNotNull(structureData.getSeqs());
     /*
      * the ID is also the group for features derived from structure data 
@@ -280,7 +280,7 @@ public class JmolParserTest
     assertNotNull(structureData.getSeqs().get(0).getSequenceFeatures()[0].featureGroup);
     assertEquals(
             structureData.getSeqs().get(0).getSequenceFeatures()[0].featureGroup,
-            "localstruct.pdb");
+            "localstruct");
 
   }
 }
index 4a59044..792f7ad 100644 (file)
@@ -33,7 +33,6 @@ import jalview.gui.StructureViewer;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.DataSourceType;
 
-import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -117,56 +116,5 @@ public class JmolViewerTest
     }
   }
 
-  @Test(groups = { "Functional", "Network" })
-  public void testStructureLoadingViaURL()
-  {
-    Cache.setProperty(Preferences.STRUCTURE_DISPLAY, ViewerType.JMOL.name());
-    String inFile = "http://www.jalview.org/builds/develop/examples/3W5V.pdb";
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
-            inFile, DataSourceType.URL);
-    assertTrue("Didn't read input file " + inFile, af != null);
-    for (SequenceI sq : af.getViewport().getAlignment().getSequences())
-    {
-      SequenceI dsq = sq.getDatasetSequence();
-      while (dsq.getDatasetSequence() != null)
-      {
-        dsq = dsq.getDatasetSequence();
-      }
-      if (dsq.getAllPDBEntries() != null
-              && dsq.getAllPDBEntries().size() > 0)
-      {
-        for (int q = 0; q < dsq.getAllPDBEntries().size(); q++)
-        {
-          final StructureViewer structureViewer = new StructureViewer(af
-                  .getViewport().getStructureSelectionManager());
-          structureViewer.setViewerType(ViewerType.JMOL);
-          JalviewStructureDisplayI jmolViewer = structureViewer
-                  .viewStructures(dsq.getAllPDBEntries().elementAt(q),
-                          new SequenceI[] { sq }, af.getCurrentView()
-                                  .getAlignPanel());
-          /*
-          * Wait for viewer load thread to complete
-          */
-          try
-          {
-            while (!jmolViewer.getBinding().isFinishedInit())
-            {
-              Thread.sleep(500);
-            }
-          } catch (InterruptedException e)
-          {
-          }
-          // System.out.println(">>>>>>>>>>>>>>>>> "
-          // + jmolViewer.getBinding().getPdbFile());
-          String[] expectedModelFiles = new String[] { "http://www.jalview.org/builds/develop/examples/3W5V.pdb" };
-          String[] actualModelFiles = jmolViewer.getBinding().getStructureFiles();
-          Assert.assertEqualsNoOrder(actualModelFiles, expectedModelFiles);
-          jmolViewer.closeViewer(true);
-          // todo: break here means only once through this loop?
-          break;
-        }
-        break;
-      }
-    }
-  }
+
 }
index c04353f..4535c93 100644 (file)
@@ -121,7 +121,7 @@ public class StructureChooserTest
     StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
     sc.populateFilterComboBox(false, false);
     int optionsSize = sc.getCmbFilterOption().getItemCount();
-    assertEquals(3, optionsSize); // if structures are not discovered then don't
+    assertEquals(2, optionsSize); // if structures are not discovered then don't
                                   // populate filter options
 
     sc.populateFilterComboBox(true, false);
index 0e21f6e..968901f 100644 (file)
@@ -14,11 +14,9 @@ public class FileLoaderTest
     fileLoader.LoadFileWaitTillLoaded(urlFile, DataSourceType.URL,
             FileFormat.PDB);
     Assert.assertNotNull(fileLoader.file);
-    // The FileLoader's file is expected to a temporary file different from the
-    // original URL.
-    Assert.assertNotEquals(urlFile, fileLoader.file);
-    // Data source type expected to be updated from DataSourceType.URL to
-    // DataSourceType.FILE
-    Assert.assertEquals(DataSourceType.FILE, fileLoader.protocol);
+    // The FileLoader's file is expected to be same as the original URL.
+    Assert.assertEquals(urlFile, fileLoader.file);
+    // Data source type expected to be DataSourceType.URL
+    Assert.assertEquals(DataSourceType.URL, fileLoader.protocol);
   }
 }