JAL-3081 sort annotations by order read from project after reloading
[jalview.git] / src / jalview / project / Jalview2XML.java
index cf5974c..eaabd47 100644 (file)
@@ -24,6 +24,8 @@ import static jalview.math.RotatableMatrix.Axis.X;
 import static jalview.math.RotatableMatrix.Axis.Y;
 import static jalview.math.RotatableMatrix.Axis.Z;
 
+import jalview.analysis.AnnotationSorter;
+import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.Conservation;
 import jalview.analysis.PCA;
 import jalview.analysis.scoremodels.ScoreModels;
@@ -1479,6 +1481,8 @@ public class Jalview2XML
       view.setRenderGaps(av.isRenderGaps());
       view.setShowAnnotation(av.isShowAnnotation());
       view.setShowBoxes(av.getShowBoxes());
+      view.setShowAutocalcAbove(av.isShowAutocalculatedAbove());
+      view.setSortAnnotationsBy(av.getSortAnnotationsBy().name());
       view.setShowColourText(av.getColourText());
       view.setShowFullId(av.getShowJVSuffix());
       view.setRightAlignIds(av.isRightAlignIds());
@@ -3619,7 +3623,7 @@ public class Jalview2XML
 
     // ////////////////////////////////
     // LOAD ANNOTATIONS
-    List<JvAnnotRow> autoAlan = new ArrayList<>();
+    List<AlignmentAnnotation> addedAnnotation = new ArrayList<>();
 
     /*
      * store any annotations which forward reference a group's ID
@@ -3710,7 +3714,11 @@ public class Jalview2XML
             }
           }
         }
-        jalview.datamodel.AlignmentAnnotation jaa = null;
+
+        /*
+         * construct the Jalview AlignmentAnnotation, add to alignment
+         */
+        AlignmentAnnotation jaa = null;
 
         if (annotation.isGraph())
         {
@@ -3808,9 +3816,10 @@ public class Jalview2XML
           jaa.autoCalculated = true; // means annotation will be marked for
           // update at end of load.
         }
-        if (annotation.getGraphHeight() != null)
+        Integer graphHeight = annotation.getGraphHeight();
+        if (graphHeight != null)
         {
-          jaa.graphHeight = annotation.getGraphHeight().intValue();
+          jaa.graphHeight = graphHeight.intValue();
         }
         jaa.belowAlignment = annotation.isBelowAlignment();
         jaa.setCalcId(annotation.getCalcId());
@@ -3822,17 +3831,16 @@ public class Jalview2XML
             jaa.setProperty(prop.getName(), prop.getValue());
           }
         }
-        if (jaa.autoCalculated)
+        if (!jaa.autoCalculated)
         {
-          autoAlan.add(new JvAnnotRow(i, jaa));
-        }
-        else
-        // if (!autoForView)
-        {
-          // add autocalculated group annotation and any user created annotation
-          // for the view
+          // TODO ensure Consensus etc is enabled if found in project?
+          /*
+           * add autocalculated group annotation and any user created annotation
+           * for the view
+           */
           al.addAnnotation(jaa);
         }
+        addedAnnotation.add(jaa);
       }
     }
     // ///////////////////////
@@ -4025,9 +4033,16 @@ public class Jalview2XML
     if (isnewview)
     {
       af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view,
-              uniqueSeqSetId, viewId, autoAlan);
+              uniqueSeqSetId, viewId);
+      // TODO restore autocalc preferences if overridden earlier?
+      /*
+       * resort annotations to their order in the project
+       * (also sets height and visibility for autocalc'd annotation)
+       */
       av = af.getViewport();
+      new AnnotationSorter(av).sort(addedAnnotation);
       ap = af.alignPanel;
