refactored conservation thread, added showgroupannotation flags
[jalview.git] / src / jalview / gui / AlignViewport.java
index 9f1d3c6..70ca6f2 100755 (executable)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
- * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
+ * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -47,6 +47,7 @@ import jalview.bin.*;
 import jalview.datamodel.*;
 
 import jalview.schemes.*;
+import jalview.structure.SelectionSource;
 import jalview.structure.StructureSelectionManager;
 
 /**
@@ -55,8 +56,10 @@ import jalview.structure.StructureSelectionManager;
  * @author $author$
  * @version $Revision$
  */
-public class AlignViewport
+public class AlignViewport implements SelectionSource
 {
+  private static final int RIGHT_JUSTIFY = 1;
+
   int startRes;
 
   int endRes;
@@ -139,7 +142,9 @@ public class AlignViewport
   AlignmentAnnotation conservation;
 
   AlignmentAnnotation quality;
-
+  AlignmentAnnotation[] groupConsensus;
+  AlignmentAnnotation[] groupConservation;
+  
   boolean autoCalculateConsensus = true;
 
   /** DOCUMENT ME!! */
@@ -181,17 +186,37 @@ public class AlignViewport
 
   Hashtable hiddenRepSequences;
 
+  boolean sortByTree;
+
   /**
    * Creates a new AlignViewport object.
    * 
-   * @param al
-   *                DOCUMENT ME!
+   * @param al alignment to view
    */
   public AlignViewport(AlignmentI al)
   {
     setAlignment(al);
     init();
   }
+  /**
+   * Create a new AlignViewport object with a specific sequence set ID
+   * @param al
+   * @param seqsetid (may be null - but potential for ambiguous constructor exception)
+   */
+  public AlignViewport(AlignmentI al, String seqsetid)
+  {
+    this(al,seqsetid,null);
+  }
+  public AlignViewport(AlignmentI al, String seqsetid, String viewid)
+  {
+    sequenceSetID = seqsetid;
+    viewId = viewid;
+    // TODO remove these once 2.4.VAMSAS release finished
+    if (Cache.log!=null && Cache.log.isDebugEnabled() && seqsetid!=null) { Cache.log.debug("Setting viewport's sequence set id : "+sequenceSetID); }
+    if (Cache.log!=null && Cache.log.isDebugEnabled() && viewId!=null) { Cache.log.debug("Setting viewport's view id : "+viewId); }
+    setAlignment(al);
+    init();
+  }
 
   /**
    * Create a new AlignViewport with hidden regions
@@ -214,6 +239,41 @@ public class AlignViewport
     }
     init();
   }
+  /**
+   * New viewport with hidden columns and an existing sequence set id
+   * @param al
+   * @param hiddenColumns
+   * @param seqsetid (may be null)
+   */
+  public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns, String seqsetid)
+  {
+    this(al,hiddenColumns,seqsetid,null);
+  }
+  /**
+   * New viewport with hidden columns and an existing sequence set id and viewid
+   * @param al
+   * @param hiddenColumns
+   * @param seqsetid (may be null)
+   * @param viewid (may be null)
+   */
+  public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns, String seqsetid, String viewid)
+  {
+    sequenceSetID = seqsetid;
+    viewId = viewid;
+    // TODO remove these once 2.4.VAMSAS release finished
+    if (Cache.log!=null && Cache.log.isDebugEnabled() && seqsetid!=null) { Cache.log.debug("Setting viewport's sequence set id : "+sequenceSetID); }
+    if (Cache.log!=null && Cache.log.isDebugEnabled() && viewId!=null) { Cache.log.debug("Setting viewport's view id : "+viewId); }
+    setAlignment(al);
+    if (hiddenColumns != null)
+    {
+      this.colSel = hiddenColumns;
+      if (hiddenColumns.getHiddenColumns() != null)
+      {
+        hasHiddenColumns = true;
+      }
+    }
+    init();
+  }
 
   void init()
   {
@@ -286,7 +346,7 @@ public class AlignViewport
           alignment.addAnnotation(quality);
         }
       }
-
+      // TODO: add menu option action that nulls or creates consensus object depending on if the user wants to see the annotation or not in a specific alignment
       consensus = new AlignmentAnnotation("Consensus", "PID",
               new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
       consensus.hasText = true;
@@ -317,13 +377,15 @@ public class AlignViewport
     }
 
     wrapAlignment = jalview.bin.Cache.getDefault("WRAP_ALIGNMENT", false);
