JAL-4366 provide options for updating (or not) the linked alignment or existing align...
[jalview.git] / src / jalview / gui / AlignViewport.java
index ea0afe1..91dded1 100644 (file)
  */
 package jalview.gui;
 
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Rectangle;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.swing.JInternalFrame;
+
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.api.AlignViewportI;
@@ -29,16 +42,25 @@ import jalview.api.FeatureSettingsModelI;
 import jalview.api.FeaturesDisplayedI;
 import jalview.api.ViewStyleI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.commands.CommandI;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.io.AppletFormatAdapter;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormatException;
+import jalview.io.FileFormatI;
+import jalview.io.FileFormats;
+import jalview.io.FileLoader;
+import jalview.io.IdentifyFile;
 import jalview.renderer.ResidueShader;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
@@ -52,17 +74,6 @@ import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.ws.params.AutoCalcSetting;
 
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Rectangle;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-
-import javax.swing.JInternalFrame;
-
 /**
  * DOCUMENT ME!
  * 
@@ -125,12 +136,12 @@ public class AlignViewport extends AlignmentViewport
     // TODO remove these once 2.4.VAMSAS release finished
     if (seqsetid != null)
     {
-      Cache.debug(
+      Console.debug(
               "Setting viewport's sequence set id : " + sequenceSetID);
     }
     if (viewId != null)
     {
-      Cache.debug("Setting viewport's view id : " + viewId);
+      Console.debug("Setting viewport's view id : " + viewId);
     }
     init();
 
@@ -187,12 +198,12 @@ public class AlignViewport extends AlignmentViewport
     // TODO remove these once 2.4.VAMSAS release finished
     if (seqsetid != null)
     {
-      Cache.debug(
+      Console.debug(
               "Setting viewport's sequence set id : " + sequenceSetID);
     }
     if (viewId != null)
     {
-      Cache.debug("Setting viewport's view id : " + viewId);
+      Console.debug("Setting viewport's view id : " + viewId);
     }
 
     if (hiddenColumns != null)
@@ -290,8 +301,8 @@ public class AlignViewport extends AlignmentViewport
       schemeName = Cache.getDefault(Preferences.DEFAULT_COLOUR,
               ResidueColourScheme.NONE);
     }
-    ColourSchemeI colourScheme = ColourSchemeProperty
-            .getColourScheme(this, alignment, schemeName);
+    ColourSchemeI colourScheme = ColourSchemeProperty.getColourScheme(this,
+            alignment, schemeName);
     residueShading = new ResidueShader(colourScheme);
 
     if (colourScheme instanceof UserColourScheme)
@@ -594,7 +605,7 @@ public class AlignViewport extends AlignmentViewport
     // calculator.getRegisteredWorkersOfClass(settings.getWorkerClass())
     if (needsUpdate)
     {
-      Cache.debug("trigger update for " + calcId);
+      Console.debug("trigger update for " + calcId);
     }
   }
 
@@ -718,12 +729,62 @@ public class AlignViewport extends AlignmentViewport
         al.addSequence(seq);
       }
     }
-
+    for (ContactMatrixI cm : toAdd.getContactMaps())
+    {
+      al.addContactList(cm);
+    }
     ranges.setEndSeq(getAlignment().getHeight() - 1); // BH 2019.04.18
     firePropertyChange("alignment", null, getAlignment().getSequences());
   }
 
   /**
+   * Load a File into this AlignViewport attempting to detect format if not
+   * given or given as null.
+   * 
+   * @param file
+   * @param format
+   */
+  public void addFile(File file, FileFormatI format)
+  {
+    addFile(file, format, true);
+  }
+
+  public void addFile(File file, FileFormatI format, boolean async)
+  {
+    DataSourceType protocol = AppletFormatAdapter.checkProtocol(file);
+
+    if (format == null)
+    {
+      try
+      {
+        format = new IdentifyFile().identify(file, protocol);
+      } catch (FileFormatException e1)
+      {
+        jalview.bin.Console.error("Unknown file format for '" + file + "'");
+      }
+    }
+    else if (FileFormats.getInstance().isIdentifiable(format))
+    {
+      try
+      {
+        format = new IdentifyFile().identify(file, protocol);
+      } catch (FileFormatException e)
+      {
+        jalview.bin.Console.error("Unknown file format for '" + file + "'",
+                e);
+      }
+    }
+
+    new FileLoader().LoadFile(this, file, DataSourceType.FILE, format,
+            async);
+  }
+
+  public void addFile(File file)
+  {
+    addFile(file, null);
+  }
+
+  /**
    * Show a dialog with the option to open and link (cDNA <-> protein) as a new
    * alignment, either as a standalone alignment or in a split frame. Returns
    * true if the new alignment was opened, false if not, because the user
@@ -735,49 +796,54 @@ public class AlignViewport extends AlignmentViewport
   protected void openLinkedAlignment(AlignmentI al, String title)
   {
     String[] options = new String[] { MessageManager.getString("action.no"),
-        MessageManager.getString("label.split_window"),
-        MessageManager.getString("label.new_window"), };
+        MessageManager.getString("label.split_window")
+                + "(update new alignment)",
+        MessageManager.getString("label.new_window"),
+        MessageManager.getString(
+                "label.split_window") + "(update this alignment)",
+        MessageManager.getString(
+                "label.split_window") + "(leave both unchanged)" };
     final String question = JvSwingUtils.wrapTooltip(true,
             MessageManager.getString("label.open_split_window?"));
     final AlignViewport us = this;
-    
+
     /*
      * options No, Split Window, New Window correspond to
      * dialog responses 0, 1, 2 (even though JOptionPane shows them
      * in reverse order)
      */
     JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop)
