Merge branch 'bug/JAL-2386groupConservationColouring' into develop
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 15 Jun 2017 13:08:32 +0000 (14:08 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 15 Jun 2017 13:08:32 +0000 (14:08 +0100)
48 files changed:
RELEASE
help/html/releases.html
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AnnotationColumnChooser.java
src/jalview/appletgui/AnnotationLabels.java
src/jalview/appletgui/OverviewCanvas.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/appletgui/SeqPanel.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/CigarArray.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/HiddenColumns.java
src/jalview/datamodel/VisibleColsIterator.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AnnotationColumnChooser.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/OverviewCanvas.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/io/AnnotationFile.java
src/jalview/io/JSONFile.java
src/jalview/renderer/OverviewRenderer.java
src/jalview/renderer/seqfeatures/FeatureRenderer.java
src/jalview/schemes/ResidueColourScheme.java
src/jalview/schemes/ScoreColourScheme.java
src/jalview/urls/UrlLinkDisplay.java
src/jalview/util/MappingUtils.java
src/jalview/viewmodel/AlignmentViewport.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/datamodel/ColumnSelectionTest.java
test/jalview/datamodel/HiddenColumnsTest.java
test/jalview/gui/AlignFrameTest.java
test/jalview/io/JSONFileTest.java
test/jalview/renderer/seqfeatures/FeatureColourFinderTest.java
test/jalview/schemes/BuriedColourSchemeTest.java [new file with mode: 0644]
test/jalview/schemes/HelixColourSchemeTest.java [new file with mode: 0644]
test/jalview/schemes/HydrophobicColourSchemeTest.java [new file with mode: 0644]
test/jalview/schemes/StrandColourSchemeTest.java [new file with mode: 0644]
test/jalview/schemes/TurnColourSchemeTest.java [new file with mode: 0644]
test/jalview/schemes/UserColourSchemeTest.java
test/jalview/urls/UrlLinkDisplayTest.java
test/jalview/util/MappingUtilsTest.java

diff --git a/RELEASE b/RELEASE
index 9bc5817..6dffc29 100644 (file)
--- a/RELEASE
+++ b/RELEASE
@@ -1,2 +1,2 @@
-jalview.release=releases/Release_2_10_1_Branch
-jalview.version=2.10.1
+jalview.release=releases/Release_2_10_2_Branch
+jalview.version=2.10.2
index 5c8da91..e39a4c1 100755 (executable)
@@ -71,7 +71,7 @@ li:before {
       <td width="60" nowrap>
         <div align="center">
           <strong><a name="Jalview.2.10.2">2.10.2</a><br />
-            <em>30/5/2017</em></strong>
+            <em>20/6/2017</em></strong>
         </div>
       </td>
       <td><div align="left">
@@ -127,7 +127,7 @@ li:before {
           <ul>
             <li>
               <!-- JAL-2398, -->Fixed incorrect value in BLOSUM 62 score
-              matrix - C->R should be '3'<br />Old matrix restored with
+              matrix - C->R should be '-3'<br />Old matrix restored with
               this one-line groovy script:<br />jalview.analysis.scoremodels.ScoreModels.instance.BLOSUM62.@matrix[4][1]=3
             </li>
             <li>
@@ -136,7 +136,7 @@ li:before {
               earlier versions of Jalview, gaps matching gaps were
               penalised, and gaps matching non-gaps penalised even more.
               In the PCA calculation, gaps were actually treated as
-              non-gaps - so different costs were applied, which mean't
+              non-gaps - so different costs were applied, which meant
               Jalview's PCAs were different to those produced by
               SeqSpace.<br />Jalview now treats gaps in the same way as
               SeqSpace (ie it scores them as 0). To restore pre-2.10.2
index 77ec373..86610a2 100644 (file)
@@ -836,12 +836,15 @@ public class APopupMenu extends java.awt.PopupMenu implements
         }
       }
 
-      if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
-              features, true, ap))
+      if (!seqs.isEmpty())
       {
-        ap.alignFrame.sequenceFeatures.setState(true);
-        ap.av.setShowSequenceFeatures(true);
-        ap.highlightSearchResults(null);
+        if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
+                features, true, ap))
+        {
+          ap.alignFrame.sequenceFeatures.setState(true);
+          ap.av.setShowSequenceFeatures(true);
+          ap.highlightSearchResults(null);
+        }
       }
     }
     else
index 2eed311..8f28658 100644 (file)
@@ -1798,7 +1798,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
   synchronized void slideSequences(boolean right, int size)
   {
-    List<SequenceI> sg = new Vector<SequenceI>();
+    List<SequenceI> sg = new Vector<>();
     if (viewport.cursorMode)
     {
       sg.add(viewport.getAlignment().getSequenceAt(
@@ -1900,7 +1900,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
   static StringBuffer copiedSequences;
 
-  static Vector copiedHiddenColumns;
+  static Vector<int[]> copiedHiddenColumns;
 
   protected void copy_actionPerformed()
   {
@@ -1911,7 +1911,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
     SequenceGroup sg = viewport.getSelectionGroup();
     copiedSequences = new StringBuffer();
-    Map<Integer, SequenceI> orderedSeqs = new HashMap<Integer, SequenceI>();
+    Map<Integer, SequenceI> orderedSeqs = new HashMap<>();
     for (int i = 0; i < sg.getSize(); i++)
     {
       SequenceI seq = sg.getSequenceAt(i);
@@ -1924,13 +1924,13 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
     if (viewport.hasHiddenColumns() && viewport.getSelectionGroup() != null)
     {
-      copiedHiddenColumns = new Vector();
+      copiedHiddenColumns = new Vector<>(viewport.getAlignment()
+              .getHiddenColumns().getHiddenColumnsCopy());
       int hiddenOffset = viewport.getSelectionGroup().getStartRes();
-      for (int[] region : viewport.getAlignment().getHiddenColumns()
-              .getHiddenRegions())
+      for (int[] region : copiedHiddenColumns)
       {
-        copiedHiddenColumns.addElement(new int[] {
-            region[0] - hiddenOffset, region[1] - hiddenOffset });
+        region[0] = region[0] - hiddenOffset;
+        region[1] = region[1] - hiddenOffset;
       }
     }
     else
@@ -2045,7 +2045,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
         {
           for (int i = 0; i < copiedHiddenColumns.size(); i++)
           {
-            int[] region = (int[]) copiedHiddenColumns.elementAt(i);
+            int[] region = copiedHiddenColumns.elementAt(i);
             af.viewport.hideColumns(region[0], region[1]);
           }
         }
index 60775d3..3a7188e 100644 (file)
@@ -46,7 +46,7 @@ import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.TextEvent;
 import java.awt.event.TextListener;
-import java.util.Iterator;
+import java.util.ArrayList;
 import java.util.Vector;
 
 //import javax.swing.JPanel;
@@ -142,7 +142,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     }
     setOldHiddenColumns(av.getAlignment().getHiddenColumns());
     adjusting = true;
-    Vector<String> list = new Vector<String>();
+    Vector<String> list = new Vector<>();
     int index = 1;
     for (int i = 0; i < anns.length; i++)
     {
@@ -298,18 +298,19 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
         HiddenColumns oldHidden = av
                 .getAnnotationColumnSelectionState()
                 .getOldHiddenColumns();
-        if (oldHidden != null && oldHidden.getHiddenRegions() != null
-                && !oldHidden.getHiddenRegions().isEmpty())
+        if (oldHidden != null)
         {
-          for (Iterator<int[]> itr = oldHidden.getHiddenRegions()
-                  .iterator(); itr.hasNext();)
+          ArrayList<int[]> regions = oldHidden.getHiddenColumnsCopy();
+          for (int[] positions : regions)
           {
-            int positions[] = itr.next();
             av.hideColumns(positions[0], positions[1]);
           }
         }
+        // TODO not clear why we need to hide all the columns (above) if we are
+        // going to copy the hidden columns over wholesale anyway
         av.getAlignment().setHiddenColumns(oldHidden);
       }
+      av.sendSelection();
       ap.paintAlignment(true);
     }
 
@@ -428,8 +429,8 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
       }
 
       adjusting = true;
-      float range = getCurrentAnnotation().graphMax * 1000
-              - getCurrentAnnotation().graphMin * 1000;
+      // float range = getCurrentAnnotation().graphMax * 1000
+      // - getCurrentAnnotation().graphMin * 1000;
 
       slider.setMinimum((int) (getCurrentAnnotation().graphMin * 1000));
       slider.setMaximum((int) (getCurrentAnnotation().graphMax * 1000));
@@ -504,10 +505,13 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
       }
     }
 
+    // show hidden columns here, before changing the column selection in
+    // filterAnnotations, because showing hidden columns has the side effect of
+    // adding them to the selection
+    av.showAllHiddenColumns();
     av.getColumnSelection().filterAnnotations(
             getCurrentAnnotation().annotations, filterParams);
 
-    av.showAllHiddenColumns();
     if (getActionOption() == ACTION_OPTION_HIDE)
     {
       av.hideSelectedColumns();
@@ -515,6 +519,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
 
     filterParams = null;
     av.setAnnotationColumnSelectionState(this);
+    av.sendSelection();
     ap.paintAlignment(true);
   }
 
index 307301d..3f7e523 100755 (executable)
@@ -838,13 +838,9 @@ public class AnnotationLabels extends Panel implements ActionListener,
             + sq.getSequenceAsString() + "\n");
     if (av.hasHiddenColumns())
     {
-      jalview.appletgui.AlignFrame.copiedHiddenColumns = new Vector();
-      for (int[] region : av.getAlignment().getHiddenColumns()
-              .getHiddenRegions())
-      {
-        jalview.appletgui.AlignFrame.copiedHiddenColumns
-                .addElement(new int[] { region[0], region[1] });
-      }
+      jalview.appletgui.AlignFrame.copiedHiddenColumns = new Vector<>(
+              av.getAlignment().getHiddenColumns()
+                      .getHiddenColumnsCopy());
     }
   }
 
index 23e82df..a0466d3 100644 (file)
@@ -40,6 +40,8 @@ public class OverviewCanvas extends Component
 
   private OverviewDimensions od;
 
+  private OverviewRenderer or = null;
+
   private Image miniMe;
 
   private Image offscreen;
@@ -92,6 +94,10 @@ public class OverviewCanvas extends Component
       if (updaterunning)
       {
         restart = true;
+        if (or != null)
+        {
+          or.setRedraw(true);
+        }
       }
       else
       {
@@ -113,7 +119,7 @@ public class OverviewCanvas extends Component
 
     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
 
-    OverviewRenderer or = new OverviewRenderer(sr, fr, od);
+    or = new OverviewRenderer(sr, fr, od);
     miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
     offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
 
index ec3e246..2abd65a 100755 (executable)
@@ -334,18 +334,8 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     int res = (evt.getX() / av.getCharWidth())
             + av.getRanges().getStartRes();
 
-    res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
-
-    reveal = null;
-    for (int[] region : av.getAlignment().getHiddenColumns()
-            .getHiddenRegions())
-    {
-      if (res + 1 == region[0] || res - 1 == region[1])
-      {
-        reveal = region;
-        break;
-      }
-    }
+    reveal = av.getAlignment().getHiddenColumns()
+            .getRegionWithEdgeAtRes(res);
 
     repaint();
   }