+    showUnconserved = jalview.bin.Cache.getDefault("SHOW_UNCONSERVED", false);
+    sortByTree = jalview.bin.Cache.getDefault("SORT_BY_TREE", false);
   }
 
   /**
-   * DOCUMENT ME!
+   * set the flag
    * 
    * @param b
-   *                DOCUMENT ME!
+   *             features are displayed if true
    */
   public void setShowSequenceFeatures(boolean b)
   {
@@ -335,146 +397,6 @@ public class AlignViewport
     return showSequenceFeatures;
   }
 
-  class ConservationThread extends Thread
-  {
-    AlignmentPanel ap;
-
-    public ConservationThread(AlignmentPanel ap)
-    {
-      this.ap = ap;
-    }
-
-    public void run()
-    {
-      try
-      {
-        updatingConservation = true;
-
-        while (UPDATING_CONSERVATION)
-        {
-          try
-          {
-            if (ap != null)
-            {
-              ap.paintAlignment(false);
-            }
-            Thread.sleep(200);
-          } catch (Exception ex)
-          {
-            ex.printStackTrace();
-          }
-        }
-
-        UPDATING_CONSERVATION = true;
-
-        int alWidth = alignment.getWidth();
-        if (alWidth < 0)
-        {
-          return;
-        }
-
-        Conservation cons = new jalview.analysis.Conservation("All",
-                jalview.schemes.ResidueProperties.propHash, 3, alignment
-                        .getSequences(), 0, alWidth - 1);
-
-        cons.calculate();
-        cons.verdict(false, ConsPercGaps);
-
-        if (quality != null)
-        {
-          cons.findQuality();
-        }
-
-        char[] sequence = cons.getConsSequence().getSequence();
-        float minR;
-        float minG;
-        float minB;
-        float maxR;
-        float maxG;
-        float maxB;
-        minR = 0.3f;
-        minG = 0.0f;
-        minB = 0f;
-        maxR = 1.0f - minR;
-        maxG = 0.9f - minG;
-        maxB = 0f - minB; // scalable range for colouring both Conservation and
-                          // Quality
-
-        float min = 0f;
-        float max = 11f;
-        float qmin = 0f;
-        float qmax = 0f;
-
-        char c;
-
-        conservation.annotations = new Annotation[alWidth];
-
-        if (quality != null)
-        {
-          quality.graphMax = cons.qualityRange[1].floatValue();
-          quality.annotations = new Annotation[alWidth];
-          qmin = cons.qualityRange[0].floatValue();
-          qmax = cons.qualityRange[1].floatValue();
-        }
-
-        for (int i = 0; i < alWidth; i++)
-        {
-          float value = 0;
-
-          c = sequence[i];
-
-          if (Character.isDigit(c))
-          {
-            value = (int) (c - '0');
-          }
-          else if (c == '*')
-          {
-            value = 11;
-          }
-          else if (c == '+')
-          {
-            value = 10;
-          }
-
-          float vprop = value - min;
-          vprop /= max;
-          conservation.annotations[i] = new Annotation(String.valueOf(c),
-                  String.valueOf(value), ' ', value, new Color(minR
-                          + (maxR * vprop), minG + (maxG * vprop), minB
-                          + (maxB * vprop)));
-
-          // Quality calc
-          if (quality != null)
-          {
-            value = ((Double) cons.quality.get(i)).floatValue();
-            vprop = value - qmin;
-            vprop /= qmax;
-            quality.annotations[i] = new Annotation(" ", String
-                    .valueOf(value), ' ', value, new Color(minR
-                    + (maxR * vprop), minG + (maxG * vprop), minB
-                    + (maxB * vprop)));
-          }
-        }
-      } catch (OutOfMemoryError error)
-      {
-        new OOMWarning("calculating conservation", error);
-
-        conservation = null;
-        quality = null;
-
-      }
-
-      UPDATING_CONSERVATION = false;
-      updatingConservation = false;
-
-      if (ap != null)
-      {
-        ap.paintAlignment(true);
-      }
-
-    }
-  }
-
   ConservationThread conservationThread;
 
   ConsensusThread consensusThread;
@@ -504,12 +426,13 @@ public class AlignViewport
    */
   public void updateConservation(final AlignmentPanel ap)
   {
-    if (alignment.isNucleotide() || conservation == null)
+    // see note in mantis : issue number 8585
+    if (alignment.isNucleotide() || conservation == null || !autoCalculateConsensus)
     {
       return;
     }
 
-    conservationThread = new ConservationThread(ap);
+    conservationThread = new ConservationThread(this, ap);
     conservationThread.start();
   }
 
