JAL-1863 allow RNA secondary structure rows exported by Jalview to be imported again
[jalview.git] / src / jalview / gui / AlignFrame.java
index cd9c533..f04744d 100644 (file)
  */
 package jalview.gui;
 
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.StringSelection;
-import java.awt.datatransfer.Transferable;
-import java.awt.dnd.DnDConstants;
-import java.awt.dnd.DropTargetDragEvent;
-import java.awt.dnd.DropTargetDropEvent;
-import java.awt.dnd.DropTargetEvent;
-import java.awt.dnd.DropTargetListener;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.print.PageFormat;
-import java.awt.print.PrinterJob;
-import java.beans.PropertyChangeEvent;
-import java.io.File;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
-
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JEditorPane;
-import javax.swing.JInternalFrame;
-import javax.swing.JLayeredPane;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JRadioButtonMenuItem;
-import javax.swing.JScrollPane;
-import javax.swing.SwingUtilities;
-
-import jalview.analysis.AAFrequency;
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AlignmentUtils;
-import jalview.analysis.Conservation;
 import jalview.analysis.CrossRef;
 import jalview.analysis.Dna;
 import jalview.analysis.ParseProperties;
 import jalview.analysis.SequenceIdMatcher;
+import jalview.api.AlignExportSettingI;
 import jalview.api.AlignViewControllerGuiI;
 import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
@@ -83,6 +36,7 @@ import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
 import jalview.api.analysis.ScoreModelI;
 import jalview.bin.Cache;
