Commands, history, consensus, refresh updated
[jalview.git] / src / jalview / appletgui / AlignViewport.java
index ca9b447..5eb5e46 100755 (executable)
@@ -106,6 +106,11 @@ public class AlignViewport
 \r
   boolean MAC = false;\r
 \r
+  Stack historyList = new Stack();\r
+  Stack redoList = new Stack();\r
+\r
+  String sequenceSetID;\r
+\r
   public AlignViewport(AlignmentI al, JalviewLite applet)\r
   {\r
     this.applet = applet;\r
@@ -159,11 +164,6 @@ public class AlignViewport
       }\r
 \r
     }\r
-    // We must set conservation and consensus before setting colour,\r
-    // as Blosum and Clustal require this to be done\r
-    updateConservation();\r
-    updateConsensus();\r
-\r
 \r
     if (applet != null)\r
     {\r
@@ -191,7 +191,48 @@ public class AlignViewport
             applet.getParameter("userDefinedColour"));\r
       }\r
 \r
+      if(hconsensus==null)\r
+      {\r
+        if(!alignment.isNucleotide())\r
+        {\r
+          conservation = new AlignmentAnnotation("Conservation",\r
+              "Conservation of total alignment less than " +\r
+              ConsPercGaps + "% gaps",\r
+              new Annotation[1], 0f,\r
+              11f,\r
+              AlignmentAnnotation.BAR_GRAPH);\r
+          conservation.hasText = true;\r
+\r
+\r
+          if (showConservation)\r
+          {\r
+            alignment.addAnnotation(conservation);\r
+          }\r
+\r
+          if (showQuality)\r
+          {\r
+            quality = new AlignmentAnnotation("Quality",\r
+                                              "Alignment Quality based on Blosum62 scores",\r
+                                              new Annotation[1],\r
+                                              0f,\r
+                                              11f,\r
+                                              AlignmentAnnotation.BAR_GRAPH);\r
+            quality.hasText = true;\r
+\r
+            alignment.addAnnotation(quality);\r
+          }\r
+        }\r
 \r
+        consensus = new AlignmentAnnotation("Consensus", "PID",\r
+                                             new Annotation[1], 0f, 100f,\r
+                                             AlignmentAnnotation.BAR_GRAPH);\r
+        consensus.hasText = true;\r
+\r
+         if (showConsensus)\r
+         {\r
+           alignment.addAnnotation(consensus);\r
+         }\r
+      }\r
     }\r
   }\r
 \r
@@ -206,159 +247,271 @@ public class AlignViewport
   }\r
 \r
 \r
