Merge branch 'develop' into features/JAL-2446NCList
[jalview.git] / src / jalview / gui / FeatureSettings.java
index 34f0b4a..45b6b0d 100644 (file)
@@ -23,7 +23,7 @@ package jalview.gui;
 import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.bin.Cache;
-import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 import jalview.gui.Help.HelpId;
 import jalview.io.JalviewFileChooser;
@@ -475,50 +475,26 @@ public class FeatureSettings extends JPanel implements
   private boolean handlingUpdate = false;
 
   /**
-   * contains a float[3] for each feature type string. created by setTableData
+   * holds {featureCount, totalExtent} for each feature type
    */
   Map<String, float[]> typeWidth = null;
 
   @Override
   synchronized public void discoverAllFeatureData()
   {
-    Vector<String> allFeatures = new Vector<String>();
-    Vector<String> allGroups = new Vector<String>();
-    SequenceFeature[] tmpfeatures;
-    String group;
-    for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
-    {
-      tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
-              .getSequenceFeatures();
-      if (tmpfeatures == null)
-      {
-        continue;
-      }
+    Set<String> allGroups = new HashSet<String>();
+    AlignmentI alignment = af.getViewport().getAlignment();
 
-      int index = 0;
-      while (index < tmpfeatures.length)
+    for (int i = 0; i < alignment.getHeight(); i++)
+    {
+      SequenceI seq = alignment.getSequenceAt(i);
+      for (String group : seq.getFeatures().getFeatureGroups(true))
       {
-        if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
+        if (group != null && !allGroups.contains(group))
         {
-          index++;
-          continue;
+          allGroups.add(group);
+          checkGroupState(group);
         }
-
-        if (tmpfeatures[index].getFeatureGroup() != null)
-        {
-          group = tmpfeatures[index].featureGroup;
-          if (!allGroups.contains(group))
-          {
-            allGroups.addElement(group);
-            checkGroupState(group);
-          }
-        }
-
-        if (!allFeatures.contains(tmpfeatures[index].getType()))
-        {
-          allFeatures.addElement(tmpfeatures[index].getType());
-        }
-        index++;
       }
     }
 
@@ -572,7 +548,7 @@ public class FeatureSettings extends JPanel implements
 
   synchronized void resetTable(String[] groupChanged)
   {
-    if (resettingTable == true)
+    if (resettingTable)
     {
       return;
     }
@@ -580,71 +556,59 @@ public class FeatureSettings extends JPanel implements
     typeWidth = new Hashtable<String, float[]>();
     // TODO: change avWidth calculation to 'per-sequence' average and use long
     // rather than float
-    float[] avWidth = null;
-    SequenceFeature[] tmpfeatures;
-    String group = null, type;
-    Vector<String> visibleChecks = new Vector<String>();
+
+    Set<String> displayableTypes = new HashSet<String>();
     Set<String> foundGroups = new HashSet<String>();
 
-    // Find out which features should be visible depending on which groups
-    // are selected / deselected
-    // and recompute average width ordering
+    /*
+     * determine which feature types may be visible depending on 
+     * which groups are selected, and recompute average width data
+     */
     for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
     {
 
-      tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
-              .getSequenceFeatures();
-      if (tmpfeatures == null)
-      {
-        continue;
-      }
+      SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
 
-      int index = 0;
-      while (index < tmpfeatures.length)
+      /*
+       * get the sequence's groups for positional features
+       * and keep track of which groups are visible
+       */
+      Set<String> groups = seq.getFeatures().getFeatureGroups(true);
+      Set<String> visibleGroups = new HashSet<String>();
+      for (String group : groups)
       {
-        group = tmpfeatures[index].featureGroup;
-        foundGroups.add(group);
-
-        if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
-        {
-          index++;
-          continue;
-        }
-
         if (group == null || checkGroupState(group))
         {
-          type = tmpfeatures[index].getType();
-          if (!visibleChecks.contains(type))
-          {
-            visibleChecks.addElement(type);
-          }
-        }
-        if (!typeWidth.containsKey(tmpfeatures[index].getType()))
-        {
-          typeWidth.put(tmpfeatures[index].getType(),
-                  avWidth = new float[3]);
+          visibleGroups.add(group);
         }
-        else
-        {
-          avWidth = typeWidth.get(tmpfeatures[index].getType());
-        }
-        avWidth[0]++;
-        if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
-        {
-          avWidth[1] += 1 + tmpfeatures[index].getBegin()
-                  - tmpfeatures[index].getEnd();
-        }
-        else
+      }
+      foundGroups.addAll(groups);
+
+      /*
+       * get distinct feature types for visible groups
+       * record distinct visible types, and their count and total length
+       */
+      Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
+              visibleGroups.toArray(new String[visibleGroups.size()]));
+      for (String type : types)
+      {
+        displayableTypes.add(type);
+        float[] avWidth = typeWidth.get(type);
+        if (avWidth == null)
         {
-          avWidth[1] += 1 + tmpfeatures[index].getEnd()
-                  - tmpfeatures[index].getBegin();
+          avWidth = new float[2];
+          typeWidth.put(type, avWidth);
         }
-        index++;
+        // todo this could include features with a non-visible group
+        // - do we greatly care?
+        // todo should we include non-displayable features here, and only
+        // update when features are added?
+        avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
+        avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
       }
     }
 
-    int fSize = visibleChecks.size();
-    Object[][] data = new Object[fSize][3];
+    Object[][] data = new Object[displayableTypes.size()][3];
     int dataIndex = 0;
 
     if (fr.hasRenderOrder())
@@ -660,9 +624,9 @@ public class FeatureSettings extends JPanel implements
       List<String> frl = fr.getRenderOrder();
       for (int ro = frl.size() - 1; ro > -1; ro--)
       {
-        type = frl.get(ro);
+        String type = frl.get(ro);
 
-        if (!visibleChecks.contains(type))
+        if (!displayableTypes.contains(type))
         {
           continue;
         }
@@ -672,16 +636,17 @@ public class FeatureSettings extends JPanel implements
         data[dataIndex][2] = new Boolean(af.getViewport()
                 .getFeaturesDisplayed().isVisible(type));
         dataIndex++;
-        visibleChecks.removeElement(type);
+        displayableTypes.remove(type);
       }
     }
 
-    fSize = visibleChecks.size();
-    for (int i = 0; i < fSize; i++)
+    /*
+     * process any extra features belonging only to 
+     * a group which was just selected
+     */
+    while (!displayableTypes.isEmpty())
     {
-      // These must be extra features belonging to the group
-      // which was just selected
-      type = visibleChecks.elementAt(i).toString();
+      String type = displayableTypes.iterator().next();
       data[dataIndex][0] = type;
 
       data[dataIndex][1] = fr.getFeatureStyle(type);
@@ -694,6 +659,7 @@ public class FeatureSettings extends JPanel implements
 
       data[dataIndex][2] = new Boolean(true);
       dataIndex++;
+      displayableTypes.remove(type);
     }
 
     if (originalData == null)