+import jalview.bin.Jalview;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
@@ -94,6 +48,7 @@ import jalview.commands.TrimRegionCommand;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentExportData;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
@@ -144,6 +99,52 @@ import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+import java.beans.PropertyChangeEvent;
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JEditorPane;
+import javax.swing.JInternalFrame;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
 /**
  * DOCUMENT ME!
  * 
@@ -305,7 +306,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (hiddenSeqs != null && hiddenSeqs.length > 0)
     {
       viewport.hideSequence(hiddenSeqs);
-      viewport.setHasHiddenRows(true);
     }
     alignPanel = new AlignmentPanel(this, viewport);
     addAlignmentPanel(alignPanel, true);
@@ -335,7 +335,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   void init()
   {
-    progressBar = new ProgressBar(this.statusPanel, this.statusBar);
+    if (!Jalview.isHeadlessMode())
+    {
+      progressBar = new ProgressBar(this.statusPanel, this.statusBar);
+    }
 
     avc = new jalview.controller.AlignViewController(this, viewport,
             alignPanel);
@@ -791,7 +794,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       public void internalFrameClosed(
               javax.swing.event.InternalFrameEvent evt)
       {
-        System.out.println("deregistering discoverer listener");
+        // System.out.println("deregistering discoverer listener");
         Desktop.instance.removeJalviewPropertyChangeListener("services",
                 thisListener);
         closeMenuItem_actionPerformed(true);
@@ -1026,7 +1029,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void addFromText_actionPerformed(ActionEvent e)
   {
-    Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);
+    Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport
+            .getAlignPanel());
   }
 
   @Override
@@ -1135,13 +1139,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
         warningMessage("Cannot save file " + fileName + " using format "
                 + format, "Alignment output format not supported");
-        saveAs_actionPerformed(null);
-        // JBPNote need to have a raise_gui flag here
+        if (!Jalview.isHeadlessMode())
+        {
+          saveAs_actionPerformed(null);
+        }
         return false;
       }
 
-      ExportData exportData = getAlignmentForExport();
-      FormatAdapter f = new FormatAdapter(viewport);
+      AlignmentExportData exportData = getAlignmentForExport(format,
+              viewport, null);
+      if (exportData.getSettings().isCancelled())
+      {
+        return false;
+      }
+      FormatAdapter f = new FormatAdapter(alignPanel,
+              exportData.getSettings());
       String output = f.formatSequences(format,
               exportData.getAlignment(), // class cast exceptions will
               // occur in the distant future
@@ -1213,13 +1225,18 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void outputText_actionPerformed(ActionEvent e)
   {
 
-    ExportData exportData = getAlignmentForExport();
+    AlignmentExportData exportData = getAlignmentForExport(
+            e.getActionCommand(), viewport, null);
+    if (exportData.getSettings().isCancelled())
+    {
+      return;
+    }
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
     cap.setForInput(null);
-
     try
     {
-      cap.setText(new FormatAdapter(viewport).formatSequences(
+      cap.setText(new FormatAdapter(alignPanel, exportData.getSettings())
+              .formatSequences(
               e.getActionCommand(),
  exportData.getAlignment(),
               exportData.getOmitHidden(), exportData.getStartEndPostions(),
@@ -1235,13 +1252,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   }
 
-  public ExportData getAlignmentForExport()
+  public static AlignmentExportData getAlignmentForExport(String exportFormat,
+ AlignViewportI viewport,
+          AlignExportSettingI exportSettings)
   {
     AlignmentI alignmentToExport = null;
+    AlignExportSettingI settings = exportSettings;
     String[] omitHidden = null;
     int[] alignmentStartEnd = new int[2];
-    FeatureRenderer fr = new FeatureRenderer(this.alignPanel);
-    viewport.setFeatureRenderer(fr);
+
     HiddenSequences hiddenSeqs = viewport.getAlignment()
             .getHiddenSequences();
 
@@ -1250,39 +1269,35 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     alignmentStartEnd = new int[]
     { 0, alignmentToExport.getWidth() - 1 };
 
-    if (viewport.hasHiddenColumns() || hiddenSeqs.getSize() > 0)
+    boolean hasHiddenSeqs = hiddenSeqs.getSize() > 0;
+    if (settings == null)
     {
-      int reply = JOptionPane
-              .showInternalConfirmDialog(
-                      Desktop.desktop,
-                      MessageManager
-                              .getString("label.alignment_contains_hidden_columns"),
-                      MessageManager
-                              .getString("action.save_omit_hidden_columns"),
-                      JOptionPane.YES_NO_OPTION,
-                      JOptionPane.QUESTION_MESSAGE);
+      settings = new AlignExportSettings(hasHiddenSeqs,
+            viewport.hasHiddenColumns(), exportFormat);
+    }
+    // settings.isExportAnnotations();
 
-      if (reply == JOptionPane.YES_OPTION)
-      {
-        // export only visible region
-        omitHidden = viewport.getViewAsString(false);
-        alignmentToExport = viewport.getAlignment();
-        alignmentStartEnd = getStartEnd(alignmentStartEnd, viewport
-                .getColumnSelection().getHiddenColumns());
-        viewport.setIncludeHiddenRegion(false);
-      }
-      else
-      {
-        // export all region including visible
-        alignmentToExport = hiddenSeqs.getFullAlignment();
-        viewport.setIncludeHiddenRegion(true);
-      }
+    if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns())
+    {
+      omitHidden = viewport.getViewAsString(false);
     }
 
-    return new ExportData(alignmentToExport, omitHidden, alignmentStartEnd);
+    if (hasHiddenSeqs && settings.isExportHiddenSequences())
+    {
+      alignmentToExport = hiddenSeqs.getFullAlignment();
+    }
+    else
+    {
+      alignmentToExport = viewport.getAlignment();
+      alignmentStartEnd = getStartEnd(alignmentStartEnd, viewport
+              .getColumnSelection().getHiddenColumns());
+    }
+    AlignmentExportData ed = new AlignmentExportData(alignmentToExport, omitHidden, alignmentStartEnd,
+            settings);
+    return ed;
   }
 
-  private static int[] getStartEnd(int[] aligmentStartEnd,
+  public static int[] getStartEnd(int[] aligmentStartEnd,
           List<int[]> hiddenCols)
   {
     int startPos = aligmentStartEnd[0];
@@ -1294,7 +1309,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     for (int[] hiddenCol : hiddenCols)
     {
       // System.out.println("comparing : " + hiddenCol[0] + "-" + hiddenCol[1]);
-
       lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange;
       higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange;
     }
@@ -1352,17 +1366,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   protected void htmlMenuItem_actionPerformed(ActionEvent e)
   {
-    // new HTMLOutput(alignPanel,
-    // alignPanel.getSeqPanel().seqCanvas.getSequenceRenderer(),
-    // alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer());
     new HtmlSvgOutput(null, alignPanel);
   }
 
   @Override
   public void bioJSMenuItem_actionPerformed(ActionEvent e)
   {
-    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel,
-            alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer());
+    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel);
     bjs.exportJalviewAlignmentAsBioJsHtmlFile();
   }
   public void createImageMap(File file, String image)
@@ -1493,6 +1503,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
       if (closeAllTabs)
       {
+        /*
+         * this will raise an INTERNAL_FRAME_CLOSED event and this method will
+         * be called recursively, with the frame now in 'closed' state
+         */
         this.setClosed(true);
       }
     } catch (Exception ex)