-  public void updateConservation()\r
+  class ConservationThread extends Thread\r
   {\r
-    if(alignment.isNucleotide())\r
-          return;\r
+    AlignmentPanel ap;\r
+    public ConservationThread(AlignmentPanel ap)\r
+    {\r
+      this.ap = ap;\r
+    }\r
 \r
-    Conservation cons = new jalview.analysis.Conservation("All",\r
-        jalview.schemes.ResidueProperties.propHash, 3,\r
-        alignment.getSequences(), 0,\r
-        alignment.getWidth() - 1);\r
-    cons.calculate();\r
-    cons.verdict(false, ConsPercGaps);\r
-    cons.findQuality();\r
-    int alWidth = alignment.getWidth();\r
-    Annotation[] annotations = new Annotation[alWidth];\r
-    Annotation[] qannotations = new Annotation[alWidth];\r
-    String sequence = cons.getConsSequence().getSequence();\r
-    float minR, minG, minB, maxR, maxG, maxB;\r
-    minR = 0.3f;\r
-    minG = 0.0f;\r
-    minB = 0f;\r
-    maxR = 1.0f - minR;\r
-    maxG = 0.9f - minG;\r
-    maxB = 0f - minB; // scalable range for colouring both Conservation and Quality\r
-    float min = 0f;\r
-    float max = 11f;\r
-    float qmin = cons.qualityRange[0].floatValue();\r
-    float qmax = cons.qualityRange[1].floatValue();\r
-\r
-    for (int i = 0; i < alWidth; i++)\r
+    public void run()\r
     {\r
-      float value = 0;\r
       try\r
       {\r
-        value = Integer.parseInt(sequence.charAt(i) + "");\r
-      }\r
-      catch (Exception ex)\r
-      {\r
-        if (sequence.charAt(i) == '*')\r
+        updatingConservation = true;\r
+\r
+        while (UPDATING_CONSERVATION)\r
         {\r
-          value = 11;\r
+          try\r
+          {\r
+            if (ap != null)\r
+            {\r
+              ap.repaint();\r
+            }\r
+            Thread.sleep(200);\r
+          }\r
+          catch (Exception ex)\r
+          {\r
+            ex.printStackTrace();\r
+          }\r
         }\r
-        if (sequence.charAt(i) == '+')\r
+\r
+        UPDATING_CONSERVATION = true;\r
+\r
+\r
+        int alWidth = alignment.getWidth();\r
+        if(alWidth<0)\r
+          return;\r
+\r
+        Conservation cons = new jalview.analysis.Conservation("All",\r
+            jalview.schemes.ResidueProperties.propHash, 3,\r
+            alignment.getSequences(), 0, alWidth -1);\r
+\r
+        cons.calculate();\r
+        cons.verdict(false, ConsPercGaps);\r
+\r
+        if (quality!=null)\r
         {\r
-          value = 10;\r
+          cons.findQuality();\r
         }\r
-      }\r
-      float vprop = value - min;\r
-      vprop /= max;\r
-\r
-      annotations[i] = new Annotation(sequence.charAt(i) + "",\r
-                                      "", ' ', value,\r
-                                      new Color(minR + maxR * vprop,\r
-                                                minG + maxG * vprop,\r
-                                                minB + maxB * vprop));\r
-      // Quality calc\r
-      value = ( (Double) cons.quality.elementAt(i)).floatValue();\r
-      vprop = value - qmin;\r
-      vprop /= qmax;\r
-      qannotations[i] = new Annotation(" ",\r
-                                       String.valueOf(value), ' ', value,\r
-                                       new\r
-                                       Color(minR + maxR * vprop,\r
-                                             minG + maxG * vprop,\r
-                                             minB + maxB * vprop));\r
-    }\r
 \r
-    if (conservation == null)\r
-    {\r
-      conservation = new AlignmentAnnotation("Conservation",\r
-                                             "Conservation of total alignment less than " +\r
-                                             ConsPercGaps + "% gaps",\r
-                                             annotations,\r
-                                             0f, // cons.qualityRange[0].floatValue(),\r
-                                             11f, // cons.qualityRange[1].floatValue()\r
-                                             AlignmentAnnotation.BAR_GRAPH);\r
-      if (showConservation)\r
+        String sequence = cons.getConsSequence().getSequence();\r
+        float minR;\r
+        float minG;\r
+        float minB;\r
+        float maxR;\r
+        float maxG;\r
+        float maxB;\r
+        minR = 0.3f;\r
+        minG = 0.0f;\r
+        minB = 0f;\r
+        maxR = 1.0f - minR;\r
+        maxG = 0.9f - minG;\r
+        maxB = 0f - minB; // scalable range for colouring both Conservation and Quality\r
+\r
+        float min = 0f;\r
+        float max = 11f;\r
+        float qmin = 0f;\r
+        float qmax = 0f;\r
+\r
+        char c;\r
+\r
+        conservation.annotations = new Annotation[alWidth];\r
+\r
+        if (quality!=null)\r
+        {\r
+          quality.graphMax = cons.qualityRange[1].floatValue();\r
+          quality.annotations = new Annotation[alWidth];\r
+          qmin = cons.qualityRange[0].floatValue();\r
+          qmax = cons.qualityRange[1].floatValue();\r
+        }\r
+\r
+        for (int i = 0; i < alWidth; i++)\r
+        {\r
+          float value = 0;\r
+\r
+          c = sequence.charAt(i);\r
+\r
+          if (Character.isDigit(c))\r
+            value = (int) (c - '0');\r
+          else if (c == '*')\r
+            value = 11;\r
+          else if (c == '+')\r
+            value = 10;\r
+\r
+          float vprop = value - min;\r
+          vprop /= max;\r
+          conservation.annotations[i] =\r
+              new Annotation(String.valueOf(c),\r
+                             String.valueOf(value), ' ', value,\r
+                             new Color(minR + (maxR * vprop),\r
+                                       minG + (maxG * vprop),\r
+                                       minB + (maxB * vprop)));\r
+\r
+          // Quality calc\r
+          if (quality!=null)\r
+          {\r
+            value = ( (Double) cons.quality.elementAt(i)).floatValue();\r
+            vprop = value - qmin;\r
+            vprop /= qmax;\r
+            quality.annotations[i] = new Annotation(" ", String.valueOf(value), ' ',\r
+                                             value,\r
+                                             new Color(minR + (maxR * vprop),\r
+                minG + (maxG * vprop),\r
+                minB + (maxB * vprop)));\r
+          }\r
+        }\r
+      }\r
+      catch (OutOfMemoryError error)\r
       {\r
-        alignment.addAnnotation(conservation);\r
+        System.out.println("Out of memory calculating conservation!!");\r
+        conservation = null;\r
+        quality = null;\r
+        System.gc();\r
       }\r
-      quality = new AlignmentAnnotation("Quality",\r
-                                        "Alignment Quality based on Blosum62 scores",\r
-                                        qannotations,\r
-                                        cons.qualityRange[0].floatValue(),\r
-                                        cons.qualityRange[1].floatValue(),\r
-                                        AlignmentAnnotation.BAR_GRAPH);\r
-      if (showQuality)\r
+\r
+      UPDATING_CONSERVATION = false;\r
+      updatingConservation = false;\r
+\r
+      if(ap!=null)\r
       {\r
-        alignment.addAnnotation(quality);\r
+        ap.repaint();\r
       }\r
-    }\r
-    else\r
-    {\r
-      conservation.annotations = annotations;\r
-      quality.annotations = qannotations;\r
-      quality.graphMax = cons.qualityRange[1].floatValue();\r
-    }\r
 \r