-            .setResponseHandler(0, new Runnable()
-            {
-              @Override
-              public void run()
-              {
-                  addDataToAlignment(al);
-              }
-            }).setResponseHandler(1, new Runnable()
-            {
-              @Override
-              public void run()
-              {
-                us.openLinkedAlignmentAs(al, title, true);
-              }
-            }).setResponseHandler(2, new Runnable()
-            {
-              @Override
-              public void run()
-              {
-                us.openLinkedAlignmentAs(al, title, false);
-              }
+            .setResponseHandler(0, () -> {
+              addDataToAlignment(al);
+            }).setResponseHandler(1, () -> {
+              us.openLinkedAlignmentAs(al, title, true, 1);
+            }).setResponseHandler(2, () -> {
+              us.openLinkedAlignmentAs(al, title, false, 1);
+            }).setResponseHandler(3, () -> {
+              us.openLinkedAlignmentAs(al, title, true, 2);
+            }).setResponseHandler(4, () -> {
+              us.openLinkedAlignmentAs(al, title, true, 0);
             });
-       dialog.showDialog(question,
+    dialog.setLayout(new FlowLayout(FlowLayout.CENTER));
+    dialog.setPreferredSize(new Dimension(350,300));
+    dialog.showDialog(question,
             MessageManager.getString("label.open_split_window"),
             JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null,
             options, options[0]);
   }
 
-  protected void openLinkedAlignmentAs(AlignmentI al, String title,
-          boolean newWindowOrSplitPane)
-    {
+  /**
+   * link given alignment to the alignment in this viewport and open
+   * @param al - alignment containing sequences to link to this alignment
+   * @param title
+   * @param newWindowOrSplitPane
+   * @param alignAs TODO
+   * @param alignAs - 0 - don't modify either alignment, 1 - align al according to us, 2- align us according to al
+   * @return alignFrame holding al
+   */
+  protected AlignFrame openLinkedAlignmentAs(AlignmentI al, String title,
+          boolean newWindowOrSplitPane, int alignAs)
+  {
     /*
      * Identify protein and dna alignments. Make a copy of this one if opening
      * in a new split pane.
@@ -785,18 +851,39 @@ public class AlignViewport extends AlignmentViewport
     AlignmentI thisAlignment = newWindowOrSplitPane
             ? new Alignment(getAlignment())
             : getAlignment();
-    AlignmentI protein = al.isNucleotide() ? thisAlignment : al;
-    final AlignmentI cdna = al.isNucleotide() ? al : thisAlignment;
+    
+    
+    if (!al.isNucleotide() && !thisAlignment.isNucleotide())
+    {
+      // link AA to 3di or other kind of 'alternative' 1:1 mapping alignment
+      if (al.getDataset()==null)
+      {
+        al.setDataset(thisAlignment.getDataset());
+      }
+      AlignmentUtils.map3diPeptideToProteinAligment(thisAlignment,al);
+      if (thisAlignment.getCodonFrames().isEmpty()) {thisAlignment.getCodonFrames().addAll(al.getCodonFrames()); }
+      else {al.getCodonFrames().addAll(thisAlignment.getCodonFrames()); };
 
-    /*
-     * 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. Note creating dataset sequences on the new alignment
-     * is a pre-requisite for building mappings.
-     */
-    al.setDataset(null);
-    AlignmentUtils.mapProteinAlignmentToCdna(protein, cdna);
 
+    }
+    else
+    {
+      // shouldn't we be merging dataset here ?
+      // always create dataset for imported alignment before doing anything else..
+        al.setDataset(null);
+        // link CODON triplets to Protein
+      AlignmentI protein = al.isNucleotide() ? thisAlignment : al;
+      final AlignmentI cdna = al.isNucleotide() ? al : thisAlignment;
+
+      /*
+       * 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. Note creating dataset sequences on the new alignment
+       * is a pre-requisite for building mappings.
+       */
+      AlignmentUtils.mapProteinAlignmentToCdna(protein, cdna);
+    }
+    
     /*
      * Create the AlignFrame for the added alignment. If it is protein, mappings
      * are registered with StructureSelectionManager as a side-effect.
@@ -823,17 +910,22 @@ public class AlignViewport extends AlignmentViewport
 
     try
     {
-      newAlignFrame.setMaximum(
-              Cache.getDefault("SHOW_FULLSCREEN", false));
+      newAlignFrame.setMaximum(Cache.getDefault("SHOW_FULLSCREEN", false));
     } catch (java.beans.PropertyVetoException ex)
     {
     }
 
     if (newWindowOrSplitPane)
     {
-      al.alignAs(thisAlignment);
-      protein = openSplitFrame(newAlignFrame, thisAlignment);
+      if (alignAs==1) {
+        al.alignAs(thisAlignment);
+      }
+      if (alignAs==2) {
+        thisAlignment.alignAs(al);
+      }
+      AlignmentI mapped = openSplitFrame(newAlignFrame, thisAlignment);
     }
+    return newAlignFrame;
   }
 
   /**
@@ -953,7 +1045,7 @@ public class AlignViewport extends AlignmentViewport
    */
   protected boolean noReferencesTo(AlignedCodonFrame acf)
   {
-    AlignFrame[] frames = Desktop.getAlignFrames();
+    AlignFrame[] frames = Desktop.getDesktopAlignFrames();
     if (frames == null)
     {
       return true;
@@ -990,10 +1082,10 @@ public class AlignViewport extends AlignmentViewport
   }
 
   /**
-   * Applies the supplied feature settings descriptor to currently known features.
-   * This supports an 'initial configuration' of feature colouring based on a
-   * preset or user favourite. This may then be modified in the usual way using
-   * the Feature Settings dialogue.
+   * Applies the supplied feature settings descriptor to currently known
+   * features. This supports an 'initial configuration' of feature colouring
+   * based on a preset or user favourite. This may then be modified in the usual
+   * way using the Feature Settings dialogue.
    * 
    * @param featureSettings
    */
@@ -1006,8 +1098,8 @@ public class AlignViewport extends AlignmentViewport
   /**
    * when mergeOnly is set, then group and feature visibility or feature colours
    * are not modified for features and groups already known to the feature
-   * renderer. Feature ordering is always adjusted, and transparency is always set
-   * regardless.
+   * renderer. Feature ordering is always adjusted, and transparency is always
+   * set regardless.
    * 
    * @param featureSettings
    * @param mergeOnly
@@ -1019,12 +1111,13 @@ public class AlignViewport extends AlignmentViewport
     {
       return;
     }
-    
+
     FeatureRenderer fr = getAlignPanel().getSeqPanel().seqCanvas
             .getFeatureRenderer();
     List<String> origRenderOrder = new ArrayList<>();
     List<String> origGroups = new ArrayList<>();
-    // preserve original render order - allows differentiation between user configured colours and autogenerated ones
+    // preserve original render order - allows differentiation between user
+    // configured colours and autogenerated ones
     origRenderOrder.addAll(fr.getRenderOrder());
     origGroups.addAll(fr.getFeatureGroups());
 
@@ -1056,7 +1149,8 @@ public class AlignViewport extends AlignmentViewport
                       && origColour.getColour().equals(
                               ColorUtils.createColourFromName(type)))))
       {
-        // if we are merging, only update if there wasn't already a colour defined for
+        // if we are merging, only update if there wasn't already a colour
+        // defined for
         // this type
         if (preferredColour != null)
         {
@@ -1080,7 +1174,8 @@ public class AlignViewport extends AlignmentViewport
     {
       if (!mergeOnly || !origGroups.contains(group))
       {
-        // when merging, display groups only if the aren't already marked as not visible
+        // when merging, display groups only if the aren't already marked as not
+        // visible
         fr.setGroupVisibility(group,
                 featureSettings.isGroupDisplayed(group));
       }
@@ -1111,4 +1206,5 @@ public class AlignViewport extends AlignmentViewport
   {
     this.viewName = viewName;
   }
+
 }