JAL-2418 source formatting
[jalview.git] / src / jalview / controller / AlignViewController.java
index 151af0e..24fc181 100644 (file)
@@ -33,11 +33,11 @@ import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
 import jalview.io.FeaturesFile;
 import jalview.util.MessageManager;
 
 import java.awt.Color;
-import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.List;
 
@@ -85,10 +85,11 @@ public class AlignViewController implements AlignViewControllerI
     SequenceGroup[] gps = null;
     if (sg != null && (cs == null || cs.isEmpty()))
     {
-      gps = jalview.analysis.Grouping.makeGroupsFrom(viewport
-              .getSequenceSelection(), viewport.getAlignmentView(true)
-              .getSequenceStrings(viewport.getGapCharacter()), viewport
-              .getAlignment().getGroups());
+      gps = jalview.analysis.Grouping.makeGroupsFrom(
+              viewport.getSequenceSelection(),
+              viewport.getAlignmentView(true)
+                      .getSequenceStrings(viewport.getGapCharacter()),
+              viewport.getAlignment().getGroups());
     }
     else
     {
@@ -96,8 +97,8 @@ public class AlignViewController implements AlignViewControllerI
       {
         gps = jalview.analysis.Grouping.makeGroupsFromCols(
                 (sg == null) ? viewport.getAlignment().getSequencesArray()
-                        : sg.getSequences().toArray(new SequenceI[0]), cs,
-                viewport.getAlignment().getGroups());
+                        : sg.getSequences().toArray(new SequenceI[0]),
+                cs, viewport.getAlignment().getGroups());
       }
     }
     if (gps != null)
@@ -170,193 +171,178 @@ public class AlignViewController implements AlignViewControllerI
     // JBPNote this routine could also mark rows, not just columns.
     // need a decent query structure to allow all types of feature searches
     BitSet bs = new BitSet();