+    }\r
   }\r
 \r
-  public void updateConsensus()\r
-  {\r
-    // this routine prevents vconsensus becoming a new object each time\r
-    // consenus is calculated. Important for speed of Blosum62\r
-    // and PID colouring of alignment\r
-    int aWidth = alignment.getWidth();\r
 \r
-    Annotation[] annotations = new Annotation[aWidth];\r
+  ConservationThread conservationThread;\r
 \r
-    hconsensus = new Hashtable[aWidth];\r
-    AAFrequency.calculate(alignment.getSequencesArray(),\r
-                          0, aWidth,\r
-                          hconsensus);\r
+  ConsensusThread consensusThread;\r
 \r
-    for (int i = 0; i < aWidth; i++)\r
-    {\r
-      float value = 0;\r
-      if(ignoreGapsInConsensusCalculation)\r
-        value = ((Float)hconsensus[i].get(AAFrequency.PID_NOGAPS)).floatValue();\r
-      else\r
-        value = ((Float)hconsensus[i].get(AAFrequency.PID_GAPS)).floatValue();\r
+  boolean consUpdateNeeded = false;\r
 \r
-      String maxRes = hconsensus[i].get(AAFrequency.MAXRESIDUE).toString();\r
-      String mouseOver = maxRes;\r
-      if (maxRes.length() > 1)\r
-      {\r
-        mouseOver = "[" + maxRes + "] ";\r
-        maxRes = "+";\r
-      }\r
+  static boolean UPDATING_CONSENSUS = false;\r
 \r
+  static boolean UPDATING_CONSERVATION = false;\r
 \r
-      mouseOver += (int) value + "%";\r
-      annotations[i] = new Annotation(maxRes, mouseOver, ' ', value);\r
+  boolean updatingConsensus = false;\r
 \r
-    }\r
+  boolean updatingConservation = false;\r
 \r
-    if (consensus == null)\r
+  /**\r
+   * DOCUMENT ME!\r
+   */\r
+  public void updateConservation(final AlignmentPanel ap)\r
+  {\r
+    if (alignment.isNucleotide() || conservation==null)\r
+      return;\r
+\r
+    conservationThread = new ConservationThread(ap);\r
+    conservationThread.start();\r
+  }\r
+\r
+  /**\r
+   * DOCUMENT ME!\r
+   */\r
+  public void updateConsensus(final AlignmentPanel ap)\r
+  {\r
+    consensusThread = new ConsensusThread(ap);\r
+    consensusThread.start();\r
+  }\r
+\r
+\r
+  class ConsensusThread extends Thread\r
+  {\r
+    AlignmentPanel ap;\r
+    public ConsensusThread(AlignmentPanel ap)\r
     {\r
-      consensus = new AlignmentAnnotation("Consensus",\r
-                                          "PID", annotations, 0f, 100f, AlignmentAnnotation.BAR_GRAPH);\r
-      if (showConsensus)\r
-      {\r
-        alignment.addAnnotation(consensus);\r
-      }\r
+      this.ap = ap;\r
     }\r
-    else\r
+    public void run()\r
     {\r
-      consensus.annotations = annotations;\r
-    }\r
+      updatingConsensus = true;\r
+      while (UPDATING_CONSENSUS)\r
+      {\r
+        try\r
+        {\r
+          if (ap != null)\r
+          {\r
+            ap.repaint();\r
+          }\r
+\r
+          Thread.sleep(200);\r
+        }\r
+        catch (Exception ex)\r
+        {\r
+          ex.printStackTrace();\r
+        }\r
+      }\r
+\r
+\r
+      UPDATING_CONSENSUS = true;\r
+\r
+      try\r
+      {\r
+        int aWidth = alignment.getWidth();\r
+        if(aWidth<0)\r
+          return;\r
+\r
+        consensus.annotations = null;\r
+        consensus.annotations = new Annotation[aWidth];\r
+\r
 \r
-    if(globalColourScheme!=null)\r
+        hconsensus = new Hashtable[aWidth];\r
+        AAFrequency.calculate(alignment.getSequencesArray(),\r
+                              0,\r
+                              alignment.getWidth(),\r
+                              hconsensus);\r
+\r
+        for (int i = 0; i < aWidth; i++)\r
+        {\r
+          float value = 0;\r
+          if (ignoreGapsInConsensusCalculation)\r
+            value = ( (Float) hconsensus[i].get(AAFrequency.PID_NOGAPS)).\r
+                floatValue();\r
+          else\r
+            value = ( (Float) hconsensus[i].get(AAFrequency.PID_GAPS)).\r
+                floatValue();\r
+\r
+          String maxRes = hconsensus[i].get(AAFrequency.MAXRESIDUE).toString();\r
+          String mouseOver = hconsensus[i].get(AAFrequency.MAXRESIDUE) + " ";\r
+\r
+          if (maxRes.length() > 1)\r
+          {\r
+            mouseOver = "[" + maxRes + "] ";\r
+            maxRes = "+";\r
+          }\r
+\r
+          mouseOver += ( (int) value + "%");\r
+          consensus.annotations[i] = new Annotation(maxRes, mouseOver, ' ', value);\r
+        }\r
+\r
+\r
+        if (globalColourScheme != null)\r
           globalColourScheme.setConsensus(hconsensus);\r
 \r
+      }\r
+      catch (OutOfMemoryError error)\r
+      {\r
+        alignment.deleteAnnotation(consensus);\r
+\r
+        consensus = null;\r
+        hconsensus = null;\r
+        System.out.println("Out of memory calculating consensus!!");\r
+        System.gc();\r
+      }\r
+      UPDATING_CONSENSUS = false;\r
+      updatingConsensus = false;\r
+\r
+      if (ap != null)\r
+      {\r
+        ap.repaint();\r
+      }\r
+    }\r
   }\r