+      ap.adjustAnnotationHeight();
     }
 
     /*
@@ -4187,10 +4202,8 @@ public class Jalview2XML
           // TODO: verify 'associate with all views' works still
           tp.getTreeCanvas().setViewport(av); // af.viewport;
           tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
-          // FIXME: should we use safeBoolean here ?
-          tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
-
         }
+        tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
         if (tp == null)
         {
           warn("There was a problem recovering stored Newick tree: \n"
@@ -4837,7 +4850,7 @@ public class Jalview2XML
   AlignFrame loadViewport(String file, List<JSeq> JSEQ,
           List<SequenceI> hiddenSeqs, AlignmentI al,
           JalviewModel jm, Viewport view, String uniqueSeqSetId,
-          String viewId, List<JvAnnotRow> autoAlan)
+          String viewId)
   {
     AlignFrame af = null;
     af = new AlignFrame(al, safeInt(view.getWidth()),
@@ -4918,9 +4931,8 @@ public class Jalview2XML
 
     viewport.setColourText(safeBoolean(view.isShowColourText()));
 
-    viewport
-            .setConservationSelected(
-                    safeBoolean(view.isConservationSelected()));
+    viewport.setConservationSelected(
+            safeBoolean(view.isConservationSelected()));
     viewport.setIncrement(safeInt(view.getConsThreshold()));
     viewport.setShowJVSuffix(safeBoolean(view.isShowFullId()));
     viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds()));
@@ -4936,10 +4948,27 @@ public class Jalview2XML
     viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment()));
     viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation()));
 
-    viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
+    Boolean autocalcFirst = view.isShowAutocalcAbove();
+    if (autocalcFirst != null)
+    {
+      af.setShowAutoCalculatedAbove(autocalcFirst.booleanValue());
+    }
+    String sortBy = view.getSortAnnotationsBy();
+    if (sortBy != null)
+    {
+      try
+      {
+        viewport.setSortAnnotationsBy(
+                SequenceAnnotationOrder.valueOf(sortBy));
+      } catch (IllegalArgumentException e)
+      {
+        Cache.log.error(
+                "Invalid annotation sort specifier in project: " + sortBy);
+      }
+    }
 
+    viewport.setShowBoxes(safeBoolean(view.isShowBoxes()));
     viewport.setShowText(safeBoolean(view.isShowText()));
-
     viewport.setTextColour(new Color(safeInt(view.getTextCol1())));
     viewport.setTextColour2(new Color(safeInt(view.getTextCol2())));
     viewport.setThresholdTextColour(safeInt(view.getTextColThreshold()));
@@ -5178,7 +5207,6 @@ public class Jalview2XML
               safeInt(view.getWidth()), safeInt(view.getHeight()));
       // recompute any autoannotation
       af.alignPanel.updateAnnotation(false, true);
-      reorderAutoannotation(af, al, autoAlan);
       af.alignPanel.alignmentChanged();
     }
     else
@@ -5305,106 +5333,6 @@ public class Jalview2XML
     return cs;
   }
 
-  private void reorderAutoannotation(AlignFrame af, AlignmentI al,
-          List<JvAnnotRow> autoAlan)
-  {
-    // copy over visualization settings for autocalculated annotation in the
-    // view
-    if (al.getAlignmentAnnotation() != null)
-    {
-      /**
-       * Kludge for magic autoannotation names (see JAL-811)
-       */
-      String[] magicNames = new String[] { "Consensus", "Quality",
-          "Conservation" };
-      JvAnnotRow nullAnnot = new JvAnnotRow(-1, null);
-      Hashtable<String, JvAnnotRow> visan = new Hashtable<>();
-      for (String nm : magicNames)
-      {
-        visan.put(nm, nullAnnot);
-      }
-      for (JvAnnotRow auan : autoAlan)
-      {
-        visan.put(auan.template.label
-                + (auan.template.getCalcId() == null ? ""
-                        : "\t" + auan.template.getCalcId()),
-                auan);
-      }
-      int hSize = al.getAlignmentAnnotation().length;
-      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<>(visan.keySet());
-      for (int h = 0; h < hSize; h++)
-      {
-        jalview.datamodel.AlignmentAnnotation jalan = al
-                .getAlignmentAnnotation()[h];
-        if (jalan.autoCalculated)
-        {
-          String k;
-          JvAnnotRow valan = visan.get(k = jalan.label);
-          if (jalan.getCalcId() != null)
-          {
-            valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId());
-          }
-
-          if (valan != null)
-          {
-            // delete the auto calculated row from the alignment
-            al.deleteAnnotation(jalan, false);
-            remains.remove(k);
-            hSize--;
-            h--;
-            if (valan != nullAnnot)
-            {
-              if (jalan != valan.template)
-              {
-                // newly created autoannotation row instance
-                // so keep a reference to the visible annotation row
-                // and copy over all relevant attributes
-                if (valan.template.graphHeight >= 0)
-
-                {
-                  jalan.graphHeight = valan.template.graphHeight;
-                }
-                jalan.visible = valan.template.visible;
-              }
-              reorder.add(new JvAnnotRow(valan.order, jalan));
-            }
-          }
-        }
-      }
-      // Add any (possibly stale) autocalculated rows that were not appended to
-      // the view during construction
-      for (String other : remains)
-      {
-        JvAnnotRow othera = visan.get(other);
-        if (othera != nullAnnot && othera.template.getCalcId() != null
-                && othera.template.getCalcId().length() > 0)
-        {
-          reorder.add(othera);
-        }
-      }
-      // now put the automatic annotation in its correct place
-      int s = 0, srt[] = new int[reorder.size()];
-      JvAnnotRow[] rws = new JvAnnotRow[reorder.size()];
-      for (JvAnnotRow jvar : reorder)
-      {
-        rws[s] = jvar;
-        srt[s++] = jvar.order;
-      }
-      reorder.clear();
-      jalview.util.QuickSort.sort(srt, rws);
-      // and re-insert the annotation at its correct position
-      for (JvAnnotRow jvar : rws)
-      {
-        al.addAnnotation(jvar.template, jvar.order);
-      }
-      af.alignPanel.adjustAnnotationHeight();
-    }
-  }
-
   Hashtable skipList = null;
 
   /**