Merge branch 'develop' into spike/JAL-4047/JAL-4048_columns_in_sequenceID
[jalview.git] / src / jalview / viewmodel / AlignmentViewport.java
index 1ae879b..7e0b6b4 100644 (file)
  */
 package jalview.viewmodel;
 
+import java.awt.Color;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.Conservation;
 import jalview.analysis.TreeModel;
 import jalview.api.AlignCalcManagerI;
+import jalview.api.AlignExportSettingsI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeaturesDisplayedI;
 import jalview.api.ViewStyleI;
+import jalview.bin.Console;
 import jalview.commands.CommandI;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentExportData;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.ProfilesI;
@@ -43,6 +60,8 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.gui.QuitHandler;
+import jalview.project.Jalview2XML;
 import jalview.renderer.ResidueShader;
 import jalview.renderer.ResidueShaderI;
 import jalview.schemes.ColourSchemeI;
@@ -53,24 +72,13 @@ import jalview.util.Comparison;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
+import jalview.viewmodel.seqfeatures.IdColumns;
 import jalview.viewmodel.styles.ViewStyle;
 import jalview.workers.AlignCalcManager;
 import jalview.workers.ComplementConsensusThread;
 import jalview.workers.ConsensusThread;
 import jalview.workers.StrucConsensusThread;
 
-import java.awt.Color;
-import java.beans.PropertyChangeSupport;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 /**
  * base class holding visualization and analysis attributes and common logic for
  * an active alignment view displayed in the GUI
@@ -98,6 +106,11 @@ public abstract class AlignmentViewport
   protected Deque<CommandI> redoList = new ArrayDeque<>();
 
   /**
+   * used to determine if quit should be confirmed
+   */
+  private boolean savedUpToDate = false;
+
+  /**
    * alignment displayed in the viewport. Please use get/setter
    */
   protected AlignmentI alignment;
@@ -662,7 +675,7 @@ public abstract class AlignmentViewport
          * retain any colour thresholds per group while
          * changing choice of colour scheme (JAL-2386)
          */
-        sg.setColourScheme(cs);
+        sg.setColourScheme(cs == null ? null : cs.getInstance(this, sg));
         if (cs != null)
         {
           sg.getGroupColourScheme().alignmentChanged(sg,
@@ -708,13 +721,13 @@ public abstract class AlignmentViewport
   /**
    * results of cDNA complement consensus visible portion of view
    */
-  protected Hashtable[] hcomplementConsensus = null;
+  protected Hashtable<String, Object>[] hcomplementConsensus = null;
 
   /**
    * results of secondary structure base pair consensus for visible portion of
    * view
    */
-  protected Hashtable[] hStrucConsensus = null;
+  protected Hashtable<String, Object>[] hStrucConsensus = null;
 
   protected Conservation hconservation = null;
 
@@ -743,7 +756,8 @@ public abstract class AlignmentViewport
   }
 
   @Override
-  public void setComplementConsensusHash(Hashtable[] hconsensus)
+  public void setComplementConsensusHash(
+          Hashtable<String, Object>[] hconsensus)
   {
     this.hcomplementConsensus = hconsensus;
   }
@@ -755,19 +769,20 @@ public abstract class AlignmentViewport
   }
 
   @Override
-  public Hashtable[] getComplementConsensusHash()
+  public Hashtable<String, Object>[] getComplementConsensusHash()
   {
     return hcomplementConsensus;
   }
 
   @Override
-  public Hashtable[] getRnaStructureConsensusHash()
+  public Hashtable<String, Object>[] getRnaStructureConsensusHash()
   {
     return hStrucConsensus;
   }
 
   @Override
-  public void setRnaStructureConsensusHash(Hashtable[] hStrucConsensus)
+  public void setRnaStructureConsensusHash(
+          Hashtable<String, Object>[] hStrucConsensus)
   {
     this.hStrucConsensus = hStrucConsensus;
 
@@ -920,7 +935,7 @@ public abstract class AlignmentViewport
     }
     if (calculator.workingInvolvedWith(alignmentAnnotation))
     {
-      // System.err.println("grey out ("+alignmentAnnotation.label+")");
+      // jalview.bin.Console.errPrintln("grey out ("+alignmentAnnotation.label+")");
       return true;
     }
     return false;