@@ -518,6 +441,11 @@ public class AlignViewport
    */
   public void updateConsensus(final AlignmentPanel ap)
   {
+    // see note in mantis : issue number 8585
+    if (consensus == null || !autoCalculateConsensus)
+    {
+      return;
+    }
     consensusThread = new ConsensusThread(ap);
     consensusThread.start();
   }
@@ -569,37 +497,8 @@ public class AlignViewport
         hconsensus = new Hashtable[aWidth];
         AAFrequency.calculate(alignment.getSequencesArray(), 0, alignment
                 .getWidth(), hconsensus);
-
-        for (int i = 0; i < aWidth; i++)
-        {
-          float value = 0;
-          if (ignoreGapsInConsensusCalculation)
-          {
-            value = ((Float) hconsensus[i].get(AAFrequency.PID_NOGAPS))
-                    .floatValue();
-          }
-          else
-          {
-            value = ((Float) hconsensus[i].get(AAFrequency.PID_GAPS))
-                    .floatValue();
-          }
-
-          String maxRes = hconsensus[i].get(AAFrequency.MAXRESIDUE)
-                  .toString();
-          String mouseOver = hconsensus[i].get(AAFrequency.MAXRESIDUE)
-                  + " ";
-
-          if (maxRes.length() > 1)
-          {
-            mouseOver = "[" + maxRes + "] ";
-            maxRes = "+";
-          }
-
-          mouseOver += ((int) value + "%");
-          consensus.annotations[i] = new Annotation(maxRes, mouseOver, ' ',
-                  value);
-        }
-
+        AAFrequency.completeConsensus(consensus,hconsensus,0,aWidth,ignoreGapsInConsensusCalculation);
+        
         if (globalColourScheme != null)
         {
           globalColourScheme.setConsensus(hconsensus);
@@ -679,7 +578,7 @@ public class AlignViewport
    */
   public void setSelectionGroup(SequenceGroup sg)
   {
-    selectionGroup = sg;
+    selectionGroup = sg;    
   }
 
   /**
@@ -1414,7 +1313,8 @@ public class AlignViewport
         seqs[index++] = sg.getSequenceAt(i);
       }
     }
-
+    sg.setSeqrep(repSequence);
+    sg.setHidereps(true);
     hideSequence(seqs);
 
   }
@@ -1463,6 +1363,7 @@ public class AlignViewport
         selectionGroup.addSequence((SequenceI) tmp.elementAt(t), false);
       }
       firePropertyChange("alignment", null, alignment.getSequences());
+      sendSelection();
     }
 
     if (alignment.getHiddenSequences().getSize() < 1)
@@ -1502,6 +1403,7 @@ public class AlignViewport
         selectionGroup.addSequence((SequenceI) tmp.elementAt(t), false);
       }
       firePropertyChange("alignment", null, alignment.getSequences());
+      sendSelection();
       hasHiddenRows = false;
       hiddenRepSequences = null;
     }
@@ -1559,14 +1461,14 @@ public class AlignViewport
    */
   public SequenceI[] getSequenceSelection()
   {
-    SequenceI[] sequences;
-    if (selectionGroup == null)
+    SequenceI[] sequences=null;
+    if (selectionGroup!=null)
     {
-      sequences = alignment.getSequencesArray();
+      sequences = selectionGroup.getSequencesInOrder(alignment);
     }
-    else
+    if (sequences == null)
     {
-      sequences = selectionGroup.getSequencesInOrder(alignment);
+      sequences = alignment.getSequencesArray();
     }
     return sequences;
   }
@@ -1800,19 +1702,36 @@ public class AlignViewport
 
     return sequenceSetID;
   }
+  /**
+   * unique viewId for synchronizing state with stored Jalview Project 
+   * 
+   */
+  private String viewId=null;
 
