JAL-1683 replace year/version strings with tokens in source
[jalview.git] / src / jalview / gui / ChimeraViewFrame.java
index 17b3ead..83ea379 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
- * 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.api.SequenceStructureBinding;
-import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
-import jalview.gui.ViewSelectionMenu.ViewSetProvider;
+import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
-import jalview.jbgui.GStructureViewer;
 import jalview.schemes.BuriedColourScheme;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.HelixColourScheme;
@@ -42,11 +39,11 @@ import jalview.schemes.StrandColourScheme;
 import jalview.schemes.TaylorColourScheme;
 import jalview.schemes.TurnColourScheme;
 import jalview.schemes.ZappoColourScheme;
+import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.ws.dbsources.Pdb;
 
-import java.awt.Component;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -78,34 +75,14 @@ import javax.swing.event.MenuListener;
  * @author jprocter
  *
  */
-public class ChimeraViewFrame extends GStructureViewer implements Runnable,
-        ViewSetProvider, JalviewStructureDisplayI
-
+public class ChimeraViewFrame extends StructureViewerBase
 {
-  private JalviewChimeraBindingModel jmb;
-
-  /*
-   * list of sequenceSet ids associated with the view
-   */
-  private ArrayList<String> _aps = new ArrayList<String>();
-
-  /*
-   * list of alignment panels to use for superposition
-   */
-  private Vector<AlignmentPanel> _alignwith = new Vector<AlignmentPanel>();
-
-  /*
-   * list of alignment panels that are used for colouring structures by aligned
-   * sequences
-   */
-  private Vector<AlignmentPanel> _colourwith = new Vector<AlignmentPanel>();
+  private JalviewChimeraBinding jmb;
 
   private boolean allChainsSelected = false;
 
   private boolean alignAddedStructures = false;
 
-  AlignmentPanel ap;
-
   /*
    * state flag for PDB retrieval thread
    */
@@ -115,13 +92,18 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
 
   private IProgressIndicator progressBar = null;
 
-  private String viewId = null;
-
   /*
    * pdb retrieval thread.
    */
   private Thread worker = null;
 
+  /*
+   * Path to Chimera session file. This is set when an open Jalview/Chimera
+   * session is saved, or on restore from a Jalview project (if it holds the
+   * filename of any saved Chimera sessions).
+   */
+  private String chimeraSessionFile = null;
+
   /**
    * Initialise menu options.
    */
@@ -244,9 +226,9 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
         // TODO : Fix multiple seq to one chain issue here.
         ap.getStructureSelectionManager().setMapping(seq, chains,
                 alreadyMapped, AppletFormatAdapter.FILE);
-        if (ap.seqPanel.seqCanvas.fr != null)
+        if (ap.getSeqPanel().seqCanvas.fr != null)
         {
-          ap.seqPanel.seqCanvas.fr.featuresAdded();
+          ap.getSeqPanel().seqCanvas.fr.featuresAdded();
           ap.paintAlignment(true);
         }
 
@@ -261,15 +243,17 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
             final ChimeraViewFrame topView = ((ChimeraViewFrame) frame);
             // JBPNOTE: this looks like a binding routine, rather than a gui
             // routine
-            for (int pe = 0; pe < topView.jmb.pdbentry.length; pe++)
+            for (int pe = 0; pe < topView.jmb.getPdbCount(); pe++)
             {
-              if (topView.jmb.pdbentry[pe].getFile().equals(alreadyMapped))
+              if (topView.jmb.getPdbEntry(pe).getFile()
+                      .equals(
+                      alreadyMapped))
               {
                 topView.jmb.addSequence(pe, seq);
                 topView.addAlignmentPanel(ap);
                 // add it to the set used for colouring
                 topView.useAlignmentPanelForColourbyseq(ap);
-                topView.buildChimeraActionMenu();
+                topView.buildActionMenu();
                 ap.getStructureSelectionManager()
                         .sequenceColoursChanged(ap);
                 break;
@@ -328,12 +312,11 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
     jmb.setColourBySequence(true);
     setSize(400, 400); // probably should be a configurable/dynamic default here
     initMenus();
-    worker = null;
-    {
-      addingStructures = false;
-      worker = new Thread(this);
-      worker.start();
-    }
+
+    addingStructures = false;
+    worker = new Thread(this);
+    worker.start();
+
     this.addInternalFrameListener(new InternalFrameAdapter()
     {
       public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
@@ -359,114 +342,37 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
     openNewChimera(ap, pe, seqs);
   }
 
-  public AlignmentPanel[] getAllAlignmentPanels()
-  {
-    AlignmentPanel[] t, list = new AlignmentPanel[0];
-    for (String setid : _aps)
-    {
-      AlignmentPanel[] panels = PaintRefresher.getAssociatedPanels(setid);
-      if (panels != null)
-      {
-        t = new AlignmentPanel[list.length + panels.length];
-        System.arraycopy(list, 0, t, 0, list.length);
-        System.arraycopy(panels, 0, t, list.length, panels.length);
-        list = t;
-      }
-    }
-
-    return list;
-  }
-
   /**
-   * set the primary alignmentPanel reference and add another alignPanel to the
-   * list of ones to use for colouring and aligning
+   * Create a new viewer from saved session state data including Chimera session
+   * file.
    * 
-   * @param nap
-   */
-  public void addAlignmentPanel(AlignmentPanel nap)
-  {
-    if (ap == null)
-    {
-      ap = nap;
-    }
-    if (!_aps.contains(nap.av.getSequenceSetId()))
-    {
-      _aps.add(nap.av.getSequenceSetId());
-    }
-  }
-
-  /**
-   * remove any references held to the given alignment panel
+   * @param chimeraSession
    * 
-   * @param nap
+   * @param alignPanel
+   * @param pdbArray
+   * @param seqsArray
+   * @param colourByChimera
+   * @param colourBySequence
    */
-  public void removeAlignmentPanel(AlignmentPanel nap)
-  {
-    try
-    {
-      _alignwith.remove(nap);
-      _colourwith.remove(nap);
-      if (ap == nap)
-      {
-        ap = null;
-        for (AlignmentPanel aps : getAllAlignmentPanels())
-        {
-          if (aps != nap)
-          {
-            ap = aps;
-            break;
-          }
-        }
-      }
-    } catch (Exception ex)
-    {
-    }
-    if (ap != null)
-    {
-      buildChimeraActionMenu();
-    }
-  }
-
-  public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
+  public ChimeraViewFrame(String chimeraSession, AlignmentPanel alignPanel,
+          PDBEntry[] pdbArray,
+          SequenceI[][] seqsArray, boolean colourByChimera,
+          boolean colourBySequence)
   {
-    addAlignmentPanel(nap);
-    if (!_alignwith.contains(nap))
-    {
-      _alignwith.add(nap);
-    }
-  }
-
-  public void excludeAlignmentPanelForSuperposition(AlignmentPanel nap)
-  {
-    if (_alignwith.contains(nap))
-    {
-      _alignwith.remove(nap);
-    }
-  }
-
-  public void useAlignmentPanelForColourbyseq(AlignmentPanel nap,
-          boolean enableColourBySeq)
-  {
-    useAlignmentPanelForColourbyseq(nap);
-    jmb.setColourBySequence(enableColourBySeq);
-    seqColour.setSelected(enableColourBySeq);
-    viewerColour.setSelected(!enableColourBySeq);
-  }
-
-  public void useAlignmentPanelForColourbyseq(AlignmentPanel nap)
-  {
-    addAlignmentPanel(nap);
-    if (!_colourwith.contains(nap))
+    super();
+    this.chimeraSessionFile = chimeraSession;
+    openNewChimera(alignPanel, pdbArray, seqsArray);
+    if (colourByChimera)
     {
-      _colourwith.add(nap);
+      jmb.setColourBySequence(false);
+      seqColour.setSelected(false);
+      viewerColour.setSelected(true);
     }
-  }
-
-  public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
-  {
-    if (_colourwith.contains(nap))
+    else if (colourBySequence)
     {
-      _colourwith.remove(nap);
+      jmb.setColourBySequence(true);
+      seqColour.setSelected(true);
+      viewerColour.setSelected(false);
     }
   }
 
@@ -535,7 +441,7 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
     {
       if (frame instanceof ChimeraViewFrame)
       {
-        if (((ChimeraViewFrame) frame).isLinkedWith(apanel))
+        if (((StructureViewerBase) frame).isLinkedWith(apanel))
         {
           result.add((ChimeraViewFrame) frame);
         }
@@ -544,18 +450,31 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
     return result;
   }
 
-  void initChimera(String command)
+  /**
+   * Launch Chimera. If we have a chimera session file name, send Chimera the
+   * command to open its saved session file.
+   */
+  void initChimera()
   {
     jmb.setFinishedInit(false);
-    // TODO: consider waiting until the structure/view is fully loaded before
-    // displaying
-    jalview.gui.Desktop.addInternalFrame(this, jmb.getViewerTitle(true),
+    jalview.gui.Desktop.addInternalFrame(this, jmb.getViewerTitle("Chimera", true),
             getBounds().width, getBounds().height);
-    if (command == null)
+
+    /*
+     * Pass an empty 'command' to launch Chimera
+     */
+    jmb.evalStateCommand("", false);
+
+    if (this.chimeraSessionFile != null)
     {
-      command = "";
+      boolean opened = jmb.openSession(chimeraSessionFile);
+      if (!opened)
+      {
+        System.err
+                .println("An error occurred opening Chimera session file "
+                        + chimeraSessionFile);
+      }
     }
-    jmb.evalStateCommand(command, false);
     jmb.setFinishedInit(true);
   }
 
@@ -633,14 +552,14 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
     {
       String prompt = MessageManager
               .formatMessage("label.confirm_close_chimera", new Object[]
-              { jmb.getViewerTitle(false) });
+              { jmb.getViewerTitle("Chimera", false) });
       prompt = JvSwingUtils.wrapTooltip(true, prompt);
       int confirm = JOptionPane.showConfirmDialog(this, prompt,
               MessageManager.getString("label.close_viewer"),
               JOptionPane.YES_NO_OPTION);
       jmb.closeViewer(confirm == JOptionPane.YES_OPTION);
     }
-    ap = null;
+    setAlignmentPanel(null);
     _aps.clear();
     _alignwith.clear();
     _colourwith.clear();
@@ -667,10 +586,10 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
       String[] curfiles = jmb.getPdbFile(); // files currently in viewer
       // TODO: replace with reference fetching/transfer code (validate PDBentry
       // as a DBRef?)
-      for (int pi = 0; pi < jmb.pdbentry.length; pi++)
+      for (int pi = 0; pi < jmb.getPdbCount(); pi++)
       {
         String file = null;
-        thePdbEntry = jmb.pdbentry[pi];
+        thePdbEntry = jmb.getPdbEntry(pi);
         if (thePdbEntry.getFile() == null)
         {
           /*
@@ -736,7 +655,7 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
       {
         try
         {
-          initChimera("");
+          initChimera();
         } catch (Exception ex)
         {
           Cache.log.error("Couldn't open Chimera viewer!", ex);
@@ -752,7 +671,7 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
           {
             int pos = filePDBpos.get(num).intValue();
             jmb.openFile(pe);
-            jmb.addSequence(pos, jmb.sequence[pos]);
+            jmb.addSequence(pos, jmb.getSequence()[pos]);
             File fl = new File(pe.getFile());
             String protocol = AppletFormatAdapter.URL;
             try
@@ -766,7 +685,8 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
             }
             // Explicitly map to the filename used by Chimera ;
             // TODO: use pe.getId() instead of pe.getFile() ?
-            jmb.ssm.setMapping(jmb.sequence[pos], null, pe.getFile(),
+            jmb.getSsm().setMapping(jmb.getSequence()[pos], null,
+                    pe.getFile(),
                     protocol);
           } catch (OutOfMemoryError oomerror)
           {
@@ -919,9 +839,9 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
     jalview.gui.CutAndPasteTransfer cap = new jalview.gui.CutAndPasteTransfer();
     try
     {
-      for (int pdbe = 0; pdbe < jmb.pdbentry.length; pdbe++)
+      for (int pdbe = 0; pdbe < jmb.getPdbCount(); pdbe++)
       {
-        cap.appendText(jmb.printMapping(jmb.pdbentry[pdbe].getFile()));
+        cap.appendText(jmb.printMapping(jmb.getPdbEntry(pdbe).getFile()));
         cap.appendText("\n");
       }
     } catch (OutOfMemoryError e)
@@ -975,16 +895,16 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
     {
       if (!jmb.isLoadingFromArchive())
       {
-        if (_colourwith.size() == 0 && ap != null)
+        if (_colourwith.size() == 0 && getAlignmentPanel() != null)
         {
           // Make the currently displayed alignment panel the associated view
-          _colourwith.add(ap.alignFrame.alignPanel);
+          _colourwith.add(getAlignmentPanel().alignFrame.alignPanel);
         }
       }
       // Set the colour using the current view for the associated alignframe
       for (AlignmentPanel ap : _colourwith)
       {
-        jmb.colourBySequence(ap.av.showSequenceFeatures, ap);
+        jmb.colourBySequence(ap.av.isShowSequenceFeatures(), ap);
       }
     }
   }
@@ -1089,15 +1009,6 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
     }
   }
 
-  public String getViewId()
-  {
-    if (viewId == null)
-    {
-      viewId = System.currentTimeMillis() + "." + this.hashCode();
-    }
-    return viewId;
-  }
-
   public void updateTitleAndMenus()
   {
     if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0)
@@ -1105,10 +1016,10 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
       repaint();
       return;
     }
-    setChainMenuItems(jmb.chainNames);
+    setChainMenuItems(jmb.getChainNames());
 
-    this.setTitle(jmb.getViewerTitle(true));
-    if (jmb.getPdbFile().length > 1 && jmb.sequence.length > 1)
+    this.setTitle(jmb.getViewerTitle("Chimera", true));
+    if (jmb.getPdbFile().length > 1 && jmb.getSequence().length > 1)
     {
       viewerActionMenu.setVisible(true);
     }
@@ -1118,26 +1029,6 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
     }
   }
 
-  protected void buildChimeraActionMenu()
-  {
-    if (_alignwith == null)
-    {
-      _alignwith = new Vector<AlignmentPanel>();
-    }
-    if (_alignwith.size() == 0 && ap != null)
-    {
-      _alignwith.add(ap);
-    }
-    ;
-    for (Component c : viewerActionMenu.getMenuComponents())
-    {
-      if (c != alignStructs)
-      {
-        viewerActionMenu.remove((JMenuItem) c);
-      }
-    }
-  }
-
   /*
    * (non-Javadoc)
    * 
@@ -1153,14 +1044,14 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
 
   private void alignStructs_withAllAlignPanels()
   {
-    if (ap == null)
+    if (getAlignmentPanel() == null)
     {
       return;
     }
     ;
     if (_alignwith.size() == 0)
     {
-      _alignwith.add(ap);
+      _alignwith.add(getAlignmentPanel());
     }
     ;
     try
@@ -1212,42 +1103,40 @@ public class ChimeraViewFrame extends GStructureViewer implements Runnable,
         return ap;
       }
     }
-    return ap;
-  }
-
-  /**
-   * 
-   * @param ap2
-   * @return true if this Chimera instance is linked with the given alignPanel
-   */
-  public boolean isLinkedWith(AlignmentPanel ap2)
-  {
-    return _aps.contains(ap2.av.getSequenceSetId());
+    return getAlignmentPanel();
   }
 
-  public boolean isUsedforaligment(AlignmentPanel ap2)
-  {
-
-    return (_alignwith != null) && _alignwith.contains(ap2);
-  }
-
-  public boolean isUsedforcolourby(AlignmentPanel ap2)
+  @Override
+  public AAStructureBindingModel getBinding()
   {
-    return (_colourwith != null) && _colourwith.contains(ap2);
+    return jmb;
   }
 
   /**
+   * Ask Chimera to save its session to the designated file path. Returns true
+   * if successful, else false.
    * 
-   * @return TRUE if the view is NOT being coloured by sequence associations.
+   * @param filepath
+   * @see getStateInfo
    */
-  public boolean isColouredByChimera()
+  public boolean saveSession(String filepath)
   {
-    return !jmb.isColourBySequence();
+    boolean result = jmb.saveSession(filepath);
+    if (result)
+    {
+      this.chimeraSessionFile = filepath;
+    }
+    return result;
   }
 
-  public SequenceStructureBinding getBinding()
+  /**
+   * Returns the file path of the Chimera session file the last time it was
+   * saved. If it was never saved, returns an empty string. There is no
+   * guarantee that the Chimera session has not changed since it was saved.
+   */
+  @Override
+  public String getStateInfo()
   {
-    return jmb;
+    return this.chimeraSessionFile;
   }
-
 }