JAL-845 start cDNA consensus on 'add alignment' (as well as translate or
[jalview.git] / src / jalview / gui / AlignViewport.java
index a89174a..289a0ea 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
 package jalview.gui;
 
 import jalview.analysis.AlignmentUtils;
-import jalview.analysis.AlignmentUtils.MappingResult;
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.NJTree;
 import jalview.api.AlignViewportI;
 import jalview.api.ViewStyleI;
 import jalview.bin.Cache;
 import jalview.commands.CommandI;
+import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
@@ -67,10 +67,7 @@ import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Rectangle;
-import java.io.File;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Deque;
 import java.util.Hashtable;
 import java.util.Set;
 import java.util.Vector;
@@ -85,7 +82,7 @@ import javax.swing.JOptionPane;
  * @version $Revision: 1.141 $
  */
 public class AlignViewport extends AlignmentViewport implements
-        SelectionSource, VamsasSource, AlignViewportI, CommandListener
+        SelectionSource, AlignViewportI, CommandListener
 {
   int startRes;
 
@@ -106,15 +103,18 @@ public class AlignViewport extends AlignmentViewport implements
 
   boolean antiAlias = false;
 
-  Rectangle explodedPosition;
+  private Rectangle explodedGeometry;
 
   String viewName;
 
-  boolean gatherViewsHere = false;
-
-  private Deque<CommandI> historyList = new ArrayDeque<CommandI>();
-
-  private Deque<CommandI> redoList = new ArrayDeque<CommandI>();
+  /*
+   * Flag set true on the view that should 'gather' multiple views of the same
+   * sequence set id when a project is reloaded. Set false on all views when
+   * they are 'exploded' into separate windows. Set true on the current view
+   * when 'Gather' is performed, and also on the first tab when the first new
+   * view is created.
+   */
+  private boolean gatherViewsHere = false;
 
   private AnnotationColumnChooser annotationColumnSelectionState;
   /**
@@ -275,7 +275,7 @@ public class AlignViewport extends AlignmentViewport implements
       style = 2;
     }
 
-    setFont(new Font(fontName, style, Integer.parseInt(fontSize)));
+    setFont(new Font(fontName, style, Integer.parseInt(fontSize)), true);
 
     alignment
             .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0));
@@ -300,10 +300,18 @@ public class AlignViewport extends AlignmentViewport implements
       showConsensus = Cache.getDefault("SHOW_IDENTITY", true);
     }
     initAutoAnnotation();
-    if (jalview.bin.Cache.getProperty("DEFAULT_COLOUR") != null)
+    String colourProperty = alignment.isNucleotide() ? Preferences.DEFAULT_COLOUR_NUC
+            : Preferences.DEFAULT_COLOUR_PROT;
+    String propertyValue = Cache.getProperty(colourProperty);
+    if (propertyValue == null)
+    {
+      // fall back on this property for backwards compatibility
+      propertyValue = Cache.getProperty(Preferences.DEFAULT_COLOUR);
+    }
+    if (propertyValue != null)
     {
       globalColourScheme = ColourSchemeProperty.getColour(alignment,
-              jalview.bin.Cache.getProperty("DEFAULT_COLOUR"));
+              propertyValue);
 
       if (globalColourScheme instanceof UserColourScheme)
       {
@@ -466,12 +474,13 @@ public class AlignViewport extends AlignmentViewport implements
   boolean validCharWidth;
 
   /**
-   * DOCUMENT ME!
+   * update view settings with the given font. You may need to call
+   * alignPanel.fontChanged to update the layout geometry
    * 
-   * @param f
-   *          DOCUMENT ME!
+   * @param setGrid
+   *          when true, charWidth/height is set according to font mentrics
    */
-  public void setFont(Font f)
+  public void setFont(Font f, boolean setGrid)
   {
     font = f;
 
@@ -480,13 +489,9 @@ public class AlignViewport extends AlignmentViewport implements
     java.awt.FontMetrics fm = c.getFontMetrics(font);
     int w = viewStyle.getCharWidth(), ww = fm.charWidth('M'), h = viewStyle
             .getCharHeight();
-    // only update width/height if the new font won't fit
-    if (h < fm.getHeight())
+    if (setGrid)
     {
       setCharHeight(fm.getHeight());
-    }
-    if (w < ww)
-    {
       setCharWidth(ww);
     }
     viewStyle.setFontName(font.getName());
@@ -501,7 +506,7 @@ public class AlignViewport extends AlignmentViewport implements
   {
     super.setViewStyle(settingsForView);
     setFont(new Font(viewStyle.getFontName(), viewStyle.getFontStyle(),
-            viewStyle.getFontSize()));
+            viewStyle.getFontSize()), false);
 
   }
   /**
@@ -765,6 +770,10 @@ public class AlignViewport extends AlignmentViewport implements
     }
   }
 
+  /**
+   * Returns the (Desktop) instance of the StructureSelectionManager
+   */
+  @Override
   public StructureSelectionManager getStructureSelectionManager()
   {
     return StructureSelectionManager
@@ -894,8 +903,8 @@ public class AlignViewport extends AlignmentViewport implements
           StructureSelectionManager ssm, VamsasSource source)
   {
     /*
-     * ...work in progress... do nothing unless we are a 'complement' of the
-     * source May replace this with direct calls not via SSM.
+     * Do nothing unless we are a 'complement' of the source. May replace this
+     * with direct calls not via SSM.
      */
     if (source instanceof AlignViewportI
             && ((AlignViewportI) source).getCodingComplement() == this)
@@ -917,76 +926,6 @@ public class AlignViewport extends AlignmentViewport implements
     }
   }
 