-    int alw, alStart;
-    SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null ? viewport
-            .getAlignment() : viewport.getSelectionGroup());
-    alStart = sqcol.getStartRes();
-    alw = sqcol.getEndRes() + 1;
+    SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null
+            || extendCurrent) ? viewport.getAlignment()
+                    : viewport.getSelectionGroup();
+
+    int nseq = findColumnsWithFeature(featureType, sqcol, bs);
+
+    ColumnSelection cs = viewport.getColumnSelection();
+    if (cs == null)
+    {
+      cs = new ColumnSelection();
+    }
+
+    if (bs.cardinality() > 0 || invert)
+    {
+      boolean changed = cs.markColumns(bs, sqcol.getStartRes(),
+              sqcol.getEndRes(), invert, extendCurrent, toggle);
+      if (changed)
+      {
+        viewport.setColumnSelection(cs);
+        alignPanel.paintAlignment(true);
+        int columnCount = invert
+                ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
+                        - bs.cardinality()
+                : bs.cardinality();
+        avcg.setStatus(MessageManager.formatMessage(
+                "label.view_controller_toggled_marked", new String[]
+                { toggle ? MessageManager.getString("label.toggled")
+                        : MessageManager.getString("label.marked"),
+                    String.valueOf(columnCount),
+                    invert ? MessageManager
+                            .getString("label.not_containing")
+                            : MessageManager.getString("label.containing"),
+                    featureType, Integer.valueOf(nseq).toString() }));
+        return true;
+      }
+    }
+    else
+    {
+      avcg.setStatus(MessageManager
+              .formatMessage("label.no_feature_of_type_found", new String[]
+              { featureType }));
+      if (!extendCurrent)
+      {
+        cs.clear();
+        alignPanel.paintAlignment(true);
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Sets a bit in the BitSet for each column (base 0) in the sequence
+   * collection which includes the specified feature type. Returns the number of
+   * sequences which have the feature in the selected range.
+   * 
+   * @param featureType
+   * @param sqcol
+   * @param bs
+   * @return
+   */
+  static int findColumnsWithFeature(String featureType,
+          SequenceCollectionI sqcol, BitSet bs)
+  {
+    final int startPosition = sqcol.getStartRes() + 1; // converted to base 1
+    final int endPosition = sqcol.getEndRes() + 1;
     List<SequenceI> seqs = sqcol.getSequences();
     int nseq = 0;
     for (SequenceI sq : seqs)
     {
-      int tfeat = 0;
+      boolean sequenceHasFeature = false;
       if (sq != null)
       {
-        SequenceFeature[] sf = sq.getSequenceFeatures();
-        if (sf != null)
+        SequenceFeature[] sfs = sq.getSequenceFeatures();
+        if (sfs != null)
         {
           int ist = sq.findIndex(sq.getStart());
           int iend = sq.findIndex(sq.getEnd());
-          if (iend < alStart || ist > alw)
+          if (iend < startPosition || ist > endPosition)
           {
             // sequence not in region
             continue;
           }
-          for (SequenceFeature sfpos : sf)
+          for (SequenceFeature sf : sfs)
           {
-            // future functionalty - featureType == null means mark columns
+            // future functionality - featureType == null means mark columns
             // containing all displayed features
-            if (sfpos != null && (featureType.equals(sfpos.getType())))
+            if (sf != null && (featureType.equals(sf.getType())))
             {
-              tfeat++;
               // optimisation - could consider 'spos,apos' like cursor argument
               // - findIndex wastes time by starting from first character and
               // counting
 
-              int i = sq.findIndex(sfpos.getBegin());
-              int j = sq.findIndex(sfpos.getEnd());
-              if (j < alStart || i > alw)
+              int sfStartCol = sq.findIndex(sf.getBegin());
+              int sfEndCol = sq.findIndex(sf.getEnd());
+
+              if (sf.isContactFeature())
+              {
+                /*
+                 * 'contact' feature - check for 'start' or 'end'
+                 * position within the selected region
+                 */
+                if (sfStartCol >= startPosition
+                        && sfStartCol <= endPosition)
+                {
+                  bs.set(sfStartCol - 1);
+                  sequenceHasFeature = true;
+                }
+                if (sfEndCol >= startPosition && sfEndCol <= endPosition)
+                {
+                  bs.set(sfEndCol - 1);
+                  sequenceHasFeature = true;
+                }
+                continue;
+              }
+
+              /*
+               * contiguous feature - select feature positions (if any) 
+               * within the selected region
+               */
+              if (sfStartCol > endPosition || sfEndCol < startPosition)
               {
                 // feature is outside selected region
                 continue;
               }
-              if (i < alStart)
+              sequenceHasFeature = true;
+              if (sfStartCol < startPosition)
               {
-                i = alStart;
+                sfStartCol = startPosition;
               }
-              if (i < ist)
+              if (sfStartCol < ist)
               {
-                i = ist;
+                sfStartCol = ist;
               }
-              if (j > alw)
+              if (sfEndCol > endPosition)
               {
-                j = alw;
+                sfEndCol = endPosition;
               }
-              for (; i <= j; i++)
+              for (; sfStartCol <= sfEndCol; sfStartCol++)
               {
-                bs.set(i - 1);
+                bs.set(sfStartCol - 1); // convert to base 0
               }
             }
           }
         }
 
-        if (tfeat > 0)
+        if (sequenceHasFeature)
         {
           nseq++;
         }
       }
     }
-    ColumnSelection cs = viewport.getColumnSelection();
-    if (bs.cardinality() > 0 || invert)
-    {
-      if (cs == null)
-      {
-        cs = new ColumnSelection();
-      }
-      else
-      {
-        if (!extendCurrent)
-        {
-          cs.clear();
-        }
-      }
-      if (invert)
-      {
-        // invert only in the currently selected sequence region
-        for (int i = bs.nextClearBit(alStart), ibs = bs.nextSetBit(alStart); i >= alStart
-                && i < (alw);)
-        {
-          if (ibs < 0 || i < ibs)
-          {
-            if (toggle && cs.contains(i))
-            {
-              cs.removeElement(i++);
-            }
-            else
-            {
-              cs.addElement(i++);
-            }
-          }
-          else
-          {
-            i = bs.nextClearBit(ibs);
-            ibs = bs.nextSetBit(i);
-          }
-        }
-      }
-      else
-      {
-        for (int i = bs.nextSetBit(alStart); i >= alStart; i = bs
-                .nextSetBit(i + 1))
-        {
-          if (toggle && cs.contains(i))
-          {
-            cs.removeElement(i);
-          }
-          else
-          {
-            cs.addElement(i);
-          }
-        }
-      }
-      viewport.setColumnSelection(cs);
-      alignPanel.paintAlignment(true);
-      avcg.setStatus(MessageManager.formatMessage(
-              "label.view_controller_toggled_marked",
-              new String[] {
-                  (toggle ? MessageManager.getString("label.toggled")
-                          : MessageManager.getString("label.marked")),
-                  (invert ? (Integer.valueOf((alw - alStart)
-                          - bs.cardinality()).toString()) : (Integer
-                          .valueOf(bs.cardinality()).toString())),
-                  featureType, Integer.valueOf(nseq).toString() }));
-      return true;
-    }
-    else
-    {
-      avcg.setStatus(MessageManager.formatMessage(
-              "label.no_feature_of_type_found",
-              new String[] { featureType }));
-      if (!extendCurrent && cs != null)
-      {
-        cs.clear();
-        alignPanel.paintAlignment(true);
-      }
-      return false;
-    }
+    return nseq;
   }
 
   @Override
-  public void sortAlignmentByFeatureDensity(String[] typ)
+  public void sortAlignmentByFeatureDensity(List<String> typ)
   {
     sortBy(typ, "Sort by Density", AlignmentSorter.FEATURE_DENSITY);
   }
 
-  protected void sortBy(String[] typ, String methodText, final String method)
+  protected void sortBy(List<String> typ, String methodText,
+          final String method)
   {
     FeatureRenderer fr = alignPanel.getFeatureRenderer();
-    if (typ == null)
+    if (typ == null && fr != null)
     {
-      typ = fr == null ? null : fr.getDisplayedFeatureTypes();
+      typ = fr.getDisplayedFeatureTypes();
     }
-    String gps[] = null;
-    gps = fr == null ? null : fr.getDisplayedFeatureGroups();
-    if (typ != null)
+    List<String> gps = null;
+    if (fr != null)
     {
-      ArrayList types = new ArrayList();
-      for (int i = 0; i < typ.length; i++)
-      {
-        if (typ[i] != null)
-        {
-          types.add(typ[i]);
-        }
-        typ = new String[types.size()];
-        types.toArray(typ);
-      }
-    }
-    if (gps != null)
-    {
-      ArrayList grps = new ArrayList();
-
-      for (int i = 0; i < gps.length; i++)
-      {
-        if (gps[i] != null)
-        {
-          grps.add(gps[i]);
-        }
-      }
-      gps = new String[grps.size()];
-      grps.toArray(gps);
+      gps = fr.getDisplayedFeatureGroups();
     }
     AlignmentI al = viewport.getAlignment();
 
@@ -374,28 +360,29 @@ public class AlignViewController implements AlignViewControllerI
     }
     SequenceI[] oldOrder = al.getSequencesArray();
     AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
-    avcg.addHistoryItem(new OrderCommand(methodText, oldOrder, viewport
-            .getAlignment()));
+    avcg.addHistoryItem(new OrderCommand(methodText, oldOrder,
+            viewport.getAlignment()));
     alignPanel.paintAlignment(true);
 
   }
 
   @Override
-  public void sortAlignmentByFeatureScore(String[] typ)
+  public void sortAlignmentByFeatureScore(List<String> typ)
   {
     sortBy(typ, "Sort by Feature Score", AlignmentSorter.FEATURE_SCORE);
   }
 
   @Override
-  public boolean parseFeaturesFile(String file, String protocol,
+  public boolean parseFeaturesFile(String file, DataSourceType protocol,
           boolean relaxedIdMatching)
   {
     boolean featuresFile = false;
     try
     {
-      featuresFile = new FeaturesFile(false, file, protocol).parse(viewport
-              .getAlignment().getDataset(), alignPanel.getFeatureRenderer()
-              .getFeatureColours(), false, relaxedIdMatching);
+      featuresFile = new FeaturesFile(false, file, protocol).parse(
+              viewport.getAlignment().getDataset(),
+              alignPanel.getFeatureRenderer().getFeatureColours(), false,
+              relaxedIdMatching);
     } catch (Exception ex)
     {
       ex.printStackTrace();
@@ -419,4 +406,67 @@ public class AlignViewController implements AlignViewControllerI
     return featuresFile;
 
   }
+
+  @Override
+  public boolean markHighlightedColumns(boolean invert,
+          boolean extendCurrent, boolean toggle)
+  {
+    if (!viewport.hasSearchResults())
+    {
+      // do nothing if no selection exists
+      return false;
+    }
+    // JBPNote this routine could also mark rows, not just columns.
+    BitSet bs = new BitSet();
+    SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null
+            || extendCurrent) ? viewport.getAlignment()
+                    : viewport.getSelectionGroup();
+
+    // this could be a lambda... - the remains of the method is boilerplate,
+    // except for the different messages for reporting selection.
+    int nseq = viewport.getSearchResults().markColumns(sqcol, bs);
+
+    ColumnSelection cs = viewport.getColumnSelection();
+    if (cs == null)
+    {
+      cs = new ColumnSelection();
+    }
+
+    if (bs.cardinality() > 0 || invert)
+    {
+      boolean changed = cs.markColumns(bs, sqcol.getStartRes(),
+              sqcol.getEndRes(), invert, extendCurrent, toggle);
+      if (changed)
+      {
+        viewport.setColumnSelection(cs);
+        alignPanel.paintAlignment(true);
+        int columnCount = invert
+                ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
+                        - bs.cardinality()
+                : bs.cardinality();
+        avcg.setStatus(MessageManager.formatMessage(
+                "label.view_controller_toggled_marked", new String[]
+                { toggle ? MessageManager.getString("label.toggled")
+                        : MessageManager.getString("label.marked"),
+                    String.valueOf(columnCount),
+                    invert ? MessageManager
+                            .getString("label.not_containing")
+                            : MessageManager.getString("label.containing"),
+                    "Highlight", Integer.valueOf(nseq).toString() }));
+        return true;
+      }
+    }
+    else
+    {
+      avcg.setStatus(MessageManager
+              .formatMessage("No highlighted regions marked"));
+      if (!extendCurrent)
+      {
+        cs.clear();
+        alignPanel.paintAlignment(true);
+      }
+    }
+    return false;
+  }
+
 }