@@ -958,6 +973,7 @@ public abstract class AlignmentViewport
     ranges = null;
     currentTree = null;
     selectionGroup = null;
+    colSel = null;
     setAlignment(null);
   }
 
@@ -1192,7 +1208,7 @@ public abstract class AlignmentViewport
   {
     if (sequenceSetID != null)
     {
-      System.err.println(
+      jalview.bin.Console.errPrintln(
               "Warning - overwriting a sequenceSetId for a viewport!");
     }
     sequenceSetID = new String(newid);
@@ -1636,6 +1652,7 @@ public abstract class AlignmentViewport
   public void invertColumnSelection()
   {
     colSel.invertColumnSelection(0, alignment.getWidth(), alignment);
+    isColSelChanged(true);
   }
 
   @Override
@@ -1796,7 +1813,7 @@ public abstract class AlignmentViewport
       }
     } while (end < max);
 
-    int[][] startEnd = new int[regions.size()][2];
+    // int[][] startEnd = new int[regions.size()][2];
 
     return regions;
   }
@@ -1814,9 +1831,8 @@ public abstract class AlignmentViewport
         AlignmentAnnotation clone = new AlignmentAnnotation(annot);
         if (selectedOnly && selectionGroup != null)
         {
-          clone.makeVisibleAnnotation(
-                  selectionGroup.getStartRes(), selectionGroup.getEndRes(),
-                  alignment.getHiddenColumns());
+          clone.makeVisibleAnnotation(selectionGroup.getStartRes(),
+                  selectionGroup.getEndRes(), alignment.getHiddenColumns());
         }
         else
         {
@@ -2085,7 +2101,7 @@ public abstract class AlignmentViewport
       {
         if (aa == null)
         {
-          System.err.println("Null annotation row: ignoring.");
+          jalview.bin.Console.errPrintln("Null annotation row: ignoring.");
           continue;
         }
         if (!aa.visible)
@@ -2117,7 +2133,7 @@ public abstract class AlignmentViewport
 
         if (aa.graph > 0)
         {
-          aa.height += aa.graphHeight;
+          aa.height += aa.graphHeight+20;
         }
 
         if (aa.height == 0)
@@ -2151,7 +2167,7 @@ public abstract class AlignmentViewport
      * TODO reorder the annotation rows according to group/sequence ordering on
      * alignment
      */
-    boolean sortg = true;
+    // boolean sortg = true;
 
     // remove old automatic annotation
     // add any new annotation
@@ -2261,7 +2277,7 @@ public abstract class AlignmentViewport
   public void clearSequenceColours()
   {
     sequenceColours.clear();
-  };
+  }
 
   @Override
   public AlignViewportI getCodingComplement()
@@ -2278,7 +2294,7 @@ public abstract class AlignmentViewport
   {
     if (this == av)
     {
-      System.err.println("Ignoring recursive setCodingComplement request");
+      jalview.bin.Console.errPrintln("Ignoring recursive setCodingComplement request");
     }
     else
     {
@@ -2609,6 +2625,8 @@ public abstract class AlignmentViewport
     {
       this.historyList.push(command);
       broadcastCommand(command, false);
+      setSavedUpToDate(false);
+      Jalview2XML.setStateSavedUpToDate(false);
     }
   }
 
@@ -2926,6 +2944,19 @@ public abstract class AlignmentViewport
     return searchResults;
   }
 
+  @Override
+  public ContactListI getContactList(AlignmentAnnotation _aa, int column)
+  {
+    return alignment.getContactListFor(_aa, column);
+  }
+
+  @Override
+  public ContactMatrixI getContactMatrix(
+          AlignmentAnnotation alignmentAnnotation)
+  {
+    return alignment.getContactMatrixFor(alignmentAnnotation);
+  }
+
   /**
    * get the consensus sequence as displayed under the PID consensus annotation
    * row.
@@ -2978,4 +3009,159 @@ public abstract class AlignmentViewport
   {
     return currentTree;
   }
+
+  @Override
+  public AlignmentExportData getAlignExportData(
+          AlignExportSettingsI options)
+  {
+    AlignmentI alignmentToExport = null;
+    String[] omitHidden = null;
+    alignmentToExport = null;
+
+    if (hasHiddenColumns() && !options.isExportHiddenColumns())
+    {
+      omitHidden = getViewAsString(false,
+              options.isExportHiddenSequences());
+    }
+
+    int[] alignmentStartEnd = new int[2];
+    if (hasHiddenRows() && options.isExportHiddenSequences())
+    {
+      alignmentToExport = getAlignment().getHiddenSequences()
+              .getFullAlignment();
+    }
+    else
+    {
+      alignmentToExport = getAlignment();
+    }
+    alignmentStartEnd = getAlignment().getHiddenColumns()
+            .getVisibleStartAndEndIndex(alignmentToExport.getWidth());
+    AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
+            omitHidden, alignmentStartEnd);
+    return ed;
+  }
+
+  /**
+   * flag set to indicate if structure views might be out of sync with sequences
+   * in the alignment
+   */
+
+  private boolean needToUpdateStructureViews = false;
+
+  @Override
+  public boolean isUpdateStructures()
+  {
+    return needToUpdateStructureViews;
+  }
+
+  @Override
+  public void setUpdateStructures(boolean update)
+  {
+    needToUpdateStructureViews = update;
+  }
+
+  @Override
+  public boolean needToUpdateStructureViews()
+  {
+    boolean update = needToUpdateStructureViews;
+    needToUpdateStructureViews = false;
+    return update;
+  }
+
+  @Override
+  public void addSequenceGroup(SequenceGroup sequenceGroup)
+  {
+    alignment.addGroup(sequenceGroup);
+
+    Color col = sequenceGroup.idColour;
+    if (col != null)
+    {
+      col = col.brighter();
+
+      for (SequenceI sq : sequenceGroup.getSequences())
+      {
+        setSequenceColour(sq, col);
+      }
+    }
+
+    if (codingComplement != null)
+    {
+      SequenceGroup mappedGroup = MappingUtils
+              .mapSequenceGroup(sequenceGroup, this, codingComplement);
+      if (mappedGroup.getSequences().size() > 0)
+      {
+        codingComplement.getAlignment().addGroup(mappedGroup);
+
+        if (col != null)
+        {
+          for (SequenceI seq : mappedGroup.getSequences())
+          {
+            codingComplement.setSequenceColour(seq, col);
+          }
+        }
+      }
+      // propagate the structure view update flag according to our own setting
+      codingComplement.setUpdateStructures(needToUpdateStructureViews);
+    }
+  }
+
+  @Override
+  public Iterator<int[]> getViewAsVisibleContigs(boolean selectedRegionOnly)
+  {
+    int start = 0;
+    int end = 0;
+    if (selectedRegionOnly && selectionGroup != null)
+    {
+      start = selectionGroup.getStartRes();
+      end = selectionGroup.getEndRes() + 1;
+    }
+    else
+    {
+      end = alignment.getWidth();
+    }
+    return (alignment.getHiddenColumns().getVisContigsIterator(start, end,
+            false));
+  }
+
+  /**
+   * ordered list of annotation values displayed per sequence in ID panel
+   */
+  private IdColumns id_columns = null;
+
+  /**
+   * available and currently visible columns for this view
+   */
+  @Override
+  public IdColumns getIdColumns()
+  {
+    if (alignment == null)
+    {
+      return null;
+    }
+    if (id_columns == null)
+    {
+      id_columns = new IdColumns(alignment);
+    }
+    return id_columns;
+  }
+
+  public void setSavedUpToDate(boolean s)
+  {
+    setSavedUpToDate(s, QuitHandler.Message.UNSAVED_CHANGES);
+  }
+
+  public void setSavedUpToDate(boolean s, QuitHandler.Message m)
+  {
+    Console.debug(
+            "Setting " + this.getViewId() + " setSavedUpToDate to " + s);
+    savedUpToDate = s;
+    QuitHandler.setMessage(m);
+  }
+
+  public boolean savedUpToDate()
+  {
+    Console.debug("Returning " + this.getViewId() + " savedUpToDate value: "
+            + savedUpToDate);
+    return savedUpToDate;
+  }
 }