-  @Override
-  public VamsasSource getVamsasSource()
-  {
-    return this;
-  }
-
-  /**
-   * Add one command to the command history list.
-   * 
-   * @param command
-   */
-  public void addToHistoryList(CommandI command)
-  {
-    if (this.historyList != null)
-    {
-      this.historyList.push(command);
-      broadcastCommand(command, false);
-    }
-  }
-
-  protected void broadcastCommand(CommandI command, boolean undo)
-  {
-    getStructureSelectionManager().commandPerformed(command, undo, getVamsasSource());
-  }
-
-  /**
-   * Add one command to the command redo list.
-   * 
-   * @param command
-   */
-  public void addToRedoList(CommandI command)
-  {
-    if (this.redoList != null)
-    {
-      this.redoList.push(command);
-    }
-    broadcastCommand(command, true);
-  }
-
-  /**
-   * Clear the command redo list.
-   */
-  public void clearRedoList()
-  {
-    if (this.redoList != null)
-    {
-      this.redoList.clear();
-    }
-  }
-
-  public void setHistoryList(Deque<CommandI> list)
-  {
-    this.historyList = list;
-  }
-
-  public Deque<CommandI> getHistoryList()
-  {
-    return this.historyList;
-  }
-
-  public void setRedoList(Deque<CommandI> list)
-  {
-    this.redoList = list;
-  }
-
-  public Deque<CommandI> getRedoList()
-  {
-    return this.redoList;
-  }
-
   /**
    * Add the sequences from the given alignment to this viewport. Optionally,
    * may give the user the option to open a new frame, or split panel, with cDNA
@@ -1011,17 +950,11 @@ public class AlignViewport extends AlignmentViewport implements
      * If one alignment is protein and one nucleotide, with at least one
      * sequence name in common, offer to open a linked alignment.
      */
-    if (getAlignment().isNucleotide() != al.isNucleotide())
+    if (AlignmentUtils.isMappable(al, getAlignment()))
     {
-      // TODO: JAL-845 try a bit harder to link up imported sequences
-      final Set<String> sequenceNames = getAlignment().getSequenceNames();
-      sequenceNames.retainAll(al.getSequenceNames());
-      if (!sequenceNames.isEmpty()) // at least one sequence name in both
+      if (openLinkedAlignment(al, title))
       {
-        if (openLinkedAlignment(al, title))
-        {
-          return;
-        }
+        return;
       }
     }
     // TODO: JAL-407 regardless of above - identical sequences (based on ID and
@@ -1053,9 +986,9 @@ public class AlignViewport extends AlignmentViewport implements
         MessageManager.getString("label.split_window"),
         MessageManager.getString("label.new_window"), };
     final String question = JvSwingUtils.wrapTooltip(true,
-            MessageManager.getString("label.open_linked_alignment?"));
+            MessageManager.getString("label.open_split_window?"));
     int response = JOptionPane.showOptionDialog(Desktop.desktop, question,
-            MessageManager.getString("label.open_linked_alignment"),
+            MessageManager.getString("label.open_split_window"),
             JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null,
             options, options[0]);
 
@@ -1102,23 +1035,11 @@ public class AlignViewport extends AlignmentViewport implements
     }
 
     /*
-     * Try to find mappings for at least one sequence. Any mappings made will be
-     * added to the protein alignment.
+     * Map sequences. At least one should get mapped as we have already passed
+     * the test for 'mappability'. Any mappings made will be added to the
+     * protein alignment.
      */