@@ -1823,9 +1837,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               viewport.getSelectionGroup().getEndRes() + groupAdjustment);
     }
 
+    /*
+     * just extend the last slide command if compatible; but not if in
+     * SplitFrame mode (to ensure all edits are broadcast - JAL-1802)
+     */
     boolean appendHistoryItem = false;
     Deque<CommandI> historyList = viewport.getHistoryList();
-    if (historyList != null
+    boolean inSplitFrame = getSplitViewContainer() != null;
+    if (!inSplitFrame && historyList != null
             && historyList.size() > 0
             && historyList.peek() instanceof SlideSequencesCommand)
     {
@@ -2740,12 +2759,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
 
     /*
-     * Views share the same edits, undo and redo stacks, mappings.
+     * Views share the same edits undo and redo stacks
      */
     newap.av.setHistoryList(viewport.getHistoryList());
     newap.av.setRedoList(viewport.getRedoList());
-    newap.av.getAlignment().setCodonFrames(
-            viewport.getAlignment().getCodonFrames());
+
+    /*
+     * Views share the same mappings; need to deregister any new mappings
+     * created by copyAlignPanel, and register the new reference to the shared
+     * mappings
+     */
+    newap.av.replaceMappings(viewport.getAlignment());
 
     newap.av.viewName = getNewViewName(viewTitle);
 
@@ -3473,115 +3497,27 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   public void changeColour(ColourSchemeI cs)
   {
-    // TODO: compare with applet and pull up to model method
-    int threshold = 0;
+    // TODO: pull up to controller method
 
     if (cs != null)
     {
+      // Make sure viewport is up to date w.r.t. any sliders
       if (viewport.getAbovePIDThreshold())
       {
-        threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
+        int threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
                 "Background");
-        cs.setThreshold(threshold, viewport.isIgnoreGapsConsensus());
-      }
-      else
-      {
-        cs.setThreshold(0, viewport.isIgnoreGapsConsensus());
+        viewport.setThreshold(threshold);
       }
 
       if (viewport.getConservationSelected())
       {
-
-        Alignment al = (Alignment) viewport.getAlignment();
-        Conservation c = new Conservation("All",
-                ResidueProperties.propHash, 3, al.getSequences(), 0,
-                al.getWidth() - 1);
-
-        c.calculate();
-        c.verdict(false, viewport.getConsPercGaps());
-
-        cs.setConservation(c);
-
         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,
                 cs, "Background"));
       }
-      else
-      {
-        cs.setConservation(null);
-      }
-
-      cs.setConsensus(viewport.getSequenceConsensusHash());
     }
 
     viewport.setGlobalColourScheme(cs);
 
-    if (viewport.getColourAppliesToAllGroups())
-    {
-
-      for (SequenceGroup sg : viewport.getAlignment().getGroups())
-      {
-        if (cs == null)
-        {
-          sg.cs = null;
-          continue;
-        }
-
-        if (cs instanceof ClustalxColourScheme)
-        {
-          sg.cs = new ClustalxColourScheme(sg,
-                  viewport.getHiddenRepSequences());
-        }
-        else if (cs instanceof UserColourScheme)
-        {
-          sg.cs = new UserColourScheme(((UserColourScheme) cs).getColours());
-        }
-        else
-        {
-          try
-          {
-            sg.cs = cs.getClass().newInstance();
-          } catch (Exception ex)
-          {
-          }
-        }
-
-        if (viewport.getAbovePIDThreshold()
-                || cs instanceof PIDColourScheme
-                || cs instanceof Blosum62ColourScheme)
-        {
-          sg.cs.setThreshold(threshold, viewport.isIgnoreGapsConsensus());
-
-          sg.cs.setConsensus(AAFrequency.calculate(
-                  sg.getSequences(viewport.getHiddenRepSequences()),
-                  sg.getStartRes(), sg.getEndRes() + 1));
-        }
-        else
-        {
-          sg.cs.setThreshold(0, viewport.isIgnoreGapsConsensus());
-        }
-
-        if (viewport.getConservationSelected())
-        {
-          Conservation c = new Conservation("Group",
-                  ResidueProperties.propHash, 3, sg.getSequences(viewport
-                          .getHiddenRepSequences()), sg.getStartRes(),
-                  sg.getEndRes() + 1);
-          c.calculate();
-          c.verdict(false, viewport.getConsPercGaps());
-          sg.cs.setConservation(c);
-        }
-        else
-        {
-          sg.cs.setConservation(null);
-        }
-      }
-    }
-
-    if (alignPanel.getOverviewPanel() != null)
-    {
-      alignPanel.getOverviewPanel().updateOverviewImage();
-    }
-
     alignPanel.paintAlignment(true);
   }
 