@@ -450,10 +440,11 @@ public class ScalePanel extends Panel implements MouseMotionListener,
       if (av.getShowHiddenMarkers())
       {
         int widthx = 1 + endx - startx;
-        for (int i = 0; i < hidden.getHiddenRegions().size(); i++)
+        List<Integer> positions = hidden.findHiddenRegionPositions();
+        for (int pos : positions)
         {
 
-          res = hidden.findHiddenRegionPosition(i) - startx;
+          res = pos - startx;
 
           if (res < 0 || res > widthx)
           {
index 46a908e..da54ecf 100755 (executable)
@@ -37,6 +37,7 @@ import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.Panel;
 import java.beans.PropertyChangeEvent;
+import java.util.List;
 
 public class SeqCanvas extends Panel implements ViewportListenerI
 {
@@ -487,11 +488,10 @@ public class SeqCanvas extends Panel implements ViewportListenerI
         HiddenColumns hidden = av.getAlignment().getHiddenColumns();
         g.setColor(Color.blue);
         int res;
-        for (int i = 0; i < hidden.getHiddenRegions()
-                .size(); i++)
+        List<Integer> positions = hidden.findHiddenRegionPositions();
+        for (int pos : positions)
         {
-          res = hidden.findHiddenRegionPosition(i)
-                  - startRes;
+          res = pos - startRes;
 
           if (res < 0 || res > endx - startRes)
           {
@@ -570,7 +570,7 @@ public class SeqCanvas extends Panel implements ViewportListenerI
       if (av.hasHiddenColumns())
       {
         HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-        for (int[] region : hidden.getHiddenRegions())
+        for (int[] region : hidden.getHiddenColumnsCopy())
         {
           int hideStart = region[0];
           int hideEnd = region[1];
index 4aa205e..a72bbaa 100644 (file)
@@ -937,7 +937,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
   List<SequenceFeature> findFeaturesAtRes(SequenceI sequence, int res)
   {
-    List<SequenceFeature> result = new ArrayList<SequenceFeature>();
+    List<SequenceFeature> result = new ArrayList<>();
     SequenceFeature[] features = sequence.getSequenceFeatures();
     if (features != null)
     {
@@ -1501,7 +1501,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         {
           if (links == null)
           {
-            links = new Vector<String>();
+            links = new Vector<>();
           }
           for (int j = 0; j < sf.links.size(); j++)
           {
@@ -1926,8 +1926,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
     if (copycolsel
             && av.hasHiddenColumns()
-            && (av.getColumnSelection() == null || av.getAlignment()
-                    .getHiddenColumns().getHiddenRegions() == null))
+            && (av.getColumnSelection() == null))
     {
       System.err.println("Bad things");
     }
index f5e6fc7..098222f 100755 (executable)
@@ -1916,42 +1916,6 @@ public class Alignment implements AlignmentI
   }
 
   @Override
-  public int[] getVisibleStartAndEndIndex(List<int[]> hiddenCols)
-  {
-    int[] alignmentStartEnd = new int[] { 0, getWidth() - 1 };
-    int startPos = alignmentStartEnd[0];
-    int endPos = alignmentStartEnd[1];
-
-    int[] lowestRange = new int[] { -1, -1 };
-    int[] higestRange = new int[] { -1, -1 };
-
-    for (int[] hiddenCol : hiddenCols)
-    {
-      lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange;
-      higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange;
-    }
-
-    if (lowestRange[0] == -1 && lowestRange[1] == -1)
-    {
-      startPos = alignmentStartEnd[0];
-    }
-    else
-    {
-      startPos = lowestRange[1] + 1;
-    }
-
-    if (higestRange[0] == -1 && higestRange[1] == -1)
-    {
-      endPos = alignmentStartEnd[1];
-    }
-    else
-    {
-      endPos = higestRange[0] - 1;
-    }
-    return new int[] { startPos, endPos };
-  }
-
-  @Override
   public void setHiddenColumns(HiddenColumns cols)
   {
     hiddenCols = cols;
index 2e61f9d..1b5207f 100755 (executable)
@@ -580,15 +580,6 @@ public interface AlignmentI extends AnnotatedCollectionI
    */
   AlignedCodonFrame getMapping(SequenceI mapFrom, SequenceI mapTo);
 
-  /**
-   * Calculate the visible start and end index of an alignment. The result is
-   * returned an int array where: int[0] = startIndex, and int[1] = endIndex.
-   * 
-   * @param hiddenCols
-   * @return
-   */
-  public int[] getVisibleStartAndEndIndex(List<int[]> hiddenCols);
-
   public void setHiddenColumns(HiddenColumns cols);
 
 }
index 837a10b..febf6b4 100644 (file)
@@ -90,7 +90,7 @@ public class CigarArray extends CigarBase
   {
     this(constructSeqCigarArray(alignment, selectionGroup));
     constructFromAlignment(alignment,
-            hidden != null ? hidden.getHiddenRegions()
+            hidden != null ? hidden.getHiddenColumnsCopy()
                     : null, selectionGroup);
   }
 
index eb2d174..4cdd7af 100644 (file)
@@ -482,7 +482,7 @@ public class ColumnSelection
    */
   public void invertColumnSelection(int first, int width, AlignmentI al)
   {
-    boolean hasHidden = al.getHiddenColumns().hasHidden();
+    boolean hasHidden = al.getHiddenColumns().hasHiddenColumns();
     for (int i = first; i < width; i++)
     {
       if (contains(i))
@@ -511,7 +511,7 @@ public class ColumnSelection
     selection = new IntList();
     if (colsel.selection != null && colsel.selection.size() > 0)
     {
-      if (hiddenColumns.hasHidden())
+      if (hiddenColumns.hasHiddenColumns())
       {
         // only select visible columns in this columns selection
         for (Integer col : colsel.getSelected())
index f0d99e5..d34b316 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
 package jalview.datamodel;
 
 import jalview.util.Comparison;
@@ -8,85 +28,159 @@ import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
 import java.util.Vector;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 public class HiddenColumns
 {
+  private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();
+  
   /*
    * list of hidden column [start, end] ranges; the list is maintained in
    * ascending start column order
    */
-  private Vector<int[]> hiddenColumns;
+  private ArrayList<int[]> hiddenColumns;
 
   /**
-   * This Method is used to return all the HiddenColumn regions
-   * 
-   * @return empty list or List of hidden column intervals
+   * Constructor
    */
-  public List<int[]> getHiddenRegions()
+  public HiddenColumns()
   {
-    return hiddenColumns == null ? Collections.<int[]> emptyList()
-            : hiddenColumns;
   }
 
   /**
-   * Find the number of hidden columns
+   * Copy constructor
    * 
-   * @return number of hidden columns
+   * @param copy
    */
-  public int getSize()
+  public HiddenColumns(HiddenColumns copy)
   {
-    int size = 0;
-    if (hasHidden())
+    try
     {
-      for (int[] range : hiddenColumns)
+      LOCK.writeLock().lock();
+      if (copy != null)
       {
-        size += range[1] - range[0] + 1;
+        if (copy.hiddenColumns != null)
+        {
+          hiddenColumns = copy.copyHiddenRegionsToArrayList();
+        }
       }
+    } finally
+    {
+      LOCK.writeLock().unlock();
     }
-    return size;
   }
 
   /**
-   * Answers if there are any hidden columns
+   * This method is used to return all the HiddenColumn regions and is intended
+   * to remain private. External callers which need a copy of the regions can
+   * call getHiddenColumnsCopyAsList.
    * 
-   * @return true if there are hidden columns
+   * @return empty list or List of hidden column intervals
    */
-  public boolean hasHidden()
+  private List<int[]> getHiddenRegions()
   {
-    return (hiddenColumns != null) && (!hiddenColumns.isEmpty());
+    return hiddenColumns == null ? Collections.<int[]> emptyList()
+            : hiddenColumns;
   }
 
-  @Override
-  public boolean equals(Object obj)
+  /**
+   * Output regions data as a string. String is in the format:
+   * reg0[0]<between>reg0[1]<delimiter>reg1[0]<between>reg1[1] ... regn[1]
+   * 
+   * @param delimiter
+   *          string to delimit regions
+   * @param betweenstring
+   *          to put between start and end region values
+   * @return regions formatted according to delimiter and between strings
+   */
+  public String regionsToString(String delimiter, String between)
   {
-    if (!(obj instanceof HiddenColumns))
+    try
+    {
+      LOCK.readLock().lock();
+      StringBuilder regionBuilder = new StringBuilder();
+      if (hiddenColumns != null)
+      {
+        for (int[] range : hiddenColumns)
+        {
+          regionBuilder.append(delimiter).append(range[0]).append(between)
+                  .append(range[1]);
+        }
+
+        regionBuilder.deleteCharAt(0);
+      }
+      return regionBuilder.toString();
+    } finally
     {
-      return false;
+      LOCK.readLock().unlock();
     }
-    HiddenColumns that = (HiddenColumns) obj;
+  }
 
-    /*
-     * check hidden columns are either both null, or match
-     */
-    if (this.hiddenColumns == null)
+  /**
+   * Find the number of hidden columns
+   * 
+   * @return number of hidden columns
+   */
+  public int getSize()
+  {
+    try
     {
-      return (that.hiddenColumns == null);
+      LOCK.readLock().lock();
+      int size = 0;
+      if (hasHiddenColumns())
+      {
+        for (int[] range : hiddenColumns)
+        {
+          size += range[1] - range[0] + 1;
+        }
+      }
+      return size;
     }
-    if (that.hiddenColumns == null
-            || that.hiddenColumns.size() != this.hiddenColumns.size())
+    finally
     {
-      return false;
+      LOCK.readLock().unlock();
     }
-    int i = 0;
-    for (int[] thisRange : hiddenColumns)
+  }
+
+  @Override
+  public boolean equals(Object obj)
+  {
+    try
     {
-      int[] thatRange = that.hiddenColumns.get(i++);
-      if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
+      LOCK.readLock().lock();
+
+      if (!(obj instanceof HiddenColumns))
+      {
+        return false;
+      }
+      HiddenColumns that = (HiddenColumns) obj;
+
+      /*
+       * check hidden columns are either both null, or match
+       */
+      if (this.hiddenColumns == null)
+      {
+        return (that.hiddenColumns == null);
+      }
+      if (that.hiddenColumns == null
+              || that.hiddenColumns.size() != this.hiddenColumns.size())
       {
         return false;
       }
+      int i = 0;
+      for (int[] thisRange : hiddenColumns)
+      {
+        int[] thatRange = that.hiddenColumns.get(i++);
+        if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
+        {
+          return false;
+        }
+      }
+      return true;
+    } finally
+    {
+      LOCK.readLock().unlock();
     }
-    return true;
   }
 
   /**
@@ -98,19 +192,26 @@ public class HiddenColumns
    */
   public int adjustForHiddenColumns(int column)
   {
-    int result = column;
-    if (hiddenColumns != null)
+    try
     {
-      for (int i = 0; i < hiddenColumns.size(); i++)
+      LOCK.readLock().lock();
+      int result = column;
+      if (hiddenColumns != null)
       {
-        int[] region = hiddenColumns.elementAt(i);
-        if (result >= region[0])
+        for (int i = 0; i < hiddenColumns.size(); i++)
         {
-          result += region[1] - region[0] + 1;
+          int[] region = hiddenColumns.get(i);
+          if (result >= region[0])
+          {
+            result += region[1] - region[0] + 1;
+          }
         }
       }
+      return result;
+    } finally
+    {
+      LOCK.readLock().unlock();
     }
-    return result;
   }
 
   /**
@@ -124,42 +225,52 @@ public class HiddenColumns
    */
   public int findColumnPosition(int hiddenColumn)
   {
-    int result = hiddenColumn;
-    if (hiddenColumns != null)
+    try
     {
-      int index = 0;
-      int[] region;
-      do
+      LOCK.readLock().lock();
+      int result = hiddenColumn;
+      if (hiddenColumns != null)
       {
-        region = hiddenColumns.elementAt(index++);
-        if (hiddenColumn > region[1])
+        int index = 0;
+        int[] region;
+        do
         {
-          result -= region[1] + 1 - region[0];
-        }
-      } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size()));
+          region = hiddenColumns.get(index++);
+          if (hiddenColumn > region[1])
+          {
+            result -= region[1] + 1 - region[0];
+          }
+        } while ((hiddenColumn > region[1])
+                && (index < hiddenColumns.size()));
 
-      if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
-      {
-        // Here the hidden column is within a region, so
-        // we want to return the position of region[0]-1, adjusted for any
-        // earlier hidden columns.
-        // Calculate the difference between the actual hidden col position
-        // and region[0]-1, and then subtract from result to convert result from
-        // the adjusted hiddenColumn value to the adjusted region[0]-1 value
-
-        // However, if the region begins at 0 we cannot return region[0]-1
-        // just return 0
-        if (region[0] == 0)
-        {
-          return 0;
-        }
-        else
+        if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
         {
-          return result - (hiddenColumn - region[0] + 1);
+          // Here the hidden column is within a region, so
+          // we want to return the position of region[0]-1, adjusted for any
+          // earlier hidden columns.
+          // Calculate the difference between the actual hidden col position
+          // and region[0]-1, and then subtract from result to convert result
+          // from
+          // the adjusted hiddenColumn value to the adjusted region[0]-1 value
+
+          // However, if the region begins at 0 we cannot return region[0]-1
+          // just return 0
+          if (region[0] == 0)
+          {
+            return 0;
+          }
+          else
+          {
+            return result - (hiddenColumn - region[0] + 1);
+          }
         }
       }
+      return result; // return the shifted position after removing hidden
+                     // columns.
+    } finally
+    {
+      LOCK.readLock().unlock();
     }
-    return result; // return the shifted position after removing hidden columns.
   }
 
   /**
@@ -175,6 +286,10 @@ public class HiddenColumns
    */
   public int subtractVisibleColumns(int visibleDistance, int startColumn)
   {
+    try
+    {
+
+      LOCK.readLock().lock();
     int distance = visibleDistance;
 
     // in case startColumn is in a hidden region, move it to the left
@@ -216,40 +331,62 @@ public class HiddenColumns
       return nextstart - distance;
     }
     return start - distance;
+    } finally
+    {
+      LOCK.readLock().unlock();
+    }
 
   }
 
   /**
-   * Use this method to determine where the next hiddenRegion starts
+   * Use this method to determine the set of hiddenRegion start positions
    * 
-   * @param hiddenRegion
-   *          index of hidden region (counts from 0)
-   * @return column number in visible view
+   * @return list of column number in visible view where hidden regions start
    */
-  public int findHiddenRegionPosition(int hiddenRegion)
+  public List<Integer> findHiddenRegionPositions()
   {
-    int result = 0;
-    if (hiddenColumns != null)
+    try
     {
-      int index = 0;
-      int gaps = 0;
-      do
+      LOCK.readLock().lock();
+      List<Integer> positions = null;
+
+      if (hiddenColumns != null)
       {
-        int[] region = hiddenColumns.elementAt(index);
-        if (hiddenRegion == 0)
+        positions = new ArrayList<>(hiddenColumns.size());
+
+        positions.add(hiddenColumns.get(0)[0]);
+        for (int i = 1; i < hiddenColumns.size(); ++i)
         {
-          return region[0];
-        }
 
-        gaps += region[1] + 1 - region[0];
-        result = region[1] + 1;
-        index++;
-      } while (index <= hiddenRegion);
+          int result = 0;
+          if (hiddenColumns != null)
+          {
+            int index = 0;
+            int gaps = 0;
+            do
+            {
+              int[] region = hiddenColumns.get(index);
+              gaps += region[1] + 1 - region[0];
+              result = region[1] + 1;
+              index++;
+            } while (index <= i);
 
-      result -= gaps;
-    }
+            result -= gaps;
+          }
+          positions.add(result);
+        }
+      }
+      else
+      {
+        positions = new ArrayList<>();
+      }
 
-    return result;
+      return positions;
+    }
+    finally
+    {
+      LOCK.readLock().unlock();
+    }
   }
 
   /**
@@ -261,22 +398,29 @@ public class HiddenColumns
    */
   public int getHiddenBoundaryRight(int alPos)
   {
-    if (hiddenColumns != null)
+    try
     {
-      int index = 0;
-      do
+      LOCK.readLock().lock();
+      if (hiddenColumns != null)
       {
-        int[] region = hiddenColumns.elementAt(index);
-        if (alPos < region[0])
+        int index = 0;
+        do
         {
-          return region[0];
-        }
+          int[] region = hiddenColumns.get(index);
+          if (alPos < region[0])
+          {
+            return region[0];
+          }
 
-        index++;
-      } while (index < hiddenColumns.size());
-    }
+          index++;
+        } while (index < hiddenColumns.size());
+      }
 
-    return alPos;
+      return alPos;
+    } finally
+    {
+      LOCK.readLock().unlock();
+    }
 
   }
 
@@ -289,12 +433,16 @@ public class HiddenColumns
    */
   public int getHiddenBoundaryLeft(int alPos)
   {
+    try
+    {
+      LOCK.readLock().lock();
+
     if (hiddenColumns != null)
     {
       int index = hiddenColumns.size() - 1;
       do
       {
-        int[] region = hiddenColumns.elementAt(index);
+          int[] region = hiddenColumns.get(index);
         if (alPos > region[1])
         {
           return region[1];
@@ -305,7 +453,10 @@ public class HiddenColumns
     }
 
     return alPos;
-
+    } finally
+    {
+      LOCK.readLock().unlock();
+    }
   }
 
   /**
@@ -318,12 +469,16 @@ public class HiddenColumns
    */
   private int getHiddenIndexLeft(int pos)
   {
+    try
+    {
+
+      LOCK.readLock().lock();
     if (hiddenColumns != null)
     {
       int index = hiddenColumns.size() - 1;
       do
       {
-        int[] region = hiddenColumns.elementAt(index);
+          int[] region = hiddenColumns.get(index);
         if (pos > region[1])
         {
           return index;
@@ -334,6 +489,10 @@ public class HiddenColumns
     }
 
     return -1;
+    } finally
+    {
+      LOCK.readLock().unlock();
+    }
 
   }
 
@@ -345,76 +504,101 @@ public class HiddenColumns
    */
   public void hideColumns(int start, int end)
   {
-    if (hiddenColumns == null)
-    {
-      hiddenColumns = new Vector<int[]>();
-    }
-
-    /*
-     * traverse existing hidden ranges and insert / amend / append as
-     * appropriate
-     */
-    for (int i = 0; i < hiddenColumns.size(); i++)
+    boolean wasAlreadyLocked = false;
+    try
     {
-      int[] region = hiddenColumns.elementAt(i);
-
-      if (end < region[0] - 1)
+      // check if the write lock was already locked by this thread,
+      // as this method can be called internally in loops within HiddenColumns
+      if (!LOCK.isWriteLockedByCurrentThread())
       {
-        /*
-         * insert discontiguous preceding range
-         */
-        hiddenColumns.insertElementAt(new int[] { start, end }, i);
-        return;
+        LOCK.writeLock().lock();
+      }
+      else
+      {
+        wasAlreadyLocked = true;
       }
 
-      if (end <= region[1])
+      if (hiddenColumns == null)
       {
-        /*
-         * new range overlaps existing, or is contiguous preceding it - adjust
-         * start column
-         */
-        region[0] = Math.min(region[0], start);
-        return;
+        hiddenColumns = new ArrayList<>();
       }
 
-      if (start <= region[1] + 1)
+      /*
+       * traverse existing hidden ranges and insert / amend / append as
+       * appropriate
+       */
+      for (int i = 0; i < hiddenColumns.size(); i++)
       {
-        /*
-         * new range overlaps existing, or is contiguous following it - adjust
-         * start and end columns
-         */
-        region[0] = Math.min(region[0], start);
-        region[1] = Math.max(region[1], end);
-
-        /*
-         * also update or remove any subsequent ranges 
-         * that are overlapped
-         */
-        while (i < hiddenColumns.size() - 1)
+        int[] region = hiddenColumns.get(i);
+
+        if (end < region[0] - 1)
+        {
+          /*
+           * insert discontiguous preceding range
+           */
+          hiddenColumns.add(i, new int[] { start, end });
+          return;
+        }
+
+        if (end <= region[1])
+        {
+          /*
+           * new range overlaps existing, or is contiguous preceding it - adjust
+           * start column
+           */
+          region[0] = Math.min(region[0], start);
+          return;
+        }
+
+        if (start <= region[1] + 1)
         {
-          int[] nextRegion = hiddenColumns.get(i + 1);
-          if (nextRegion[0] > end + 1)
+          /*
+           * new range overlaps existing, or is contiguous following it - adjust
+           * start and end columns
+           */
+          region[0] = Math.min(region[0], start);
+          region[1] = Math.max(region[1], end);
+
+          /*
+           * also update or remove any subsequent ranges 
+           * that are overlapped
+           */
+          while (i < hiddenColumns.size() - 1)
           {
-            /*
-             * gap to next hidden range - no more to update
-             */
-            break;
+            int[] nextRegion = hiddenColumns.get(i + 1);
+            if (nextRegion[0] > end + 1)
+            {
+              /*
+               * gap to next hidden range - no more to update
+               */
+              break;
+            }
+            region[1] = Math.max(nextRegion[1], end);
+            hiddenColumns.remove(i + 1);
           }
-          region[1] = Math.max(nextRegion[1], end);
-          hiddenColumns.remove(i + 1);
+          return;
         }
-        return;
-      }
     }
 
     /*
      * remaining case is that the new range follows everything else
      */
-    hiddenColumns.addElement(new int[] { start, end });
+      hiddenColumns.add(new int[] { start, end });
+    } finally
+    {
+      if (!wasAlreadyLocked)
+      {
+        LOCK.writeLock().unlock();
+      }
+    }
   }
 
   public boolean isVisible(int column)
   {
+    try
+    {
+      LOCK.readLock().lock();
+
     if (hiddenColumns != null)
     {
       for (int[] region : hiddenColumns)
@@ -427,39 +611,54 @@ public class HiddenColumns
     }
 
     return true;
+    } finally
+    {
+      LOCK.readLock().unlock();
+    }
   }
 
-  /**
-   * ColumnSelection
-   */
-  public HiddenColumns()
+  private ArrayList<int[]> copyHiddenRegionsToArrayList()
   {
-  }
+    int size = 0;
+    if (hiddenColumns != null)
+    {
+      size = hiddenColumns.size();
+    }
+    ArrayList<int[]> copy = new ArrayList<>(size);
+
+    for (int i = 0, j = size; i < j; i++)
+    {
+      int[] rh;
+      int[] cp;
+      rh = hiddenColumns.get(i);
+      if (rh != null)
+      {
+        cp = new int[rh.length];
+        System.arraycopy(rh, 0, cp, 0, rh.length);
+        copy.add(cp);
+      }
+    }
 
+    return copy;
+  }
+  
   /**
-   * Copy constructor
+   * Returns a copy of the vector of hidden regions, as an ArrayList. Before
+   * using this method please consider if you really need access to the hidden
+   * regions - a new (or existing!) method on HiddenColumns might be more
+   * appropriate.
    * 
-   * @param copy
+   * @return hidden regions as an ArrayList of [start,end] pairs
    */
-  public HiddenColumns(HiddenColumns copy)
+  public ArrayList<int[]> getHiddenColumnsCopy()
   {
-    if (copy != null)
+    try
     {
-      if (copy.hiddenColumns != null)
-      {
-        hiddenColumns = new Vector<int[]>(copy.hiddenColumns.size());
-        for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++)
-        {
-          int[] rh, cp;
-          rh = copy.hiddenColumns.elementAt(i);
-          if (rh != null)
-          {
-            cp = new int[rh.length];
-            System.arraycopy(rh, 0, cp, 0, rh.length);
-            hiddenColumns.addElement(cp);
-          }
-        }
-      }
+      LOCK.readLock().lock();
+      return copyHiddenRegionsToArrayList();
+    } finally
+    {
+      LOCK.readLock().unlock();
     }
   }
 
@@ -474,42 +673,49 @@ public class HiddenColumns
   public List<int[]> compensateForEdit(int start, int change,
           ColumnSelection sel)
   {
-    List<int[]> deletedHiddenColumns = null;
-
-    if (hiddenColumns != null)
+    try
     {
-      deletedHiddenColumns = new ArrayList<int[]>();
-      int hSize = hiddenColumns.size();
-      for (int i = 0; i < hSize; i++)
+      LOCK.writeLock().lock();
+      List<int[]> deletedHiddenColumns = null;
+
+      if (hiddenColumns != null)
       {
-        int[] region = hiddenColumns.elementAt(i);
-        if (region[0] > start && start + change > region[1])
+        deletedHiddenColumns = new ArrayList<>();
+        int hSize = hiddenColumns.size();
+        for (int i = 0; i < hSize; i++)
         {
-          deletedHiddenColumns.add(region);
+          int[] region = hiddenColumns.get(i);
+          if (region[0] > start && start + change > region[1])
+          {
+            deletedHiddenColumns.add(region);
 
-          hiddenColumns.removeElementAt(i);
-          i--;
-          hSize--;
-          continue;
-        }
+            hiddenColumns.remove(i);
+            i--;
+            hSize--;
+            continue;
+          }
 
-        if (region[0] > start)
-        {
-          region[0] -= change;
-          region[1] -= change;
-        }
+          if (region[0] > start)
+          {
+            region[0] -= change;
+            region[1] -= change;
+          }
+
+          if (region[0] < 0)
+          {
+            region[0] = 0;
+          }
 
-        if (region[0] < 0)
-        {
-          region[0] = 0;
         }
 
+        this.revealHiddenColumns(0, sel);
       }
 
-      this.revealHiddenColumns(0, sel);
+      return deletedHiddenColumns;
+    } finally
+    {
+      LOCK.writeLock().unlock();
     }
-
-    return deletedHiddenColumns;
   }
 
   /**
@@ -523,34 +729,42 @@ public class HiddenColumns
    */
   public void compensateForDelEdits(int start, int change)
   {
-    if (hiddenColumns != null)
+    try
     {
-      for (int i = 0; i < hiddenColumns.size(); i++)
+      LOCK.writeLock().lock();
+      if (hiddenColumns != null)
       {
-        int[] region = hiddenColumns.elementAt(i);
-        if (region[0] >= start)
-        {
-          region[0] -= change;
-        }
-        if (region[1] >= start)
-        {
-          region[1] -= change;
-        }
-        if (region[1] < region[0])
+        for (int i = 0; i < hiddenColumns.size(); i++)
         {
-          hiddenColumns.removeElementAt(i--);
-        }
+          int[] region = hiddenColumns.get(i);
+          if (region[0] >= start)
+          {
+            region[0] -= change;
+          }
+          if (region[1] >= start)
+          {
+            region[1] -= change;
+          }
+          if (region[1] < region[0])
+          {
+            hiddenColumns.remove(i--);
+          }
 
-        if (region[0] < 0)
-        {
-          region[0] = 0;
-        }
-        if (region[1] < 0)
-        {
-          region[1] = 0;
+          if (region[0] < 0)
+          {
+            region[0] = 0;
+          }
+          if (region[1] < 0)
+          {
+            region[1] = 0;
+          }
         }
       }
     }
+    finally
+    {
+      LOCK.writeLock().unlock();
+    }
   }
 
   /**
@@ -565,111 +779,130 @@ public class HiddenColumns
    */
   public int[] getVisibleContigs(int start, int end)
   {
-    if (hiddenColumns != null && hiddenColumns.size() > 0)
+    try
     {
-      List<int[]> visiblecontigs = new ArrayList<int[]>();
-      List<int[]> regions = getHiddenRegions();
+      LOCK.readLock().lock();
+      if (hiddenColumns != null && hiddenColumns.size() > 0)
+      {
+        List<int[]> visiblecontigs = new ArrayList<>();
+        List<int[]> regions = getHiddenRegions();
 
-      int vstart = start;
-      int[] region;
-      int hideStart, hideEnd;
+        int vstart = start;
+        int[] region;
+        int hideStart;
+        int hideEnd;
 
-      for (int j = 0; vstart < end && j < regions.size(); j++)
-      {
-        region = regions.get(j);
-        hideStart = region[0];
-        hideEnd = region[1];
+        for (int j = 0; vstart < end && j < regions.size(); j++)
+        {
+          region = regions.get(j);
+          hideStart = region[0];
+          hideEnd = region[1];
+
+          if (hideEnd < vstart)
+          {
+            continue;
+          }
+          if (hideStart > vstart)
+          {
+            visiblecontigs.add(new int[] { vstart, hideStart - 1 });
+          }
+          vstart = hideEnd + 1;
+        }
 
-        if (hideEnd < vstart)
+        if (vstart < end)
         {
-          continue;
+          visiblecontigs.add(new int[] { vstart, end - 1 });
         }
-        if (hideStart > vstart)
+        int[] vcontigs = new int[visiblecontigs.size() * 2];
+        for (int i = 0, j = visiblecontigs.size(); i < j; i++)
         {
-          visiblecontigs.add(new int[] { vstart, hideStart - 1 });
+          int[] vc = visiblecontigs.get(i);
+          visiblecontigs.set(i, null);
+          vcontigs[i * 2] = vc[0];
+          vcontigs[i * 2 + 1] = vc[1];
         }
-        vstart = hideEnd + 1;
-      }
-
-      if (vstart < end)
-      {
-        visiblecontigs.add(new int[] { vstart, end - 1 });
+        visiblecontigs.clear();
+        return vcontigs;
       }
-      int[] vcontigs = new int[visiblecontigs.size() * 2];
-      for (int i = 0, j = visiblecontigs.size(); i < j; i++)
+      else
       {
-        int[] vc = visiblecontigs.get(i);
-        visiblecontigs.set(i, null);
-        vcontigs[i * 2] = vc[0];
-        vcontigs[i * 2 + 1] = vc[1];
+        return new int[] { start, end - 1 };
       }
-      visiblecontigs.clear();
-      return vcontigs;
     }
-    else
+    finally
     {
-      return new int[] { start, end - 1 };
+      LOCK.readLock().unlock();
     }
   }
 
   public String[] getVisibleSequenceStrings(int start, int end,
           SequenceI[] seqs)
   {
-    int i, iSize = seqs.length;
-    String selections[] = new String[iSize];
-    if (hiddenColumns != null && hiddenColumns.size() > 0)
+    try
     {
-      for (i = 0; i < iSize; i++)
+      LOCK.readLock().lock();
+      int iSize = seqs.length;
+      String[] selections = new String[iSize];
+      if (hiddenColumns != null && hiddenColumns.size() > 0)
       {
-        StringBuffer visibleSeq = new StringBuffer();
-        List<int[]> regions = getHiddenRegions();
-
-        int blockStart = start, blockEnd = end;
-        int[] region;
-        int hideStart, hideEnd;
-
-        for (int j = 0; j < regions.size(); j++)
+        for (int i = 0; i < iSize; i++)
         {
-          region = regions.get(j);
-          hideStart = region[0];
-          hideEnd = region[1];
+          StringBuffer visibleSeq = new StringBuffer();
+          List<int[]> regions = getHiddenRegions();
 
-          if (hideStart < start)
+          int blockStart = start;
+          int blockEnd = end;
+          int[] region;
+          int hideStart;
+          int hideEnd;
+
+          for (int j = 0; j < regions.size(); j++)
           {
-            continue;
-          }
+            region = regions.get(j);
+            hideStart = region[0];
+            hideEnd = region[1];
 
-          blockStart = Math.min(blockStart, hideEnd + 1);
-          blockEnd = Math.min(blockEnd, hideStart);
+            if (hideStart < start)
+            {
+              continue;
+            }
 
-          if (blockStart > blockEnd)
-          {
-            break;
+            blockStart = Math.min(blockStart, hideEnd + 1);
+            blockEnd = Math.min(blockEnd, hideStart);
+
+            if (blockStart > blockEnd)
+            {
+              break;
+            }
+
+            visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
+
+            blockStart = hideEnd + 1;
+            blockEnd = end;
           }
 
-          visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
+          if (end > blockStart)
+          {
+            visibleSeq.append(seqs[i].getSequence(blockStart, end));
+          }
 
-          blockStart = hideEnd + 1;
-          blockEnd = end;
+          selections[i] = visibleSeq.toString();
         }
-
-        if (end > blockStart)
+      }
+      else
+      {
+        for (int i = 0; i < iSize; i++)
         {
-          visibleSeq.append(seqs[i].getSequence(blockStart, end));
+          selections[i] = seqs[i].getSequenceAsString(start, end);
         }
-
-        selections[i] = visibleSeq.toString();
       }
+
+      return selections;
     }
-    else
+    finally
     {
-      for (i = 0; i < iSize; i++)
-      {
-        selections[i] = seqs[i].getSequenceAsString(start, end);
-      }
+      LOCK.readLock().unlock();
     }
-
-    return selections;
   }
 
   /**
@@ -684,70 +917,86 @@ public class HiddenColumns
    */
   public int[] locateVisibleBoundsOfSequence(SequenceI seq)
   {
-    int fpos = seq.getStart(), lpos = seq.getEnd();
-    int start = 0;
-
-    if (hiddenColumns == null || hiddenColumns.size() == 0)
+    try
     {
-      int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1;
-      return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
-    }
+      LOCK.readLock().lock();
+      int fpos = seq.getStart();
+      int lpos = seq.getEnd();
+      int start = 0;
 
-    // Simply walk along the sequence whilst watching for hidden column
-    // boundaries
-    List<int[]> regions = getHiddenRegions();
-    int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq
-            .getLength(), hideEnd = -1;
-    int visPrev = 0, visNext = 0, firstP = -1, lastP = -1;
-    boolean foundStart = false;
-    for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
-            && p < pLen; p++)
-    {
-      if (!Comparison.isGap(seq.getCharAt(p)))
+      if (hiddenColumns == null || hiddenColumns.size() == 0)
       {
-        // keep track of first/last column
-        // containing sequence data regardless of visibility
-        if (firstP == -1)
-        {
-          firstP = p;
-        }
-        lastP = p;
-        // update hidden region start/end
-        while (hideEnd < p && rcount < regions.size())
-        {
-          int[] region = regions.get(rcount++);
-          visPrev = visNext;
-          visNext += region[0] - visPrev;
-          hideStart = region[0];
-          hideEnd = region[1];
-        }
-        if (hideEnd < p)
-        {
-          hideStart = seq.getLength();
-        }
-        // update visible boundary for sequence
-        if (p < hideStart)
+        int ifpos = seq.findIndex(fpos) - 1;
+        int ilpos = seq.findIndex(lpos) - 1;
+        return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
+      }
+
+      // Simply walk along the sequence whilst watching for hidden column
+      // boundaries
+      List<int[]> regions = getHiddenRegions();
+      int spos = fpos;
+      int lastvispos = -1;
+      int rcount = 0;
+      int hideStart = seq.getLength();
+      int hideEnd = -1;
+      int visPrev = 0;
+      int visNext = 0;
+      int firstP = -1;
+      int lastP = -1;
+      boolean foundStart = false;
+      for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
+              && p < pLen; p++)
+      {
+        if (!Comparison.isGap(seq.getCharAt(p)))
         {
-          if (!foundStart)
+          // keep track of first/last column
+          // containing sequence data regardless of visibility
+          if (firstP == -1)
+          {
+            firstP = p;
+          }
+          lastP = p;
+          // update hidden region start/end
+          while (hideEnd < p && rcount < regions.size())
+          {
+            int[] region = regions.get(rcount++);
+            visPrev = visNext;
+            visNext += region[0] - visPrev;
+            hideStart = region[0];
+            hideEnd = region[1];
+          }
+          if (hideEnd < p)
           {
-            fpos = spos;
-            start = p;
-            foundStart = true;
+            hideStart = seq.getLength();
           }
-          lastvispos = p;
-          lpos = spos;
+          // update visible boundary for sequence
+          if (p < hideStart)
+          {
+            if (!foundStart)
+            {
+              fpos = spos;
+              start = p;
+              foundStart = true;
+            }
+            lastvispos = p;
+            lpos = spos;
+          }
+          // look for next sequence position
+          spos++;
         }
-        // look for next sequence position
-        spos++;
       }
+      if (foundStart)
+      {
+        return new int[] { findColumnPosition(start),
+            findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
+      }
+      // otherwise, sequence was completely hidden
+      return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
     }
-    if (foundStart)
+    finally
     {
-      return new int[] { findColumnPosition(start),
-          findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
+      LOCK.readLock().unlock();
     }
-    // otherwise, sequence was completely hidden
-    return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
   }
 
   /**
@@ -775,88 +1024,100 @@ public class HiddenColumns
   public void makeVisibleAnnotation(int start, int end,
           AlignmentAnnotation alignmentAnnotation)
   {
-    if (alignmentAnnotation.annotations == null)
+    try
     {
-      return;
-    }
-    if (start == end && end == -1)
-    {
-      start = 0;
-      end = alignmentAnnotation.annotations.length;
-    }
-    if (hiddenColumns != null && hiddenColumns.size() > 0)
-    {
-      // then mangle the alignmentAnnotation annotation array
-      Vector<Annotation[]> annels = new Vector<Annotation[]>();
-      Annotation[] els = null;
-      List<int[]> regions = getHiddenRegions();
-      int blockStart = start, blockEnd = end;
-      int[] region;
-      int hideStart, hideEnd, w = 0;
-
-      for (int j = 0; j < regions.size(); j++)
+      LOCK.readLock().lock();
+      if (alignmentAnnotation.annotations == null)
       {
-        region = regions.get(j);
-        hideStart = region[0];
-        hideEnd = region[1];
+        return;
+      }
+      if (start == end && end == -1)
+      {
+        start = 0;
+        end = alignmentAnnotation.annotations.length;
+      }
+      if (hiddenColumns != null && hiddenColumns.size() > 0)
+      {
+        // then mangle the alignmentAnnotation annotation array
+        Vector<Annotation[]> annels = new Vector<>();
+        Annotation[] els = null;
+        List<int[]> regions = getHiddenRegions();
+        int blockStart = start;
+        int blockEnd = end;
+        int[] region;
+        int hideStart;
+        int hideEnd;
+        int w = 0;
 
-        if (hideStart < start)
+        for (int j = 0; j < regions.size(); j++)
         {
-          continue;
-        }
+          region = regions.get(j);
+          hideStart = region[0];
+          hideEnd = region[1];
 
-        blockStart = Math.min(blockStart, hideEnd + 1);
-        blockEnd = Math.min(blockEnd, hideStart);
+          if (hideStart < start)
+          {
+            continue;
+          }
 
-        if (blockStart > blockEnd)
-        {
-          break;
-        }
+          blockStart = Math.min(blockStart, hideEnd + 1);
+          blockEnd = Math.min(blockEnd, hideStart);
 
-        annels.addElement(els = new Annotation[blockEnd - blockStart]);
-        System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
-                0, els.length);
-        w += els.length;
-        blockStart = hideEnd + 1;
-        blockEnd = end;
-      }
+          if (blockStart > blockEnd)
+          {
+            break;
+          }
 
-      if (end > blockStart)
-      {
-        annels.addElement(els = new Annotation[end - blockStart + 1]);
-        if ((els.length + blockStart) <= alignmentAnnotation.annotations.length)
+          annels.addElement(els = new Annotation[blockEnd - blockStart]);
+          System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
+                  0, els.length);
+          w += els.length;
+          blockStart = hideEnd + 1;
+          blockEnd = end;
+        }
+
+        if (end > blockStart)
         {
-          // copy just the visible segment of the annotation row
-          System.arraycopy(alignmentAnnotation.annotations, blockStart,
-                  els, 0, els.length);
+          annels.addElement(els = new Annotation[end - blockStart + 1]);
+          if ((els.length
+                  + blockStart) <= alignmentAnnotation.annotations.length)
+          {
+            // copy just the visible segment of the annotation row
+            System.arraycopy(alignmentAnnotation.annotations, blockStart,
+                    els, 0, els.length);
+          }
+          else
+          {
+            // copy to the end of the annotation row
+            System.arraycopy(alignmentAnnotation.annotations, blockStart,
+                    els, 0,
+                    (alignmentAnnotation.annotations.length - blockStart));
+          }
+          w += els.length;
         }
-        else
+        if (w == 0)
         {
-          // copy to the end of the annotation row
-          System.arraycopy(alignmentAnnotation.annotations, blockStart,
-                  els, 0,
-                  (alignmentAnnotation.annotations.length - blockStart));
+          return;
         }
-        w += els.length;
-      }
-      if (w == 0)
-      {
-        return;
-      }
 
-      alignmentAnnotation.annotations = new Annotation[w];
-      w = 0;
+        alignmentAnnotation.annotations = new Annotation[w];
+        w = 0;
 
-      for (Annotation[] chnk : annels)
+        for (Annotation[] chnk : annels)
+        {
+          System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
+                  chnk.length);
+          w += chnk.length;
+        }
+      }
+      else
       {
-        System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
-                chnk.length);
-        w += chnk.length;
+        alignmentAnnotation.restrict(start, end);
       }
     }
-    else
+    finally
     {
-      alignmentAnnotation.restrict(start, end);
+      LOCK.readLock().unlock();
     }
   }
 
@@ -866,7 +1127,14 @@ public class HiddenColumns
    */
   public boolean hasHiddenColumns()
   {
-    return hiddenColumns != null && hiddenColumns.size() > 0;
+    try
+    {
+      LOCK.readLock().lock();
+      return hiddenColumns != null && hiddenColumns.size() > 0;
+    } finally
+    {
+      LOCK.readLock().unlock();
+    }
   }
 
   /**
@@ -875,7 +1143,14 @@ public class HiddenColumns
    */
   public boolean hasManyHiddenColumns()
   {
-    return hiddenColumns != null && hiddenColumns.size() > 1;
+    try
+    {
+      LOCK.readLock().lock();
+      return hiddenColumns != null && hiddenColumns.size() > 1;
+    } finally
+    {
+      LOCK.readLock().unlock();
+    }
   }
 
   /**
@@ -886,10 +1161,17 @@ public class HiddenColumns
    */
   public void hideInsertionsFor(SequenceI sr)
   {
-    List<int[]> inserts = sr.getInsertions();
-    for (int[] r : inserts)
+    try
     {
-      hideColumns(r[0], r[1]);
+      LOCK.writeLock().lock();
+      List<int[]> inserts = sr.getInsertions();
+      for (int[] r : inserts)
+      {
+        hideColumns(r[0], r[1]);
+      }
+    } finally
+    {
+      LOCK.writeLock().unlock();
     }
   }
 
@@ -898,19 +1180,27 @@ public class HiddenColumns
    */
   public void revealAllHiddenColumns(ColumnSelection sel)
   {
-    if (hiddenColumns != null)
+    try
     {
-      for (int i = 0; i < hiddenColumns.size(); i++)
+      LOCK.writeLock().lock();
+      if (hiddenColumns != null)
       {
-        int[] region = hiddenColumns.elementAt(i);
-        for (int j = region[0]; j < region[1] + 1; j++)
+        for (int i = 0; i < hiddenColumns.size(); i++)
         {
-          sel.addElement(j);
+          int[] region = hiddenColumns.get(i);
+          for (int j = region[0]; j < region[1] + 1; j++)
+          {
+            sel.addElement(j);
+          }
         }
       }
-    }
 
-    hiddenColumns = null;
+      hiddenColumns = null;
+    }
+    finally
+    {
+      LOCK.writeLock().unlock();
+    }
   }
 
   /**
@@ -921,23 +1211,31 @@ public class HiddenColumns
    */
   public void revealHiddenColumns(int start, ColumnSelection sel)
   {
-    for (int i = 0; i < hiddenColumns.size(); i++)
+    try
     {
-      int[] region = hiddenColumns.elementAt(i);
-      if (start == region[0])
+      LOCK.writeLock().lock();
+      for (int i = 0; i < hiddenColumns.size(); i++)
       {
-        for (int j = region[0]; j < region[1] + 1; j++)
+        int[] region = hiddenColumns.get(i);
+        if (start == region[0])
         {
-          sel.addElement(j);
-        }
+          for (int j = region[0]; j < region[1] + 1; j++)
+          {
+            sel.addElement(j);
+          }
 
-        hiddenColumns.removeElement(region);
-        break;
+          hiddenColumns.remove(region);
+          break;
+        }
+      }
+      if (hiddenColumns.size() == 0)
+      {
+        hiddenColumns = null;
       }
     }
-    if (hiddenColumns.size() == 0)
+    finally
     {
-      hiddenColumns = null;
+      LOCK.writeLock().unlock();
     }
   }
 
@@ -949,13 +1247,16 @@ public class HiddenColumns
    * @param intervals
    * @return
    */
-  private boolean pruneIntervalVector(final List<int[]> shifts,
-          Vector<int[]> intervals)
+  private boolean pruneIntervalList(final List<int[]> shifts,
+          ArrayList<int[]> intervals)
   {
     boolean pruned = false;
-    int i = 0, j = intervals.size() - 1, s = 0, t = shifts.size() - 1;
-    int hr[] = intervals.elementAt(i);
-    int sr[] = shifts.get(s);
+    int i = 0;
+    int j = intervals.size() - 1;
+    int s = 0;
+    int t = shifts.size() - 1;
+    int[] hr = intervals.get(i);
+    int[] sr = shifts.get(s);
     while (i <= j && s <= t)
     {
       boolean trailinghn = hr[1] >= sr[0];
@@ -963,7 +1264,7 @@ public class HiddenColumns
       {
         if (i < j)
         {
-          hr = intervals.elementAt(++i);
+          hr = intervals.get(++i);
         }
         else
         {
@@ -991,12 +1292,12 @@ public class HiddenColumns
       {
         if (trailinghc)
         { // deleted hidden region.
-          intervals.removeElementAt(i);
+          intervals.remove(i);
           pruned = true;
           j--;
           if (i <= j)
           {
-            hr = intervals.elementAt(i);
+            hr = intervals.get(i);
           }
           continue;
         }
@@ -1044,15 +1345,23 @@ public class HiddenColumns
    */
   public void pruneDeletions(List<int[]> shifts)
   {
-    // delete any intervals intersecting.
-    if (hiddenColumns != null)
+    try
     {
-      pruneIntervalVector(shifts, hiddenColumns);
-      if (hiddenColumns != null && hiddenColumns.size() == 0)
+      LOCK.writeLock().lock();
+      // delete any intervals intersecting.
+      if (hiddenColumns != null)
       {
-        hiddenColumns = null;
+        pruneIntervalList(shifts, hiddenColumns);
+        if (hiddenColumns != null && hiddenColumns.size() == 0)
+        {
+          hiddenColumns = null;
+        }
       }
     }
+    finally
+    {
+      LOCK.writeLock().unlock();
+    }
   }
 
   /**
@@ -1251,16 +1560,24 @@ public class HiddenColumns
   @Override
   public int hashCode()
   {
-    int hashCode = 1;
-    if (hiddenColumns != null)
+    try
     {
-      for (int[] hidden : hiddenColumns)
+      LOCK.readLock().lock();
+      int hashCode = 1;
+      if (hiddenColumns != null)
       {
-        hashCode = 31 * hashCode + hidden[0];
-        hashCode = 31 * hashCode + hidden[1];
+        for (int[] hidden : hiddenColumns)
+        {
+          hashCode = 31 * hashCode + hidden[0];
+          hashCode = 31 * hashCode + hidden[1];
+        }
       }
+      return hashCode;
+    }
+    finally
+    {
+      LOCK.readLock().unlock();
     }
-    return hashCode;
   }
 
   /**
@@ -1271,11 +1588,19 @@ public class HiddenColumns
    */
   public void hideMarkedBits(BitSet inserts)
   {
-    for (int firstSet = inserts.nextSetBit(0), lastSet = 0; firstSet >= 0; firstSet = inserts
-            .nextSetBit(lastSet))
+    try
     {
-      lastSet = inserts.nextClearBit(firstSet);
-      hideColumns(firstSet, lastSet - 1);
+      LOCK.writeLock().lock();
+      for (int firstSet = inserts
+              .nextSetBit(0), lastSet = 0; firstSet >= 0; firstSet = inserts
+                      .nextSetBit(lastSet))
+      {
+        lastSet = inserts.nextClearBit(firstSet);
+        hideColumns(firstSet, lastSet - 1);
+      }
+    } finally
+    {
+      LOCK.writeLock().unlock();
     }
   }
 
@@ -1286,13 +1611,109 @@ public class HiddenColumns
    */
   public void markHiddenRegions(BitSet inserts)
   {
-    if (hiddenColumns == null)
+    try
+    {
+      LOCK.readLock().lock();
+      if (hiddenColumns == null)
+      {
+        return;
+      }
+      for (int[] range : hiddenColumns)
+      {
+        inserts.set(range[0], range[1] + 1);
+      }
+    }
+    finally
     {
-      return;
+      LOCK.readLock().unlock();
     }
-    for (int[] range : hiddenColumns)
+  }
+
+  /**
+   * Calculate the visible start and end index of an alignment.
+   * 
+   * @param width
+   *          full alignment width
+   * @return integer array where: int[0] = startIndex, and int[1] = endIndex
+   */
+  public int[] getVisibleStartAndEndIndex(int width)
+  {
+    try
+    {
+      LOCK.readLock().lock();
+      int[] alignmentStartEnd = new int[] { 0, width - 1 };
+      int startPos = alignmentStartEnd[0];
+      int endPos = alignmentStartEnd[1];
+
+      int[] lowestRange = new int[] { -1, -1 };
+      int[] higestRange = new int[] { -1, -1 };
+
+      if (hiddenColumns == null)
+      {
+        return new int[] { startPos, endPos };
+      }
+
+      for (int[] hiddenCol : hiddenColumns)
+      {
+        lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange;
+        higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange;
+      }
+
+      if (lowestRange[0] == -1 && lowestRange[1] == -1)
+      {
+        startPos = alignmentStartEnd[0];
+      }
+      else
+      {
+        startPos = lowestRange[1] + 1;
+      }
+
+      if (higestRange[0] == -1 && higestRange[1] == -1)
+      {
+        endPos = alignmentStartEnd[1];
+      }
+      else
+      {
+        endPos = higestRange[0] - 1;
+      }
+      return new int[] { startPos, endPos };
+    } finally
+    {
+      LOCK.readLock().unlock();
+    }
+
+  }
+
+  /**
+   * Finds the hidden region (if any) which starts or ends at res
+   * 
+   * @param res
+   *          visible residue position, unadjusted for hidden columns
+   * @return region as [start,end] or null if no matching region is found
+   */
+  public int[] getRegionWithEdgeAtRes(int res)
+  {
+    try
+    {
+      LOCK.readLock().lock();
+      int adjres = adjustForHiddenColumns(res);
+
+      int[] reveal = null;
+      if (hiddenColumns != null)
+      {
+        for (int[] region : hiddenColumns)
+        {
+          if (adjres + 1 == region[0] || adjres - 1 == region[1])
+          {
+            reveal = region;
+            break;
+          }
+        }
+      }
+      return reveal;
+    } finally
     {
-      inserts.set(range[0], range[1] + 1);
+      LOCK.readLock().unlock();
     }
   }
 
index 70de1e3..a82de93 100644 (file)
@@ -48,7 +48,7 @@ public class VisibleColsIterator implements Iterator<Integer>
     last = lastcol;
     current = firstcol;
     next = firstcol;
-    hidden = hiddenCols.getHiddenRegions();
+    hidden = hiddenCols.getHiddenColumnsCopy();
     lasthiddenregion = -1;
 
     if (hidden != null)
index a9a970f..fe84012 100644 (file)
@@ -167,7 +167,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   public AlignViewControllerI avc;
 
-  List<AlignmentPanel> alignPanels = new ArrayList<AlignmentPanel>();
+  List<AlignmentPanel> alignPanels = new ArrayList<>();
 
   /**
    * Last format used to load or save alignments in this window
@@ -396,8 +396,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     addKeyListener();
 
-    final List<AlignmentPanel> selviews = new ArrayList<AlignmentPanel>();
-    final List<AlignmentPanel> origview = new ArrayList<AlignmentPanel>();
+    final List<AlignmentPanel> selviews = new ArrayList<>();
+    final List<AlignmentPanel> origview = new ArrayList<>();
     final String menuLabel = MessageManager
             .getString("label.copy_format_from");
     ViewSelectionMenu vsel = new ViewSelectionMenu(menuLabel,
@@ -410,7 +410,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 origview.clear();
                 origview.add(alignPanel);
                 // make an array of all alignment panels except for this one
-                List<AlignmentPanel> aps = new ArrayList<AlignmentPanel>(
+                List<AlignmentPanel> aps = new ArrayList<>(
                         Arrays.asList(Desktop.getAlignmentPanels(null)));
                 aps.remove(AlignFrame.this.alignPanel);
                 return aps.toArray(new AlignmentPanel[aps.size()]);
@@ -1320,10 +1320,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       alignmentToExport = viewport.getAlignment();
     }
-    alignmentStartEnd = alignmentToExport
-            .getVisibleStartAndEndIndex(viewport.getAlignment()
-                    .getHiddenColumns()
-                    .getHiddenRegions());
+    alignmentStartEnd = viewport.getAlignment().getHiddenColumns()
+            .getVisibleStartAndEndIndex(alignmentToExport.getWidth());
     AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
             omitHidden, alignmentStartEnd, settings);
     return ed;
@@ -1732,7 +1730,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   synchronized void slideSequences(boolean right, int size)
   {
-    List<SequenceI> sg = new ArrayList<SequenceI>();
+    List<SequenceI> sg = new ArrayList<>();
     if (viewport.cursorMode)
     {
       sg.add(viewport.getAlignment().getSequenceAt(
@@ -1751,7 +1749,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       return;
     }
 
-    List<SequenceI> invertGroup = new ArrayList<SequenceI>();
+    List<SequenceI> invertGroup = new ArrayList<>();
 
     for (SequenceI seq : viewport.getAlignment().getSequences())
     {
@@ -1884,11 +1882,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     ArrayList<int[]> hiddenColumns = null;
     if (viewport.hasHiddenColumns())
     {
-      hiddenColumns = new ArrayList<int[]>();
-      int hiddenOffset = viewport.getSelectionGroup().getStartRes(), hiddenCutoff = viewport
-              .getSelectionGroup().getEndRes();
-      for (int[] region : viewport.getAlignment().getHiddenColumns()
-              .getHiddenRegions())
+      hiddenColumns = new ArrayList<>();
+      int hiddenOffset = viewport.getSelectionGroup().getStartRes();
+      int hiddenCutoff = viewport.getSelectionGroup().getEndRes();
+      ArrayList<int[]> hiddenRegions = viewport.getAlignment()
+              .getHiddenColumns().getHiddenColumnsCopy();
+      for (int[] region : hiddenRegions)
       {
         if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
         {
@@ -1994,7 +1993,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       }
 
       int alwidth = 0;
-      ArrayList<Integer> newGraphGroups = new ArrayList<Integer>();
+      ArrayList<Integer> newGraphGroups = new ArrayList<>();
       int fgroup = -1;
 
       if (newAlignment)
@@ -2826,7 +2825,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   protected List<String> getExistingViewNames(List<Component> comps)
   {
-    List<String> existingNames = new ArrayList<String>();
+    List<String> existingNames = new ArrayList<>();
     for (Component comp : comps)
     {
       if (comp instanceof AlignmentPanel)
@@ -3760,7 +3759,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     List<Component> comps = PaintRefresher.components.get(viewport
             .getSequenceSetId());
-    List<TreePanel> treePanels = new ArrayList<TreePanel>();
+    List<TreePanel> treePanels = new ArrayList<>();
     for (Component comp : comps)
     {
       if (comp instanceof TreePanel)
@@ -4020,7 +4019,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       @Override
       public void run()
       {
-        final List<JMenuItem> legacyItems = new ArrayList<JMenuItem>();
+        final List<JMenuItem> legacyItems = new ArrayList<>();
         try
         {
           // System.err.println("Building ws menu again "
@@ -4035,7 +4034,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           // TODO: group services by location as well as function and/or
           // introduce
           // object broker mechanism.
-          final Vector<JMenu> wsmenu = new Vector<JMenu>();
+          final Vector<JMenu> wsmenu = new Vector<>();
           final IProgressIndicator af = me;
 
           /*
@@ -4403,8 +4402,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // Java's Transferable for native dnd
     evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
     Transferable t = evt.getTransferable();
-    List<String> files = new ArrayList<String>();
-    List<DataSourceType> protocols = new ArrayList<DataSourceType>();
+    List<String> files = new ArrayList<>();
+    List<DataSourceType> protocols = new ArrayList<>();
 
     try
     {
@@ -4424,8 +4423,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         /**
          * Object[] { String,SequenceI}
          */
-        ArrayList<Object[]> filesmatched = new ArrayList<Object[]>();
-        ArrayList<String> filesnotmatched = new ArrayList<String>();
+        ArrayList<Object[]> filesmatched = new ArrayList<>();
+        ArrayList<String> filesnotmatched = new ArrayList<>();
         for (int i = 0; i < files.size(); i++)
         {
           String file = files.get(i).toString();
@@ -5416,7 +5415,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       return;
     }
-    List<SequenceI> cdnaSeqs = new ArrayList<SequenceI>();
+    List<SequenceI> cdnaSeqs = new ArrayList<>();
     for (SequenceI aaSeq : alignment.getSequences())
     {
       for (AlignedCodonFrame acf : mappings)
index 9c2a1b9..6fc5fad 100644 (file)
@@ -36,7 +36,7 @@ import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.awt.event.KeyEvent;
-import java.util.Iterator;
+import java.util.ArrayList;
 
 import javax.swing.ButtonGroup;
 import javax.swing.JCheckBox;
@@ -244,21 +244,21 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
         HiddenColumns oldHidden = av
                 .getAnnotationColumnSelectionState()
                 .getOldHiddenColumns();
-        if (oldHidden != null && oldHidden.getHiddenRegions() != null
-                && !oldHidden.getHiddenRegions().isEmpty())
+        if (oldHidden != null)
         {
-          for (Iterator<int[]> itr = oldHidden.getHiddenRegions()
-                  .iterator(); itr.hasNext();)
+          ArrayList<int[]> regions = oldHidden.getHiddenColumnsCopy();
+          for (int[] positions : regions)
           {
-            int positions[] = itr.next();
             av.hideColumns(positions[0], positions[1]);
           }
         }
+        // TODO not clear why we need to hide all the columns (above) if we are
+        // going to copy the hidden columns over wholesale anyway
         av.getAlignment().setHiddenColumns(oldHidden);
       }
+      av.sendSelection();
       ap.paintAlignment(true);
     }
-
   }
 
   @Override
@@ -397,6 +397,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     {
       av.hideSelectedColumns();
     }
+    av.sendSelection();
 
     filterParams = null;
     av.setAnnotationColumnSelectionState(this);
@@ -727,7 +728,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
 
     private static final String FILTER_BY_ANN_CACHE_KEY = "CACHE.SELECT_FILTER_BY_ANNOT";
 
-    public JvCacheableInputBox<String> searchBox = new JvCacheableInputBox<String>(
+    public JvCacheableInputBox<String> searchBox = new JvCacheableInputBox<>(
             FILTER_BY_ANN_CACHE_KEY);
 
     public SearchPanel(AnnotationColumnChooser aColChooser)
index 8ca1a4e..e16867a 100755 (executable)
@@ -52,7 +52,6 @@ import java.awt.image.BufferedImage;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.List;
 import java.util.regex.Pattern;
 
 import javax.swing.JCheckBoxMenuItem;
@@ -953,13 +952,12 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     }
 
     int[] alignmentStartEnd = new int[] { 0, ds.getWidth() - 1 };
-    List<int[]> hiddenCols = av.getAlignment().getHiddenColumns()
-            .getHiddenRegions();
-    if (hiddenCols != null)
+    if (av.hasHiddenColumns())
     {
-      alignmentStartEnd = av.getAlignment().getVisibleStartAndEndIndex(
-              hiddenCols);
+      alignmentStartEnd = av.getAlignment().getHiddenColumns()
+            .getVisibleStartAndEndIndex(av.getAlignment().getWidth());
     }
+
     String output = new FormatAdapter().formatSequences(FileFormat.Fasta,
             seqs, omitHidden, alignmentStartEnd);
 
@@ -967,14 +965,11 @@ public class AnnotationLabels extends JPanel implements MouseListener,
             .setContents(new StringSelection(output), Desktop.instance);
 
     ArrayList<int[]> hiddenColumns = null;
+
     if (av.hasHiddenColumns())
     {
-      hiddenColumns = new ArrayList<int[]>();
-      for (int[] region : av.getAlignment().getHiddenColumns()
-              .getHiddenRegions())
-      {
-        hiddenColumns.add(new int[] { region[0], region[1] });
-      }
+      hiddenColumns = av.getAlignment().getHiddenColumns()
+              .getHiddenColumnsCopy();
     }
 
     Desktop.jalviewClipboard = new Object[] { seqs, ds, // what is the dataset
index dee921e..45988fb 100644 (file)
@@ -180,13 +180,13 @@ public class Jalview2XML
    * Map of reconstructed AlignFrame objects that appear to have come from
    * SplitFrame objects (have a dna/protein complement view).
    */
-  private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<Viewport, AlignFrame>();
+  private Map<Viewport, AlignFrame> splitFrameCandidates = new HashMap<>();
 
   /*
    * Map from displayed rna structure models to their saved session state jar
    * entry names
    */
-  private Map<RnaModel, String> rnaSessions = new HashMap<RnaModel, String>();
+  private Map<RnaModel, String> rnaSessions = new HashMap<>();
 
   /**
    * create/return unique hash string for sq
@@ -247,19 +247,19 @@ public class Jalview2XML
   {
     if (seqsToIds == null)
     {
-      seqsToIds = new IdentityHashMap<SequenceI, String>();
+      seqsToIds = new IdentityHashMap<>();
     }
     if (seqRefIds == null)
     {
-      seqRefIds = new HashMap<String, SequenceI>();
+      seqRefIds = new HashMap<>();
     }
     if (incompleteSeqs == null)
     {
-      incompleteSeqs = new HashMap<String, SequenceI>();
+      incompleteSeqs = new HashMap<>();
     }
     if (frefedSequence == null)
     {
-      frefedSequence = new ArrayList<SeqFref>();
+      frefedSequence = new ArrayList<>();
     }
   }
 
@@ -458,9 +458,9 @@ public class Jalview2XML
    * This maintains a map of viewports, the key being the seqSetId. Important to
    * set historyItem and redoList for multiple views
    */
-  Map<String, AlignViewport> viewportsAdded = new HashMap<String, AlignViewport>();
+  Map<String, AlignViewport> viewportsAdded = new HashMap<>();
 
-  Map<String, AlignmentAnnotation> annotationIds = new HashMap<String, AlignmentAnnotation>();
+  Map<String, AlignmentAnnotation> annotationIds = new HashMap<>();
 
   String uniqueSetSuffix = "";
 
@@ -536,7 +536,7 @@ public class Jalview2XML
    */
   private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
   {
-    Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
+    Hashtable<String, AlignFrame> dsses = new Hashtable<>();
 
     /*
      * ensure cached data is clear before starting
@@ -551,8 +551,8 @@ public class Jalview2XML
       // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
       // //////////////////////////////////////////////////
 
-      List<String> shortNames = new ArrayList<String>();
-      List<String> viewIds = new ArrayList<String>();
+      List<String> shortNames = new ArrayList<>();
+      List<String> viewIds = new ArrayList<>();
 
       // REVERSE ORDER
       for (int i = frames.size() - 1; i > -1; i--)
@@ -662,7 +662,7 @@ public class Jalview2XML
     {
       FileOutputStream fos = new FileOutputStream(jarFile);
       JarOutputStream jout = new JarOutputStream(fos);
-      List<AlignFrame> frames = new ArrayList<AlignFrame>();
+      List<AlignFrame> frames = new ArrayList<>();
 
       // resolve splitframes
       if (af.getViewport().getCodingComplement() != null)
@@ -748,12 +748,12 @@ public class Jalview2XML
   {
     if (viewIds == null)
     {
-      viewIds = new ArrayList<String>();
+      viewIds = new ArrayList<>();
     }
 
     initSeqRefs();
 
-    List<UserColourScheme> userColours = new ArrayList<UserColourScheme>();
+    List<UserColourScheme> userColours = new ArrayList<>();
 
     AlignViewport av = ap.av;
     ViewportRanges vpRanges = av.getRanges();
@@ -807,9 +807,9 @@ public class Jalview2XML
     }
 
     JSeq jseq;
-    Set<String> calcIdSet = new HashSet<String>();
+    Set<String> calcIdSet = new HashSet<>();
     // record the set of vamsas sequence XML POJO we create.
-    HashMap<String, Sequence> vamsasSetIds = new HashMap<String, Sequence>();
+    HashMap<String, Sequence> vamsasSetIds = new HashMap<>();
     // SAVE SEQUENCES
     for (final SequenceI jds : rjal.getSequences())
     {
@@ -986,7 +986,7 @@ public class Jalview2XML
             pdb.setFile(matchedFile); // entry.getFile());
             if (pdbfiles == null)
             {
-              pdbfiles = new ArrayList<String>();
+              pdbfiles = new ArrayList<>();
             }
 
             if (!pdbfiles.contains(pdbId))
@@ -1135,7 +1135,7 @@ public class Jalview2XML
     /**
      * store forward refs from an annotationRow to any groups
      */
-    IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<SequenceGroup, String>();
+    IdentityHashMap<SequenceGroup, String> groupRefs = new IdentityHashMap<>();
     if (storeDS)
     {
       for (SequenceI sq : jal.getSequences())
@@ -1349,7 +1349,7 @@ public class Jalview2XML
                 .getFeatureRenderer().getRenderOrder()
                 .toArray(new String[0]);
 
-        Vector<String> settingsAdded = new Vector<String>();
+        Vector<String> settingsAdded = new Vector<>();
         if (renderOrder != null)
         {
           for (String featureType : renderOrder)
@@ -1392,7 +1392,7 @@ public class Jalview2XML
         // is groups actually supposed to be a map here ?
         Iterator<String> en = ap.getSeqPanel().seqCanvas
                 .getFeatureRenderer().getFeatureGroups().iterator();
-        Vector<String> groupsAdded = new Vector<String>();
+        Vector<String> groupsAdded = new Vector<>();
         while (en.hasNext())
         {
           String grp = en.next();
@@ -1415,17 +1415,16 @@ public class Jalview2XML
       {
         jalview.datamodel.HiddenColumns hidden = av.getAlignment()
                 .getHiddenColumns();
-        if (hidden == null || hidden.getHiddenRegions() == null)
+        if (hidden == null)
         {
           warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
         }
         else
         {
-          for (int c = 0; c < hidden.getHiddenRegions()
-                  .size(); c++)
+          ArrayList<int[]> hiddenRegions = hidden
+                  .getHiddenColumnsCopy();
+          for (int[] region : hiddenRegions)
           {
-            int[] region = hidden.getHiddenRegions()
-                    .get(c);
             HiddenColumns hc = new HiddenColumns();
             hc.setStart(region[0]);
             hc.setEnd(region[1]);
@@ -2290,7 +2289,7 @@ public class Jalview2XML
     try
     {
       // create list to store references for any new Jmol viewers created
-      newStructureViewers = new Vector<JalviewStructureDisplayI>();
+      newStructureViewers = new Vector<>();
       // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING
       // Workaround is to make sure caller implements the JarInputStreamProvider
       // interface
@@ -2383,8 +2382,8 @@ public class Jalview2XML
       initSeqRefs();
     }
     AlignFrame af = null, _af = null;
-    IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<AlignmentI, AlignmentI>();
-    Map<String, AlignFrame> gatherToThisFrame = new HashMap<String, AlignFrame>();
+    IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<>();
+    Map<String, AlignFrame> gatherToThisFrame = new HashMap<>();
     final String file = jprovider.getFilename();
     try
     {
@@ -2525,9 +2524,9 @@ public class Jalview2XML
    */
   protected void restoreSplitFrames()
   {
-    List<SplitFrame> gatherTo = new ArrayList<SplitFrame>();
-    List<AlignFrame> addedToSplitFrames = new ArrayList<AlignFrame>();
-    Map<String, AlignFrame> dna = new HashMap<String, AlignFrame>();
+    List<SplitFrame> gatherTo = new ArrayList<>();
+    List<AlignFrame> addedToSplitFrames = new ArrayList<>();
+    Map<String, AlignFrame> dna = new HashMap<>();
 
     /*
      * Identify the DNA alignments
@@ -2669,7 +2668,7 @@ public class Jalview2XML
     errorMessage = null;
   }
 
-  Map<String, String> alreadyLoadedPDB = new HashMap<String, String>();
+  Map<String, String> alreadyLoadedPDB = new HashMap<>();
 
   /**
    * when set, local views will be updated from view stored in JalviewXML
@@ -2840,7 +2839,7 @@ public class Jalview2XML
 
     List<SequenceI> hiddenSeqs = null;
 
-    List<SequenceI> tmpseqs = new ArrayList<SequenceI>();
+    List<SequenceI> tmpseqs = new ArrayList<>();
 
     boolean multipleView = false;
     SequenceI referenceseqForView = null;
@@ -2908,7 +2907,7 @@ public class Jalview2XML
       {
         if (hiddenSeqs == null)
         {
-          hiddenSeqs = new ArrayList<SequenceI>();
+          hiddenSeqs = new ArrayList<>();
         }
 
         hiddenSeqs.add(tmpSeq);
@@ -3116,12 +3115,12 @@ public class Jalview2XML
 
     // ////////////////////////////////
     // LOAD ANNOTATIONS
-    List<JvAnnotRow> autoAlan = new ArrayList<JvAnnotRow>();
+    List<JvAnnotRow> autoAlan = new ArrayList<>();
 
     /*
      * store any annotations which forward reference a group's ID
      */
-    Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<String, List<AlignmentAnnotation>>();
+    Map<String, List<AlignmentAnnotation>> groupAnnotRefs = new Hashtable<>();
 
     if (vamsasSet.getAnnotationCount() > 0)
     {
@@ -3276,7 +3275,7 @@ public class Jalview2XML
                   .get(an[i].getGroupRef());
           if (aal == null)
           {
-            aal = new ArrayList<jalview.datamodel.AlignmentAnnotation>();
+            aal = new ArrayList<>();
             groupAnnotRefs.put(an[i].getGroupRef(), aal);
           }
           aal.add(jaa);
@@ -3366,7 +3365,7 @@ public class Jalview2XML
         }
         int pidThreshold = jGroup.getPidThreshold();
 
-        Vector<SequenceI> seqs = new Vector<SequenceI>();
+        Vector<SequenceI> seqs = new Vector<>();
 
         for (int s = 0; s < jGroup.getSeqCount(); s++)
         {
@@ -3759,7 +3758,7 @@ public class Jalview2XML
      * Run through all PDB ids on the alignment, and collect mappings between
      * distinct view ids and all sequences referring to that view.
      */
-    Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<String, StructureViewerModel>();
+    Map<String, StructureViewerModel> structureViewers = new LinkedHashMap<>();
 
     for (int i = 0; i < jseqs.length; i++)
     {
@@ -3957,8 +3956,8 @@ public class Jalview2XML
 
     Set<Entry<File, StructureData>> fileData = data.getFileData()
             .entrySet();
-    List<PDBEntry> pdbs = new ArrayList<PDBEntry>();
-    List<SequenceI[]> allseqs = new ArrayList<SequenceI[]>();
+    List<PDBEntry> pdbs = new ArrayList<>();
+    List<SequenceI[]> allseqs = new ArrayList<>();
     for (Entry<File, StructureData> pdb : fileData)
     {
       String filePath = pdb.getValue().getFilePath();
@@ -4014,9 +4013,9 @@ public class Jalview2XML
               getViewerJarEntryName(svattrib.getViewId()));
     }
 
-    List<String> pdbfilenames = new ArrayList<String>();
-    List<SequenceI[]> seqmaps = new ArrayList<SequenceI[]>();
-    List<String> pdbids = new ArrayList<String>();
+    List<String> pdbfilenames = new ArrayList<>();
+    List<SequenceI[]> seqmaps = new ArrayList<>();
+    List<String> pdbids = new ArrayList<>();
     StringBuilder newFileLoc = new StringBuilder(64);
     int cp = 0, ncp, ecp;
     Map<File, StructureData> oldFiles = svattrib.getFileData();
@@ -4577,8 +4576,8 @@ public class Jalview2XML
       af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
       String[] renderOrder = new String[jms.getFeatureSettings()
               .getSettingCount()];
-      Map<String, FeatureColourI> featureColours = new Hashtable<String, FeatureColourI>();
-      Map<String, Float> featureOrder = new Hashtable<String, Float>();
+      Map<String, FeatureColourI> featureColours = new Hashtable<>();
+      Map<String, Float> featureOrder = new Hashtable<>();
 
       for (int fs = 0; fs < jms.getFeatureSettings().getSettingCount(); fs++)
       {
@@ -4637,7 +4636,7 @@ public class Jalview2XML
           fdi.setVisible(setting.getType());
         }
       }
-      Map<String, Boolean> fgtable = new Hashtable<String, Boolean>();
+      Map<String, Boolean> fgtable = new Hashtable<>();
       for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
       {
         Group grp = jms.getFeatureSettings().getGroup(gs);
@@ -4830,7 +4829,7 @@ public class Jalview2XML
       String[] magicNames = new String[] { "Consensus", "Quality",
           "Conservation" };
       JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
-      Hashtable<String, JvAnnotRow> visan = new Hashtable<String, JvAnnotRow>();
+      Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
       for (String nm : magicNames)
       {
         visan.put(nm, nullAnnot);
@@ -4842,11 +4841,11 @@ public class Jalview2XML
                         + auan.template.getCalcId()), auan);
       }
       int hSize = al.getAlignmentAnnotation().length;
-      List<JvAnnotRow> reorder = new ArrayList<JvAnnotRow>();
+      List<JvAnnotRow> reorder = new ArrayList<>();
       // work through any autoCalculated annotation already on the view
       // removing it if it should be placed in a different location on the
       // annotation panel.
-      List<String> remains = new ArrayList<String>(visan.keySet());
+      List<String> remains = new ArrayList<>(visan.keySet());
       for (int h = 0; h < hSize; h++)
       {
         jalview.datamodel.AlignmentAnnotation jalan = al
@@ -5174,7 +5173,7 @@ public class Jalview2XML
   {
     if (datasetIds == null)
     {
-      datasetIds = new Hashtable<String, AlignmentI>();
+      datasetIds = new Hashtable<>();
       return null;
     }
     if (datasetIds.containsKey(datasetId))
@@ -5188,7 +5187,7 @@ public class Jalview2XML
   {
     if (datasetIds == null)
     {
-      datasetIds = new Hashtable<String, AlignmentI>();
+      datasetIds = new Hashtable<>();
     }
     datasetIds.put(datasetId, dataset);
   }
@@ -5211,7 +5210,7 @@ public class Jalview2XML
       // make a new datasetId and record it
       if (dataset2Ids == null)
       {
-        dataset2Ids = new IdentityHashMap<AlignmentI, String>();
+        dataset2Ids = new IdentityHashMap<>();
       }
       else
       {
@@ -5490,11 +5489,11 @@ public class Jalview2XML
         // register sequence object so the XML parser can recover it.
         if (seqRefIds == null)
         {
-          seqRefIds = new HashMap<String, SequenceI>();
+          seqRefIds = new HashMap<>();
         }
         if (seqsToIds == null)
         {
-          seqsToIds = new IdentityHashMap<SequenceI, String>();
+          seqsToIds = new IdentityHashMap<>();
         }
         seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
         seqsToIds.put((SequenceI) jvobj, id);
index 6f9fbbf..27f9c3f 100644 (file)
@@ -53,6 +53,8 @@ public class OverviewCanvas extends JComponent
 
   private OverviewDimensions od;
 
+  private OverviewRenderer or = null;
+
   private AlignViewportI av;
 
   public OverviewCanvas(OverviewDimensions overviewDims,
@@ -89,6 +91,10 @@ public class OverviewCanvas extends JComponent
       if (updaterunning)
       {
         restart = true;
+        if (or != null)
+        {
+          or.setRedraw(true);
+        }
       }
       else
       {
@@ -120,7 +126,7 @@ public class OverviewCanvas extends JComponent
 
     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
 
-    OverviewRenderer or = new OverviewRenderer(sr, fr, od);
+    or = new OverviewRenderer(sr, fr, od);
     miniMe = or.draw(od.getRows(av.getAlignment()),
             od.getColumns(av.getAlignment()));
 
index 9a6c760..756b77b 100644 (file)
@@ -1944,11 +1944,17 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       }
     }
 
-    if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
-            features, true, ap))
+    /*
+     * an entirely gapped region will generate empty lists of sequence / features
+     */
+    if (!seqs.isEmpty())
     {
-      ap.alignFrame.setShowSeqFeatures(true);
-      ap.highlightSearchResults(null);
+      if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(
+              seqs, features, true, ap))
+      {
+        ap.alignFrame.setShowSeqFeatures(true);
+        ap.highlightSearchResults(null);
+      }
     }
   }
 
index cb19539..3cdba8d 100755 (executable)
@@ -401,24 +401,15 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     int res = (evt.getX() / av.getCharWidth())
             + av.getRanges().getStartRes();
 
+    reveal = av.getAlignment().getHiddenColumns()
+            .getRegionWithEdgeAtRes(res);
+
     res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
 
-    if (av.getAlignment().getHiddenColumns().getHiddenRegions() != null)
-    {
-      for (int[] region : av.getAlignment().getHiddenColumns()
-              .getHiddenRegions())
-      {
-        if (res + 1 == region[0] || res - 1 == region[1])
-        {
-          reveal = region;
-          ToolTipManager.sharedInstance().registerComponent(this);
-          this.setToolTipText(MessageManager
-                  .getString("label.reveal_hidden_columns"));
-          repaint();
-          return;
-        }
-      }
-    }
+    ToolTipManager.sharedInstance().registerComponent(this);
+    this.setToolTipText(
+            MessageManager.getString("label.reveal_hidden_columns"));
+    repaint();
   }
 
   /**
@@ -499,13 +490,12 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
       gg.setColor(Color.blue);
       int res;
 
-      if (av.getShowHiddenMarkers() && hidden.getHiddenRegions() != null)
+      if (av.getShowHiddenMarkers())
       {
-        for (int i = 0; i < hidden.getHiddenRegions()
-                .size(); i++)
+        List<Integer> positions = hidden.findHiddenRegionPositions();
+        for (int pos : positions)
         {
-          res = hidden.findHiddenRegionPosition(i)
-                  - startx;
+          res = pos - startx;
 
           if (res < 0 || res > widthx)
           {
index 0e5e1b8..1625c52 100755 (executable)
@@ -563,9 +563,10 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
         g.setColor(Color.blue);
         int res;
         HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-        for (int i = 0; i < hidden.getHiddenRegions().size(); i++)
+        List<Integer> positions = hidden.findHiddenRegionPositions();
+        for (int pos : positions)
         {
-          res = hidden.findHiddenRegionPosition(i) - startRes;
+          res = pos - startRes;
 
           if (res < 0 || res > endx - startRes)
           {
@@ -662,14 +663,12 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     }
     else
     {
-      List<int[]> regions = av.getAlignment().getHiddenColumns()
-              .getHiddenRegions();
-
       int screenY = 0;
       int blockStart = startRes;
       int blockEnd = endRes;
 
-      for (int[] region : regions)
+      for (int[] region : av.getAlignment().getHiddenColumns()
+              .getHiddenColumnsCopy())
       {
         int hideStart = region[0];
         int hideEnd = region[1];
index c6c2deb..7651eb4 100644 (file)
@@ -2145,8 +2145,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     if (copycolsel
             && av.hasHiddenColumns()
-            && (av.getAlignment().getHiddenColumns() == null || av
-                    .getAlignment().getHiddenColumns().getHiddenRegions() == null))
+            && (av.getAlignment().getHiddenColumns() == null))
     {
       System.err.println("Bad things");
     }
index c3e71da..b669ee5 100755 (executable)
@@ -171,22 +171,9 @@ public class AnnotationFile
     if (cs != null && cs.hasHiddenColumns())
     {
       text.append("VIEW_HIDECOLS\t");
-      List<int[]> hc = cs.getHiddenRegions();
-      boolean comma = false;
-      for (int[] r : hc)
-      {
-        if (!comma)
-        {
-          comma = true;
-        }
-        else
-        {
-          text.append(",");
-        }
-        text.append(r[0]);
-        text.append("-");
-        text.append(r[1]);
-      }
+
+      String regions = cs.regionsToString(",", "-");
+      text.append(regions);
       text.append("\n");
     }
     // TODO: allow efficient recovery of annotation data shown in several
@@ -202,8 +189,8 @@ public class AnnotationFile
       StringBuffer colours = new StringBuffer();
       StringBuffer graphLine = new StringBuffer();
       StringBuffer rowprops = new StringBuffer();
-      Hashtable<Integer, String> graphGroup = new Hashtable<Integer, String>();
-      Hashtable<Integer, Object[]> graphGroup_refs = new Hashtable<Integer, Object[]>();
+      Hashtable<Integer, String> graphGroup = new Hashtable<>();
+      Hashtable<Integer, Object[]> graphGroup_refs = new Hashtable<>();
       BitSet graphGroupSeen = new BitSet();
 
       java.awt.Color color;
@@ -748,8 +735,8 @@ public class AnnotationFile
           BufferedReader in) throws Exception
   {
     nlinesread = 0;
-    ArrayList<Object[]> combineAnnotation_calls = new ArrayList<Object[]>();
-    ArrayList<Object[]> deferredAnnotation_calls = new ArrayList<Object[]>();
+    ArrayList<Object[]> combineAnnotation_calls = new ArrayList<>();
+    ArrayList<Object[]> deferredAnnotation_calls = new ArrayList<>();
     boolean modified = false;
     String groupRef = null;
     Hashtable groupRefRows = new Hashtable();
@@ -1112,7 +1099,7 @@ public class AnnotationFile
         modified = true;
       }
       // Resolve the groupRefs
-      Hashtable<String, SequenceGroup> groupRefLookup = new Hashtable<String, SequenceGroup>();
+      Hashtable<String, SequenceGroup> groupRefLookup = new Hashtable<>();
       Enumeration en = groupRefRows.keys();
 
       while (en.hasMoreElements())
index 816346a..c293cd4 100644 (file)
@@ -279,18 +279,8 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
     // hidden column business
     if (getViewport().hasHiddenColumns())
     {
-      List<int[]> hiddenCols = getViewport().getAlignment()
-              .getHiddenColumns()
-              .getHiddenRegions();
-      StringBuilder hiddenColsBuilder = new StringBuilder();
-      for (int[] range : hiddenCols)
-      {
-        hiddenColsBuilder.append(";").append(range[0]).append("-")
-                .append(range[1]);
-      }
-
-      hiddenColsBuilder.deleteCharAt(0);
-      hiddenSections[0] = hiddenColsBuilder.toString();
+      hiddenSections[0] = getViewport().getAlignment().getHiddenColumns()
+              .regionsToString(";", "-");
     }
 
     // hidden rows/seqs business
@@ -323,7 +313,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
           SequenceI[] sqs, FeatureRenderer fr)
   {
     displayedFeatures = (fr == null) ? null : fr.getFeaturesDisplayed();
-    List<SequenceFeaturesPojo> sequenceFeaturesPojo = new ArrayList<SequenceFeaturesPojo>();
+    List<SequenceFeaturesPojo> sequenceFeaturesPojo = new ArrayList<>();
     if (sqs == null)
     {
       return sequenceFeaturesPojo;
@@ -374,7 +364,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
   public static List<AlignmentAnnotationPojo> annotationToJsonPojo(
           Vector<AlignmentAnnotation> annotations)
   {
-    List<AlignmentAnnotationPojo> jsonAnnotations = new ArrayList<AlignmentAnnotationPojo>();
+    List<AlignmentAnnotationPojo> jsonAnnotations = new ArrayList<>();
     if (annotations == null)
     {
       return jsonAnnotations;
@@ -471,8 +461,8 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
         parseHiddenCols(jvSettingsJsonObj);
       }
 
-      hiddenSequences = new ArrayList<SequenceI>();
-      seqMap = new Hashtable<String, Sequence>();
+      hiddenSequences = new ArrayList<>();
+      seqMap = new Hashtable<>();
       for (Iterator<JSONObject> sequenceIter = seqJsonArray.iterator(); sequenceIter
               .hasNext();)
       {
@@ -515,7 +505,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
         int endRes = Integer.valueOf(seqGrpObj.get("endRes").toString());
         JSONArray sequenceRefs = (JSONArray) seqGrpObj.get("sequenceRefs");
 
-        ArrayList<SequenceI> grpSeqs = new ArrayList<SequenceI>();
+        ArrayList<SequenceI> grpSeqs = new ArrayList<>();
         if (sequenceRefs.size() > 0)
         {
           Iterator<String> seqHashIter = sequenceRefs.iterator();
@@ -649,7 +639,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
 
   public void parseHiddenSeqRefsAsList(JSONObject jvSettingsJson)
   {
-    hiddenSeqRefs = new ArrayList<String>();
+    hiddenSeqRefs = new ArrayList<>();
     String hiddenSeqs = (String) jvSettingsJson.get("hiddenSeqs");
     if (hiddenSeqs != null && !hiddenSeqs.isEmpty())
     {
index 9291ca6..46490cd 100644 (file)
@@ -48,12 +48,14 @@ public class OverviewRenderer
   // raw number of pixels to allocate to each row
   private float pixelsPerSeq;
 
+  // flag to indicate whether to halt drawing
+  private volatile boolean redraw = false;
+
   public OverviewRenderer(jalview.api.SequenceRenderer seqRenderer,
           FeatureRenderer fr, OverviewDimensions od)
-  // FeatureColourFinder colfinder, OverviewDimensions od)
   {
     sr = seqRenderer;
-    finder = new FeatureColourFinder(fr); // colfinder;
+    finder = new FeatureColourFinder(fr);
 
     pixelsPerCol = od.getPixelsPerCol();
     pixelsPerSeq = od.getPixelsPerSeq();
@@ -76,8 +78,14 @@ public class OverviewRenderer
     int rgbcolor = Color.white.getRGB();
     int seqIndex = 0;
     int pixelRow = 0;
+
     for (int alignmentRow : rows)
     {
+      if (redraw)
+      {
+        break;
+      }
+
       // get details of this alignment row
       boolean hidden = rows.isHidden(alignmentRow);
       SequenceI seq = rows.getSequence(alignmentRow);
@@ -90,6 +98,11 @@ public class OverviewRenderer
       int pixelCol = 0;
       for (int alignmentCol : cols)
       {
+        if (redraw)
+        {
+          break;
+        }
+
         // calculate where this column extends to in pixels
         int endCol = Math.min(
                 Math.round((colIndex + 1) * pixelsPerCol) - 1,
@@ -171,6 +184,10 @@ public class OverviewRenderer
     int pixelCol = 0;
     for (int alignmentCol : cols)
     {
+      if (redraw)
+      {
+        break;
+      }
       if (alignmentCol >= annotations.length)
       {
         break; // no more annotations to draw here
@@ -205,4 +222,12 @@ public class OverviewRenderer
       }
     }
   }
+
+  public void setRedraw(boolean b)
+  {
+    synchronized (this)
+    {
+      redraw = b;
+    }
+  }
 }
index 72ac2c8..98f5bff 100644 (file)
@@ -223,7 +223,11 @@ public class FeatureRenderer extends FeatureRendererModel
 
     if (Comparison.isGap(seq.getCharAt(column)))
     {
-      return Color.white;
+      /*
+       * returning null allows the colour scheme to provide gap colour
+       * - normally white, but can be customised otherwise
+       */
+      return null;
     }
 
     Color renderedColour = null;
index 03fc129..b47b82e 100755 (executable)
@@ -24,7 +24,6 @@ import jalview.datamodel.AnnotatedCollectionI;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
-import jalview.util.Comparison;
 
 import java.awt.Color;
 import java.util.Map;
@@ -91,7 +90,7 @@ public abstract class ResidueColourScheme implements ColourSchemeI
   {
     Color colour = Color.white;
 
-    if (!Comparison.isGap(c) && colors != null && symbolIndex != null
+    if (colors != null && symbolIndex != null
             && c < symbolIndex.length
             && symbolIndex[c] < colors.length)
     {
index aa20121..e1b60ca 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.schemes;
 import jalview.datamodel.AnnotatedCollectionI;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 
 import java.awt.Color;
 import java.util.Map;
@@ -35,13 +36,10 @@ import java.util.Map;
  */
 public class ScoreColourScheme extends ResidueColourScheme
 {
-  /** DOCUMENT ME!! */
   public double min;
 
-  /** DOCUMENT ME!! */
   public double max;
 
-  /** DOCUMENT ME!! */
   public double[] scores;
 
   /**
@@ -65,25 +63,38 @@ public class ScoreColourScheme extends ResidueColourScheme
 
     // Make colours in constructor
     // Why wasn't this done earlier?
-    int i, iSize = scores.length;
+    int iSize = scores.length;
     colors = new Color[scores.length];
-    for (i = 0; i < iSize; i++)
+    for (int i = 0; i < iSize; i++)
     {
-      float red = (float) (scores[i] - (float) min) / (float) (max - min);
+      /*
+       * scale score between min and max to the range 0.0 - 1.0
+       */
+      float score = (float) (scores[i] - (float) min) / (float) (max - min);
 
-      if (red > 1.0f)
+      if (score > 1.0f)
       {
-        red = 1.0f;
+        score = 1.0f;
       }
 
-      if (red < 0.0f)
+      if (score < 0.0f)
       {
-        red = 0.0f;
+        score = 0.0f;
       }
-      colors[i] = makeColour(red);
+      colors[i] = makeColour(score);
     }
   }
 
+  @Override
+  public Color findColour(char c, int j, SequenceI seq)
+  {
+    if (Comparison.isGap(c))
+    {
+      return Color.white;
+    }
+    return super.findColour(c);
+  }
+
   /**
    * DOCUMENT ME!
    * 
index 5b376a2..09566c3 100644 (file)
@@ -177,7 +177,7 @@ public class UrlLinkDisplay
       break;
     case NAME:
       setDescription((String) value);
-      break;
+      // deliberate fall through
     case DATABASE:
       setDBName((String) value);
       break;
index 926ccc7..b2ec120 100644 (file)
@@ -108,7 +108,7 @@ public final class MappingUtils
      * Cache a copy of the target sequences so we can mimic successive edits on
      * them. This lets us compute mappings for all edits in the set.
      */
-    Map<SequenceI, SequenceI> targetCopies = new HashMap<SequenceI, SequenceI>();
+    Map<SequenceI, SequenceI> targetCopies = new HashMap<>();
     for (SequenceI seq : mapTo.getSequences())
     {
       SequenceI ds = seq.getDatasetSequence();
@@ -433,7 +433,7 @@ public final class MappingUtils
           boolean undo, AlignmentI mapTo, List<AlignedCodonFrame> mappings)
   {
     SequenceI[] sortOrder = command.getSequenceOrder(undo);
-    List<SequenceI> mappedOrder = new ArrayList<SequenceI>();
+    List<SequenceI> mappedOrder = new ArrayList<>();
     int j = 0;
 
     /*
@@ -518,7 +518,6 @@ public final class MappingUtils
     AlignViewportI protein = targetIsNucleotide ? mapFrom : mapTo;
     List<AlignedCodonFrame> codonFrames = protein.getAlignment()
             .getCodonFrames();
-    // ColumnSelection mappedColumns = new ColumnSelection();
 
     if (colsel == null)
     {
@@ -540,7 +539,7 @@ public final class MappingUtils
               toSequences, fromGapChar);
     }
 
-    for (int[] hidden : hiddencols.getHiddenRegions())
+    for (int[] hidden : hiddencols.getHiddenColumnsCopy())
     {
       mapHiddenColumns(hidden, codonFrames, newHidden, fromSequences,
               toSequences, fromGapChar);
@@ -696,7 +695,7 @@ public final class MappingUtils
   public static List<char[]> findCodonsFor(SequenceI seq, int col,
           List<AlignedCodonFrame> mappings)
   {
-    List<char[]> result = new ArrayList<char[]>();
+    List<char[]> result = new ArrayList<>();
     int dsPos = seq.findPosition(col);
     for (AlignedCodonFrame mapping : mappings)
     {
@@ -775,7 +774,7 @@ public final class MappingUtils
           SequenceI sequence, List<AlignedCodonFrame> mappings,
           List<SequenceI> filterList)
   {
-    List<AlignedCodonFrame> result = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> result = new ArrayList<>();
     if (sequence == null || mappings == null)
     {
       return result;
index 60cee46..107cdd4 100644 (file)
@@ -1159,7 +1159,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   @Override
   public boolean hasHiddenColumns()
   {
-    return colSel != null
+    return alignment.getHiddenColumns() != null
             && alignment.getHiddenColumns().hasHiddenColumns();
   }
 
index d6e09fd..1cfa771 100644 (file)
@@ -37,7 +37,6 @@ import jalview.io.FormatAdapter;
 import jalview.util.MapList;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
@@ -1107,35 +1106,6 @@ public class AlignmentTest
             "addSequence broke dataset reference integrity");
   }
 
-  @Test(groups = "Functional")
-  public void getVisibleStartAndEndIndexTest()
-  {
-    Sequence seq = new Sequence("testSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
-    AlignmentI align = new Alignment(new SequenceI[] { seq });
-    ArrayList<int[]> hiddenCols = new ArrayList<int[]>();
-
-    int[] startEnd = align.getVisibleStartAndEndIndex(hiddenCols);
-    assertEquals(0, startEnd[0]);
-    assertEquals(25, startEnd[1]);
-
-    hiddenCols.add(new int[] { 0, 0 });
-    startEnd = align.getVisibleStartAndEndIndex(hiddenCols);
-    assertEquals(1, startEnd[0]);
-    assertEquals(25, startEnd[1]);
-
-    hiddenCols.add(new int[] { 6, 9 });
-    hiddenCols.add(new int[] { 11, 12 });
-    startEnd = align.getVisibleStartAndEndIndex(hiddenCols);
-    assertEquals(1, startEnd[0]);
-    assertEquals(25, startEnd[1]);
-
-    hiddenCols.add(new int[] { 24, 25 });
-    startEnd = align.getVisibleStartAndEndIndex(hiddenCols);
-    System.out.println(startEnd[0] + " : " + startEnd[1]);
-    assertEquals(1, startEnd[0]);
-    assertEquals(23, startEnd[1]);
-  }
-
   /**
    * Tests that dbrefs with mappings to sequence get updated if the sequence
    * acquires a dataset sequence
index 7237e63..e99e952 100644 (file)
@@ -132,7 +132,7 @@ public class ColumnSelectionTest
     // hide column 5 (and adjacent):
     cs.hideSelectedColumns(5, al.getHiddenColumns());
     // 4,5,6 now hidden:
-    List<int[]> hidden = al.getHiddenColumns().getHiddenRegions();
+    List<int[]> hidden = al.getHiddenColumns().getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
     // none now selected:
@@ -145,7 +145,7 @@ public class ColumnSelectionTest
     cs.addElement(5);
     cs.addElement(6);
     cs.hideSelectedColumns(4, al.getHiddenColumns());
-    hidden = al.getHiddenColumns().getHiddenRegions();
+    hidden = al.getHiddenColumns().getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
     assertTrue(cs.getSelected().isEmpty());
@@ -157,7 +157,7 @@ public class ColumnSelectionTest
     cs.addElement(5);
     cs.addElement(6);
     cs.hideSelectedColumns(6, al.getHiddenColumns());
-    hidden = al.getHiddenColumns().getHiddenRegions();
+    hidden = al.getHiddenColumns().getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
     assertTrue(cs.getSelected().isEmpty());
@@ -168,7 +168,7 @@ public class ColumnSelectionTest
     cs.addElement(4);
     cs.addElement(6);
     cs.hideSelectedColumns(5, al.getHiddenColumns());
-    hidden = al.getHiddenColumns().getHiddenRegions();
+    hidden = al.getHiddenColumns().getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
     assertTrue(cs.getSelected().isEmpty());
@@ -196,7 +196,7 @@ public class ColumnSelectionTest
 
     cs.hideSelectedColumns(al);
     assertTrue(cs.getSelected().isEmpty());
-    List<int[]> hidden = cols.getHiddenRegions();
+    List<int[]> hidden = cols.getHiddenColumnsCopy();
     assertEquals(4, hidden.size());
     assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
     assertEquals("[7, 9]", Arrays.toString(hidden.get(1)));
index 10808d6..fbb354b 100644 (file)
@@ -20,9 +20,9 @@
  */
 package jalview.datamodel;
 
+import static org.testng.Assert.assertNull;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
-import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.analysis.AlignmentGenerator;
@@ -232,14 +232,17 @@ public class HiddenColumnsTest
     HiddenColumns cs = new HiddenColumns();
     cs.hideColumns(10, 11);
     cs.hideColumns(5, 7);
-    assertEquals("[5, 7]", Arrays.toString(cs.getHiddenRegions().get(0)));
+    assertEquals("[5, 7]",
+            Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
 
     HiddenColumns cs2 = new HiddenColumns(cs);
     assertTrue(cs2.hasHiddenColumns());
-    assertEquals(2, cs2.getHiddenRegions().size());
+    assertEquals(2, cs2.getHiddenColumnsCopy().size());
     // hidden columns are held in column order
-    assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenRegions().get(0)));
-    assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenRegions().get(1)));
+    assertEquals("[5, 7]",
+            Arrays.toString(cs2.getHiddenColumnsCopy().get(0)));
+    assertEquals("[10, 11]",
+            Arrays.toString(cs2.getHiddenColumnsCopy().get(1)));
   }
 
   /**
@@ -336,66 +339,78 @@ public class HiddenColumnsTest
     ColumnSelection colsel = new ColumnSelection();
     HiddenColumns cs = al.getHiddenColumns();
     colsel.hideSelectedColumns(5, al.getHiddenColumns());
-    List<int[]> hidden = cs.getHiddenRegions();
+    List<int[]> hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[5, 5]", Arrays.toString(hidden.get(0)));
 
     colsel.hideSelectedColumns(3, al.getHiddenColumns());
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(2, hidden.size());
     // two hidden ranges, in order:
-    assertSame(hidden, cs.getHiddenRegions());
+    assertEquals(hidden.size(), cs.getHiddenColumnsCopy().size());
     assertEquals("[3, 3]", Arrays.toString(hidden.get(0)));
     assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
 
     // hiding column 4 expands [3, 3] to [3, 4]
     // and merges to [5, 5] to make [3, 5]
     colsel.hideSelectedColumns(4, al.getHiddenColumns());
-    hidden = cs.getHiddenRegions();
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[3, 5]", Arrays.toString(hidden.get(0)));
 
     // clear hidden columns (note they are added to selected)
     cs.revealAllHiddenColumns(colsel);
     // it is now actually null but getter returns an empty list
-    assertTrue(cs.getHiddenRegions().isEmpty());
+    assertTrue(cs.getHiddenColumnsCopy().isEmpty());
 
     cs.hideColumns(3, 6);
-    hidden = cs.getHiddenRegions();
+    hidden = cs.getHiddenColumnsCopy();
     int[] firstHiddenRange = hidden.get(0);
     assertEquals("[3, 6]", Arrays.toString(firstHiddenRange));
 
     // adding a subrange of already hidden should do nothing
     cs.hideColumns(4, 5);
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
-    assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+    assertEquals("[3, 6]",
+            Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
     cs.hideColumns(3, 5);
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
-    assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+    assertEquals("[3, 6]",
+            Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
     cs.hideColumns(4, 6);
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
-    assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+    assertEquals("[3, 6]",
+            Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
     cs.hideColumns(3, 6);
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
-    assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+    assertEquals("[3, 6]",
+            Arrays.toString(cs.getHiddenColumnsCopy().get(0)));
 
     cs.revealAllHiddenColumns(colsel);
     cs.hideColumns(2, 4);
-    hidden = cs.getHiddenRegions();
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
 
     // extend contiguous with 2 positions overlap
     cs.hideColumns(3, 5);
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[2, 5]", Arrays.toString(hidden.get(0)));
 
     // extend contiguous with 1 position overlap
     cs.hideColumns(5, 6);
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[2, 6]", Arrays.toString(hidden.get(0)));
 
     // extend contiguous with overlap both ends:
     cs.hideColumns(1, 7);
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[1, 7]", Arrays.toString(hidden.get(0)));
   }
@@ -413,7 +428,7 @@ public class HiddenColumnsTest
     colsel.addElement(10);
     cs.revealHiddenColumns(5, colsel);
     // hidden columns list now null but getter returns empty list:
-    assertTrue(cs.getHiddenRegions().isEmpty());
+    assertTrue(cs.getHiddenColumnsCopy().isEmpty());
     // revealed columns are marked as selected (added to selection):
     assertEquals("[10, 5, 6, 7, 8]", colsel.getSelected().toString());
 
@@ -421,9 +436,9 @@ public class HiddenColumnsTest
     colsel = new ColumnSelection();
     cs = new HiddenColumns();
     cs.hideColumns(5, 8);
-    List<int[]> hidden = cs.getHiddenRegions();
+    List<int[]> hidden = cs.getHiddenColumnsCopy();
     cs.revealHiddenColumns(6, colsel);
-    assertSame(hidden, cs.getHiddenRegions());
+    assertEquals(hidden.size(), cs.getHiddenColumnsCopy().size());
     assertTrue(colsel.getSelected().isEmpty());
   }
 
@@ -442,7 +457,7 @@ public class HiddenColumnsTest
      * revealing hidden columns adds them (in order) to the (unordered)
      * selection list
      */
-    assertTrue(cs.getHiddenRegions().isEmpty());
+    assertTrue(cs.getHiddenColumnsCopy().isEmpty());
     assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", colsel.getSelected()
             .toString());
   }
@@ -478,13 +493,13 @@ public class HiddenColumnsTest
     HiddenColumns cs = new HiddenColumns();
     cs.hideColumns(49, 59);
     cs.hideColumns(69, 79);
-    List<int[]> hidden = cs.getHiddenRegions();
+    List<int[]> hidden = cs.getHiddenColumnsCopy();
     assertEquals(2, hidden.size());
     assertEquals("[49, 59]", Arrays.toString(hidden.get(0)));
     assertEquals("[69, 79]", Arrays.toString(hidden.get(1)));
 
     cs.hideColumns(48, 80);
-    hidden = cs.getHiddenRegions();
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[48, 80]", Arrays.toString(hidden.get(0)));
 
@@ -497,7 +512,7 @@ public class HiddenColumnsTest
     cs.hideColumns(50, 60);
     // hiding 21-49 should merge to one range
     cs.hideColumns(21, 49);
-    hidden = cs.getHiddenRegions();
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[10, 60]", Arrays.toString(hidden.get(0)));
 
@@ -513,7 +528,7 @@ public class HiddenColumnsTest
     cs.hideColumns(60, 70);
 
     cs.hideColumns(15, 45);
-    hidden = cs.getHiddenRegions();
+    hidden = cs.getHiddenColumnsCopy();
     assertEquals(2, hidden.size());
     assertEquals("[10, 50]", Arrays.toString(hidden.get(0)));
     assertEquals("[60, 70]", Arrays.toString(hidden.get(1)));
@@ -530,23 +545,23 @@ public class HiddenColumnsTest
     one.set(1);
     cs = new HiddenColumns();
     cs.hideMarkedBits(one);
-    assertEquals(1, cs.getHiddenRegions().size());
+    assertEquals(1, cs.getHiddenColumnsCopy().size());
 
     one.set(2);
     cs = new HiddenColumns();
     cs.hideMarkedBits(one);
-    assertEquals(1, cs.getHiddenRegions().size());
+    assertEquals(1, cs.getHiddenColumnsCopy().size());
 
     one.set(3);
     cs = new HiddenColumns();
     cs.hideMarkedBits(one);
-    assertEquals(1, cs.getHiddenRegions().size());
+    assertEquals(1, cs.getHiddenColumnsCopy().size());
 
     // split
     one.clear(2);
     cs = new HiddenColumns();
     cs.hideMarkedBits(one);
-    assertEquals(2, cs.getHiddenRegions().size());
+    assertEquals(2, cs.getHiddenColumnsCopy().size());
 
     assertEquals(0, cs.adjustForHiddenColumns(0));
     assertEquals(2, cs.adjustForHiddenColumns(1));
@@ -557,7 +572,7 @@ public class HiddenColumnsTest
     cs = new HiddenColumns();
     cs.hideMarkedBits(one);
 
-    assertEquals(1, cs.getHiddenRegions().size());
+    assertEquals(1, cs.getHiddenColumnsCopy().size());
 
     assertEquals(0, cs.adjustForHiddenColumns(0));
     assertEquals(1, cs.adjustForHiddenColumns(1));
@@ -585,4 +600,93 @@ public class HiddenColumnsTest
       assertEquals(toMark, fromMark);
     }
   }
+
+  @Test(groups = { "Functional" })
+  public void testFindHiddenRegionPositions()
+  {
+    HiddenColumns hc = new HiddenColumns();
+
+    List<Integer> positions = hc.findHiddenRegionPositions();
+    assertTrue(positions.isEmpty());
+
+    hc.hideColumns(3, 7);
+    hc.hideColumns(10, 10);
+    hc.hideColumns(14, 15);
+
+    positions = hc.findHiddenRegionPositions();
+    assertEquals(3, positions.size());
+    assertEquals(3, positions.get(0).intValue());
+    assertEquals(5, positions.get(1).intValue());
+    assertEquals(8, positions.get(2).intValue());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testRegionsToString()
+  {
+    HiddenColumns hc = new HiddenColumns();
+
+    String result = hc.regionsToString(",", "--");
+    assertEquals("", result);
+
+    hc.hideColumns(3, 7);
+    hc.hideColumns(10, 10);
+    hc.hideColumns(14, 15);
+
+    result = hc.regionsToString(",", "--");
+    assertEquals("3--7,10--10,14--15", result);
+  }
+
+  @Test(groups = "Functional")
+  public void getVisibleStartAndEndIndexTest()
+  {
+    Sequence seq = new Sequence("testSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    AlignmentI align = new Alignment(new SequenceI[] { seq });
+    HiddenColumns hc = new HiddenColumns();
+
+    int[] startEnd = hc.getVisibleStartAndEndIndex(align.getWidth());
+    assertEquals(0, startEnd[0]);
+    assertEquals(25, startEnd[1]);
+
+    hc.hideColumns(0, 0);
+    startEnd = hc.getVisibleStartAndEndIndex(align.getWidth());
+    assertEquals(1, startEnd[0]);
+    assertEquals(25, startEnd[1]);
+
+    hc.hideColumns(6, 9);
+    hc.hideColumns(11, 12);
+    startEnd = hc.getVisibleStartAndEndIndex(align.getWidth());
+    assertEquals(1, startEnd[0]);
+    assertEquals(25, startEnd[1]);
+
+    hc.hideColumns(24, 25);
+    startEnd = hc.getVisibleStartAndEndIndex(align.getWidth());
+    System.out.println(startEnd[0] + " : " + startEnd[1]);
+    assertEquals(1, startEnd[0]);
+    assertEquals(23, startEnd[1]);
+  }
+
+  @Test(groups = "Functional")
+  public void testGetRegionWithEdgeAtRes()
+  {
+    HiddenColumns hc = new HiddenColumns();
+
+    int[] result = hc.getRegionWithEdgeAtRes(5);
+    assertNull(result);
+
+    hc.hideColumns(3, 7);
+    hc.hideColumns(10, 10);
+    hc.hideColumns(14, 15);
+
+    result = hc.getRegionWithEdgeAtRes(3);
+    assertEquals(3, result[0]);
+    assertEquals(7, result[1]);
+
+    result = hc.getRegionWithEdgeAtRes(5);
+    assertEquals(10, result[0]);
+    assertEquals(10, result[1]);
+
+    result = hc.getRegionWithEdgeAtRes(6);
+    assertNull(result);
+  }
+
 }
index fed5992..67098ae 100644 (file)
@@ -86,12 +86,12 @@ public class AlignFrameTest
     assertFalse(alignFrame.hideFeatureColumns("exon", true));
     assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
     assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
-            .getHiddenRegions()
+            .getHiddenColumnsCopy()
             .isEmpty());
     assertFalse(alignFrame.hideFeatureColumns("exon", false));
     assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
     assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
-            .getHiddenRegions()
+            .getHiddenColumnsCopy()
             .isEmpty());
 
     /*
@@ -101,7 +101,7 @@ public class AlignFrameTest
     assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
     List<int[]> hidden = alignFrame.getViewport().getAlignment()
             .getHiddenColumns()
-            .getHiddenRegions();
+            .getHiddenColumnsCopy();
     assertTrue(hidden.isEmpty());
 
     /*
@@ -111,7 +111,7 @@ public class AlignFrameTest
      */
     assertTrue(alignFrame.hideFeatureColumns("Turn", true));
     hidden = alignFrame.getViewport().getAlignment().getHiddenColumns()
-            .getHiddenRegions();
+            .getHiddenColumnsCopy();
     assertEquals(hidden.size(), 2);
     assertEquals(hidden.get(0)[0], 1);
     assertEquals(hidden.get(0)[1], 3);
index 2aff5cc..e046d94 100644 (file)
@@ -73,11 +73,11 @@ public class JSONFileTest
 
   private Alignment alignment;
 
-  private HashMap<String, SequenceI> expectedSeqs = new HashMap<String, SequenceI>();
+  private HashMap<String, SequenceI> expectedSeqs = new HashMap<>();
 
-  private HashMap<String, AlignmentAnnotation> expectedAnnots = new HashMap<String, AlignmentAnnotation>();
+  private HashMap<String, AlignmentAnnotation> expectedAnnots = new HashMap<>();
 
-  private HashMap<String, SequenceGroup> expectedGrps = new HashMap<String, SequenceGroup>();
+  private HashMap<String, SequenceGroup> expectedGrps = new HashMap<>();
 
   private HiddenColumns expectedColSel = new HiddenColumns();
 
@@ -131,7 +131,7 @@ public class JSONFileTest
     }
 
     // create and add a sequence group
-    List<SequenceI> grpSeqs = new ArrayList<SequenceI>();
+    List<SequenceI> grpSeqs = new ArrayList<>();
     grpSeqs.add(seqs[1]);
     grpSeqs.add(seqs[2]);
     grpSeqs.add(seqs[3]);
@@ -195,7 +195,7 @@ public class JSONFileTest
     TEST_SEQ_HEIGHT = expectedSeqs.size();
     TEST_GRP_HEIGHT = expectedGrps.size();
     TEST_ANOT_HEIGHT = expectedAnnots.size();
-    TEST_CS_HEIGHT = expectedColSel.getHiddenRegions().size();
+    TEST_CS_HEIGHT = expectedColSel.getHiddenColumnsCopy().size();
 
     exportSettings = new AlignExportSettingI()
     {
@@ -315,11 +315,11 @@ public class JSONFileTest
   {
     HiddenColumns cs = testJsonFile.getHiddenColumns();
     Assert.assertNotNull(cs);
-    Assert.assertNotNull(cs.getHiddenRegions());
-    List<int[]> hiddenCols = cs.getHiddenRegions();
+    Assert.assertNotNull(cs.getHiddenColumnsCopy());
+    List<int[]> hiddenCols = cs.getHiddenColumnsCopy();
     Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT);
     Assert.assertEquals(hiddenCols.get(0), expectedColSel
-            .getHiddenRegions().get(0),
+            .getHiddenColumnsCopy().get(0),
             "Mismatched hidden columns!");
   }
 
index 59566ed..9b68b43 100644 (file)
@@ -2,6 +2,7 @@ package jalview.renderer.seqfeatures;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
 import jalview.api.FeatureColourI;
@@ -126,6 +127,10 @@ public class FeatureColourFinderTest
     assertEquals(c, Color.red);
   }
 
+  /**
+   * feature colour at a gap is null (not white) - a user defined colour scheme
+   * can then provide a bespoke gap colour if configured to do so
+   */
   @Test(groups = "Functional")
   public void testFindFeatureColour_gapPosition()
   {
@@ -135,7 +140,7 @@ public class FeatureColourFinderTest
     fr.featuresAdded();
     av.setShowSequenceFeatures(true);
     Color c = finder.findFeatureColour(null, seq, 6);
-    assertEquals(c, Color.white);
+    assertNull(c);
   }
 
   @Test(groups = "Functional")
diff --git a/test/jalview/schemes/BuriedColourSchemeTest.java b/test/jalview/schemes/BuriedColourSchemeTest.java
new file mode 100644 (file)
index 0000000..cdb0e80
--- /dev/null
@@ -0,0 +1,33 @@
+package jalview.schemes;
+
+import static org.testng.Assert.assertEquals;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class BuriedColourSchemeTest
+{
+  /**
+   * Turn colours are based on the scores in ResidueProperties.buried A = 1.7, R
+   * = 0.1, N = 0.4, D = 0.4... min = 0.05 max = 4.6
+   * <p>
+   * scores are scaled to c 0-1 between min and max and colour is (0, 1-c, c)
+   */
+  @Test(groups = "Functional")
+  public void testFindColour()
+  {
+    ScoreColourScheme scheme = new BuriedColourScheme();
+
+    float min = 0.05f;
+    float max = 4.6f;
+    float a = (1.7f - min) / (max - min);
+    assertEquals(scheme.findColour('A', 0, null), new Color(0, 1 - a, a));
+
+    float d = (0.4f - min) / (max - min);
+    assertEquals(scheme.findColour('D', 0, null), new Color(0, 1 - d, d));
+
+    assertEquals(scheme.findColour('-', 0, null), Color.WHITE);
+  }
+
+}
diff --git a/test/jalview/schemes/HelixColourSchemeTest.java b/test/jalview/schemes/HelixColourSchemeTest.java
new file mode 100644 (file)
index 0000000..ed46419
--- /dev/null
@@ -0,0 +1,33 @@
+package jalview.schemes;
+
+import static org.testng.Assert.assertEquals;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class HelixColourSchemeTest
+{
+  /**
+   * Turn colours are based on the scores in ResidueProperties.helix A = 1.42, R
+   * = 0.98, N = 0.67, D = 1.01... min = 0.57 max = 1.51
+   * <p>
+   * scores are scaled to c 0-1 between min and max and colour is (c, 1-c, c)
+   */
+  @Test(groups = "Functional")
+  public void testFindColour()
+  {
+    ScoreColourScheme scheme = new HelixColourScheme();
+
+    float min = 0.57f;
+    float max = 1.51f;
+    float a = (1.42f - min) / (max - min);
+    assertEquals(scheme.findColour('A', 0, null), new Color(a, 1 - a, a));
+
+    float d = (1.01f - min) / (max - min);
+    assertEquals(scheme.findColour('D', 0, null), new Color(d, 1 - d, d));
+
+    assertEquals(scheme.findColour('-', 0, null), Color.WHITE);
+  }
+
+}
diff --git a/test/jalview/schemes/HydrophobicColourSchemeTest.java b/test/jalview/schemes/HydrophobicColourSchemeTest.java
new file mode 100644 (file)
index 0000000..f3b93a9
--- /dev/null
@@ -0,0 +1,35 @@
+package jalview.schemes;
+
+import static org.testng.Assert.assertEquals;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class HydrophobicColourSchemeTest
+{
+  /**
+   * Turn colours are based on the scores in ResidueProperties.hyd A = 1.8, R =
+   * -4.5, N = -3.5, D = -3.5... min = -3.9 max = 4.5
+   * <p>
+   * scores are scaled to c 0-1 between min and max and colour is (c, 0, 1-c)
+   */
+  @Test(groups = "Functional")
+  public void testFindColour()
+  {
+    ScoreColourScheme scheme = new HydrophobicColourScheme();
+
+    float min = -3.9f;
+    float max = 4.5f;
+    float a = (1.8f - min) / (max - min);
+    assertEquals(scheme.findColour('A', 0, null),
+ new Color(a, 0, 1 - a));
+
+    float d = (-3.5f - min) / (max - min);
+    assertEquals(scheme.findColour('D', 0, null),
+ new Color(d, 0, 1 - d));
+
+    assertEquals(scheme.findColour('-', 0, null), Color.WHITE);
+  }
+
+}
diff --git a/test/jalview/schemes/StrandColourSchemeTest.java b/test/jalview/schemes/StrandColourSchemeTest.java
new file mode 100644 (file)
index 0000000..4a8d0e9
--- /dev/null
@@ -0,0 +1,35 @@
+package jalview.schemes;
+
+import static org.testng.Assert.assertEquals;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class StrandColourSchemeTest
+{
+  /**
+   * Turn colours are based on the scores in ResidueProperties.strand A = 0.83,
+   * R = 0.93, N = 0.89, D = 0.54... min = 0.37 max = 1.7
+   * <p>
+   * scores are scaled to c 0-1 between min and max and colour is (c, c, 1-c)
+   */
+  @Test(groups = "Functional")
+  public void testFindColour()
+  {
+    ScoreColourScheme scheme = new StrandColourScheme();
+
+    float min = 0.37f;
+    float max = 1.7f;
+    float a = (0.83f - min) / (max - min);
+    assertEquals(scheme.findColour('A', 0, null),
+ new Color(a, a, 1 - a));
+
+    float d = (0.54f - min) / (max - min);
+    assertEquals(scheme.findColour('D', 0, null),
+ new Color(d, d, 1 - d));
+
+    assertEquals(scheme.findColour('-', 0, null), Color.WHITE);
+  }
+
+}
diff --git a/test/jalview/schemes/TurnColourSchemeTest.java b/test/jalview/schemes/TurnColourSchemeTest.java
new file mode 100644 (file)
index 0000000..5e6baf0
--- /dev/null
@@ -0,0 +1,35 @@
+package jalview.schemes;
+
+import static org.testng.Assert.assertEquals;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class TurnColourSchemeTest
+{
+  /**
+   * Turn colours are based on the scores in ResidueProperties.turn A = 0.66, R
+   * = 0.95, N = 1.56, D = 1.46... min = 0.47 max = 1.56
+   * <p>
+   * scores are scaled to c 0-1 between min and max and colour is (c, 1-c, 1-c)
+   */
+  @Test(groups = "Functional")
+  public void testFindColour()
+  {
+    ScoreColourScheme scheme = new TurnColourScheme();
+
+    float min = 0.47f;
+    float max = 1.56f;
+    float a = (0.66f - min) / (max - min);
+    assertEquals(scheme.findColour('A', 0, null),
+            new Color(a, 1 - a, 1 - a));
+
+    float d = (1.46f - min) / (max - min);
+    assertEquals(scheme.findColour('D', 0, null),
+            new Color(d, 1 - d, 1 - d));
+
+    assertEquals(scheme.findColour('-', 0, null), Color.WHITE);
+  }
+
+}
index 497014e..2a482ee 100644 (file)
@@ -54,6 +54,10 @@ public class UserColourSchemeTest
     assertEquals(c1, cs.findColour('h'));
     Color c2 = new Color(10, 20, 30);
     assertEquals(c2, cs.findColour('c'));
+    assertEquals(Color.WHITE, cs.findColour('G'));
+    assertEquals(Color.WHITE, cs.findColour('-'));
+    assertEquals(Color.WHITE, cs.findColour('.'));
+    assertEquals(Color.WHITE, cs.findColour(' '));
 
     cs = new UserColourScheme("white");
     cs.parseAppletParameter("D,E=red; K,R,H=0022FF; c=10 , 20,30;t=orange;lowercase=blue;s=pink");
@@ -80,4 +84,29 @@ public class UserColourSchemeTest
     String param = cs.toAppletParameter();
     assertEquals("D,E=ff0000;H,K,R=0022ff;c=0a141e", param);
   }
+
+  /**
+   * Test for user colour scheme constructed with a colour per residue,
+   * including gap. Note this can currently be done from the User Defined
+   * Colours dialog, but not by parsing a colours parameter, as
+   * parseAppletParameter only recognises amino acid codes.
+   */
+  @Test(groups = "Functional")
+  public void testConstructor_coloursArray()
+  {
+    Color g = Color.green;
+    Color y = Color.yellow;
+    Color b = Color.blue;
+    Color r = Color.red;
+    // colours for ARNDCQEGHILKMFPSTWYVBZ and gap
+    Color[] colours = new Color[] { g, y, b, r, g, y, r, b, g, y, r, b, g,
+        y, r, b, g, y, r, b, g, y, r, g };
+    UserColourScheme cs = new UserColourScheme(colours);
+
+    assertEquals(g, cs.findColour('A'));
+    assertEquals(b, cs.findColour('n'));
+    assertEquals(g, cs.findColour('-'));
+    assertEquals(g, cs.findColour('.'));
+    assertEquals(g, cs.findColour(' '));
+  }
 }
index ff7d957..9eeac9f 100644 (file)
@@ -131,7 +131,7 @@ public class UrlLinkDisplayTest {
 
     u.setValue(UrlLinkDisplay.NAME, "New Desc");
     Assert.assertEquals(u.getValue(UrlLinkDisplay.NAME), "New Desc");
-    Assert.assertEquals(u.getValue(UrlLinkDisplay.DATABASE), "TestDB");
+    Assert.assertEquals(u.getValue(UrlLinkDisplay.DATABASE), "New Desc");
 
     u.setValue(UrlLinkDisplay.DATABASE, "NewName");
     Assert.assertEquals(u.getValue(UrlLinkDisplay.DATABASE), "NewName");
index 19c8438..d0ec3e8 100644 (file)
@@ -689,7 +689,7 @@ public class MappingUtilsTest
     AlignedCodonFrame acf3 = new AlignedCodonFrame();
     acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map);
 
-    List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> mappings = new ArrayList<>();
     mappings.add(acf1);
     mappings.add(acf2);
     mappings.add(acf3);
@@ -764,7 +764,7 @@ public class MappingUtilsTest
     AlignedCodonFrame acf4 = new AlignedCodonFrame();
     acf4.addMap(seq3.getDatasetSequence(), seq4.getDatasetSequence(), map);
 
-    List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> mappings = new ArrayList<>();
     mappings.add(acf1);
     mappings.add(acf2);
     mappings.add(acf3);
@@ -821,7 +821,7 @@ public class MappingUtilsTest
     AlignedCodonFrame acf = new AlignedCodonFrame();
     MapList map = new MapList(new int[] { 8, 16 }, new int[] { 5, 7 }, 3, 1);
     acf.addMap(dna.getDatasetSequence(), protein.getDatasetSequence(), map);
-    List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
+    List<AlignedCodonFrame> mappings = new ArrayList<>();
     mappings.add(acf);
 
     AlignmentI prot = new Alignment(new SequenceI[] { protein });
@@ -913,7 +913,7 @@ public class MappingUtilsTest
     MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
             proteinView, dnaView, dnaSelection, dnaHidden);
     assertEquals("[]", dnaSelection.getSelected().toString());
-    List<int[]> hidden = dnaHidden.getHiddenRegions();
+    List<int[]> hidden = dnaHidden.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[0, 4]", Arrays.toString(hidden.get(0)));
 
@@ -930,7 +930,7 @@ public class MappingUtilsTest
     proteinSelection.hideSelectedColumns(1, hiddenCols);
     MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
             proteinView, dnaView, dnaSelection, dnaHidden);
-    hidden = dnaHidden.getHiddenRegions();
+    hidden = dnaHidden.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
 
@@ -944,7 +944,7 @@ public class MappingUtilsTest
     proteinSelection.hideSelectedColumns(2, hiddenCols);
     MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
             proteinView, dnaView, dnaSelection, dnaHidden);
-    assertTrue(dnaHidden.getHiddenRegions().isEmpty());
+    assertTrue(dnaHidden.getHiddenColumnsCopy().isEmpty());
 
     /*
      * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
@@ -959,7 +959,7 @@ public class MappingUtilsTest
     MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
             proteinView, dnaView, dnaSelection, dnaHidden);
     assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString());
-    hidden = dnaHidden.getHiddenRegions();
+    hidden = dnaHidden.getHiddenColumnsCopy();
     assertEquals(1, hidden.size());
     assertEquals("[5, 10]", Arrays.toString(hidden.get(0)));
 
@@ -974,7 +974,7 @@ public class MappingUtilsTest
     proteinSelection.hideSelectedColumns(3, hiddenCols);
     MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
             proteinView, dnaView, dnaSelection, dnaHidden);
-    hidden = dnaHidden.getHiddenRegions();
+    hidden = dnaHidden.getHiddenColumnsCopy();
     assertEquals(2, hidden.size());
     assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
     assertEquals("[5, 10]", Arrays.toString(hidden.get(1)));
@@ -988,7 +988,7 @@ public class MappingUtilsTest
     /*
      * [start, end] ranges
      */
-    List<int[]> ranges = new ArrayList<int[]>();
+    List<int[]> ranges = new ArrayList<>();
     assertEquals(0, MappingUtils.getLength(ranges));
     ranges.add(new int[] { 1, 1 });
     assertEquals(1, MappingUtils.getLength(ranges));
@@ -1011,7 +1011,7 @@ public class MappingUtilsTest
   public void testContains()
   {
     assertFalse(MappingUtils.contains(null, 1));
-    List<int[]> ranges = new ArrayList<int[]>();
+    List<int[]> ranges = new ArrayList<>();
     assertFalse(MappingUtils.contains(ranges, 1));
 
     ranges.add(new int[] { 1, 4 });