-    MappingResult mapped = AlignmentUtils.mapProteinToCdna(protein, cdna);
-    final StructureSelectionManager ssm = StructureSelectionManager
-            .getStructureSelectionManager(Desktop.instance);
-    if (mapped != MappingResult.Mapped)
-    {
-      /*
-       * No mapping possible - warn the user, but leave window open.
-       */
-      final String msg = JvSwingUtils.wrapTooltip(true,
-              MessageManager.getString("label.mapping_failed"));
-      JOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
-              MessageManager.getString("label.no_mappings"),
-              JOptionPane.WARNING_MESSAGE);
-    }
+    AlignmentUtils.mapProteinToCdna(protein, cdna);
 
     try
     {
@@ -1131,57 +1052,61 @@ public class AlignViewport extends AlignmentViewport implements
 
     if (openSplitPane)
     {
-      // TODO: move this kind of constructor stuff to a factory/controller
-      // method ?
-      /*
-       * Open in split pane. DNA sequence above, protein below.
-       */
-      AlignFrame copyMe = new AlignFrame(thisAlignment,
-              AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
-      copyMe.setTitle(getAlignPanel().alignFrame.getTitle());
-      final AlignFrame proteinFrame = al.isNucleotide() ? copyMe
-              : newAlignFrame;
-      final AlignFrame cdnaFrame = al.isNucleotide() ? newAlignFrame
-              : copyMe;
-      protein = proteinFrame.viewport.getAlignment();
-
-      cdnaFrame.setVisible(true);
-      proteinFrame.setVisible(true);
-      String sep = String.valueOf(File.separatorChar);
-      String proteinShortName = proteinFrame.getTitle().substring(
-              proteinFrame.getTitle().lastIndexOf(sep) + 1);
-      String dnaShortName = cdnaFrame.getTitle().substring(
-              cdnaFrame.getTitle().lastIndexOf(sep) + 1);
-      String linkedTitle = MessageManager.formatMessage(
-              "label.linked_view_title", dnaShortName, proteinShortName);
-      JInternalFrame splitFrame = new SplitFrame(cdnaFrame, proteinFrame);
-      Desktop.addInternalFrame(splitFrame, linkedTitle,
-              AlignFrame.DEFAULT_WIDTH,
-              AlignFrame.DEFAULT_HEIGHT);
-
-      /*
-       * Set the frames to listen for each other's edit and sort commands.
-       */
-      ssm.addCommandListener(cdnaFrame.getViewport());
-      ssm.addCommandListener(proteinFrame.getViewport());
-
-      /*
-       * 'Coding complement' (dna/protein) views will mirror each others' edits,
-       * selections, sorting etc as decided from time to time by the relevant
-       * authorities.
-       */
-      proteinFrame.getViewport().setCodingComplement(cdnaFrame.getViewport());
+      protein = openSplitFrame(newAlignFrame, thisAlignment,
+              protein.getCodonFrames());
     }
 
     /*
      * Register the mappings (held on the protein alignment) with the
      * StructureSelectionManager (for mouseover linking).
      */
+    final StructureSelectionManager ssm = StructureSelectionManager
+            .getStructureSelectionManager(Desktop.instance);
     ssm.addMappings(protein.getCodonFrames());
 
     return true;
   }
 
+  /**
+   * Helper method to open a new SplitFrame holding linked dna and protein
+   * alignments.
+   * 
+   * @param newAlignFrame
+   *          containing a new alignment to be shown
+   * @param complement
+   *          cdna/protein complement alignment to show in the other split half
+   * @param mappings
+   * @return the protein alignment in the split frame
+   */
+  protected AlignmentI openSplitFrame(AlignFrame newAlignFrame,
+          AlignmentI complement, Set<AlignedCodonFrame> mappings)
+  {
+    /*
+     * Open in split pane. DNA sequence above, protein below.
+     */
+    AlignFrame copyMe = new AlignFrame(complement,
+            AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+    copyMe.setTitle(getAlignPanel().alignFrame.getTitle());
+
+    AlignmentI al = newAlignFrame.viewport.getAlignment();
+    final AlignFrame proteinFrame = al.isNucleotide() ? copyMe
+            : newAlignFrame;
+    final AlignFrame cdnaFrame = al.isNucleotide() ? newAlignFrame
+            : copyMe;
+    AlignmentI protein = proteinFrame.viewport.getAlignment();
+    protein.setCodonFrames(mappings);
+    proteinFrame.viewport.initComplementConsensus();
+
+    cdnaFrame.setVisible(true);
+    proteinFrame.setVisible(true);
+    String linkedTitle = MessageManager
+            .getString("label.linked_view_title");
+    JInternalFrame splitFrame = new SplitFrame(cdnaFrame, proteinFrame);
+    Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
+
+    return protein;
+  }
+
   public AnnotationColumnChooser getAnnotationColumnSelectionState()
   {
     return annotationColumnSelectionState;
@@ -1207,4 +1132,24 @@ public class AlignViewport extends AlignmentViewport implements
       getAlignPanel().getIdPanel().getIdCanvas().setPreferredSize(idw);
     }
   }
+
+  public Rectangle getExplodedGeometry()
+  {
+    return explodedGeometry;
+  }
+
+  public void setExplodedGeometry(Rectangle explodedPosition)
+  {
+    this.explodedGeometry = explodedPosition;
+  }
+
+  public boolean isGatherViewsHere()
+  {
+    return gatherViewsHere;
+  }
+
+  public void setGatherViewsHere(boolean gatherViewsHere)
+  {
+    this.gatherViewsHere = gatherViewsHere;
+  }
 }