+  
+  public String getViewId()
+  {
+    if (viewId==null)
+    {
+      viewId = this.getSequenceSetId()+"."+this.hashCode()+"";
+    }
+    return viewId;
+  }
+  
   public void alignmentChanged(AlignmentPanel ap)
   {
     if (padGaps)
     {
       alignment.padGaps();
     }
-
     if (hconsensus != null && autoCalculateConsensus)
     {
-      updateConsensus(ap);
       updateConservation(ap);
     }
+    if (autoCalculateConsensus)
+    {
+      updateConsensus(ap);
+    }
 
     // Reset endRes of groups if beyond alignment width
     int alWidth = alignment.getWidth();
@@ -2040,4 +1959,152 @@ public class AlignViewport
   {
     shownpfeats=show;
   }
+  /**
+   * 
+   * @return true if view has hidden rows
+   */
+  public boolean hasHiddenRows()
+  {
+    return hasHiddenRows;
+  }
+  /**
+   * 
+   * @return true if view has hidden columns
+   */
+  public boolean hasHiddenColumns()
+  {
+    return hasHiddenColumns;
+  }
+  /**
+   * when set, view will scroll to show the highlighted position
+   */
+  public boolean followHighlight=true;
+  /**
+   * @return true if view should scroll to show the highlighted region of a sequence
+   * @return
+   */
+  public boolean getFollowHighlight() {
+    return followHighlight;
+  }
+  public boolean followSelection=true;
+  /**
+   * @return true if view selection should always follow the selections broadcast by other selection sources
+   */
+  public boolean getFollowSelection() {
+    return followSelection;
+  }
+  private long sgrouphash=-1,colselhash=-1;
+
+  boolean showSeqFeaturesHeight;
+  /**
+   * checks current SelectionGroup against record of last hash value, and updates record.
+   * @return true if SelectionGroup changed since last call
+   */
+  boolean isSelectionGroupChanged() {
+    int hc=(selectionGroup==null) ? -1 : selectionGroup.hashCode();
+    if (hc!=sgrouphash)
+    {
+      sgrouphash = hc;
+      return true;
+    }
+    return false;
+  }
+  /**
+   * checks current colsel against record of last hash value, and updates record.
+   * @return true if colsel changed since last call
+   */
+  boolean isColSelChanged() {
+    int hc=(colSel==null) ? -1 : colSel.hashCode();
+    if (hc!=colselhash)
+    {
+      colselhash = hc;
+      return true;
+    }
+    return false;
+  }
+  public void sendSelection()
+  {
+    jalview.structure.StructureSelectionManager.getStructureSelectionManager().sendSelection(new SequenceGroup(getSelectionGroup()), new ColumnSelection(getColumnSelection()), this);
+  }
+  public void setShowSequenceFeaturesHeight(boolean selected)
+  {
+    showSeqFeaturesHeight = selected; 
+  }
+  public boolean getShowSequenceFeaturesHeight()
+  {
+    return showSeqFeaturesHeight; 
+  }
+  boolean showUnconserved=false;
+  public boolean getShowUnconserved()
+  {
+    return showUnconserved;
+  }
+  public void setShowUnconserved(boolean showunconserved)
+  {
+    showUnconserved=showunconserved;
+  }
+  /**
+   * return the alignPanel containing the given viewport. Use this to get the
+   * components currently handling the given viewport.
+   * @param av
+   * @return null or an alignPanel guaranteed to have non-null alignFrame reference
+   */
+  public AlignmentPanel getAlignPanel()
+  {
+    AlignmentPanel[] aps = PaintRefresher.getAssociatedPanels(this.getSequenceSetId());
+    AlignmentPanel ap=null;
+    for (int p=0;aps!=null && p<aps.length; p++)
+    {
+      if (aps[p].av == this)
+      {
+        return aps[p];
+      }
+    }
+    return null;
+  }
+  public boolean getSortByTree()
+  {
+    return sortByTree;
+  }
+  public void setSortByTree(boolean sort) {
+    sortByTree = sort;
+  }
+  /**
+   * should conservation rows be shown for groups
+   */
+  boolean showGroupConservation = false;
+  /**
+   * should consensus rows be shown for groups
+   */
+  boolean showGroupConsensus = false;
+
+  /**
+   * @return the showGroupConservation
+   */
+  public boolean isShowGroupConservation()
+  {
+    return showGroupConservation;
+  }
+  /**
+   * @param showGroupConservation the showGroupConservation to set
+   */
+  public void setShowGroupConservation(boolean showGroupConservation)
+  {
+    this.showGroupConservation = showGroupConservation;
+  }
+  /**
+   * @return the showGroupConsensus
+   */
+  public boolean isShowGroupConsensus()
+  {
+    return showGroupConsensus;
+  }
+  /**
+   * @param showGroupConsensus the showGroupConsensus to set
+   */
+  public void setShowGroupConsensus(boolean showGroupConsensus)
+  {
+    this.showGroupConsensus = showGroupConsensus;
+  }
+  
 }