@@ -4516,8 +4452,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         final List<JMenuItem> legacyItems = new ArrayList<JMenuItem>();
         try
         {
-          System.err.println("Building ws menu again "
-                  + Thread.currentThread());
+          // System.err.println("Building ws menu again "
+          // + Thread.currentThread());
           // TODO: add support for context dependent disabling of services based
           // on
           // alignment and current selection
@@ -4851,7 +4787,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
             // temporary flag until SplitFrame is released
             boolean asSplitFrame = Cache.getDefault(
-                    Preferences.ENABLE_SPLIT_FRAME, false);
+                    Preferences.ENABLE_SPLIT_FRAME, true);
             if (asSplitFrame)
             {
               /*
@@ -4869,7 +4805,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 al.getCodonFrames().addAll(cf);
                 final StructureSelectionManager ssm = StructureSelectionManager
                         .getStructureSelectionManager(Desktop.instance);
-                ssm.addMappings(cf);
+                ssm.registerMappings(cf);
               }
               else
               {
@@ -4959,10 +4895,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               "Exception during translation. Please report this !", ex);
       final String msg = MessageManager
               .getString("label.error_when_translating_sequences_submit_bug_report");
-      final String title = MessageManager
+      final String errorTitle = MessageManager
               .getString("label.implementation_error")
               + MessageManager.getString("translation_failed");
-      JOptionPane.showMessageDialog(Desktop.desktop, msg, title,
+      JOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
               JOptionPane.ERROR_MESSAGE);
       return;
     }
@@ -4970,9 +4906,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       final String msg = MessageManager
               .getString("label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation");
-      final String title = MessageManager
+      final String errorTitle = MessageManager
               .getString("label.translation_failed");
-      JOptionPane.showMessageDialog(Desktop.desktop, msg, title,
+      JOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
               JOptionPane.WARNING_MESSAGE);
     }
     else
@@ -4983,11 +4919,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               "label.translation_of_params", new Object[]
               { this.getTitle() });
       af.setTitle(newTitle);
-      if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, false))
+      if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
       {
         final SequenceI[] seqs = viewport.getSelectionAsNewSequence();
-        viewport.openSplitFrame(af, new Alignment(seqs),
-                al.getCodonFrames());
+        viewport.openSplitFrame(af, new Alignment(seqs));
       }
       else
       {
@@ -5992,7 +5927,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         aa.visible = visible;
       }
     }
-    alignPanel.validateAnnotationDimensions(false);
+    alignPanel.validateAnnotationDimensions(true);
     alignPanel.alignmentChanged();
   }
 
@@ -6079,53 +6014,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       sf.setComplementVisible(this, show);
     }
   }
-
-  public class ExportData
-  {
-    private AlignmentI alignment;
-
-    private String[] omitHidden;
-
-    private int[] startEnd;
-
-    public ExportData(AlignmentI align, String[] ommit, int[] startEnd)
-    {
-      this.alignment = align;
-      this.omitHidden = ommit;
-      this.startEnd = startEnd;
-    }
-
-    public AlignmentI getAlignment()
-    {
-      return alignment;
-    }
-
-    public void setAlignment(AlignmentI alignment)
-    {
-      this.alignment = alignment;
-    }
-
-    public String[] getOmitHidden()
-    {
-      return omitHidden;
-    }
-
-    public void setOmitHidden(String[] omitHidden)
-    {
-      this.omitHidden = omitHidden;
-    }
-
-    public int[] getStartEndPostions()
-    {
-      return startEnd;
-    }
-
-    public void setStartEndPostions(int[] startEnd)
-    {
-      this.startEnd = startEnd;
-    }
-  }
-
 }
 
 class PrintThread extends Thread