+\r
   /**\r
    * get the consensus sequence as displayed under the PID consensus annotation row.\r
    * @return consensus sequence as a new sequence object\r
@@ -367,9 +520,8 @@ public class AlignViewport
    * get the consensus sequence as displayed under the PID consensus annotation row.\r
    * @return consensus sequence as a new sequence object\r
    */\r
-  public SequenceI getConsensusSeq() {\r
-    if (consensus==null)\r
-      updateConsensus();\r
+  public SequenceI getConsensusSeq()\r
+  {\r
     if (consensus==null)\r
       return null;\r
     StringBuffer seqs=new StringBuffer();\r
@@ -712,7 +864,7 @@ public class AlignViewport
   public void setIgnoreGapsConsensus(boolean b)\r
   {\r
     ignoreGapsInConsensusCalculation = b;\r
-    updateConsensus();\r
+    updateConsensus(null);\r
     if (globalColourScheme!=null)\r
     {\r
       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),\r
@@ -1084,4 +1236,84 @@ public class AlignViewport
       sequenceColours.put(seq, col);\r
   }\r
 \r
+  public String getSequenceSetId()\r
+  {\r
+    if (sequenceSetID == null)\r
+      sequenceSetID = alignment.hashCode() + "";\r
+\r
+    return sequenceSetID;\r
+  }\r
+\r
+  public void alignmentChanged(AlignmentPanel ap)\r
+  {\r
+    alignment.padGaps();\r
+\r
+    if (hconsensus != null && autocalculateConsensus)\r
+    {\r
+      updateConsensus(ap);\r
+      updateConservation(ap);\r
+    }\r
+\r
+    //Reset endRes of groups if beyond alignment width\r
+    int alWidth = alignment.getWidth();\r
+    Vector groups = alignment.getGroups();\r
+    if(groups!=null)\r
+    {\r
+      for(int i=0; i<groups.size(); i++)\r
+      {\r
+        SequenceGroup sg = (SequenceGroup)groups.elementAt(i);\r
+        if(sg.getEndRes()>alWidth)\r
+          sg.setEndRes(alWidth-1);\r
+      }\r
+    }\r
+\r
+    if(selectionGroup!=null && selectionGroup.getEndRes()>alWidth)\r
+      selectionGroup.setEndRes(alWidth-1);\r
+\r
+    resetAllColourSchemes();\r
+\r
+    alignment.adjustSequenceAnnotations();\r
+  }\r
+\r
+  void resetAllColourSchemes()\r
+  {\r
+    ColourSchemeI cs = globalColourScheme;\r
+    if(cs!=null)\r
+    {\r
+      if (cs instanceof ClustalxColourScheme)\r
+      {\r
+        ( (ClustalxColourScheme) cs).\r
+            resetClustalX(alignment.getSequences(),\r
+                          alignment.getWidth());\r
+      }\r
+\r
+      cs.setConsensus(hconsensus);\r
+      if (cs.conservationApplied())\r
+      {\r
+        Alignment al = (Alignment) alignment;\r
+        Conservation c = new Conservation("All",\r
+                                          ResidueProperties.propHash, 3,\r
+                                          al.getSequences(), 0,\r
+                                          al.getWidth() - 1);\r
+        c.calculate();\r
+        c.verdict(false, ConsPercGaps);\r
+\r
+        cs.setConservation(c);\r
+      }\r
+    }\r
+\r
+    int s, sSize = alignment.getGroups().size();\r
+    for(s=0; s<sSize; s++)\r
+    {\r
+      SequenceGroup sg = (SequenceGroup)alignment.getGroups().elementAt(s);\r
+      if(sg.cs!=null && sg.cs instanceof ClustalxColourScheme)\r
+      {\r
+        ((ClustalxColourScheme)sg.cs).resetClustalX(\r
+            sg.getSequences(true), sg.getWidth());\r
+      }\r
+      sg.recalcConservation();\r
+    }\r
+  }\r
+\r
+\r
 }\r