Merge branch 'features/JAL-1588saveChimeraSession' into develop
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 26 Jan 2015 16:45:29 +0000 (16:45 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 26 Jan 2015 16:45:29 +0000 (16:45 +0000)
33 files changed:
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
src/jalview/api/SequenceStructureBinding.java
src/jalview/api/structures/JalviewStructureDisplayI.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AppletJmol.java
src/jalview/appletgui/AppletJmolBinding.java
src/jalview/appletgui/ExtJmol.java
src/jalview/datamodel/PDBEntry.java
src/jalview/datamodel/ViewerData.java [new file with mode: 0644]
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/ext/varna/JalviewVarnaBinding.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AppJmol.java
src/jalview/gui/AppJmolBinding.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/Desktop.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/JalviewChimeraBindingModel.java
src/jalview/gui/Preferences.java
src/jalview/gui/ScriptWindow.java
src/jalview/gui/SplashScreen.java
src/jalview/gui/StructureViewer.java
src/jalview/gui/StructureViewerBase.java [new file with mode: 0644]
src/jalview/io/FileLoader.java
src/jalview/io/VamsasAppDatastore.java
src/jalview/jbgui/GPreferences.java
src/jalview/jbgui/GStructureViewer.java
src/jalview/structures/models/AAStructureBindingModel.java [new file with mode: 0644]
src/jalview/structures/models/SequenceStructureBindingModel.java
test/jalview/ext/rbvi/chimera/JalviewChimeraView.java
test/jalview/ws/jabaws/JpredJabaStructExportImport.java
test/jalview/ws/jabaws/RNAStructExportImport.java

index b45404e..2c40e1c 100644 (file)
@@ -29,12 +29,6 @@ public class ChimeraManager
 {
   private static final boolean debug = false;
 
-  /*
-   * true: use REST API (recommended), false: use stdout/stdin (deprecated)
-   */
-  // TODO remove once definitely happy with using REST
-  private static final boolean USE_REST = true;
-
   private int chimeraRestPort;
 
   private Process chimera;
@@ -224,10 +218,14 @@ public class ChimeraManager
                     modelNumbers[0], modelNumbers[1]);
             currentModelsMap.put(modelNumber, newModel);
             models.add(newModel);
+
+            //
             // patch for Jalview - set model name in Chimera
+            //
             sendChimeraCommand("setattr M name " + modelName + " #"
                     + modelNumbers[0], false);
             // end patch for Jalview
+
             modelNumbers = null;
           }
         }
@@ -370,15 +368,7 @@ public class ChimeraManager
   {
     chimera = null;
     currentModelsMap.clear();
-    if (USE_REST)
-    {
       this.chimeraRestPort = 0;
-    }
-    else
-    {
-      chimeraListenerThread.requestStop();
-      chimeraListenerThread = null;
-    }
     structureManager.clearOnChimeraExit();
   }
 
@@ -549,13 +539,11 @@ public class ChimeraManager
         List<String> args = new ArrayList<String>();
         args.add(chimeraPath);
         args.add("--start");
-        args.add(USE_REST ? "RESTServer" : "ReadStdin");
+        args.add("RESTServer");
         ProcessBuilder pb = new ProcessBuilder(args);
         chimera = pb.start();
         error = "";
         workingPath = chimeraPath;
-        logger.info("Starting " + chimeraPath + " with "
-                + (USE_REST ? "REST API" : "stdin/stdout"));
         break;
       } catch (Exception e)
       {
@@ -566,18 +554,9 @@ public class ChimeraManager
     // If no error, then Chimera was launched successfully
     if (error.length() == 0)
     {
-      if (USE_REST)
-      {
-        this.chimeraRestPort = getPortNumber();
-        System.out.println("Chimera REST API on port " + chimeraRestPort);
-      }
-      else
-      {
-        // Initialize the listener threads
-        chimeraListenerThread = new ListenerThreads(chimera,
-                structureManager);
-        chimeraListenerThread.start();
-      }
+      this.chimeraRestPort = getPortNumber();
+      System.out.println("Chimera REST API started on port "
+              + chimeraRestPort);
       // structureManager.initChimTable();
       structureManager.setChimeraPathProperty(workingPath);
       // TODO: [Optional] Check Chimera version and show a warning if below 1.8
@@ -766,22 +745,17 @@ public class ChimeraManager
       } catch (InterruptedException q)
       {
       }
-      ;
     }
     busy = true;
     long startTime = System.currentTimeMillis();
     try
     {
-      if (USE_REST)
-      {
-        return sendRestCommand(command);
-      }
-      else
-      {
-        return sendStdinCommand(command, reply);
-      }
+      return sendRestCommand(command);
     } finally
     {
+      /*
+       * Make sure busy flag is reset come what may!
+       */
       busy = false;
       if (debug)
       {
index 32c5bca..d620401 100644 (file)
@@ -32,7 +32,7 @@ public interface SequenceStructureBinding
   /**
    * 
    * @return true if Jalview or the Viewer is still restoring state or loading
-   *         is still going on (see setFinsihedLoadingFromArchive)
+   *         is still going on (see setFinishedLoadingFromArchive)
    */
   void setLoadingFromArchive(boolean loadingFromArchive);
 
index efb60dd..45b074b 100644 (file)
  */
 package jalview.api.structures;
 
-import jalview.api.FeatureRenderer;
-import jalview.api.SequenceRenderer;
-import jalview.api.SequenceStructureBinding;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.SequenceI;
-import jalview.ext.jmol.JalviewJmolBinding;
 import jalview.schemes.ColourSchemeI;
-import jalview.schemes.UserColourScheme;
-import jalview.structure.StructureMappingcommandSet;
-import jalview.structure.StructureSelectionManager;
+import jalview.structures.models.AAStructureBindingModel;
 
 public interface JalviewStructureDisplayI
 {
 
-  SequenceStructureBinding getBinding();
+  AAStructureBindingModel getBinding();
 
   /**
    * @return true if there is an active GUI handling a structure display
index 5421050..1f32da0 100644 (file)
@@ -63,6 +63,7 @@ import jalview.schemes.TaylorColourScheme;
 import jalview.schemes.TurnColourScheme;
 import jalview.schemes.ZappoColourScheme;
 import jalview.structure.StructureSelectionManager;
+import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -3636,7 +3637,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
         return null;
       }
     }
-    ExtJmol jmv = null;
+    AAStructureBindingModel jmv = null;
     // TODO: search for a jmv that involves viewer
     if (jmv == null)
     { // create a new viewer/jalview binding.
index 322a60f..4dcb5d7 100644 (file)
  */
 package jalview.appletgui;
 
-import java.util.*;
-import java.awt.*;
-import java.awt.event.*;
-
-import jalview.api.SequenceStructureBinding;
-import jalview.datamodel.*;
-import jalview.structure.*;
-import jalview.io.*;
-
-import jalview.schemes.*;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.io.AppletFormatAdapter;
+import jalview.io.FileParse;
+import jalview.schemes.BuriedColourScheme;
+import jalview.schemes.HelixColourScheme;
+import jalview.schemes.HydrophobicColourScheme;
+import jalview.schemes.PurinePyrimidineColourScheme;
+import jalview.schemes.StrandColourScheme;
+import jalview.schemes.TaylorColourScheme;
+import jalview.schemes.TurnColourScheme;
+import jalview.schemes.UserColourScheme;
+import jalview.schemes.ZappoColourScheme;
+import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 
+import java.awt.BorderLayout;
+import java.awt.CheckboxMenuItem;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.Rectangle;
+import java.awt.TextArea;
+import java.awt.TextField;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Vector;
+
 public class AppletJmol extends EmbmenuFrame implements
 // StructureListener,
         KeyListener, ActionListener, ItemListener
@@ -398,9 +429,9 @@ public class AppletJmol extends EmbmenuFrame implements
       StringBuffer sb = new StringBuffer();
       try
       {
-        for (int s = 0; s < jmb.pdbentry.length; s++)
+        for (int s = 0; s < jmb.getPdbCount(); s++)
         {
-          sb.append(jmb.printMapping(jmb.pdbentry[s].getFile()));
+          sb.append(jmb.printMapping(jmb.getPdbEntry(s).getFile()));
           sb.append("\n");
         }
         cap.setText(sb.toString());
@@ -488,7 +519,9 @@ public class AppletJmol extends EmbmenuFrame implements
       for (int i = 0; i < chainMenu.getItemCount(); i++)
       {
         if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
+        {
           ((CheckboxMenuItem) chainMenu.getItem(i)).setState(true);
+        }
       }
 
       centerViewer();
@@ -522,7 +555,9 @@ public class AppletJmol extends EmbmenuFrame implements
       jmb.colourBySequence(ap.av.isShowSequenceFeatures(), ap);
     }
     else if (!allChainsSelected)
+    {
       centerViewer();
+    }
   }
 
   public void keyPressed(KeyEvent evt)
index d2a6e6c..ff1f5b2 100644 (file)
@@ -77,7 +77,9 @@ class AppletJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
   public void sendConsoleEcho(String strEcho)
   {
     if (appletJmolBinding.scriptWindow == null)
+    {
       appletJmolBinding.showConsole(true);
+    }
 
     appletJmolBinding.history.append("\n" + strEcho);
   }
@@ -138,10 +140,10 @@ class AppletJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
 
   }
 
+  @Override
   public void refreshPdbEntries()
   {
-    // TODO Auto-generated method stub
-
+    // noop
   }
 
   @Override
@@ -164,20 +166,7 @@ class AppletJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
   protected void releaseUIResources()
   {
     appletJmolBinding = null;
-    if (console != null)
-    {
-      try
-      {
-        console.setVisible(false);
-      } catch (Error e)
-      {
-      } catch (Exception x)
-      {
-      }
-      ;
-      console = null;
-    }
-
+    closeConsole();
   }
 
   @Override
index 1efb971..cb99f87 100644 (file)
  */
 package jalview.appletgui;
 
-import java.awt.Container;
-import java.util.BitSet;
-import java.util.Hashtable;
-import java.util.Vector;
-
-import org.jmol.api.JmolAppConsoleInterface;
-import org.jmol.api.JmolViewer;
-
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
@@ -35,6 +27,15 @@ import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.ext.jmol.JalviewJmolBinding;
 
+import java.awt.Container;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Vector;
+
+import org.jmol.api.JmolAppConsoleInterface;
+import org.jmol.api.JmolViewer;
+
 /**
  * bind an alignment view to an external Jmol instance.
  * 
@@ -57,9 +58,8 @@ public class ExtJmol extends JalviewJmolBinding
   public ExtJmol(JmolViewer viewer, AlignmentPanel alignPanel,
           SequenceI[][] seqs)
   {
-    super(alignPanel.getStructureSelectionManager(), viewer);
+    super(alignPanel.getStructureSelectionManager(), seqs, viewer);
     ap = alignPanel;
-    this.sequence = seqs;
     notifyFileLoaded(null, null, null, null, 0);
   }
 
@@ -125,8 +125,8 @@ public class ExtJmol extends JalviewJmolBinding
 
   public void refreshPdbEntries()
   {
-    Vector pdbe = new Vector();
-    Hashtable fileids = new Hashtable();
+    List<PDBEntry> pdbe = new ArrayList<PDBEntry>();
+    List<String> fileids = new ArrayList<String>();
     SequenceI[] sq = ap.av.getAlignment().getSequencesArray();
     for (int s = 0; s < sq.length; s++)
     {
@@ -136,18 +136,23 @@ public class ExtJmol extends JalviewJmolBinding
         for (int pe = 0, peSize = pdbids.size(); pe < peSize; pe++)
         {
           PDBEntry pentry = (PDBEntry) pdbids.elementAt(pe);
-          if (!fileids.containsKey(pentry.getId()))
+          if (!fileids.contains(pentry.getId()))
           {
-            pdbe.addElement(pentry);
+            pdbe.add(pentry);
+          }
+          else
+          {
+            fileids.add(pentry.getId());
           }
         }
       }
     }
-    pdbentry = new PDBEntry[pdbe.size()];
+    PDBEntry[] newEntries = new PDBEntry[pdbe.size()];
     for (int pe = 0; pe < pdbe.size(); pe++)
     {
-      pdbentry[pe] = (PDBEntry) pdbe.elementAt(pe);
+      newEntries[pe] = pdbe.get(pe);
     }
+    setPdbentry(newEntries);
   }
 
   @Override
@@ -172,19 +177,7 @@ public class ExtJmol extends JalviewJmolBinding
   protected void releaseUIResources()
   {
     ap = null;
-    if (console != null)
-    {
-      try
-      {
-        console.setVisible(false);
-      } catch (Error e)
-      {
-      } catch (Exception x)
-      {
-      }
-      ;
-      console = null;
-    }
+    closeConsole();
 
   }
 
index ee2b549..1cf9cd7 100755 (executable)
@@ -20,7 +20,7 @@
  */
 package jalview.datamodel;
 
-import java.util.*;
+import java.util.Hashtable;
 
 public class PDBEntry
 {
@@ -37,6 +37,7 @@ public class PDBEntry
    * 
    * @see java.lang.Object#equals(java.lang.Object)
    */
+  @Override
   public boolean equals(Object obj)
   {
     if (obj == null || !(obj instanceof PDBEntry))
@@ -44,7 +45,9 @@ public class PDBEntry
       return false;
     }
     if (obj == this)
+    {
       return true;
+    }
     PDBEntry o = (PDBEntry) obj;
     return (file == o.file || (file != null && o.file != null && o.file
             .equals(file)))
@@ -57,10 +60,29 @@ public class PDBEntry
                       .equals(o.properties)));
   }
 
+  /**
+   * Default constructor
+   */
   public PDBEntry()
   {
   }
 
+  /**
+   * Constructor given file path and PDB id.
+   * 
+   * @param filePath
+   */
+  public PDBEntry(String filePath, String pdbId)
+  {
+    this.file = filePath;
+    this.id = pdbId;
+  }
+  
+  /**
+   * Copy constructor.
+   * 
+   * @param entry
+   */
   public PDBEntry(PDBEntry entry)
   {
     file = entry.file;
diff --git a/src/jalview/datamodel/ViewerData.java b/src/jalview/datamodel/ViewerData.java
new file mode 100644 (file)
index 0000000..0b6b8d1
--- /dev/null
@@ -0,0 +1,189 @@
+package jalview.datamodel;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A data bean to hold stored data about a structure viewer.
+ */
+public class ViewerData
+{
+  private int x;
+
+  private int y;
+
+  private int width;
+
+  private int height;
+
+  private boolean alignWithPanel;
+
+  private boolean colourWithAlignPanel;
+
+  private boolean colourByViewer;
+
+  private String stateData = "";
+
+  private Map<File, StructureData> fileData = new HashMap<File, StructureData>();
+
+  public class StructureData
+  {
+    private String filePath;
+
+    private String pdbId;
+
+    private List<SequenceI> seqList;
+
+    // TODO and possibly a list of chains?
+
+    /**
+     * Constructor given structure file path and id.
+     * 
+     * @param pdbFile
+     * @param id
+     */
+    public StructureData(String pdbFile, String id)
+    {
+      this.filePath = pdbFile;
+      this.pdbId = id;
+      this.seqList = new ArrayList<SequenceI>();
+    }
+
+    public String getFilePath()
+    {
+      return filePath;
+    }
+
+    protected void setFilePath(String filePath)
+    {
+      this.filePath = filePath;
+    }
+
+    public String getPdbId()
+    {
+      return pdbId;
+    }
+
+    protected void setPdbId(String pdbId)
+    {
+      this.pdbId = pdbId;
+    }
+
+    public List<SequenceI> getSeqList()
+    {
+      return seqList;
+    }
+
+    protected void setSeqList(List<SequenceI> seqList)
+    {
+      this.seqList = seqList;
+    }
+  }
+
+  public ViewerData(int x, int y, int width, int height,
+          boolean alignWithPanel, boolean colourWithAlignPanel,
+          boolean colourByViewer)
+  {
+    this.x = x;
+    this.y = y;
+    this.width = width;
+    this.height = height;
+    this.alignWithPanel = alignWithPanel;
+    this.colourWithAlignPanel = colourWithAlignPanel;
+    this.colourByViewer = colourByViewer;
+  }
+
+  public int getX()
+  {
+    return x;
+  }
+
+  protected void setX(int x)
+  {
+    this.x = x;
+  }
+
+  public int getY()
+  {
+    return y;
+  }
+
+  protected void setY(int y)
+  {
+    this.y = y;
+  }
+
+  public int getWidth()
+  {
+    return width;
+  }
+
+  protected void setWidth(int width)
+  {
+    this.width = width;
+  }
+
+  public int getHeight()
+  {
+    return height;
+  }
+
+  public void setHeight(int height)
+  {
+    this.height = height;
+  }
+
+  public boolean isAlignWithPanel()
+  {
+    return alignWithPanel;
+  }
+
+  public void setAlignWithPanel(boolean alignWithPanel)
+  {
+    this.alignWithPanel = alignWithPanel;
+  }
+
+  public boolean isColourWithAlignPanel()
+  {
+    return colourWithAlignPanel;
+  }
+
+  public void setColourWithAlignPanel(boolean colourWithAlignPanel)
+  {
+    this.colourWithAlignPanel = colourWithAlignPanel;
+  }
+
+  public boolean isColourByViewer()
+  {
+    return colourByViewer;
+  }
+
+  public void setColourByViewer(boolean colourByViewer)
+  {
+    this.colourByViewer = colourByViewer;
+  }
+
+  public String getStateData()
+  {
+    return stateData;
+  }
+
+  public void setStateData(String stateData)
+  {
+    this.stateData = stateData;
+  }
+
+  public Map<File, StructureData> getFileData()
+  {
+    return fileData;
+  }
+
+  protected void setFileData(Map<File, StructureData> fileData)
+  {
+    this.fileData = fileData;
+  }
+
+}
index 9187912..619144e 100644 (file)
@@ -23,8 +23,6 @@ package jalview.ext.jmol;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
-import jalview.api.SequenceStructureBinding;
-import jalview.api.StructureSelectionManagerProvider;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.PDBEntry;
@@ -32,10 +30,10 @@ import jalview.datamodel.SequenceI;
 import jalview.io.AppletFormatAdapter;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ResidueProperties;
-import jalview.structure.StructureListener;
 import jalview.structure.StructureMapping;
+import jalview.structure.StructureMappingcommandSet;
 import jalview.structure.StructureSelectionManager;
-import jalview.structures.models.SequenceStructureBindingModel;
+import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MessageManager;
 
 import java.awt.Color;
@@ -58,30 +56,18 @@ import org.jmol.api.JmolViewer;
 import org.jmol.constant.EnumCallback;
 import org.jmol.popup.JmolPopup;
 
-public abstract class JalviewJmolBinding extends SequenceStructureBindingModel implements StructureListener,
-        JmolStatusListener, SequenceStructureBinding,
-        JmolSelectionListener, ComponentListener,
-        StructureSelectionManagerProvider
-
+public abstract class JalviewJmolBinding extends AAStructureBindingModel
+        implements JmolStatusListener, JmolSelectionListener,
+        ComponentListener
 {
-  /**
+  /*
    * state flag used to check if the Jmol viewer's paint method can be called
    */
   private boolean finishedInit = false;
 
-  public boolean isFinishedInit()
-  {
-    return finishedInit;
-  }
-
-  public void setFinishedInit(boolean finishedInit)
-  {
-    this.finishedInit = finishedInit;
-  }
-
   boolean allChainsSelected = false;
 
-  /**
+  /*
    * when true, try to search the associated datamodel for sequences that are
    * associated with any unknown structures in the Jmol view.
    */
@@ -93,18 +79,11 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
 
   Hashtable chainFile;
 
-  /**
-   * array of target chains for seuqences - tied to pdbentry and sequence[]
-   */
-  protected String[][] chains;
-
-  boolean colourBySequence = true;
-
   StringBuffer eval = new StringBuffer();
 
   public String fileLoadingError;
 
-  /**
+  /*
    * the default or current model displayed if the model cannot be identified
    * from the selection message
    */
@@ -123,37 +102,15 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
    */
   String[] modelFileNames = null;
 
-  public PDBEntry[] pdbentry;
-
-  /**
-   * datasource protocol for access to PDBEntrylatest
-   */
-  String protocol = null;
-
   StringBuffer resetLastRes = new StringBuffer();
 
-  /**
-   * sequences mapped to each pdbentry
-   */
-  public SequenceI[][] sequence;
-
-  public StructureSelectionManager ssm;
-
   public JmolViewer viewer;
 
   public JalviewJmolBinding(StructureSelectionManager ssm,
           PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
           String protocol)
   {
-    this.ssm = ssm;
-    this.sequence = sequenceIs;
-    this.chains = chains;
-    this.pdbentry = pdbentry;
-    this.protocol = protocol;
-    if (chains == null)
-    {
-      this.chains = new String[pdbentry.length][];
-    }
+    super(ssm, pdbentry, sequenceIs, chains, protocol);
     /*
      * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
      * "jalviewJmol", ap.av.applet .getDocumentBase(),
@@ -164,10 +121,11 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
   }
 
   public JalviewJmolBinding(StructureSelectionManager ssm,
-          JmolViewer viewer2)
+          SequenceI[][] seqs, JmolViewer theViewer)
   {
-    this.ssm = ssm;
-    viewer = viewer2;
+    super(ssm, seqs);
+
+    viewer = theViewer;
     viewer.setJmolStatusListener(this);
     viewer.addSelectionListener(this);
   }
@@ -180,30 +138,7 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
    */
   public String getViewerTitle()
   {
-    if (sequence == null || pdbentry == null || sequence.length < 1
-            || pdbentry.length < 1 || sequence[0].length < 1)
-    {
-      return ("Jalview Jmol Window");
-    }
-    // TODO: give a more informative title when multiple structures are
-    // displayed.
-    StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
-            + pdbentry[0].getId());
-
-    if (pdbentry[0].getProperty() != null)
-    {
-      if (pdbentry[0].getProperty().get("method") != null)
-      {
-        title.append(" Method: ");
-        title.append(pdbentry[0].getProperty().get("method"));
-      }
-      if (pdbentry[0].getProperty().get("chains") != null)
-      {
-        title.append(" Chain:");
-        title.append(pdbentry[0].getProperty().get("chains"));
-      }
-    }
-    return title.toString();
+    return getViewerTitle("JMol", true);
   }
 
   /**
@@ -232,7 +167,9 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
               + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");
     }
     if (cmd.length() > 0)
+    {
       cmd.setLength(cmd.length() - 4);
+    }
     evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
   }
 
@@ -240,7 +177,7 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
   {
     viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
     // remove listeners for all structures in viewer
-    ssm.removeStructureViewerListener(this, this.getPdbFile());
+    getSsm().removeStructureViewerListener(this, this.getPdbFile());
     // and shut down jmol
     viewer.evalStringQuiet("zap");
     viewer.setJmolStatusListener(null);
@@ -249,12 +186,6 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
     releaseUIResources();
   }
 
-  /**
-   * called by JalviewJmolbinding after closeViewer is called - release any
-   * resources and references so they can be garbage collected.
-   */
-  protected abstract void releaseUIResources();
-
   public void colourByChain()
   {
     colourBySequence = false;
@@ -330,7 +261,7 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
         {
           // HACK - in Jalview 2.8 this call may not be threadsafe so we catch
           // every possible exception
-          StructureMapping[] sm = ssm.getMapping(file);
+          StructureMapping[] sm = getSsm().getMapping(file);
           if (sm == null || sm.length == 0)
           {
             waiting = true;
@@ -408,7 +339,7 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
       String[] chainNames = new String[files.length];
       for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
       {
-        StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
+        StructureMapping[] mapping = getSsm().getMapping(files[pdbfnum]);
         // RACE CONDITION - getMapping only returns Jmol loaded filenames once
         // Jmol callback has completed.
         if (mapping == null || mapping.length < 1)
@@ -416,12 +347,13 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
           throw new Error(MessageManager.getString("error.implementation_error_jmol_getting_data"));
         }
         int lastPos = -1;
-        for (int s = 0; s < sequence[pdbfnum].length; s++)
+        final int sequenceCountForPdbFile = getSequence()[pdbfnum].length;
+        for (int s = 0; s < sequenceCountForPdbFile; s++)
         {
           for (int sp, m = 0; m < mapping.length; m++)
           {
-            if (mapping[m].getSequence() == sequence[pdbfnum][s]
-                    && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
+            if (mapping[m].getSequence() == getSequence()[pdbfnum][s]
+                    && (sp = alignment.findIndex(getSequence()[pdbfnum][s])) > -1)
             {
               if (refStructure == -1)
               {
@@ -473,7 +405,7 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
               chainNames[pdbfnum] = mapping[m].getPdbId()
                       + targetC[pdbfnum];
               // move on to next pdb file
-              s = sequence[pdbfnum].length;
+              s = getSequence()[pdbfnum].length;
               break;
             }
           }
@@ -630,8 +562,10 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
           jalview.api.AlignmentViewPanel alignmentv)
   {
     if (!colourBySequence || !isLoadingFinished())
+    {
       return;
-    if (ssm == null)
+    }
+    if (getSsm() == null)
     {
       return;
     }
@@ -646,23 +580,38 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
     }
     AlignmentI alignment = alignmentv.getAlignment();
 
-    for (jalview.structure.StructureMappingcommandSet cpdbbyseq : JmolCommands
-            .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
-                    alignment))
+    for (jalview.structure.StructureMappingcommandSet cpdbbyseq : getColourBySequenceCommands(files, sr, fr, alignment))
+    {
       for (String cbyseq : cpdbbyseq.commands)
       {
-        evalStateCommand(cbyseq);
+        executeWhenReady(cbyseq);
       }
+    }
   }
 
-  public boolean isColourBySequence()
+  /**
+   * @param files
+   * @param sr
+   * @param fr
+   * @param alignment
+   * @return
+   */
+  protected StructureMappingcommandSet[] getColourBySequenceCommands(
+          String[] files, SequenceRenderer sr, FeatureRenderer fr,
+          AlignmentI alignment)
   {
-    return colourBySequence;
+    return JmolCommands
+            .getColourBySequenceCommand(getSsm(), files, getSequence(), sr,
+                    fr,
+                    alignment);
   }
 
-  public void setColourBySequence(boolean colourBySequence)
+  /**
+   * @param command
+   */
+  protected void executeWhenReady(String command)
   {
-    this.colourBySequence = colourBySequence;
+    evalStateCommand(command);
   }
 
   public void createImage(String file, String type, int quality)
@@ -702,7 +651,9 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
           String pdbfile)
   {
     if (getModelNum(pdbfile) < 0)
+    {
       return null;
+    }
     // TODO: verify atomIndex is selecting correct model.
     return new Color(viewer.getAtomArgb(atomIndex));
   }
@@ -735,7 +686,9 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
     for (int i = 0; i < mfn.length; i++)
     {
       if (mfn[i].equalsIgnoreCase(modelFileName))
+      {
         return i;
+      }
     }
     return -1;
   }
@@ -806,7 +759,8 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
   /**
    * map from string to applet
    */
-  public Map getRegistryInfo()
+  @Override
+  public Map<String, Object> getRegistryInfo()
   {
     // TODO Auto-generated method stub
     return null;
@@ -944,8 +898,10 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
     String chainId;
 
     if (strInfo.indexOf(":") > -1)
+    {
       chainId = strInfo.substring(strInfo.indexOf(":") + 1,
               strInfo.indexOf("."));
+    }
     else
     {
       chainId = " ";
@@ -983,7 +939,9 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
       ;
     }
     if (lastMessage == null || !lastMessage.equals(strInfo))
-      ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
+    {
+      getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
+    }
 
     lastMessage = strInfo;
   }
@@ -1017,13 +975,17 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
     int chainSeparator = strInfo.indexOf(":");
     int p = 0;
     if (chainSeparator == -1)
+    {
       chainSeparator = strInfo.indexOf(".");
+    }
 
     String picked = strInfo.substring(strInfo.indexOf("]") + 1,
             chainSeparator);
     String mdlString = "";
     if ((p = strInfo.indexOf(":")) > -1)
+    {
       picked += strInfo.substring(p + 1, strInfo.indexOf("."));
+    }
 
     if ((p = strInfo.indexOf("/")) > -1)
     {
@@ -1195,7 +1157,7 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
         }
         // deregister the Jmol instance for these structures - we'll add
         // ourselves again at the end for the current structure set.
-        ssm.removeStructureViewerListener(this, oldmfn);
+        getSsm().removeStructureViewerListener(this, oldmfn);
       }
     }
     refreshPdbEntries();
@@ -1215,70 +1177,68 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
                 + ".0", "PDB");
         pdbfhash = "" + pdbfile.hashCode();
       }
-      if (pdbentry != null)
-      {
         // search pdbentries and sequences to find correct pdbentry for this
         // model
-        for (int pe = 0; pe < pdbentry.length; pe++)
+      for (int pe = 0; pe < getPdbCount(); pe++)
+      {
+        boolean matches = false;
+        if (fileName == null)
         {
-          boolean matches = false;
-          if (fileName == null)
+          if (false)
+          // see JAL-623 - need method of matching pasted data up
           {
-            if (false)
-            // see JAL-623 - need method of matching pasted data up
-            {
-              pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,
-                      AppletFormatAdapter.PASTE);
-              pdbentry[modelnum].setFile("INLINE" + pdb.id);
-              matches = true;
-              foundEntry = true;
-            }
+            pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
+                    pdbfile, AppletFormatAdapter.PASTE);
+            getPdbEntry(modelnum).setFile("INLINE" + pdb.id);
+            matches = true;
+            foundEntry = true;
           }
-          else
+        }
+        else
+        {
+          File fl;
+          if (matches = (fl = new File(getPdbEntry(pe).getFile()))
+                  .equals(new File(fileName)))
           {
-            File fl;
-            if (matches = (fl = new File(pdbentry[pe].getFile()))
-                    .equals(new File(fileName)))
+            foundEntry = true;
+            // TODO: Jmol can in principle retrieve from CLASSLOADER but
+            // this
+            // needs
+            // to be tested. See mantis bug
+            // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
+            String protocol = AppletFormatAdapter.URL;
+            try
             {
-              foundEntry = true;
-              // TODO: Jmol can in principle retrieve from CLASSLOADER but
-              // this
-              // needs
-              // to be tested. See mantis bug
-              // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
-              String protocol = AppletFormatAdapter.URL;
-              try
-              {
-                if (fl.exists())
-                {
-                  protocol = AppletFormatAdapter.FILE;
-                }
-              } catch (Exception e)
-              {
-              } catch (Error e)
+              if (fl.exists())
               {
+                protocol = AppletFormatAdapter.FILE;
               }
-              // Explicitly map to the filename used by Jmol ;
-              pdb = ssm.setMapping(sequence[pe], chains[pe], fileName,
-                      protocol);
-              // pdbentry[pe].getFile(), protocol);
-
+            } catch (Exception e)
+            {
+            } catch (Error e)
+            {
             }
+            // Explicitly map to the filename used by Jmol ;
+            pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
+                    fileName, protocol);
+            // pdbentry[pe].getFile(), protocol);
+
           }
-          if (matches)
+        }
+        if (matches)
+        {
+          // add an entry for every chain in the model
+          for (int i = 0; i < pdb.chains.size(); i++)
           {
-            // add an entry for every chain in the model
-            for (int i = 0; i < pdb.chains.size(); i++)
-            {
-              String chid = new String(pdb.id + ":"
-                      + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);
-              chainFile.put(chid, fileName);
-              chainNames.addElement(chid);
-            }
-            notifyLoaded = true;
+            String chid = new String(pdb.id + ":"
+                    + pdb.chains.elementAt(i).id);
+            chainFile.put(chid, fileName);
+            chainNames.addElement(chid);
           }
+          notifyLoaded = true;
         }
       }
+
       if (!foundEntry && associateNewStructs)
       {
         // this is a foreign pdb file that jalview doesn't know about - add
@@ -1307,7 +1267,7 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
     }
     // register ourselves as a listener and notify the gui that it needs to
     // update itself.
-    ssm.addStructureViewerListener(this);
+    getSsm().addStructureViewerListener(this);
     if (notifyLoaded)
     {
       FeatureRenderer fr = getFeatureRenderer(null);
@@ -1364,7 +1324,9 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
     colourBySequence = false;
 
     if (cs == null)
+    {
       return;
+    }
 
     String res;
     int index;
@@ -1378,7 +1340,9 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
       res = en.nextElement().toString();
       index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
       if (index > 20)
+      {
         continue;
+      }
 
       col = cs.findColour(ResidueProperties.aa[index].charAt(0));
 
@@ -1477,185 +1441,93 @@ public abstract class JalviewJmolBinding extends SequenceStructureBindingModel i
 
   protected org.jmol.api.JmolAppConsoleInterface console = null;
 
-  public void componentResized(ComponentEvent e)
+  public void setBackgroundColour(java.awt.Color col)
   {
-
+    jmolHistory(false);
+    viewer.evalStringQuiet("background [" + col.getRed() + ","
+            + col.getGreen() + "," + col.getBlue() + "];");
+    jmolHistory(true);
   }
 
-  public void componentMoved(ComponentEvent e)
+  /**
+   * 
+   * @param pdbfile
+   * @return text report of alignment between pdbfile and any associated
+   *         alignment sequences
+   */
+  public String printMapping(String pdbfile)
   {
-
+    return getSsm().printMapping(pdbfile);
   }
 
-  public void componentShown(ComponentEvent e)
+  @Override
+  public void resizeInnerPanel(String data)
   {
-    showConsole(true);
+    // Jalview doesn't honour resize panel requests
+
   }
 
-  public void componentHidden(ComponentEvent e)
+  public boolean isFinishedInit()
   {
-    showConsole(false);
+    return finishedInit;
   }
 
-  public void setBackgroundColour(java.awt.Color col)
+  public void setFinishedInit(boolean finishedInit)
   {
-    jmolHistory(false);
-    viewer.evalStringQuiet("background [" + col.getRed() + ","
-            + col.getGreen() + "," + col.getBlue() + "];");
-    jmolHistory(true);
+    this.finishedInit = finishedInit;
   }
 
   /**
-   * add structures and any known sequence associations
    * 
-   * @returns the pdb entries added to the current set.
    */
-  public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
-          SequenceI[][] seq, String[][] chns)
+  protected void closeConsole()
   {
-    int pe = -1;
-    Vector v = new Vector();
-    Vector rtn = new Vector();
-    for (int i = 0; i < pdbentry.length; i++)
-    {
-      v.addElement(pdbentry[i]);
-    }
-    for (int i = 0; i < pdbe.length; i++)
+    if (console != null)
     {
-      int r = v.indexOf(pdbe[i]);
-      if (r == -1 || r >= pdbentry.length)
+      try
       {
-        rtn.addElement(new int[]
-        { v.size(), i });
-        v.addElement(pdbe[i]);
-      }
-      else
+        console.setVisible(false);
+      } catch (Error e)
       {
-        // just make sure the sequence/chain entries are all up to date
-        addSequenceAndChain(r, seq[i], chns[i]);
-      }
-    }
-    pdbe = new PDBEntry[v.size()];
-    v.copyInto(pdbe);
-    pdbentry = pdbe;
-    if (rtn.size() > 0)
-    {
-      // expand the tied seuqence[] and string[] arrays
-      SequenceI[][] sqs = new SequenceI[pdbentry.length][];
-      String[][] sch = new String[pdbentry.length][];
-      System.arraycopy(sequence, 0, sqs, 0, sequence.length);
-      System.arraycopy(chains, 0, sch, 0, this.chains.length);
-      sequence = sqs;
-      chains = sch;
-      pdbe = new PDBEntry[rtn.size()];
-      for (int r = 0; r < pdbe.length; r++)
+      } catch (Exception x)
       {
-        int[] stri = ((int[]) rtn.elementAt(r));
-        // record the pdb file as a new addition
-        pdbe[r] = pdbentry[stri[0]];
-        // and add the new sequence/chain entries
-        addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
       }
+      ;
+      console = null;
     }
-    else
-    {
-      pdbe = null;
-    }
-    return pdbe;
   }
 
-  public void addSequence(int pe, SequenceI[] seq)
+  /**
+   * ComponentListener method
+   */
+  @Override
+  public void componentMoved(ComponentEvent e)
   {
-    // add sequences to the pe'th pdbentry's seuqence set.
-    addSequenceAndChain(pe, seq, null);
   }
 
-  private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
+  /**
+   * ComponentListener method
+   */
+  @Override
+  public void componentResized(ComponentEvent e)
   {
-    if (pe < 0 || pe >= pdbentry.length)
-    {
-      throw new Error(MessageManager.formatMessage("error.implementation_error_no_pdbentry_from_index", new String[]{Integer.valueOf(pe).toString()}));
-    }
-    final String nullChain = "TheNullChain";
-    Vector s = new Vector();
-    Vector c = new Vector();
-    if (chains == null)
-    {
-      chains = new String[pdbentry.length][];
-    }
-    if (sequence[pe] != null)
-    {
-      for (int i = 0; i < sequence[pe].length; i++)
-      {
-        s.addElement(sequence[pe][i]);
-        if (chains[pe] != null)
-        {
-          if (i < chains[pe].length)
-          {
-            c.addElement(chains[pe][i]);
-          }
-          else
-          {
-            c.addElement(nullChain);
-          }
-        }
-        else
-        {
-          if (tchain != null && tchain.length > 0)
-          {
-            c.addElement(nullChain);
-          }
-        }
-      }
-    }
-    for (int i = 0; i < seq.length; i++)
-    {
-      if (!s.contains(seq[i]))
-      {
-        s.addElement(seq[i]);
-        if (tchain != null && i < tchain.length)
-        {
-          c.addElement(tchain[i] == null ? nullChain : tchain[i]);
-        }
-      }
-    }
-    SequenceI[] tmp = new SequenceI[s.size()];
-    s.copyInto(tmp);
-    sequence[pe] = tmp;
-    if (c.size() > 0)
-    {
-      String[] tch = new String[c.size()];
-      c.copyInto(tch);
-      for (int i = 0; i < tch.length; i++)
-      {
-        if (tch[i] == nullChain)
-        {
-          tch[i] = null;
-        }
-      }
-      chains[pe] = tch;
-    }
-    else
-    {
-      chains[pe] = null;
-    }
   }
 
   /**
-   * 
-   * @param pdbfile
-   * @return text report of alignment between pdbfile and any associated
-   *         alignment sequences
+   * ComponentListener method
    */
-  public String printMapping(String pdbfile)
+  @Override
+  public void componentShown(ComponentEvent e)
   {
-    return ssm.printMapping(pdbfile);
+    showConsole(true);
   }
 
+  /**
+   * ComponentListener method
+   */
   @Override
-  public void resizeInnerPanel(String data)
+  public void componentHidden(ComponentEvent e)
   {
-    // Jalview doesn't honour resize panel requests
-
+    showConsole(false);
   }
 }
index b5bfbaa..b345c5e 100644 (file)
@@ -23,24 +23,21 @@ package jalview.ext.rbvi.chimera;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
-import jalview.api.SequenceStructureBinding;
-import jalview.api.StructureSelectionManagerProvider;
+import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
-import jalview.io.AppletFormatAdapter;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ResidueProperties;
-import jalview.structure.StructureListener;
 import jalview.structure.StructureMapping;
+import jalview.structure.StructureMappingcommandSet;
 import jalview.structure.StructureSelectionManager;
-import jalview.structures.models.SequenceStructureBindingModel;
+import jalview.structures.models.AAStructureBindingModel;
+import jalview.util.Comparison;
 import jalview.util.MessageManager;
 
 import java.awt.Color;
-import java.awt.event.ComponentEvent;
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -53,10 +50,7 @@ import ext.edu.ucsf.rbvi.strucviz2.ChimeraModel;
 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
 import ext.edu.ucsf.rbvi.strucviz2.StructureManager.ModelType;
 
-public abstract class JalviewChimeraBinding extends
-        SequenceStructureBindingModel implements StructureListener,
-        SequenceStructureBinding, StructureSelectionManagerProvider
-
+public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 {
 
   private static final boolean debug = false;
@@ -69,130 +63,106 @@ public abstract class JalviewChimeraBinding extends
 
   private ChimeraManager viewer;
 
-  /**
+  /*
    * set if chimera state is being restored from some source - instructs binding
    * not to apply default display style when structure set is updated for first
    * time.
    */
   private boolean loadingFromArchive = false;
 
-  /**
-   * second flag to indicate if the Chimera viewer should ignore sequence
-   * colouring events from the structure manager because the GUI is still
-   * setting up
+  /*
+   * flag to indicate if the Chimera viewer should ignore sequence colouring
+   * events from the structure manager because the GUI is still setting up
    */
   private boolean loadingFinished = true;
 
-  /**
+  /*
    * state flag used to check if the Chimera viewer's paint method can be called
    */
   private boolean finishedInit = false;
 
-  public boolean isFinishedInit()
-  {
-    return finishedInit;
-  }
-
-  public void setFinishedInit(boolean finishedInit)
-  {
-    this.finishedInit = finishedInit;
-  }
+  private List<String> atomsPicked = new ArrayList<String>();
 
-  boolean allChainsSelected = false;
-
-  /**
-   * when true, try to search the associated datamodel for sequences that are
-   * associated with any unknown structures in the Chimera view.
-   */
-  private boolean associateNewStructs = false;
-
-  List<String> atomsPicked = new ArrayList<String>();
-
-  public List<String> chainNames;
+  private List<String> chainNames;
 
   private Map<String, String> chainFile;
 
-  /**
-   * array of target chains for sequences - tied to pdbentry and sequence[]
-   */
-  protected String[][] chains;
-
-  boolean colourBySequence = true;
-
-  StringBuffer eval = new StringBuffer();
+  private StringBuffer eval = new StringBuffer();
 
   public String fileLoadingError;
 
-  private Map<String, List<ChimeraModel>> chimmaps = new LinkedHashMap<String, List<ChimeraModel>>();
-
-  private List<String> mdlToFile = new ArrayList<String>();
+  /*
+   * Map of ChimeraModel objects keyed by PDB full local file name
+   */
+  private Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<String, List<ChimeraModel>>();
 
-  /**
+  /*
    * the default or current model displayed if the model cannot be identified
    * from the selection message
    */
-  int frameNo = 0;
+  private int frameNo = 0;
 
-  String lastCommand;
+  private String lastCommand;
 
-  String lastMessage;
+  private String lastMessage;
 
-  boolean loadedInline;
+  private boolean loadedInline;
 
+  /**
+   * Open a PDB structure file in Chimera and set up mappings from Jalview.
+   * 
+   * We check if the PDB model id is already loaded in Chimera, if so don't
+   * reopen it. This is the case if Chimera has opened a saved session file.
+   * 
+   * @param pe
+   * @return
+   */
   public boolean openFile(PDBEntry pe)
   {
     String file = pe.getFile();
     try
     {
+      List<ChimeraModel> modelsToMap = new ArrayList<ChimeraModel>();
       List<ChimeraModel> oldList = viewer.getModelList();
-      viewer.openModel(file, pe.getId(), ModelType.PDB_MODEL);
-      List<ChimeraModel> newList = viewer.getModelList();
-      if (oldList.size() < newList.size())
+      boolean alreadyOpen = false;
+
+      /*
+       * If Chimera already has this model, don't reopen it, but do remap it.
+       */
+      for (ChimeraModel open : oldList)
       {
-        while (oldList.size() > 0)
+        if (open.getModelName().equals(pe.getId()))
         {
-          oldList.remove(0);
-          newList.remove(0);
-        }
-        chimmaps.put(file, newList);
-        for (ChimeraModel cm : newList)
-        {
-          while (mdlToFile.size() < 1 + cm.getModelNumber())
-          {
-            mdlToFile.add(new String(""));
-          }
-          mdlToFile.set(cm.getModelNumber(), file);
+          alreadyOpen = true;
+          modelsToMap.add(open);
         }
+      }
 
-        File fl = new File(file);
-        String protocol = AppletFormatAdapter.URL;
-        try
-        {
-          if (fl.exists())
-          {
-            protocol = AppletFormatAdapter.FILE;
-          }
-        } catch (Exception e)
-        {
-        } catch (Error e)
-        {
-        }
-        // Explicitly map to the filename used by Chimera ;
-        // pdbentry[pe].getFile(), protocol);
+      /*
+       * If Chimera doesn't yet have this model, ask it to open it, and retrieve
+       * the model names added by Chimera.
+       */
+      if (!alreadyOpen)
+      {
+        viewer.openModel(file, pe.getId(), ModelType.PDB_MODEL);
+        modelsToMap = viewer.getModelList();
+        modelsToMap.removeAll(oldList);
+      }
+
+      chimeraMaps.put(file, modelsToMap);
 
-        if (ssm != null)
+      if (getSsm() != null)
+      {
+        getSsm().addStructureViewerListener(this);
+        // ssm.addSelectionListener(this);
+        FeatureRenderer fr = getFeatureRenderer(null);
+        if (fr != null)
         {
-          ssm.addStructureViewerListener(this);
-          // ssm.addSelectionListener(this);
-          FeatureRenderer fr = getFeatureRenderer(null);
-          if (fr != null)
-          {
-            fr.featuresAdded();
-          }
-          refreshGUI();
+          fr.featuresAdded();
         }
-        return true;
+        refreshGUI();
       }
+      return true;
     } catch (Exception q)
     {
       log("Exception when trying to open model " + file + "\n"
@@ -207,46 +177,40 @@ public abstract class JalviewChimeraBinding extends
    */
   String[] modelFileNames = null;
 
-  public PDBEntry[] pdbentry;
-
-  /**
-   * datasource protocol for access to PDBEntrylatest
-   */
-  String protocol = null;
 
   StringBuffer resetLastRes = new StringBuffer();
 
-  /**
-   * sequences mapped to each pdbentry
-   */
-  public SequenceI[][] sequence;
-
-  public StructureSelectionManager ssm;
-
   private List<String> lastReply;
 
+  /**
+   * Constructor
+   * 
+   * @param ssm
+   * @param pdbentry
+   * @param sequenceIs
+   * @param chains
+   * @param protocol
+   */
   public JalviewChimeraBinding(StructureSelectionManager ssm,
           PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
           String protocol)
   {
-    this.ssm = ssm;
-    this.sequence = sequenceIs;
-    this.chains = chains;
-    this.pdbentry = pdbentry;
-    this.protocol = protocol;
-    if (chains == null)
-    {
-      this.chains = new String[pdbentry.length][];
-    }
+    super(ssm, pdbentry, sequenceIs, chains, protocol);
     viewer = new ChimeraManager(
             csm = new ext.edu.ucsf.rbvi.strucviz2.StructureManager(true));
   }
 
+  /**
+   * Constructor
+   * 
+   * @param ssm
+   * @param theViewer
+   */
   public JalviewChimeraBinding(StructureSelectionManager ssm,
-          ChimeraManager viewer2)
+          ChimeraManager theViewer)
   {
-    this.ssm = ssm;
-    viewer = viewer2;
+    super(ssm, null);
+    viewer = theViewer;
     csm = viewer.getStructureManager();
   }
 
@@ -259,34 +223,7 @@ public abstract class JalviewChimeraBinding extends
    */
   public String getViewerTitle(boolean verbose)
   {
-    if (sequence == null || pdbentry == null || sequence.length < 1
-            || pdbentry.length < 1 || sequence[0].length < 1)
-    {
-      return ("Jalview Chimera Window");
-    }
-    // TODO: give a more informative title when multiple structures are
-    // displayed.
-    StringBuilder title = new StringBuilder(64);
-    title.append("Chimera view for " + sequence[0][0].getName() + ":"
-            + pdbentry[0].getId());
-
-    if (verbose)
-    {
-      if (pdbentry[0].getProperty() != null)
-      {
-        if (pdbentry[0].getProperty().get("method") != null)
-        {
-          title.append(" Method: ");
-          title.append(pdbentry[0].getProperty().get("method"));
-        }
-        if (pdbentry[0].getProperty().get("chains") != null)
-        {
-          title.append(" Chain:");
-          title.append(pdbentry[0].getProperty().get("chains"));
-        }
-      }
-    }
-    return title.toString();
+    return getViewerTitle("Chimera", verbose);
   }
 
   /**
@@ -322,12 +259,12 @@ public abstract class JalviewChimeraBinding extends
   }
 
   /**
-   * Close down the Jalview viewer, and (optionally) the associate Chimera
+   * Close down the Jalview viewer, and (optionally) the associated Chimera
    * window.
    */
   public void closeViewer(boolean closeChimera)
   {
-    ssm.removeStructureViewerListener(this, this.getPdbFile());
+    getSsm().removeStructureViewerListener(this, this.getPdbFile());
     if (closeChimera)
     {
       viewer.exitChimera();
@@ -337,12 +274,6 @@ public abstract class JalviewChimeraBinding extends
     releaseUIResources();
   }
 
-  /**
-   * called by JalviewChimerabinding after closeViewer is called - release any
-   * resources and references so they can be garbage collected.
-   */
-  protected abstract void releaseUIResources();
-
   public void colourByChain()
   {
     colourBySequence = false;
@@ -416,7 +347,7 @@ public abstract class JalviewChimeraBinding extends
         {
           // HACK - in Jalview 2.8 this call may not be threadsafe so we catch
           // every possible exception
-          StructureMapping[] sm = ssm.getMapping(file);
+          StructureMapping[] sm = getSsm().getMapping(file);
           if (sm == null || sm.length == 0)
           {
             waiting = true;
@@ -478,7 +409,7 @@ public abstract class JalviewChimeraBinding extends
       String[] atomSpec = new String[files.length];
       for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
       {
-        StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
+        StructureMapping[] mapping = getSsm().getMapping(files[pdbfnum]);
         // RACE CONDITION - getMapping only returns Jmol loaded filenames once
         // Jmol callback has completed.
         if (mapping == null || mapping.length < 1)
@@ -486,12 +417,14 @@ public abstract class JalviewChimeraBinding extends
           throw new Error(MessageManager.getString("error.implementation_error_chimera_getting_data"));
         }
         int lastPos = -1;
-        for (int s = 0; s < sequence[pdbfnum].length; s++)
+        final int seqCountForPdbFile = getSequence()[pdbfnum].length;
+        for (int s = 0; s < seqCountForPdbFile; s++)
         {
           for (int sp, m = 0; m < mapping.length; m++)
           {
-            if (mapping[m].getSequence() == sequence[pdbfnum][s]
-                    && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
+            final SequenceI theSequence = getSequence()[pdbfnum][s];
+            if (mapping[m].getSequence() == theSequence
+                    && (sp = alignment.findIndex(theSequence)) > -1)
             {
               if (refStructure == -1)
               {
@@ -510,7 +443,7 @@ public abstract class JalviewChimeraBinding extends
                   continue;
                 }
 
-                if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
+                if (Comparison.isGap(asp.getCharAt(r)))
                 {
                   // no mapping to gaps in sequence
                   continue;
@@ -544,7 +477,7 @@ public abstract class JalviewChimeraBinding extends
                       + targetC[pdbfnum];
               atomSpec[pdbfnum] = asp.getRNA() != null ? PHOSPHORUS : ALPHACARBON;
               // move on to next pdb file
-              s = sequence[pdbfnum].length;
+              s = seqCountForPdbFile;
               break;
             }
           }
@@ -690,7 +623,7 @@ public abstract class JalviewChimeraBinding extends
   {
     if (!viewer.isChimeraLaunched())
     {
-      viewer.launchChimera(csm.getChimeraPaths());
+      viewer.launchChimera(StructureManager.getChimeraPaths());
     }
     if (!viewer.isChimeraLaunched())
     {
@@ -710,7 +643,8 @@ public abstract class JalviewChimeraBinding extends
   }
 
   /**
-   * Send a command to Chimera, and optionally log any responses.
+   * Send a command to Chimera, launching it first if necessary, and optionally
+   * log any responses.
    * 
    * @param command
    * @param logResponse
@@ -721,28 +655,12 @@ public abstract class JalviewChimeraBinding extends
     checkLaunched();
     if (lastCommand == null || !lastCommand.equals(command))
     {
-//      Thread t = new Thread(new Runnable()
-//      {
-//        @Override
-//        public void run()
-//        {
       // trim command or it may never find a match in the replyLog!!
       lastReply = viewer.sendChimeraCommand(command.trim(), logResponse);
       if (debug && logResponse)
-          {
-            log("Response from command ('" + command + "') was:\n"
-                    + lastReply);
-          }
-//        }
-//      });
-      // TODO - use j7/8 thread management
-//      try
-//      {
-//        t.join();
-//      } catch (InterruptedException foo)
-//      {
-//      }
-//      ;
+      {
+        log("Response from command ('" + command + "') was:\n" + lastReply);
+      }
     }
     viewerCommandHistory(true);
     lastCommand = command;
@@ -760,7 +678,7 @@ public abstract class JalviewChimeraBinding extends
     {
       return;
     }
-    if (ssm == null)
+    if (getSsm() == null)
     {
       return;
     }
@@ -775,19 +693,42 @@ public abstract class JalviewChimeraBinding extends
     }
     AlignmentI alignment = alignmentv.getAlignment();
 
-    for (jalview.structure.StructureMappingcommandSet cpdbbyseq : ChimeraCommands
-            .getColourBySequenceCommand(ssm, files, sequence, sr, fr,
-                    alignment))
+    for (jalview.structure.StructureMappingcommandSet cpdbbyseq : getColourBySequenceCommands(files, sr, fr, alignment))
     {
-      for (String cbyseq : cpdbbyseq.commands)
+      for (String command : cpdbbyseq.commands)
       {
-        waitForChimera();
-        evalStateCommand(cbyseq, false);
-        waitForChimera();
+        executeWhenReady(command);
       }
     }
   }
 
+  /**
+   * @param files
+   * @param sr
+   * @param fr
+   * @param alignment
+   * @return
+   */
+  protected StructureMappingcommandSet[] getColourBySequenceCommands(
+          String[] files, SequenceRenderer sr, FeatureRenderer fr,
+          AlignmentI alignment)
+  {
+    return ChimeraCommands
+            .getColourBySequenceCommand(getSsm(), files, getSequence(), sr,
+                    fr,
+                    alignment);
+  }
+
+  /**
+   * @param command
+   */
+  protected void executeWhenReady(String command)
+  {
+    waitForChimera();
+    evalStateCommand(command, false);
+    waitForChimera();
+  }
+
   private void waitForChimera()
   {
     while (viewer != null && viewer.isBusy())
@@ -799,30 +740,11 @@ public abstract class JalviewChimeraBinding extends
     }
   }
 
-  public boolean isColourBySequence()
-  {
-    return colourBySequence;
-  }
-
-  public void setColourBySequence(boolean colourBySequence)
-  {
-    this.colourBySequence = colourBySequence;
-  }
+  
 
   // End StructureListener
   // //////////////////////////
 
-  public float[][] functionXY(String functionName, int x, int y)
-  {
-    return null;
-  }
-
-  public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
   public Color getColour(int atomIndex, int pdbResNum, String chain,
           String pdbfile)
   {
@@ -897,8 +819,8 @@ public abstract class JalviewChimeraBinding extends
     // // System.arraycopy(mset, 0, modelFileNames, 0, j);
     // }
 
-    return chimmaps.keySet().toArray(
-            modelFileNames = new String[chimmaps.size()]);
+    return chimeraMaps.keySet().toArray(
+            modelFileNames = new String[chimeraMaps.size()]);
   }
 
   /**
@@ -925,7 +847,7 @@ public abstract class JalviewChimeraBinding extends
   public void highlightAtom(int atomIndex, int pdbResNum, String chain,
           String pdbfile)
   {
-    List<ChimeraModel> cms = chimmaps.get(pdbfile);
+    List<ChimeraModel> cms = chimeraMaps.get(pdbfile);
     if (cms != null)
     {
       int mdlNum = cms.get(0).getModelNumber();
@@ -1063,7 +985,7 @@ public abstract class JalviewChimeraBinding extends
     }
     if (lastMessage == null || !lastMessage.equals(strInfo))
     {
-      ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
+      getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
     }
 
     lastMessage = strInfo;
@@ -1188,13 +1110,13 @@ public abstract class JalviewChimeraBinding extends
         }
         // deregister the Jmol instance for these structures - we'll add
         // ourselves again at the end for the current structure set.
-        ssm.removeStructureViewerListener(this, oldmfn);
+        getSsm().removeStructureViewerListener(this, oldmfn);
       }
     }
 
     // register ourselves as a listener and notify the gui that it needs to
     // update itself.
-    ssm.addStructureViewerListener(this);
+    getSsm().addStructureViewerListener(this);
 
     if (notifyLoaded)
     {
@@ -1254,24 +1176,6 @@ public abstract class JalviewChimeraBinding extends
    */
   public abstract void refreshGUI();
 
-  public void componentResized(ComponentEvent e)
-  {
-
-  }
-
-  public void componentMoved(ComponentEvent e)
-  {
-
-  }
-
-  public void componentShown(ComponentEvent e)
-  {
-  }
-
-  public void componentHidden(ComponentEvent e)
-  {
-  }
-
   public void setLoadingFromArchive(boolean loadingFromArchive)
   {
     this.loadingFromArchive = loadingFromArchive;
@@ -1318,154 +1222,69 @@ public abstract class JalviewChimeraBinding extends
   }
 
   /**
-   * add structures and any known sequence associations
    * 
-   * @returns the pdb entries added to the current set.
+   * @param pdbfile
+   * @return text report of alignment between pdbfile and any associated
+   *         alignment sequences
    */
-  public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
-          SequenceI[][] seq, String[][] chns)
+  public String printMapping(String pdbfile)
   {
-    List<PDBEntry> v = new ArrayList<PDBEntry>();
-    List<int[]> rtn = new ArrayList<int[]>();
-    for (int i = 0; i < pdbentry.length; i++)
-    {
-      v.add(pdbentry[i]);
-    }
-    for (int i = 0; i < pdbe.length; i++)
+    return getSsm().printMapping(pdbfile);
+  }
+
+  /**
+   * Ask Chimera to save its session to the given file. Returns true if
+   * successful, else false.
+   * 
+   * @param filepath
+   * @return
+   */
+  public boolean saveSession(String filepath)
+  {
+    if (isChimeraRunning())
     {
-      int r = v.indexOf(pdbe[i]);
-      if (r == -1 || r >= pdbentry.length)
+      List<String> reply = viewer.sendChimeraCommand("save " + filepath,
+              true);
+      if (reply.contains("Session written"))
       {
-        rtn.add(new int[]
-        { v.size(), i });
-        v.add(pdbe[i]);
+        return true;
       }
       else
       {
-        // just make sure the sequence/chain entries are all up to date
-        addSequenceAndChain(r, seq[i], chns[i]);
-      }
-    }
-    pdbe = v.toArray(new PDBEntry[v.size()]);
-    pdbentry = pdbe;
-    if (rtn.size() > 0)
-    {
-      // expand the tied sequence[] and string[] arrays
-      SequenceI[][] sqs = new SequenceI[pdbentry.length][];
-      String[][] sch = new String[pdbentry.length][];
-      System.arraycopy(sequence, 0, sqs, 0, sequence.length);
-      System.arraycopy(chains, 0, sch, 0, this.chains.length);
-      sequence = sqs;
-      chains = sch;
-      pdbe = new PDBEntry[rtn.size()];
-      for (int r = 0; r < pdbe.length; r++)
-      {
-        int[] stri = (rtn.get(r));
-        // record the pdb file as a new addition
-        pdbe[r] = pdbentry[stri[0]];
-        // and add the new sequence/chain entries
-        addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
+        Cache.log
+                .error("Error saving Chimera session: " + reply.toString());
       }
     }
-    else
-    {
-      pdbe = null;
-    }
-    return pdbe;
+    return false;
   }
 
   /**
-   * Adds sequences to the pe'th pdbentry's sequence set.
+   * Ask Chimera to open a session file. Returns true if successful, else false.
+   * The filename must have a .py extension for this command to work.
    * 
-   * @param pe
-   * @param seq
+   * @param filepath
+   * @return
    */
-  public void addSequence(int pe, SequenceI[] seq)
+  public boolean openSession(String filepath)
   {
-    addSequenceAndChain(pe, seq, null);
+    evalStateCommand("open " + filepath, true);
+    // todo: test for failure - how?
+    return true;
   }
 
-  private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
+  public boolean isFinishedInit()
   {
-    if (pe < 0 || pe >= pdbentry.length)
-    {
-      throw new Error(MessageManager.formatMessage(
-              "error.implementation_error_no_pdbentry_from_index",
-              new Object[]
-              { Integer.valueOf(pe).toString() }));
-    }
-    final String nullChain = "TheNullChain";
-    List<SequenceI> s = new ArrayList<SequenceI>();
-    List<String> c = new ArrayList<String>();
-    if (chains == null)
-    {
-      chains = new String[pdbentry.length][];
-    }
-    if (sequence[pe] != null)
-    {
-      for (int i = 0; i < sequence[pe].length; i++)
-      {
-        s.add(sequence[pe][i]);
-        if (chains[pe] != null)
-        {
-          if (i < chains[pe].length)
-          {
-            c.add(chains[pe][i]);
-          }
-          else
-          {
-            c.add(nullChain);
-          }
-        }
-        else
-        {
-          if (tchain != null && tchain.length > 0)
-          {
-            c.add(nullChain);
-          }
-        }
-      }
-    }
-    for (int i = 0; i < seq.length; i++)
-    {
-      if (!s.contains(seq[i]))
-      {
-        s.add(seq[i]);
-        if (tchain != null && i < tchain.length)
-        {
-          c.add(tchain[i] == null ? nullChain : tchain[i]);
-        }
-      }
-    }
-    SequenceI[] tmp = s.toArray(new SequenceI[s.size()]);
-    sequence[pe] = tmp;
-    if (c.size() > 0)
-    {
-      String[] tch = c.toArray(new String[c.size()]);
-      for (int i = 0; i < tch.length; i++)
-      {
-        if (tch[i] == nullChain)
-        {
-          tch[i] = null;
-        }
-      }
-      chains[pe] = tch;
-    }
-    else
-    {
-      chains[pe] = null;
-    }
+    return finishedInit;
   }
 
-  /**
-   * 
-   * @param pdbfile
-   * @return text report of alignment between pdbfile and any associated
-   *         alignment sequences
-   */
-  public String printMapping(String pdbfile)
+  public void setFinishedInit(boolean finishedInit)
+  {
+    this.finishedInit = finishedInit;
+  }
+
+  public List<String> getChainNames()
   {
-    return ssm.printMapping(pdbfile);
+    return chainNames;
   }
 
 }
index 6a32f30..0df55b1 100644 (file)
  */
 package jalview.ext.varna;
 
-import java.awt.event.*;
-
-import jalview.api.SequenceStructureBinding;
 import jalview.api.StructureSelectionManagerProvider;
-import jalview.structure.*;
+import jalview.structure.StructureListener;
 import jalview.structures.models.SequenceStructureBindingModel;
 
-public abstract class JalviewVarnaBinding extends SequenceStructureBindingModel implements StructureListener,
-        SequenceStructureBinding, ComponentListener,
-        StructureSelectionManagerProvider
+import java.awt.event.ComponentListener;
+
+public abstract class JalviewVarnaBinding extends
+        SequenceStructureBindingModel implements StructureListener,
+        ComponentListener, StructureSelectionManagerProvider
 
 {
 
index 235deda..6e3024d 100644 (file)
@@ -1076,10 +1076,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 .lastIndexOf(java.io.File.separatorChar) + 1);
       }
 
-      success = new Jalview2XML().SaveAlignment(this, file, shortName);
+      /*
+       * First save any linked Chimera session.
+       */
+      Desktop.instance.saveChimeraSessions(file);
+
+      success = new Jalview2XML().saveAlignment(this, file, shortName);
 
       statusBar.setText(MessageManager.formatMessage(
-              "label.successfully_saved_to_file_in_format", new String[]
+              "label.successfully_saved_to_file_in_format", new Object[]
               { fileName, format }));
 
     }
index 09b0fdd..df7f43c 100644 (file)
  */
 package jalview.gui;
 
-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.ext.jmol.JalviewJmolBinding;
-import jalview.gui.ViewSelectionMenu.ViewSetProvider;
 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,12 +38,12 @@ 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 java.awt.BorderLayout;
 import java.awt.Color;
-import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Graphics;
@@ -61,7 +57,6 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Vector;
 
@@ -78,9 +73,7 @@ import javax.swing.event.InternalFrameEvent;
 import javax.swing.event.MenuEvent;
 import javax.swing.event.MenuListener;
 
-public class AppJmol extends GStructureViewer implements Runnable,
-        ViewSetProvider, JalviewStructureDisplayI
-
+public class AppJmol extends StructureViewerBase
 {
   AppJmolBinding jmb;
 
@@ -90,8 +83,6 @@ public class AppJmol extends GStructureViewer implements Runnable,
 
   RenderPanel renderPanel;
 
-  AlignmentPanel ap;
-
   Vector atomsPicked = new Vector();
 
   private boolean addingStructures = false;
@@ -156,9 +147,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
     PDBEntry[] pdbentrys = new PDBEntry[files.length];
     for (int i = 0; i < pdbentrys.length; i++)
     {
-      PDBEntry pdbentry = new PDBEntry();
-      pdbentry.setFile(files[i]);
-      pdbentry.setId(ids[i]);
+      PDBEntry pdbentry = new PDBEntry(files[i], ids[i]);
       pdbentrys[i] = pdbentry;
     }
     // / TODO: check if protocol is needed to be set, and if chains are
@@ -178,7 +167,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
       seqColour.setSelected(false);
       viewerColour.setSelected(true);
     }
-    if (usetoColour)
+    else if (usetoColour)
     {
       useAlignmentPanelForColourbyseq(ap);
       jmb.setColourBySequence(true);
@@ -187,7 +176,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
     }
     this.setBounds(bounds);
     initMenus();
-    viewId = viewid;
+    setViewId(viewid);
     // jalview.gui.Desktop.addInternalFrame(this, "Loading File",
     // bounds.width,bounds.height);
 
@@ -332,15 +321,16 @@ public class AppJmol extends GStructureViewer implements Runnable,
             final AppJmol topJmol = ((AppJmol) frames[i]);
             // JBPNOTE: this looks like a binding routine, rather than a gui
             // routine
-            for (int pe = 0; pe < topJmol.jmb.pdbentry.length; pe++)
+            for (int pe = 0; pe < topJmol.jmb.getPdbCount(); pe++)
             {
-              if (topJmol.jmb.pdbentry[pe].getFile().equals(alreadyMapped))
+              if (topJmol.jmb.getPdbEntry(pe).getFile()
+                      .equals(alreadyMapped))
               {
                 topJmol.jmb.addSequence(pe, seq);
                 topJmol.addAlignmentPanel(ap);
                 // add it to the set used for colouring
                 topJmol.useAlignmentPanelForColourbyseq(ap);
-                topJmol.buildJmolActionMenu();
+                topJmol.buildActionMenu();
                 ap.getStructureSelectionManager()
                         .sequenceColoursChanged(ap);
                 break;
@@ -436,133 +426,6 @@ public class AppJmol extends GStructureViewer implements Runnable,
   }
 
   /**
-   * list of sequenceSet ids associated with the view
-   */
-  ArrayList<String> _aps = new ArrayList();
-
-  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;
-  }
-
-  /**
-   * list of alignment panels to use for superposition
-   */
-  Vector<AlignmentPanel> _alignwith = new Vector<AlignmentPanel>();
-
-  /**
-   * list of alignment panels that are used for colouring structures by aligned
-   * sequences
-   */
-  Vector<AlignmentPanel> _colourwith = new Vector<AlignmentPanel>();
-
-  /**
-   * set the primary alignmentPanel reference and add another alignPanel to the
-   * list of ones to use for colouring and aligning
-   * 
-   * @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 nap
-   */
-  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)
-    {
-      buildJmolActionMenu();
-    }
-  }
-
-  public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
-  {
-    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))
-    {
-      _colourwith.add(nap);
-    }
-  }
-
-  public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
-  {
-    if (_colourwith.contains(nap))
-    {
-      _colourwith.remove(nap);
-    }
-  }
-
-  /**
    * pdb retrieval thread.
    */
   private Thread worker = null;
@@ -632,7 +495,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
     {
       if (frame instanceof AppJmol)
       {
-        if (((AppJmol) frame).isLinkedWith(apanel))
+        if (((StructureViewerBase) frame).isLinkedWith(apanel))
         {
           result.addElement(frame);
         }
@@ -742,7 +605,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
   public void closeViewer()
   {
     jmb.closeViewer();
-    ap = null;
+    setAlignmentPanel(null);
     _aps.clear();
     _alignwith.clear();
     _colourwith.clear();
@@ -768,14 +631,14 @@ public class AppJmol extends GStructureViewer implements Runnable,
       // TODO: replace with reference fetching/transfer code (validate PDBentry
       // as a DBRef?)
       jalview.ws.dbsources.Pdb pdbclient = new jalview.ws.dbsources.Pdb();
-      for (int pi = 0; pi < jmb.pdbentry.length; pi++)
+      for (int pi = 0; pi < jmb.getPdbCount(); pi++)
       {
-        String file = jmb.pdbentry[pi].getFile();
+        String file = jmb.getPdbEntry(pi).getFile();
         if (file == null)
         {
           // retrieve the pdb and store it locally
           AlignmentI pdbseq = null;
-          pdbid = jmb.pdbentry[pi].getId();
+          pdbid = jmb.getPdbEntry(pi).getId();
           long hdl = pdbid.hashCode() - System.currentTimeMillis();
           if (progressBar != null)
           {
@@ -783,7 +646,8 @@ public class AppJmol extends GStructureViewer implements Runnable,
           }
           try
           {
-            pdbseq = pdbclient.getSequenceRecords(pdbid = jmb.pdbentry[pi]
+            pdbseq = pdbclient.getSequenceRecords(pdbid = jmb.getPdbEntry(
+                    pi)
                     .getId());
           } catch (OutOfMemoryError oomerror)
           {
@@ -803,7 +667,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
             // PDBEntry
             file = new File(((PDBEntry) pdbseq.getSequenceAt(0).getPDBId()
                     .elementAt(0)).getFile()).getAbsolutePath();
-            jmb.pdbentry[pi].setFile(file);
+            jmb.getPdbEntry(pi).setFile(file);
 
             files.append(" \"" + Platform.escapeString(file) + "\"");
           }
@@ -898,7 +762,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
       // need to wait around until script has finished
       while (addingStructures ? lastnotify >= jmb.getLoadNotifiesHandled()
               : (jmb.isFinishedInit() && jmb.getPdbFile() != null && jmb
-                      .getPdbFile().length != jmb.pdbentry.length))
+                      .getPdbFile().length != jmb.getPdbCount()))
       {
         try
         {
@@ -977,9 +841,9 @@ public class AppJmol 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)
@@ -1065,10 +929,10 @@ public class AppJmol 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
@@ -1232,15 +1096,15 @@ public class AppJmol extends GStructureViewer implements Runnable,
                 + "...", 20, currentSize.height / 2);
         StringBuffer sb = new StringBuffer();
         int lines = 0;
-        for (int e = 0; e < jmb.pdbentry.length; e++)
+        for (int e = 0; e < jmb.getPdbCount(); e++)
         {
-          sb.append(jmb.pdbentry[e].getId());
-          if (e < jmb.pdbentry.length - 1)
+          sb.append(jmb.getPdbEntry(e).getId());
+          if (e < jmb.getPdbCount() - 1)
           {
             sb.append(",");
           }
 
-          if (e == jmb.pdbentry.length - 1 || sb.length() > 20)
+          if (e == jmb.getPdbCount() - 1 || sb.length() > 20)
           {
             lines++;
             g.drawString(sb.toString(), 20, currentSize.height / 2 - lines
@@ -1264,17 +1128,6 @@ public class AppJmol extends GStructureViewer implements Runnable,
     }
   }
 
-  String viewId = null;
-
-  public String getViewId()
-  {
-    if (viewId == null)
-    {
-      viewId = System.currentTimeMillis() + "." + this.hashCode();
-    }
-    return viewId;
-  }
-
   public void updateTitleAndMenus()
   {
     if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0)
@@ -1285,7 +1138,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
     setChainMenuItems(jmb.chainNames);
 
     this.setTitle(jmb.getViewerTitle());
-    if (jmb.getPdbFile().length > 1 && jmb.sequence.length > 1)
+    if (jmb.getPdbFile().length > 1 && jmb.getSequence().length > 1)
     {
       viewerActionMenu.setVisible(true);
     }
@@ -1295,27 +1148,6 @@ public class AppJmol extends GStructureViewer implements Runnable,
     }
   }
 
-  protected void buildJmolActionMenu()
-  {
-    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);
-      }
-    }
-    final ItemListener handler;
-  }
-
   /*
    * (non-Javadoc)
    * 
@@ -1331,14 +1163,14 @@ public class AppJmol 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
@@ -1390,42 +1222,19 @@ public class AppJmol extends GStructureViewer implements Runnable,
         return ap;
       }
     }
-    return ap;
+    return getAlignmentPanel();
   }
 
-  /**
-   * 
-   * @param ap2
-   * @return true if this Jmol instance is linked with the given alignPanel
-   */
-  public boolean isLinkedWith(AlignmentPanel ap2)
-  {
-    return _aps.contains(ap2.av.getSequenceSetId());
-  }
-
-  public boolean isUsedforaligment(AlignmentPanel ap2)
-  {
-
-    return (_alignwith != null) && _alignwith.contains(ap2);
-  }
-
-  public boolean isUsedforcolourby(AlignmentPanel ap2)
-  {
-    return (_colourwith != null) && _colourwith.contains(ap2);
-  }
-
-  /**
-   * 
-   * @return TRUE if the view is NOT being coloured by sequence associations.
-   */
-  public boolean isColouredByJmol()
+  @Override
+  public AAStructureBindingModel getBinding()
   {
-    return !jmb.isColourBySequence();
+    return this.jmb;
   }
 
-  public JalviewJmolBinding getBinding()
+  @Override
+  public String getStateInfo()
   {
-    return jmb;
+    return jmb == null ? null : jmb.viewer.getStateInfo();
   }
 
 }
index 42a2f74..b7617ce 100644 (file)
  */
 package jalview.gui;
 
-import java.awt.Container;
-import java.util.BitSet;
-
 import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
+import jalview.ext.jmol.JalviewJmolBinding;
 import jalview.structure.StructureSelectionManager;
 
+import java.awt.Container;
+import java.util.BitSet;
+
 import org.jmol.api.JmolAppConsoleInterface;
 import org.jmol.api.JmolViewer;
 import org.jmol.popup.JmolPopup;
 import org.openscience.jmol.app.jmolpanel.AppConsole;
 
-public class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
+public class AppJmolBinding extends JalviewJmolBinding
 {
-
-  /**
-   * 
-   */
   private AppJmol appJmolWindow;
 
+  private FeatureRenderer fr = null;
+
   public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm,
           PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
           String protocol)
@@ -50,13 +49,11 @@ public class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
     appJmolWindow = appJmol;
   }
 
-  FeatureRenderer fr = null;
-
   @Override
-  public jalview.api.FeatureRenderer getFeatureRenderer(
+  public FeatureRenderer getFeatureRenderer(
           AlignmentViewPanel alignment)
   {
-    AlignmentPanel ap = (alignment == null) ? appJmolWindow.ap
+    AlignmentPanel ap = (alignment == null) ? appJmolWindow.getAlignmentPanel()
             : (AlignmentPanel) alignment;
     if (ap.av.isShowSequenceFeatures())
     {
@@ -74,7 +71,7 @@ public class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
   }
 
   @Override
-  public jalview.api.SequenceRenderer getSequenceRenderer(
+  public SequenceRenderer getSequenceRenderer(
           AlignmentViewPanel alignment)
   {
     return new SequenceRenderer(((AlignmentPanel) alignment).av);
@@ -130,7 +127,9 @@ public class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
     AlignmentPanel ap = (AlignmentPanel) source, topap;
     // ignore events from panels not used to colour this view
     if (!appJmolWindow.isUsedforcolourby(ap))
+    {
       return;
+    }
     if (!isLoadingFromArchive())
     {
       colourBySequence(ap.av.isShowSequenceFeatures(), ap);
@@ -153,7 +152,6 @@ public class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
   public void newJmolPopup(boolean translateLocale, String menuName,
           boolean asPopup)
   {
-
     jmolpopup = new JmolPopup();
     jmolpopup.initialize(viewer, translateLocale, menuName, asPopup);
   }
@@ -175,25 +173,6 @@ public class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
     appJmolWindow.showConsole(b);
   }
 
-  /**
-   * add the given sequences to the mapping scope for the given pdb file handle
-   * 
-   * @param pdbFile
-   *          - pdbFile identifier
-   * @param seq
-   *          - set of sequences it can be mapped to
-   */
-  public void addSequenceForStructFile(String pdbFile, SequenceI[] seq)
-  {
-    for (int pe = 0; pe < pdbentry.length; pe++)
-    {
-      if (pdbentry[pe].getFile().equals(pdbFile))
-      {
-        addSequence(pe, seq);
-      }
-    }
-  }
-
   @Override
   protected JmolAppConsoleInterface createJmolConsole(JmolViewer viewer2,
           Container consolePanel, String buttonsToShow)
@@ -205,20 +184,7 @@ public class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
   protected void releaseUIResources()
   {
     appJmolWindow = null;
-    if (console != null)
-    {
-      try
-      {
-        console.setVisible(false);
-      } catch (Error e)
-      {
-      } catch (Exception x)
-      {
-      }
-      ;
-      console = null;
-    }
-
+    closeConsole();
   }
 
   @Override
@@ -227,8 +193,6 @@ public class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
     if (svl instanceof SeqPanel)
     {
       appJmolWindow.removeAlignmentPanel(((SeqPanel) svl).ap);
-
     }
-    ;
   }
 }
index 48123fa..384e1cc 100644 (file)
  */
 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.
    */
@@ -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,10 +895,10 @@ 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
@@ -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;
   }
-
 }
index b8f629a..70c8355 100644 (file)
@@ -26,6 +26,7 @@ import jalview.io.FormatAdapter;
 import jalview.io.IdentifyFile;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
+import jalview.jbgui.GStructureViewer;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.ImageMaker;
 import jalview.util.MessageManager;
@@ -113,6 +114,8 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    */
   private BlogReader jvnews = null;
 
+  private File projectFile;
+
   /**
    * @param listener
    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
@@ -1462,6 +1465,11 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     {
       final Desktop me = this;
       final java.io.File choice = chooser.getSelectedFile();
+      setProjectFile(choice);
+
+      // TODO or move inside the new Thread?
+      saveChimeraSessions(choice.getAbsolutePath());
+
       new Thread(new Runnable()
       {
         public void run()
@@ -1475,7 +1483,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
           // TODO prevent user from messing with the Desktop whilst we're saving
           try
           {
-            new Jalview2XML().SaveState(choice);
+            new Jalview2XML().saveState(choice);
           } catch (OutOfMemoryError oom)
           {
             new OOMWarning("Whilst saving current state to "
@@ -1498,6 +1506,42 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   }
 
   /**
+   * Request any open, linked Chimera sessions to save their state.
+   * 
+   * @param jalviewProjectFilename
+   *          the filename of the Jalview project; Chimera session files should
+   *          be given distinct, but obviously related, names.
+   */
+  public void saveChimeraSessions(String jalviewProjectFilename)
+  {
+    int i = 0;
+    for (JInternalFrame frame : getAllFrames())
+    {
+      if (frame instanceof ChimeraViewFrame)
+      {
+        /*
+         * Construct a filename for the Chimera session by append _chimera<n>.py
+         * to the Jalview project file name.
+         */
+        String chimeraPath = jalviewProjectFilename + "_chimera_" + i
+                + ".py";
+        ((ChimeraViewFrame) frame).saveSession(chimeraPath);
+        i++;
+      }
+    }
+  }
+
+  private void setProjectFile(File choice)
+  {
+    this.projectFile = choice;
+  }
+
+  public File getProjectFile()
+  {
+    return this.projectFile;
+  }
+
+  /**
    * DOCUMENT ME!
    * 
    * @param e
@@ -1517,9 +1561,10 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
     if (value == JalviewFileChooser.APPROVE_OPTION)
     {
-      final String choice = chooser.getSelectedFile().getAbsolutePath();
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
-              .getSelectedFile().getParent());
+      final File selectedFile = chooser.getSelectedFile();
+      setProjectFile(selectedFile);
+      final String choice = selectedFile.getAbsolutePath();
+      jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
       new Thread(new Runnable()
       {
         public void run()
@@ -1528,7 +1573,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
                   choice.hashCode());
           try
           {
-            new Jalview2XML().LoadJalviewAlign(choice);
+            new Jalview2XML().loadJalviewAlign(choice);
           } catch (OutOfMemoryError oom)
           {
             new OOMWarning("Whilst loading project from " + choice, oom);
@@ -2312,7 +2357,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     return afs;
   }
 
-  public AppJmol[] getJmols()
+  public GStructureViewer[] getJmols()
   {
     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
 
@@ -2328,7 +2373,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       {
         if (frames[i] instanceof AppJmol)
         {
-          AppJmol af = (AppJmol) frames[i];
+          GStructureViewer af = (GStructureViewer) frames[i];
           avp.addElement(af);
         }
       }
@@ -2340,10 +2385,10 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     {
       return null;
     }
-    AppJmol afs[] = new AppJmol[avp.size()];
+    GStructureViewer afs[] = new GStructureViewer[avp.size()];
     for (int i = 0, j = avp.size(); i < j; i++)
     {
-      afs[i] = (AppJmol) avp.elementAt(i);
+      afs[i] = (GStructureViewer) avp.elementAt(i);
     }
     avp.clear();
     return afs;
index 9bb27ed..102e463 100644 (file)
@@ -25,7 +25,10 @@ import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.ViewerData;
+import jalview.datamodel.ViewerData.StructureData;
 import jalview.schemabinding.version2.AlcodMap;
 import jalview.schemabinding.version2.Alcodon;
 import jalview.schemabinding.version2.AlcodonFrame;
@@ -64,7 +67,9 @@ import jalview.schemes.ColourSchemeProperty;
 import jalview.schemes.GraduatedColor;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.ResidueProperties;
+import jalview.schemes.UserColourScheme;
 import jalview.structure.StructureSelectionManager;
+import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.util.jarInputStreamProvider;
@@ -94,11 +99,14 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.StringTokenizer;
@@ -125,6 +133,23 @@ import org.exolab.castor.xml.Unmarshaller;
  */
 public class Jalview2XML
 {
+  /*
+   * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
+   * of sequence objects are created.
+   */
+  IdentityHashMap<SequenceI, String> seqsToIds = null;
+
+  /**
+   * jalview XML Sequence ID to jalview sequence object reference (both dataset
+   * and alignment sequences. Populated as XML reps of sequence objects are
+   * created.)
+   */
+  Map<String, SequenceI> seqRefIds = null;
+
+  Vector frefedSequence = null;
+
+  boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
+
   /**
    * create/return unique hash string for sq
    * 
@@ -139,7 +164,7 @@ public class Jalview2XML
     }
     if (seqsToIds.containsKey(sq))
     {
-      return (String) seqsToIds.get(sq);
+      return seqsToIds.get(sq);
     }
     else
     {
@@ -180,31 +205,14 @@ public class Jalview2XML
   {
     if (seqsToIds == null)
     {
-      seqsToIds = new IdentityHashMap();
+      seqsToIds = new IdentityHashMap<SequenceI, String>();
     }
     if (seqRefIds == null)
     {
-      seqRefIds = new Hashtable();
+      seqRefIds = new HashMap<String, SequenceI>();
     }
   }
 
-  /**
-   * SequenceI reference -> XML ID string in jalview XML. Populated as XML reps
-   * of sequence objects are created.
-   */
-  java.util.IdentityHashMap seqsToIds = null;
-
-  /**
-   * jalview XML Sequence ID to jalview sequence object reference (both dataset
-   * and alignment sequences. Populated as XML reps of sequence objects are
-   * created.)
-   */
-  java.util.Hashtable seqRefIds = null; // key->SequenceI resolution
-
-  Vector frefedSequence = null;
-
-  boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
-
   public Jalview2XML()
   {
   }
@@ -229,7 +237,7 @@ public class Jalview2XML
           {
             if (ref[1] instanceof jalview.datamodel.Mapping)
             {
-              SequenceI seq = (SequenceI) seqRefIds.get(sref);
+              SequenceI seq = seqRefIds.get(sref);
               while (seq.getDatasetSequence() != null)
               {
                 seq = seq.getDatasetSequence();
@@ -240,7 +248,7 @@ public class Jalview2XML
             {
               if (ref[1] instanceof jalview.datamodel.AlignedCodonFrame)
               {
-                SequenceI seq = (SequenceI) seqRefIds.get(sref);
+                SequenceI seq = seqRefIds.get(sref);
                 while (seq.getDatasetSequence() != null)
                 {
                   seq = seq.getDatasetSequence();
@@ -302,16 +310,17 @@ public class Jalview2XML
   /**
    * List of pdbfiles added to Jar
    */
-  Vector pdbfiles = null;
+  List<String> pdbfiles = null;
 
   // SAVES SEVERAL ALIGNMENT WINDOWS TO SAME JARFILE
-  public void SaveState(File statefile)
+  public void saveState(File statefile)
   {
+    FileOutputStream fos = null;
     try
     {
-      FileOutputStream fos = new FileOutputStream(statefile);
+      fos = new FileOutputStream(statefile);
       JarOutputStream jout = new JarOutputStream(fos);
-      SaveState(jout);
+      saveState(jout);
 
     } catch (Exception e)
     {
@@ -327,6 +336,18 @@ public class Jalview2XML
         errorMessage += "(output file was '" + statefile + "')";
       }
       e.printStackTrace();
+    } finally
+    {
+      if (fos != null)
+      {
+        try
+        {
+          fos.close();
+        } catch (IOException e)
+        {
+          // ignore
+        }
+      }
     }
     reportErrors();
   }
@@ -336,7 +357,7 @@ public class Jalview2XML
    * 
    * @param jout
    */
-  public void SaveState(JarOutputStream jout)
+  public void saveState(JarOutputStream jout)
   {
     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
 
@@ -352,8 +373,6 @@ public class Jalview2XML
 
       // NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS
       // //////////////////////////////////////////////////
-      // NOTE ALSO new PrintWriter must be used for each new JarEntry
-      PrintWriter out = null;
 
       Vector shortNames = new Vector();
 
@@ -412,7 +431,7 @@ public class Jalview2XML
               fileName = fileName + ".xml";
             }
 
-            SaveState(apanel, fileName, jout);
+            saveState(apanel, fileName, jout);
 
             String dssid = getDatasetIdRef(af.getViewport().getAlignment()
                     .getDataset());
@@ -449,7 +468,7 @@ public class Jalview2XML
   }
 
   // USE THIS METHOD TO SAVE A SINGLE ALIGNMENT WINDOW
-  public boolean SaveAlignment(AlignFrame af, String jarFile,
+  public boolean saveAlignment(AlignFrame af, String jarFile,
           String fileName)
   {
     try
@@ -467,7 +486,7 @@ public class Jalview2XML
         {
           jfileName = jfileName + ".xml";
         }
-        SaveState(apanel, jfileName, jout);
+        saveState(apanel, jfileName, jout);
         String dssid = getDatasetIdRef(af.getViewport().getAlignment()
                 .getDataset());
         if (!dsses.containsKey(dssid))
@@ -505,12 +524,12 @@ public class Jalview2XML
       {
         jfileName = jfileName + ".xml";
       }
-      SaveState(_af.alignPanel, jfileName, true, jout);
+      saveState(_af.alignPanel, jfileName, true, jout);
     }
   }
 
   /**
-   * create a JalviewModel from an algnment view and marshall it to a
+   * create a JalviewModel from an alignment view and marshall it to a
    * JarOutputStream
    * 
    * @param ap
@@ -522,14 +541,14 @@ public class Jalview2XML
    * @param out
    *          jar entry name
    */
-  public JalviewModel SaveState(AlignmentPanel ap, String fileName,
+  public JalviewModel saveState(AlignmentPanel ap, String fileName,
           JarOutputStream jout)
   {
-    return SaveState(ap, fileName, false, jout);
+    return saveState(ap, fileName, false, jout);
   }
 
   /**
-   * create a JalviewModel from an algnment view and marshall it to a
+   * create a JalviewModel from an alignment view and marshall it to a
    * JarOutputStream
    * 
    * @param ap
@@ -544,12 +563,12 @@ public class Jalview2XML
    * @param out
    *          jar entry name
    */
-  public JalviewModel SaveState(AlignmentPanel ap, String fileName,
+  public JalviewModel saveState(AlignmentPanel ap, String fileName,
           boolean storeDS, JarOutputStream jout)
   {
     initSeqRefs();
-    Vector jmolViewIds = new Vector(); //
-    Vector userColours = new Vector();
+    List<String> viewIds = new ArrayList<String>();
+    List<UserColourScheme> userColours = new ArrayList<UserColourScheme>();
 
     AlignViewport av = ap.av;
 
@@ -718,81 +737,22 @@ public class Jalview2XML
 
           pdb.setId(entry.getId());
           pdb.setType(entry.getType());
-          //
-          // store any JMol views associated with this seqeunce
-          // this section copes with duplicate entries in the project, so a
-          // dataset only view *should* be coped with sensibly
-          AppJmol jmol;
+
+          /*
+           * Store any structure views associated with this sequence. This
+           * section copes with duplicate entries in the project, so a dataset
+           * only view *should* be coped with sensibly.
+           */
           // This must have been loaded, is it still visible?
           JInternalFrame[] frames = Desktop.desktop.getAllFrames();
           String matchedFile = null;
           for (int f = frames.length - 1; f > -1; f--)
           {
-            if (frames[f] instanceof AppJmol)
+            if (frames[f] instanceof StructureViewerBase)
             {
-              jmol = (AppJmol) frames[f];
-              for (int peid = 0; peid < jmol.jmb.pdbentry.length; peid++)
-              {
-                if (!jmol.jmb.pdbentry[peid].getId().equals(entry.getId())
-                        && !(entry.getId().length() > 4 && entry
-                                .getId()
-                                .toLowerCase()
-                                .startsWith(
-                                        jmol.jmb.pdbentry[peid].getId()
-                                                .toLowerCase())))
-                {
-                  continue;
-                }
-                if (matchedFile == null)
-                {
-                  matchedFile = jmol.jmb.pdbentry[peid].getFile();
-                }
-                else if (!matchedFile.equals(jmol.jmb.pdbentry[peid]
-                        .getFile()))
-                {
-                  Cache.log
-                          .warn("Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
-                                  + jmol.jmb.pdbentry[peid].getFile());
-                  ; // record the
-                }
-                // file so we
-                // can get at it if the ID
-                // match is ambiguous (e.g.
-                // 1QIP==1qipA)
-                String statestring = jmol.jmb.viewer.getStateInfo();
-
-                for (int smap = 0; smap < jmol.jmb.sequence[peid].length; smap++)
-                {
-                  // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
-                  if (jds == jmol.jmb.sequence[peid][smap])
-                  {
-                    StructureState state = new StructureState();
-                    state.setVisible(true);
-                    state.setXpos(jmol.getX());
-                    state.setYpos(jmol.getY());
-                    state.setWidth(jmol.getWidth());
-                    state.setHeight(jmol.getHeight());
-                    state.setViewId(jmol.getViewId());
-                    state.setAlignwithAlignPanel(jmol.isUsedforaligment(ap));
-                    state.setColourwithAlignPanel(jmol
-                            .isUsedforcolourby(ap));
-                    state.setColourByJmol(jmol.isColouredByJmol());
-                    if (!jmolViewIds.contains(state.getViewId()))
-                    {
-                      // Make sure we only store a Jmol state once in each XML
-                      // document.
-                      jmolViewIds.addElement(state.getViewId());
-                      state.setContent(statestring.replaceAll("\n", ""));
-                    }
-                    else
-                    {
-                      state.setContent("# duplicate state");
-                    }
-                    pdb.addStructureState(state);
-                  }
-
-                }
-              }
+              StructureViewerBase viewFrame = (StructureViewerBase) frames[f];
+              matchedFile = saveStructureState(ap, jds, pdb, entry,
+                      viewIds, matchedFile, viewFrame);
             }
           }
 
@@ -806,12 +766,13 @@ public class Jalview2XML
             pdb.setFile(matchedFile); // entry.getFile());
             if (pdbfiles == null)
             {
-              pdbfiles = new Vector();
+              pdbfiles = new ArrayList<String>();
             }
 
             if (!pdbfiles.contains(entry.getId()))
             {
-              pdbfiles.addElement(entry.getId());
+              pdbfiles.add(entry.getId());
+              DataInputStream dis = null;
               try
               {
                 File file = new File(matchedFile);
@@ -819,7 +780,7 @@ public class Jalview2XML
                 {
                   byte[] data = new byte[(int) file.length()];
                   jout.putNextEntry(new JarEntry(entry.getId()));
-                  DataInputStream dis = new DataInputStream(
+                  dis = new DataInputStream(
                           new FileInputStream(file));
                   dis.readFully(data);
 
@@ -831,6 +792,18 @@ public class Jalview2XML
               } catch (Exception ex)
               {
                 ex.printStackTrace();
+              } finally
+              {
+                if (dis != null)
+                {
+                  try
+                  {
+                    dis.close();
+                  } catch (IOException e)
+                  {
+                    // ignore
+                  }
+                }
               }
 
             }
@@ -999,7 +972,7 @@ public class Jalview2XML
 
             if (sg.cs instanceof jalview.schemes.UserColourScheme)
             {
-              groups[i].setColour(SetUserColourScheme(sg.cs, userColours,
+              groups[i].setColour(setUserColourScheme(sg.cs, userColours,
                       jms));
             }
             else
@@ -1018,7 +991,7 @@ public class Jalview2XML
           else if (sg.cs instanceof jalview.schemes.UserColourScheme)
           {
             groups[i]
-                    .setColour(SetUserColourScheme(sg.cs, userColours, jms));
+                    .setColour(setUserColourScheme(sg.cs, userColours, jms));
           }
           else
           {
@@ -1081,7 +1054,7 @@ public class Jalview2XML
 
       if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
       {
-        view.setBgColour(SetUserColourScheme(av.getGlobalColourScheme(),
+        view.setBgColour(setUserColourScheme(av.getGlobalColourScheme(),
                 userColours, jms));
       }
       else if (av.getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient)
@@ -1109,7 +1082,7 @@ public class Jalview2XML
           view.setConsThreshold(cs.getConservationInc());
           if (cs instanceof jalview.schemes.UserColourScheme)
           {
-            view.setBgColour(SetUserColourScheme(cs, userColours, jms));
+            view.setBgColour(setUserColourScheme(cs, userColours, jms));
           }
         }
 
@@ -1312,8 +1285,94 @@ public class Jalview2XML
     return object;
   }
 
+  /**
+   * Save the state of a structure viewer
+   * 
+   * @param ap
+   * @param jds
+   * @param pdb
+   *          the archive XML element under which to save the state
+   * @param entry
+   * @param viewIds
+   * @param matchedFile
+   * @param viewFrame
+   * @return
+   */
+  protected String saveStructureState(AlignmentPanel ap, SequenceI jds,
+          Pdbids pdb, PDBEntry entry, List<String> viewIds,
+          String matchedFile, StructureViewerBase viewFrame)
+  {
+    final AAStructureBindingModel bindingModel = viewFrame
+            .getBinding();
+    for (int peid = 0; peid < bindingModel
+            .getPdbCount(); peid++)
+    {
+      final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
+      final String pdbId = pdbentry.getId();
+      if (!pdbId.equals(entry.getId())
+              && !(entry.getId().length() > 4 && entry.getId()
+                      .toLowerCase()
+                      .startsWith(pdbId.toLowerCase())))
+      {
+        continue;
+      }
+      if (matchedFile == null)
+      {
+        matchedFile = pdbentry.getFile();
+      }
+      else if (!matchedFile.equals(pdbentry
+              .getFile()))
+      {
+        Cache.log
+                .warn("Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
+                        + pdbentry.getFile());
+      }
+      // record the
+      // file so we
+      // can get at it if the ID
+      // match is ambiguous (e.g.
+      // 1QIP==1qipA)
+      String statestring = viewFrame.getStateInfo();
+
+      for (int smap = 0; smap < viewFrame.getBinding()
+              .getSequence()[peid].length; smap++)
+      {
+        // if (jal.findIndex(jmol.jmb.sequence[peid][smap]) > -1)
+        if (jds == viewFrame.getBinding().getSequence()[peid][smap])
+        {
+          StructureState state = new StructureState();
+          state.setVisible(true);
+          state.setXpos(viewFrame.getX());
+          state.setYpos(viewFrame.getY());
+          state.setWidth(viewFrame.getWidth());
+          state.setHeight(viewFrame.getHeight());
+          final String viewId = viewFrame.getViewId();
+          state.setViewId(viewId);
+          state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
+          state.setColourwithAlignPanel(viewFrame
+                  .isUsedforcolourby(ap));
+          state.setColourByJmol(viewFrame.isColouredByViewer());
+          /*
+           * Only store each structure viewer's state once in each XML document.
+           */
+          if (!viewIds.contains(viewId))
+          {
+            viewIds.add(viewId);
+            state.setContent(statestring.replaceAll("\n", ""));
+          }
+          else
+          {
+            state.setContent("# duplicate state");
+          }
+          pdb.addStructureState(state);
+        }
+      }
+    }
+    return matchedFile;
+  }
+
   private AnnotationColours constructAnnotationColours(
-          AnnotationColourGradient acg, Vector userColours,
+          AnnotationColourGradient acg, List<UserColourScheme> userColours,
           JalviewModelSequence jms)
   {
     AnnotationColours ac = new AnnotationColours();
@@ -1322,7 +1381,7 @@ public class Jalview2XML
     ac.setAnnotation(acg.getAnnotation());
     if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme)
     {
-      ac.setColourScheme(SetUserColourScheme(acg.getBaseColour(),
+      ac.setColourScheme(setUserColourScheme(acg.getBaseColour(),
               userColours, jms));
     }
     else
@@ -1767,8 +1826,8 @@ public class Jalview2XML
     return mp;
   }
 
-  String SetUserColourScheme(jalview.schemes.ColourSchemeI cs,
-          Vector userColours, JalviewModelSequence jms)
+  String setUserColourScheme(jalview.schemes.ColourSchemeI cs,
+          List<UserColourScheme> userColours, JalviewModelSequence jms)
   {
     String id = null;
     jalview.schemes.UserColourScheme ucs = (jalview.schemes.UserColourScheme) cs;
@@ -1813,7 +1872,7 @@ public class Jalview2XML
     return id;
   }
 
-  jalview.schemes.UserColourScheme GetUserColourScheme(
+  jalview.schemes.UserColourScheme getUserColourScheme(
           JalviewModelSequence jms, String id)
   {
     UserColours[] uc = jms.getUserColours();
@@ -1871,7 +1930,7 @@ public class Jalview2XML
    * @param file
    *          - HTTP URL or filename
    */
-  public AlignFrame LoadJalviewAlign(final String file)
+  public AlignFrame loadJalviewAlign(final String file)
   {
 
     jalview.gui.AlignFrame af = null;
@@ -1886,7 +1945,7 @@ public class Jalview2XML
       // so we can re-open the jar input stream for each entry.
 
       jarInputStreamProvider jprovider = createjarInputStreamProvider(file);
-      af = LoadJalviewAlign(jprovider);
+      af = loadJalviewAlign(jprovider);
 
     } catch (MalformedURLException e)
     {
@@ -1959,7 +2018,7 @@ public class Jalview2XML
    * @param jprovider
    * @return
    */
-  public AlignFrame LoadJalviewAlign(final jarInputStreamProvider jprovider)
+  public AlignFrame loadJalviewAlign(final jarInputStreamProvider jprovider)
   {
     errorMessage = null;
     if (uniqueSetSuffix == null)
@@ -1968,7 +2027,7 @@ public class Jalview2XML
     }
     if (seqRefIds == null)
     {
-      seqRefIds = new Hashtable();
+      seqRefIds = new HashMap<String, SequenceI>();
     }
     if (viewportsAdded == null)
     {
@@ -2006,7 +2065,7 @@ public class Jalview2XML
           object = (JalviewModel) unmar.unmarshal(in);
           if (true) // !skipViewport(object))
           {
-            _af = LoadFromObject(object, file, true, jprovider);
+            _af = loadFromObject(object, file, true, jprovider);
             if (object.getJalviewModelSequence().getViewportCount() > 0)
             {
               af = _af;
@@ -2232,7 +2291,7 @@ public class Jalview2XML
    *          data source provider
    * @return alignment frame created from view stored in DOM
    */
-  AlignFrame LoadFromObject(JalviewModel object, String file,
+  AlignFrame loadFromObject(JalviewModel object, String file,
           boolean loadTreesAndStructures, jarInputStreamProvider jprovider)
   {
     SequenceSet vamsasSet = object.getVamsasModel().getSequenceSet(0);
@@ -2253,11 +2312,11 @@ public class Jalview2XML
 
     boolean multipleView = false;
 
-    JSeq[] JSEQ = object.getJalviewModelSequence().getJSeq();
+    JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
     int vi = 0; // counter in vamsasSeq array
-    for (int i = 0; i < JSEQ.length; i++)
+    for (int i = 0; i < jseqs.length; i++)
     {
-      String seqId = JSEQ[i].getId();
+      String seqId = jseqs[i].getId();
 
       if (seqRefIds.get(seqId) != null)
       {
@@ -2269,15 +2328,15 @@ public class Jalview2XML
         jseq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
                 vamsasSeq[vi].getSequence());
         jseq.setDescription(vamsasSeq[vi].getDescription());
-        jseq.setStart(JSEQ[i].getStart());
-        jseq.setEnd(JSEQ[i].getEnd());
+        jseq.setStart(jseqs[i].getStart());
+        jseq.setEnd(jseqs[i].getEnd());
         jseq.setVamsasId(uniqueSetSuffix + seqId);
         seqRefIds.put(vamsasSeq[vi].getId(), jseq);
         tmpseqs.add(jseq);
         vi++;
       }
 
-      if (JSEQ[i].getHidden())
+      if (jseqs[i].getHidden())
       {
         if (hiddenSeqs == null)
         {
@@ -2332,9 +2391,9 @@ public class Jalview2XML
       // structures for the alignment
       for (int i = 0; i < vamsasSeq.length; i++)
       {
-        if (JSEQ[i].getFeaturesCount() > 0)
+        if (jseqs[i].getFeaturesCount() > 0)
         {
-          Features[] features = JSEQ[i].getFeatures();
+          Features[] features = jseqs[i].getFeatures();
           for (int f = 0; f < features.length; f++)
           {
             jalview.datamodel.SequenceFeature sf = new jalview.datamodel.SequenceFeature(
@@ -2364,9 +2423,9 @@ public class Jalview2XML
         {
           addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]);
         }
-        if (JSEQ[i].getPdbidsCount() > 0)
+        if (jseqs[i].getPdbidsCount() > 0)
         {
-          Pdbids[] ids = JSEQ[i].getPdbids();
+          Pdbids[] ids = jseqs[i].getPdbids();
           for (int p = 0; p < ids.length; p++)
           {
             jalview.datamodel.PDBEntry entry = new jalview.datamodel.PDBEntry();
@@ -2429,7 +2488,7 @@ public class Jalview2XML
           AlcodMap[] maps = alc[i].getAlcodMap();
           for (int m = 0; m < maps.length; m++)
           {
-            SequenceI dnaseq = (SequenceI) seqRefIds
+            SequenceI dnaseq = seqRefIds
                     .get(maps[m].getDnasq());
             // Load Mapping
             jalview.datamodel.Mapping mapping = null;
@@ -2683,7 +2742,7 @@ public class Jalview2XML
         {
           if (groups[i].getColour().startsWith("ucs"))
           {
-            cs = GetUserColourScheme(jms, groups[i].getColour());
+            cs = getUserColourScheme(jms, groups[i].getColour());
           }
           else if (groups[i].getColour().equals("AnnotationColourGradient")
                   && groups[i].getAnnotationColours() != null)
@@ -2707,7 +2766,7 @@ public class Jalview2XML
         for (int s = 0; s < groups[i].getSeqCount(); s++)
         {
           String seqId = groups[i].getSeq(s) + "";
-          jalview.datamodel.SequenceI ts = (jalview.datamodel.SequenceI) seqRefIds
+          jalview.datamodel.SequenceI ts = seqRefIds
                   .get(seqId);
 
           if (ts != null)
@@ -2879,7 +2938,7 @@ public class Jalview2XML
 
     if (isnewview)
     {
-      af = loadViewport(file, JSEQ, hiddenSeqs, al, jms, view,
+      af = loadViewport(file, jseqs, hiddenSeqs, al, jms, view,
               uniqueSeqSetId, viewId, autoAlan);
       av = af.viewport;
       ap = af.alignPanel;
@@ -2964,358 +3023,501 @@ public class Jalview2XML
     // //LOAD STRUCTURES
     if (loadTreesAndStructures)
     {
-      // run through all PDB ids on the alignment, and collect mappings between
-      // jmol view ids and all sequences referring to it
-      Hashtable<String, Object[]> jmolViewIds = new Hashtable();
+      loadStructures(jprovider, jseqs, af, ap);
+    }
+    // and finally return.
+    return af;
+  }
 
-      for (int i = 0; i < JSEQ.length; i++)
+  /**
+   * Load and link any saved structure viewers.
+   * 
+   * @param jprovider
+   * @param jseqs
+   * @param af
+   * @param ap
+   */
+  protected void loadStructures(jarInputStreamProvider jprovider,
+          JSeq[] jseqs, AlignFrame af, AlignmentPanel ap)
+  {
+    /*
+     * Run through all PDB ids on the alignment, and collect mappings between
+     * distinct view ids and all sequences referring to that view.
+     */
+    Map<String, ViewerData> structureViewers = new LinkedHashMap<String, ViewerData>();
+
+    for (int i = 0; i < jseqs.length; i++)
+    {
+      if (jseqs[i].getPdbidsCount() > 0)
       {
-        if (JSEQ[i].getPdbidsCount() > 0)
+        Pdbids[] ids = jseqs[i].getPdbids();
+        for (int p = 0; p < ids.length; p++)
         {
-          Pdbids[] ids = JSEQ[i].getPdbids();
-          for (int p = 0; p < ids.length; p++)
+          final int structureStateCount = ids[p].getStructureStateCount();
+          for (int s = 0; s < structureStateCount; s++)
           {
-            for (int s = 0; s < ids[p].getStructureStateCount(); s++)
+            // check to see if we haven't already created this structure view
+            final StructureState structureState = ids[p].getStructureState(s);
+            String sviewid = (structureState.getViewId() == null) ? null
+                    : structureState.getViewId()
+                            + uniqueSetSuffix;
+            jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
+            // Originally : ids[p].getFile()
+            // : TODO: verify external PDB file recovery still works in normal
+            // jalview project load
+            jpdb.setFile(loadPDBFile(jprovider, ids[p].getId()));
+            jpdb.setId(ids[p].getId());
+
+            int x = structureState.getXpos();
+            int y = structureState.getYpos();
+            int width = structureState.getWidth();
+            int height = structureState.getHeight();
+
+            // Probably don't need to do this anymore...
+            // Desktop.desktop.getComponentAt(x, y);
+            // TODO: NOW: check that this recovers the PDB file correctly.
+            String pdbFile = loadPDBFile(jprovider, ids[p].getId());
+            jalview.datamodel.SequenceI seq = seqRefIds
+                    .get(jseqs[i].getId() + "");
+            if (sviewid == null)
             {
-              // check to see if we haven't already created this structure view
-              String sviewid = (ids[p].getStructureState(s).getViewId() == null) ? null
-                      : ids[p].getStructureState(s).getViewId()
-                              + uniqueSetSuffix;
-              jalview.datamodel.PDBEntry jpdb = new jalview.datamodel.PDBEntry();
-              // Originally : ids[p].getFile()
-              // : TODO: verify external PDB file recovery still works in normal
-              // jalview project load
-              jpdb.setFile(loadPDBFile(jprovider, ids[p].getId()));
-              jpdb.setId(ids[p].getId());
-
-              int x = ids[p].getStructureState(s).getXpos();
-              int y = ids[p].getStructureState(s).getYpos();
-              int width = ids[p].getStructureState(s).getWidth();
-              int height = ids[p].getStructureState(s).getHeight();
-
-              // Probably don't need to do this anymore...
-              // Desktop.desktop.getComponentAt(x, y);
-              // TODO: NOW: check that this recovers the PDB file correctly.
-              String pdbFile = loadPDBFile(jprovider, ids[p].getId());
-              jalview.datamodel.SequenceI seq = (jalview.datamodel.SequenceI) seqRefIds
-                      .get(JSEQ[i].getId() + "");
-              if (sviewid == null)
-              {
-                sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width
-                        + "," + height;
-              }
-              if (!jmolViewIds.containsKey(sviewid))
-              {
-                jmolViewIds.put(sviewid, new Object[]
-                { new int[]
-                { x, y, width, height }, "",
-                    new Hashtable<String, Object[]>(), new boolean[]
-                    { false, false, true } });
-                // Legacy pre-2.7 conversion JAL-823 :
-                // do not assume any view has to be linked for colour by
-                // sequence
-              }
+              sviewid = "_jalview_pre2_4_" + x + "," + y + "," + width
+                      + "," + height;
+            }
+            if (!structureViewers.containsKey(sviewid))
+            {
+              structureViewers.put(sviewid, new ViewerData(x, y, width, height,
+                      false, false, true));
+              // Legacy pre-2.7 conversion JAL-823 :
+              // do not assume any view has to be linked for colour by
+              // sequence
+            }
 
-              // assemble String[] { pdb files }, String[] { id for each
-              // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
-              // seqs_file 2}, boolean[] {
-              // linkAlignPanel,superposeWithAlignpanel}} from hash
-              Object[] jmoldat = jmolViewIds.get(sviewid);
-              ((boolean[]) jmoldat[3])[0] |= ids[p].getStructureState(s)
-                      .hasAlignwithAlignPanel() ? ids[p].getStructureState(
-                      s).getAlignwithAlignPanel() : false;
-              // never colour by linked panel if not specified
-              ((boolean[]) jmoldat[3])[1] |= ids[p].getStructureState(s)
-                      .hasColourwithAlignPanel() ? ids[p]
-                      .getStructureState(s).getColourwithAlignPanel()
-                      : false;
-              // default for pre-2.7 projects is that Jmol colouring is enabled
-              ((boolean[]) jmoldat[3])[2] &= ids[p].getStructureState(s)
-                      .hasColourByJmol() ? ids[p].getStructureState(s)
-                      .getColourByJmol() : true;
-
-              if (((String) jmoldat[1]).length() < ids[p]
-                      .getStructureState(s).getContent().length())
+            // assemble String[] { pdb files }, String[] { id for each
+            // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
+            // seqs_file 2}, boolean[] {
+            // linkAlignPanel,superposeWithAlignpanel}} from hash
+            ViewerData jmoldat = structureViewers.get(sviewid);
+            jmoldat.setAlignWithPanel(jmoldat.isAlignWithPanel()
+                    | (structureState.hasAlignwithAlignPanel() ? structureState
+                            .getAlignwithAlignPanel() : false));
+
+            /*
+             * Default colour by linked panel to false if not specified (e.g.
+             * for pre-2.7 projects)
+             */
+            boolean colourWithAlignPanel = jmoldat.isColourWithAlignPanel();
+            colourWithAlignPanel |= (structureState
+                    .hasColourwithAlignPanel() ? structureState
+                    .getColourwithAlignPanel() : false);
+            jmoldat.setColourWithAlignPanel(colourWithAlignPanel);
+
+            /*
+             * Default colour by viewer to true if not specified (e.g. for
+             * pre-2.7 projects)
+             */
+            boolean colourByViewer = jmoldat.isColourByViewer();
+            colourByViewer &= structureState
+                    .hasColourByJmol() ? structureState
+                    .getColourByJmol() : true;
+            jmoldat.setColourByViewer(colourByViewer);
+
+            if (jmoldat.getStateData().length() < structureState
+                    .getContent().length())
+            {
               {
-                {
-                  jmoldat[1] = ids[p].getStructureState(s).getContent();
-                }
+                jmoldat.setStateData(structureState.getContent());
               }
-              if (ids[p].getFile() != null)
+            }
+            if (ids[p].getFile() != null)
+            {
+              File mapkey = new File(ids[p].getFile());
+              StructureData seqstrmaps = jmoldat.getFileData().get(mapkey);
+              if (seqstrmaps == null)
               {
-                File mapkey = new File(ids[p].getFile());
-                Object[] seqstrmaps = (Object[]) ((Hashtable) jmoldat[2])
-                        .get(mapkey);
-                if (seqstrmaps == null)
-                {
-                  ((Hashtable) jmoldat[2]).put(mapkey,
-                          seqstrmaps = new Object[]
-                          { pdbFile, ids[p].getId(), new Vector(),
-                              new Vector() });
-                }
-                if (!((Vector) seqstrmaps[2]).contains(seq))
-                {
-                  ((Vector) seqstrmaps[2]).addElement(seq);
-                  // ((Vector)seqstrmaps[3]).addElement(n) :
-                  // in principle, chains
-                  // should be stored here : do we need to
-                  // TODO: store and recover seq/pdb_id :
-                  // chain mappings
-                }
+                jmoldat.getFileData().put(
+                        mapkey,
+                        seqstrmaps = jmoldat.new StructureData(pdbFile,
+                                ids[p].getId()));
               }
-              else
+              if (!seqstrmaps.getSeqList().contains(seq))
               {
-                errorMessage = ("The Jmol views in this project were imported\nfrom an older version of Jalview.\nPlease review the sequence colour associations\nin the Colour by section of the Jmol View menu.\n\nIn the case of problems, see note at\nhttp://issues.jalview.org/browse/JAL-747");
-                warn(errorMessage);
+                seqstrmaps.getSeqList().add(seq);
+                // TODO and chains?
               }
             }
+            else
+            {
+              errorMessage = ("The Jmol views in this project were imported\nfrom an older version of Jalview.\nPlease review the sequence colour associations\nin the Colour by section of the Jmol View menu.\n\nIn the case of problems, see note at\nhttp://issues.jalview.org/browse/JAL-747");
+              warn(errorMessage);
+            }
           }
         }
       }
+    }
+      // Instantiate the associated structure views
+      for (Entry<String, ViewerData> entry : structureViewers.entrySet())
+      {
+        createOrLinkStructureViewer(entry, af, ap);
+      }
+  }
+
+  /**
+   * 
+   * @param viewerData
+   * @param af
+   * @param ap
+   */
+  protected void createOrLinkStructureViewer(
+          Entry<String, ViewerData> viewerData, AlignFrame af,
+          AlignmentPanel ap)
+  {
+    final ViewerData svattrib = viewerData.getValue();
+
+    /*
+     * Search for any viewer windows already open from other alignment views
+     * that exactly match the stored structure state
+     */
+    StructureViewerBase comp = findMatchingViewer(viewerData);
+
+    if (comp != null)
+    {
+      linkStructureViewer(ap, comp, svattrib);
+      return;
+    }
+
+    /*
+     * Pending an XML element for ViewerType, just check if stateData contains
+     * "chimera" (part of the chimera session filename).
+     */
+    if (svattrib.getStateData().indexOf("chimera") > -1)
+    {
+      createChimeraViewer(viewerData, af);
+    }
+    else
+    {
+      createJmolViewer(viewerData, af);
+    }
+  }
+
+  /**
+   * Create a new Chimera viewer.
+   * 
+   * @param viewerData
+   * @param af
+   */
+  protected void createChimeraViewer(Entry<String, ViewerData> viewerData,
+          AlignFrame af)
+  {
+    final ViewerData data = viewerData.getValue();
+    String chimeraSession = data.getStateData();
+
+    if (new File(chimeraSession).exists())
+    {
+      Set<Entry<File, StructureData>> fileData = data.getFileData()
+              .entrySet();
+      List<PDBEntry> pdbs = new ArrayList<PDBEntry>();
+      List<SequenceI[]> allseqs = new ArrayList<SequenceI[]>();
+      for (Entry<File, StructureData> pdb : fileData)
+      {
+        String filePath = pdb.getValue().getFilePath();
+        String pdbId = pdb.getValue().getPdbId();
+        pdbs.add(new PDBEntry(filePath, pdbId));
+        final List<SequenceI> seqList = pdb.getValue().getSeqList();
+        SequenceI[] seqs = seqList.toArray(new SequenceI[seqList.size()]);
+        allseqs.add(seqs);
+      }
+
+      boolean colourByChimera = data.isColourByViewer();
+      boolean colourBySequence = data.isColourWithAlignPanel();
+
+      // TODO can/should this be done via StructureViewer (like Jmol)?
+      final PDBEntry[] pdbArray = pdbs.toArray(new PDBEntry[pdbs
+              .size()]);
+      final SequenceI[][] seqsArray = allseqs.toArray(new SequenceI[allseqs.size()][]);
+      new ChimeraViewFrame(chimeraSession, af.alignPanel, pdbArray,
+              seqsArray,
+              colourByChimera, colourBySequence);
+    }
+    else
+    {
+      Cache.log.error("Chimera session file " + chimeraSession
+              + " not found");
+    }
+  }
+
+  /**
+   * Create a new Jmol window. First parse the Jmol state to translate filenames
+   * loaded into the view, and record the order in which files are shown in the
+   * Jmol view, so we can add the sequence mappings in same order.
+   * 
+   * @param viewerData
+   * @param af
+   */
+  protected void createJmolViewer(
+          final Entry<String, ViewerData> viewerData, AlignFrame af)
+  {
+    final ViewerData svattrib = viewerData.getValue();
+    String state = svattrib.getStateData();
+    List<String> pdbfilenames = new ArrayList<String>();
+    List<SequenceI[]> seqmaps = new ArrayList<SequenceI[]>();
+    List<String> pdbids = new ArrayList<String>();
+    StringBuilder newFileLoc = new StringBuilder(64);
+    int cp = 0, ncp, ecp;
+    Map<File, StructureData> oldFiles = svattrib.getFileData();
+    while ((ncp = state.indexOf("load ", cp)) > -1)
+    {
+      do
       {
+        // look for next filename in load statement
+        newFileLoc.append(state.substring(cp,
+                ncp = (state.indexOf("\"", ncp + 1) + 1)));
+        String oldfilenam = state.substring(ncp,
+                ecp = state.indexOf("\"", ncp));
+        // recover the new mapping data for this old filename
+        // have to normalize filename - since Jmol and jalview do
+        // filename
+        // translation differently.
+        StructureData filedat = oldFiles.get(new File(oldfilenam));
+        newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
+        pdbfilenames.add(filedat.getFilePath());
+        pdbids.add(filedat.getPdbId());
+        seqmaps.add(filedat.getSeqList()
+                .toArray(new SequenceI[0]));
+        newFileLoc.append("\"");
+        cp = ecp + 1; // advance beyond last \" and set cursor so we can
+                      // look for next file statement.
+      } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
+    }
+    if (cp > 0)
+    {
+      // just append rest of state
+      newFileLoc.append(state.substring(cp));
+    }
+    else
+    {
+      System.err.print("Ignoring incomplete Jmol state for PDB ids: ");
+      newFileLoc = new StringBuilder(state);
+      newFileLoc.append("; load append ");
+      for (File id : oldFiles.keySet())
+      {
+        // add this and any other pdb files that should be present in
+        // the viewer
+        StructureData filedat = oldFiles.get(id);
+        newFileLoc.append(filedat.getFilePath());
+        pdbfilenames.add(filedat.getFilePath());
+        pdbids.add(filedat.getPdbId());
+        seqmaps.add(filedat.getSeqList()
+                .toArray(new SequenceI[0]));
+        newFileLoc.append(" \"");
+        newFileLoc.append(filedat.getFilePath());
+        newFileLoc.append("\"");
+
+      }
+      newFileLoc.append(";");
+    }
 
-        // Instantiate the associated Jmol views
-        for (Entry<String, Object[]> entry : jmolViewIds.entrySet())
+    if (newFileLoc.length() > 0)
+    {
+      int histbug = newFileLoc.indexOf("history = ");
+      histbug += 10;
+      int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";", histbug);
+      String val = (diff == -1) ? null : newFileLoc
+              .substring(histbug, diff);
+      if (val != null && val.length() >= 4)
+      {
+        if (val.contains("e"))
         {
-          String sviewid = entry.getKey();
-          Object[] svattrib = entry.getValue();
-          int[] geom = (int[]) svattrib[0];
-          String state = (String) svattrib[1];
-          Hashtable<File, Object[]> oldFiles = (Hashtable<File, Object[]>) svattrib[2];
-          final boolean useinJmolsuperpos = ((boolean[]) svattrib[3])[0], usetoColourbyseq = ((boolean[]) svattrib[3])[1], jmolColouring = ((boolean[]) svattrib[3])[2];
-          int x = geom[0], y = geom[1], width = geom[2], height = geom[3];
-          // collate the pdbfile -> sequence mappings from this view
-          Vector<String> pdbfilenames = new Vector<String>();
-          Vector<SequenceI[]> seqmaps = new Vector<SequenceI[]>();
-          Vector<String> pdbids = new Vector<String>();
-
-          // Search to see if we've already created this Jmol view
-          AppJmol comp = null;
-          JInternalFrame[] frames = null;
-          do
+          if (val.trim().equals("true"))
           {
-            try
-            {
-              frames = Desktop.desktop.getAllFrames();
-            } catch (ArrayIndexOutOfBoundsException e)
-            {
-              // occasional No such child exceptions are thrown here...
-              frames = null;
-              try
-              {
-                Thread.sleep(10);
-              } catch (Exception f)
-              {
-              }
-              ;
-            }
-          } while (frames == null);
-          // search for any Jmol windows already open from other
-          // alignment views that exactly match the stored structure state
-          for (int f = 0; comp == null && f < frames.length; f++)
+            val = "1";
+          }
+          else
           {
-            if (frames[f] instanceof AppJmol)
-            {
-              if (sviewid != null
-                      && ((AppJmol) frames[f]).getViewId().equals(sviewid))
-              {
-                // post jalview 2.4 schema includes structure view id
-                comp = (AppJmol) frames[f];
-              }
-              else if (frames[f].getX() == x && frames[f].getY() == y
-                      && frames[f].getHeight() == height
-                      && frames[f].getWidth() == width)
-              {
-                comp = (AppJmol) frames[f];
-              }
-            }
+            val = "0";
           }
+          newFileLoc.replace(histbug, diff, val);
+        }
+      }
 
-          if (comp == null)
+      final String[] pdbf = pdbfilenames.toArray(new String[pdbfilenames
+              .size()]);
+      final String[] id = pdbids.toArray(new String[pdbids.size()]);
+      final SequenceI[][] sq = seqmaps
+              .toArray(new SequenceI[seqmaps.size()][]);
+      final String fileloc = newFileLoc.toString();
+      final String sviewid = viewerData.getKey();
+      final AlignFrame alf = af;
+      final Rectangle rect = new Rectangle(svattrib.getX(),
+              svattrib.getY(), svattrib.getWidth(), svattrib.getHeight());
+      try
+      {
+        javax.swing.SwingUtilities.invokeAndWait(new Runnable()
+        {
+          @Override
+          public void run()
           {
-            // create a new Jmol window.
-            // First parse the Jmol state to translate filenames loaded into the
-            // view, and record the order in which files are shown in the Jmol
-            // view, so we can add the sequence mappings in same order.
-            StringBuffer newFileLoc = null;
-            int cp = 0, ncp, ecp;
-            while ((ncp = state.indexOf("load ", cp)) > -1)
+            JalviewStructureDisplayI sview = null;
+            try
             {
-              if (newFileLoc == null)
-              {
-                newFileLoc = new StringBuffer();
-              }
-              do
-              {
-                // look for next filename in load statement
-                newFileLoc.append(state.substring(cp,
-                        ncp = (state.indexOf("\"", ncp + 1) + 1)));
-                String oldfilenam = state.substring(ncp,
-                        ecp = state.indexOf("\"", ncp));
-                // recover the new mapping data for this old filename
-                // have to normalize filename - since Jmol and jalview do
-                // filename
-                // translation differently.
-                Object[] filedat = oldFiles.get(new File(oldfilenam));
-                newFileLoc.append(Platform
-                        .escapeString((String) filedat[0]));
-                pdbfilenames.addElement((String) filedat[0]);
-                pdbids.addElement((String) filedat[1]);
-                seqmaps.addElement(((Vector<SequenceI>) filedat[2])
-                        .toArray(new SequenceI[0]));
-                newFileLoc.append("\"");
-                cp = ecp + 1; // advance beyond last \" and set cursor so we can
-                              // look for next file statement.
-              } while ((ncp = state.indexOf("/*file*/", cp)) > -1);
-            }
-            if (cp > 0)
+              // JAL-1333 note - we probably can't migrate Jmol views to UCSF
+              // Chimera!
+              sview = new StructureViewer(alf.alignPanel
+                      .getStructureSelectionManager()).createView(
+                      StructureViewer.ViewerType.JMOL, pdbf, id, sq,
+                      alf.alignPanel, svattrib, fileloc, rect, sviewid);
+              addNewStructureViewer(sview);
+            } catch (OutOfMemoryError ex)
             {
-              // just append rest of state
-              newFileLoc.append(state.substring(cp));
-            }
-            else
-            {
-              System.err
-                      .print("Ignoring incomplete Jmol state for PDB ids: ");
-              newFileLoc = new StringBuffer(state);
-              newFileLoc.append("; load append ");
-              for (File id : oldFiles.keySet())
+              new OOMWarning("restoring structure view for PDB id " + id,
+                      (OutOfMemoryError) ex.getCause());
+              if (sview != null && sview.isVisible())
               {
-                // add this and any other pdb files that should be present in
-                // the viewer
-                Object[] filedat = oldFiles.get(id);
-                String nfilename;
-                newFileLoc.append(((String) filedat[0]));
-                pdbfilenames.addElement((String) filedat[0]);
-                pdbids.addElement((String) filedat[1]);
-                seqmaps.addElement(((Vector<SequenceI>) filedat[2])
-                        .toArray(new SequenceI[0]));
-                newFileLoc.append(" \"");
-                newFileLoc.append((String) filedat[0]);
-                newFileLoc.append("\"");
-
+                sview.closeViewer();
+                sview.setVisible(false);
+                sview.dispose();
               }
-              newFileLoc.append(";");
             }
+          }
+        });
+      } catch (InvocationTargetException ex)
+      {
+        warn("Unexpected error when opening Jmol view.", ex);
 
-            if (newFileLoc != null)
-            {
-              int histbug = newFileLoc.indexOf("history = ");
-              histbug += 10;
-              int diff = histbug == -1 ? -1 : newFileLoc.indexOf(";",
-                      histbug);
-              String val = (diff == -1) ? null : newFileLoc.substring(
-                      histbug, diff);
-              if (val != null && val.length() >= 4)
-              {
-                if (val.contains("e"))
-                {
-                  if (val.trim().equals("true"))
-                  {
-                    val = "1";
-                  }
-                  else
-                  {
-                    val = "0";
-                  }
-                  newFileLoc.replace(histbug, diff, val);
-                }
-              }
-              // TODO: assemble String[] { pdb files }, String[] { id for each
-              // file }, orig_fileloc, SequenceI[][] {{ seqs_file 1 }, {
-              // seqs_file 2}} from hash
-              final String[] pdbf = pdbfilenames
-                      .toArray(new String[pdbfilenames.size()]), id = pdbids
-                      .toArray(new String[pdbids.size()]);
-              final SequenceI[][] sq = seqmaps
-                      .toArray(new SequenceI[seqmaps.size()][]);
-              final String fileloc = newFileLoc.toString(), vid = sviewid;
-              final AlignFrame alf = af;
-              final java.awt.Rectangle rect = new java.awt.Rectangle(x, y,
-                      width, height);
-              try
-              {
-                javax.swing.SwingUtilities.invokeAndWait(new Runnable()
-                {
-                  @Override
-                  public void run()
-                  {
-                    JalviewStructureDisplayI sview = null;
-                    try
-                    {
-                      // JAL-1333 note - we probably can't migrate Jmol views to UCSF Chimera!
-                      sview = new StructureViewer(alf.alignPanel.getStructureSelectionManager()).createView(StructureViewer.Viewer.JMOL, pdbf, id, sq, alf.alignPanel,
-                              useinJmolsuperpos, usetoColourbyseq,
-                              jmolColouring, fileloc, rect, vid);
-                      addNewStructureViewer(sview);
-                    } catch (OutOfMemoryError ex)
-                    {
-                      new OOMWarning("restoring structure view for PDB id "
-                              + id, (OutOfMemoryError) ex.getCause());
-                      if (sview != null && sview.isVisible())
-                      {
-                        sview.closeViewer();
-                        sview.setVisible(false);
-                        sview.dispose();
-                      }
-                    }
-                  }
-                });
-              } catch (InvocationTargetException ex)
-              {
-                warn("Unexpected error when opening Jmol view.", ex);
+      } catch (InterruptedException e)
+      {
+        // e.printStackTrace();
+      }
+    }
+  }
 
-              } catch (InterruptedException e)
-              {
-                // e.printStackTrace();
-              }
-            }
+  /**
+   * Returns any open frame that matches given structure viewer data. The match
+   * is based on the unique viewId, or (for older project versions) the frame's
+   * geometry.
+   * 
+   * @param viewerData
+   * @return
+   */
+  protected StructureViewerBase findMatchingViewer(
+          Entry<String, ViewerData> viewerData)
+  {
+    final String sviewid = viewerData.getKey();
+    final ViewerData svattrib = viewerData.getValue();
+    StructureViewerBase comp = null;
+    JInternalFrame[] frames = getAllFrames();
+    for (JInternalFrame frame : frames)
+    {
+      if (frame instanceof StructureViewerBase)
+      {
+        /*
+         * Post jalview 2.4 schema includes structure view id
+         */
+        if (sviewid != null
+                && ((StructureViewerBase) frame).getViewId().equals(
+                        sviewid))
+        {
+          comp = (AppJmol) frame;
+          // todo: break?
+        }
+        /*
+         * Otherwise test for matching position and size of viewer frame
+         */
+        else if (frame.getX() == svattrib.getX()
+                && frame.getY() == svattrib.getY()
+                && frame.getHeight() == svattrib.getHeight()
+                && frame.getWidth() == svattrib.getWidth())
+        {
+          comp = (AppJmol) frame;
+          // todo: break?
+        }
+      }
+    }
+    return comp;
+  }
 
-          }
-          else
-          // if (comp != null)
-          {
-            // NOTE: if the jalview project is part of a shared session then
-            // view synchronization should/could be done here.
+  /**
+   * Link an AlignmentPanel to an existing structure viewer.
+   * 
+   * @param ap
+   * @param viewer
+   * @param oldFiles
+   * @param useinViewerSuperpos
+   * @param usetoColourbyseq
+   * @param viewerColouring
+   */
+  protected void linkStructureViewer(AlignmentPanel ap,
+          StructureViewerBase viewer, ViewerData svattrib)
+  {
+    // NOTE: if the jalview project is part of a shared session then
+    // view synchronization should/could be done here.
 
-            // add mapping for sequences in this view to an already open Jmol
-            // instance
-            for (File id : oldFiles.keySet())
-            {
-              // add this and any other pdb files that should be present in the
-              // viewer
-              Object[] filedat = oldFiles.get(id);
-              String pdbFile = (String) filedat[0];
-              SequenceI[] seq = ((Vector<SequenceI>) filedat[2])
-                      .toArray(new SequenceI[0]);
-              comp.jmb.ssm.setMapping(seq, null, pdbFile,
-                      jalview.io.AppletFormatAdapter.FILE);
-              comp.jmb.addSequenceForStructFile(pdbFile, seq);
-            }
-            // and add the AlignmentPanel's reference to the Jmol view
-            comp.addAlignmentPanel(ap);
-            if (useinJmolsuperpos)
-            {
-              comp.useAlignmentPanelForSuperposition(ap);
-            }
-            else
-            {
-              comp.excludeAlignmentPanelForSuperposition(ap);
-            }
-            if (usetoColourbyseq)
-            {
-              comp.useAlignmentPanelForColourbyseq(ap, !jmolColouring);
-            }
-            else
-            {
-              comp.excludeAlignmentPanelForColourbyseq(ap);
-            }
-          }
+    final boolean useinViewerSuperpos = svattrib.isAlignWithPanel();
+    final boolean usetoColourbyseq = svattrib.isColourWithAlignPanel();
+    final boolean viewerColouring = svattrib.isColourByViewer();
+    Map<File, StructureData> oldFiles = svattrib.getFileData();
+
+    /*
+     * Add mapping for sequences in this view to an already open viewer
+     */
+    final AAStructureBindingModel binding = viewer.getBinding();
+    for (File id : oldFiles.keySet())
+    {
+      // add this and any other pdb files that should be present in the
+      // viewer
+      StructureData filedat = oldFiles.get(id);
+      String pdbFile = filedat.getFilePath();
+      SequenceI[] seq = filedat.getSeqList().toArray(new SequenceI[0]);
+      binding.getSsm().setMapping(seq, null, pdbFile,
+              jalview.io.AppletFormatAdapter.FILE);
+      binding.addSequenceForStructFile(pdbFile, seq);
+    }
+    // and add the AlignmentPanel's reference to the view panel
+    viewer.addAlignmentPanel(ap);
+    if (useinViewerSuperpos)
+    {
+      viewer.useAlignmentPanelForSuperposition(ap);
+    }
+    else
+    {
+      viewer.excludeAlignmentPanelForSuperposition(ap);
+    }
+    if (usetoColourbyseq)
+    {
+      viewer.useAlignmentPanelForColourbyseq(ap, !viewerColouring);
+    }
+    else
+    {
+      viewer.excludeAlignmentPanelForColourbyseq(ap);
+    }
+  }
+
+  /**
+   * Get all frames within the Desktop.
+   * 
+   * @return
+   */
+  protected JInternalFrame[] getAllFrames()
+  {
+    JInternalFrame[] frames = null;
+    // TODO is this necessary - is it safe - risk of hanging?
+    do
+    {
+      try
+      {
+        frames = Desktop.desktop.getAllFrames();
+      } catch (ArrayIndexOutOfBoundsException e)
+      {
+        // occasional No such child exceptions are thrown here...
+        try
+        {
+          Thread.sleep(10);
+        } catch (InterruptedException f)
+        {
         }
       }
-    }
-    // and finally return.
-    return af;
+    } while (frames == null);
+    return frames;
   }
 
   /**
@@ -3507,7 +3709,7 @@ public class Jalview2XML
     {
       if (view.getBgColour().startsWith("ucs"))
       {
-        cs = GetUserColourScheme(jms, view.getBgColour());
+        cs = getUserColourScheme(jms, view.getBgColour());
       }
       else if (view.getBgColour().startsWith("Annotation"))
       {
@@ -3768,7 +3970,7 @@ public class Jalview2XML
           {
             cs = new AnnotationColourGradient(
                     annAlignment.getAlignmentAnnotation()[i],
-                    GetUserColourScheme(jms,
+                    getUserColourScheme(jms,
                             viewAnnColour.getColourScheme()),
                     viewAnnColour.getAboveThreshold());
           }
@@ -3979,7 +4181,7 @@ public class Jalview2XML
     return false;
   }
 
-  public void AddToSkipList(AlignFrame af)
+  public void addToSkipList(AlignFrame af)
   {
     if (skipList == null)
     {
@@ -4060,7 +4262,7 @@ public class Jalview2XML
       // need to create or add a new dataset sequence reference to this sequence
       if (sqid != null)
       {
-        dsq = (jalview.datamodel.SequenceI) seqRefIds.get(sqid);
+        dsq = seqRefIds.get(sqid);
       }
       // check again
       if (dsq == null)
@@ -4256,7 +4458,7 @@ public class Jalview2XML
           /**
            * recover from hash
            */
-          jmap.setTo((SequenceI) seqRefIds.get(dsfor));
+          jmap.setTo(seqRefIds.get(dsfor));
         }
         else
         {
@@ -4315,7 +4517,7 @@ public class Jalview2XML
           boolean keepSeqRefs)
   {
     initSeqRefs();
-    jalview.schemabinding.version2.JalviewModel jm = SaveState(ap, null,
+    jalview.schemabinding.version2.JalviewModel jm = saveState(ap, null,
             null);
 
     if (!keepSeqRefs)
@@ -4338,7 +4540,7 @@ public class Jalview2XML
 
     viewportsAdded = new Hashtable();
 
-    AlignFrame af = LoadFromObject(jm, null, false, null);
+    AlignFrame af = loadFromObject(jm, null, false, null);
     af.alignPanels.clear();
     af.closeMenuItem_actionPerformed(true);
 
@@ -4472,14 +4674,14 @@ public class Jalview2XML
         // register sequence object so the XML parser can recover it.
         if (seqRefIds == null)
         {
-          seqRefIds = new Hashtable();
+          seqRefIds = new HashMap<String, SequenceI>();
         }
         if (seqsToIds == null)
         {
-          seqsToIds = new IdentityHashMap();
+          seqsToIds = new IdentityHashMap<SequenceI, String>();
         }
-        seqRefIds.put(jv2vobj.get(jvobj).toString(), jvobj);
-        seqsToIds.put(jvobj, id);
+        seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj);
+        seqsToIds.put((SequenceI) jvobj, id);
       }
       else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation)
       {
index ece8856..0dcde11 100644 (file)
@@ -10,6 +10,8 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding
 {
   private ChimeraViewFrame cvf;
 
+  private FeatureRenderer fr = null;
+
   public JalviewChimeraBindingModel(ChimeraViewFrame chimeraViewFrame,
           StructureSelectionManager ssm, PDBEntry[] pdbentry,
           SequenceI[][] sequenceIs, String[][] chains, String protocol)
@@ -18,13 +20,11 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding
     cvf = chimeraViewFrame;
   }
 
-  FeatureRenderer fr = null;
-
   @Override
-  public jalview.api.FeatureRenderer getFeatureRenderer(
+  public FeatureRenderer getFeatureRenderer(
           AlignmentViewPanel alignment)
   {
-    AlignmentPanel ap = (alignment == null) ? cvf.ap
+    AlignmentPanel ap = (alignment == null) ? cvf.getAlignmentPanel()
             : (AlignmentPanel) alignment;
     if (ap.av.isShowSequenceFeatures())
     {
@@ -47,10 +47,10 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding
   {
     return new SequenceRenderer(((AlignmentPanel) alignment).av);
   }
+
   @Override
   public void refreshGUI()
   {
-    // appJmolWindow.repaint();
     javax.swing.SwingUtilities.invokeLater(new Runnable()
     {
       public void run()
@@ -63,7 +63,7 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding
 
   public void updateColours(Object source)
   {
-    AlignmentPanel ap = (AlignmentPanel) source, topap;
+    AlignmentPanel ap = (AlignmentPanel) source;
     // ignore events from panels not used to colour this view
     if (!cvf.isUsedforcolourby(ap))
     {
@@ -74,24 +74,19 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding
       colourBySequence(ap.av.isShowSequenceFeatures(), ap);
     }
   }
+
   @Override
   public void releaseReferences(Object svl)
   {
-    // TODO Auto-generated method stub
-
   }
 
   @Override
   protected void releaseUIResources()
   {
-    // TODO Auto-generated method stub
-
   }
 
   @Override
   public void refreshPdbEntries()
   {
-    // TODO Auto-generated method stub
-
   }
 }
index bdc83e5..c024b1c 100755 (executable)
@@ -23,7 +23,7 @@ package jalview.gui;
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.bin.Cache;
 import jalview.gui.Help.HelpId;
-import jalview.gui.StructureViewer.Viewer;
+import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.jbgui.GPreferences;
@@ -289,7 +289,7 @@ public class Preferences extends GPreferences
     addTempFactor.setSelected(Cache.getDefault(ADD_TEMPFACT_ANN, false));
     addTempFactor.setEnabled(structSelected);
     structViewer.setSelectedItem(Cache.getDefault(STRUCTURE_DISPLAY,
-            Viewer.JMOL.name()));
+            ViewerType.JMOL.name()));
     chimeraPath.setText(Cache.getDefault(CHIMERA_PATH, ""));
     chimeraPath.addActionListener(new ActionListener()
     {
@@ -892,7 +892,7 @@ public class Preferences extends GPreferences
   @Override
   protected void structureViewer_actionPerformed(String selectedItem)
   {
-    if (!selectedItem.equals(Viewer.CHIMERA.name()))
+    if (!selectedItem.equals(ViewerType.CHIMERA.name()))
     {
       return;
     }
index d935eb7..641efcb 100644 (file)
@@ -22,10 +22,14 @@ package jalview.gui;
 
 import org.jmol.api.*;
 
+import jalview.jbgui.GStructureViewer;
+
 import java.awt.*;
 import java.awt.event.*;
+
 import javax.swing.*;
 import javax.swing.text.*;
+
 import java.util.Vector;
 
 import org.jmol.i18n.GT;
@@ -53,7 +57,7 @@ public final class ScriptWindow extends JPanel implements ActionListener,
 
   JmolViewer viewer;
 
-  AppJmol appJmol;
+  GStructureViewer appJmol;
 
   public ScriptWindow(AppJmol appJmol)
   {
index 14e1a0e..76565ce 100755 (executable)
  */
 package jalview.gui;
 
-import java.awt.*;
-import java.awt.event.*;
-
-import javax.swing.*;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.MediaTracker;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.JInternalFrame;
+import javax.swing.JLayeredPane;
+import javax.swing.JPanel;
+import javax.swing.JTextPane;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkListener;
 
@@ -172,8 +182,8 @@ public class SplashScreen extends JPanel implements Runnable,
       authlist.setSize(new Dimension(750, 375));
       add(authlist, BorderLayout.CENTER);
       revalidate();
-      iframe.setBounds((int) ((Desktop.instance.getWidth() - 750) / 2),
-              (int) ((Desktop.instance.getHeight() - 375) / 2), 750,
+      iframe.setBounds((Desktop.instance.getWidth() - 750) / 2,
+              (Desktop.instance.getHeight() - 375) / 2, 750,
               authlist.getHeight() + iconimg.getHeight());
       iframe.validate();
       iframe.setVisible(true);
index 22f12ea..b3b1962 100644 (file)
@@ -24,6 +24,7 @@ import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.ViewerData;
 import jalview.structure.StructureSelectionManager;
 
 import java.awt.Rectangle;
@@ -41,19 +42,19 @@ public class StructureViewer
 {
   StructureSelectionManager ssm;
 
-  public enum Viewer
+  public enum ViewerType
   {
     JMOL, CHIMERA
   };
 
-  public Viewer getViewerType()
+  public ViewerType getViewerType()
   {
     String viewType = Cache.getDefault(Preferences.STRUCTURE_DISPLAY,
-            Viewer.JMOL.name());
-    return Viewer.valueOf(viewType);
+            ViewerType.JMOL.name());
+    return ViewerType.valueOf(viewType);
   }
 
-  public void setViewerType(Viewer type)
+  public void setViewerType(ViewerType type)
   {
     Cache.setProperty(Preferences.STRUCTURE_DISPLAY, type.name());
   }
@@ -69,15 +70,15 @@ public class StructureViewer
     return viewStructures(getViewerType(), ap, pr, collateForPDB);
   }
 
-  public JalviewStructureDisplayI viewStructures(Viewer viewerType,
+  public JalviewStructureDisplayI viewStructures(ViewerType viewerType,
           AlignmentPanel ap, PDBEntry[] pr, SequenceI[][] collateForPDB)
   {
     JalviewStructureDisplayI sview = null;
-    if (viewerType.equals(Viewer.JMOL))
+    if (viewerType.equals(ViewerType.JMOL))
     {
       sview = new AppJmol(ap, pr, ap.av.collateForPDB(pr));
     }
-    else if (viewerType.equals(Viewer.CHIMERA))
+    else if (viewerType.equals(ViewerType.CHIMERA))
     {
       sview = new ChimeraViewFrame(ap, pr, ap.av.collateForPDB(pr));
     }
@@ -89,15 +90,15 @@ public class StructureViewer
     return sview;
   }
 
-  public JalviewStructureDisplayI viewStructures(Viewer viewerType,
+  public JalviewStructureDisplayI viewStructures(ViewerType viewerType,
           AlignmentPanel ap, PDBEntry pr, SequenceI[] collateForPDB)
   {
     JalviewStructureDisplayI sview = null;
-    if (viewerType.equals(Viewer.JMOL))
+    if (viewerType.equals(ViewerType.JMOL))
     {
       sview = new AppJmol(pr, collateForPDB, null, ap);
     }
-    else if (viewerType.equals(Viewer.CHIMERA))
+    else if (viewerType.equals(ViewerType.CHIMERA))
     {
       sview = new ChimeraViewFrame(pr, collateForPDB, null, ap);
     }
@@ -115,24 +116,42 @@ public class StructureViewer
     return viewStructures(getViewerType(), ap, pdb, sequenceIs);
   }
 
-  public JalviewStructureDisplayI createView(Viewer viewer, String[] pdbf,
-          String[] id, SequenceI[][] sq, AlignmentPanel alignPanel,
-          boolean useinJmolsuperpos, boolean usetoColourbyseq,
-          boolean jmolColouring, String fileloc, Rectangle rect, String vid)
+  /**
+   * Create a new panel controlling a structure viewer.
+   * 
+   * @param type
+   * @param pdbf
+   * @param id
+   * @param sq
+   * @param alignPanel
+   * @param viewerData
+   * @param fileloc
+   * @param rect
+   * @param vid
+   * @return
+   */
+  public JalviewStructureDisplayI createView(ViewerType type,
+          String[] pdbf, String[] id, SequenceI[][] sq,
+          AlignmentPanel alignPanel, ViewerData viewerData, String fileloc,
+          Rectangle rect, String vid)
   {
+    final boolean useinViewerSuperpos = viewerData.isAlignWithPanel();
+    final boolean usetoColourbyseq = viewerData.isColourWithAlignPanel();
+    final boolean viewerColouring = viewerData.isColourByViewer();
+
     JalviewStructureDisplayI sview = null;
-    switch (viewer)
+    switch (type)
     {
     case JMOL:
-      sview = new AppJmol(pdbf, id, sq, alignPanel, useinJmolsuperpos,
-              usetoColourbyseq, jmolColouring, fileloc, rect, vid);
+      sview = new AppJmol(pdbf, id, sq, alignPanel, usetoColourbyseq,
+              useinViewerSuperpos, viewerColouring, fileloc, rect, vid);
       break;
     case CHIMERA:
       Cache.log.error("Unsupported structure viewer type "
-              + viewer.toString());
+              + type.toString());
       break;
     default:
-      Cache.log.error("Unknown structure viewer type " + viewer.toString());
+      Cache.log.error("Unknown structure viewer type " + type.toString());
     }
     return sview;
   }
diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java
new file mode 100644 (file)
index 0000000..13af0e8
--- /dev/null
@@ -0,0 +1,225 @@
+package jalview.gui;
+
+import jalview.gui.ViewSelectionMenu.ViewSetProvider;
+import jalview.jbgui.GStructureViewer;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.JMenuItem;
+
+/**
+ * Base class with common functionality for JMol, Chimera or other structure
+ * viewers.
+ * 
+ * @author gmcarstairs
+ *
+ */
+public abstract class StructureViewerBase extends GStructureViewer
+        implements Runnable, ViewSetProvider
+{
+
+  /**
+   * list of sequenceSet ids associated with the view
+   */
+  protected List<String> _aps = new ArrayList<String>();
+  /**
+   * list of alignment panels to use for superposition
+   */
+  protected Vector<AlignmentPanel> _alignwith = new Vector<AlignmentPanel>();
+  /**
+   * list of alignment panels that are used for colouring structures by aligned
+   * sequences
+   */
+  protected Vector<AlignmentPanel> _colourwith = new Vector<AlignmentPanel>();
+  private String viewId = null;
+  private AlignmentPanel ap;
+
+  /**
+   * 
+   * @param ap2
+   * @return true if this Jmol instance is linked with the given alignPanel
+   */
+  public boolean isLinkedWith(AlignmentPanel ap2)
+  {
+    return _aps.contains(ap2.av.getSequenceSetId());
+  }
+
+  public boolean isUsedforaligment(AlignmentPanel ap2)
+  {
+  
+    return (_alignwith != null) && _alignwith.contains(ap2);
+  }
+
+  public boolean isUsedforcolourby(AlignmentPanel ap2)
+  {
+    return (_colourwith != null) && _colourwith.contains(ap2);
+  }
+
+  /**
+   * 
+   * @return TRUE if the view is NOT being coloured by the alignment colours.
+   */
+  public boolean isColouredByViewer()
+  {
+    return !getBinding().isColourBySequence();
+  }
+
+  public String getViewId()
+  {
+    if (viewId == null)
+    {
+      viewId = System.currentTimeMillis() + "." + this.hashCode();
+    }
+    return viewId;
+  }
+
+  protected void setViewId(String viewId)
+  {
+    this.viewId = viewId;
+  }
+
+  public abstract String getStateInfo();
+
+  protected void buildActionMenu()
+  {
+    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);
+      }
+    }
+  }
+
+  public AlignmentPanel getAlignmentPanel()
+  {
+    return ap;
+  }
+
+  protected void setAlignmentPanel(AlignmentPanel alp)
+  {
+    this.ap = alp;
+  }
+
+  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
+   * 
+   * @param nap
+   */
+  public void addAlignmentPanel(AlignmentPanel nap)
+  {
+    if (getAlignmentPanel() == null)
+    {
+      setAlignmentPanel(nap);
+    }
+    if (!_aps.contains(nap.av.getSequenceSetId()))
+    {
+      _aps.add(nap.av.getSequenceSetId());
+    }
+  }
+
+  /**
+   * remove any references held to the given alignment panel
+   * 
+   * @param nap
+   */
+  public void removeAlignmentPanel(AlignmentPanel nap)
+  {
+    try
+    {
+      _alignwith.remove(nap);
+      _colourwith.remove(nap);
+      if (getAlignmentPanel() == nap)
+      {
+        setAlignmentPanel(null);
+        for (AlignmentPanel aps : getAllAlignmentPanels())
+        {
+          if (aps != nap)
+          {
+            setAlignmentPanel(aps);
+            break;
+          }
+        }
+      }
+    } catch (Exception ex)
+    {
+    }
+    if (getAlignmentPanel() != null)
+    {
+      buildActionMenu();
+    }
+  }
+
+  public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
+  {
+    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);
+    getBinding().setColourBySequence(enableColourBySeq);
+    seqColour.setSelected(enableColourBySeq);
+    viewerColour.setSelected(!enableColourBySeq);
+  }
+
+  public void useAlignmentPanelForColourbyseq(AlignmentPanel nap)
+  {
+    addAlignmentPanel(nap);
+    if (!_colourwith.contains(nap))
+    {
+      _colourwith.add(nap);
+    }
+  }
+
+  public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
+  {
+    if (_colourwith.contains(nap))
+    {
+      _colourwith.remove(nap);
+    }
+  }
+}
index 833f590..0285bf0 100755 (executable)
@@ -277,7 +277,7 @@ public class FileLoader implements Runnable
                   .println("IMPLEMENTATION ERROR: Cannot read consecutive Jalview XML projects from a stream.");
           // We read the data anyway - it might make sense.
         }
-        alignFrame = new Jalview2XML(raiseGUI).LoadJalviewAlign(file);
+        alignFrame = new Jalview2XML(raiseGUI).loadJalviewAlign(file);
       }
       else
       {
index 6293a1b..90447db 100644 (file)
@@ -1304,7 +1304,7 @@ public class VamsasAppDatastore
             };
             if (dojvsync)
             {
-              fromxml.LoadJalviewAlign(jprovider);
+              fromxml.loadJalviewAlign(jprovider);
             }
           } catch (Exception e)
           {
@@ -1352,7 +1352,7 @@ public class VamsasAppDatastore
           };
           if (dojvsync)
           {
-            fromxml.LoadJalviewAlign(jarstream);
+            fromxml.loadJalviewAlign(jarstream);
           }
         } catch (Exception e)
         {
@@ -1498,7 +1498,7 @@ public class VamsasAppDatastore
         jxml.setSkipList(skipList);
         if (dojvsync)
         {
-          jxml.SaveState(new JarOutputStream(cappdata
+          jxml.saveState(new JarOutputStream(cappdata
                   .getClientOutputStream()));
         }
 
index 610f32e..3596619 100755 (executable)
@@ -21,7 +21,7 @@
 package jalview.jbgui;
 
 import jalview.gui.JvSwingUtils;
-import jalview.gui.StructureViewer.Viewer;
+import jalview.gui.StructureViewer.ViewerType;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -780,8 +780,8 @@ public class GPreferences extends JPanel
 
     structViewer.setFont(verdana11);
     structViewer.setBounds(new Rectangle(160, ypos, 120, height));
-    structViewer.addItem(Viewer.JMOL.name());
-    structViewer.addItem(Viewer.CHIMERA.name());
+    structViewer.addItem(ViewerType.JMOL.name());
+    structViewer.addItem(ViewerType.CHIMERA.name());
     structViewer.addActionListener(new ActionListener()
     {
       @Override
index 58b2eb1..24e7ee3 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.jbgui;
 
+import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.util.MessageManager;
 
 import java.awt.event.ActionEvent;
@@ -32,8 +33,52 @@ import javax.swing.JMenuBar;
 import javax.swing.JMenuItem;
 import javax.swing.JRadioButtonMenuItem;
 
-public class GStructureViewer extends JInternalFrame
+public abstract class GStructureViewer extends JInternalFrame implements
+        JalviewStructureDisplayI
 {
+  // private AAStructureBindingModel bindingModel;
+
+  protected JMenu savemenu = new JMenu();
+
+  protected JMenu viewMenu = new JMenu();
+
+  protected JMenu chainMenu = new JMenu();
+
+  protected JMenu viewerActionMenu = new JMenu();
+
+  protected JMenuItem alignStructs = new JMenuItem();
+
+  protected JRadioButtonMenuItem seqColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem chainColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem chargeColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem zappoColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem taylorColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem hydroColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem strandColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem helixColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem turnColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem buriedColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem purinePyrimidineColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem userColour = new JRadioButtonMenuItem();
+
+  protected JRadioButtonMenuItem viewerColour = new JRadioButtonMenuItem();
+
+  protected JMenuItem helpItem = new JMenuItem();
+
+  /**
+   * Constructor
+   */
   public GStructureViewer()
   {
     try
@@ -47,10 +92,16 @@ public class GStructureViewer extends JInternalFrame
 
   private void jbInit() throws Exception
   {
+    JMenuBar menuBar = new JMenuBar();
     this.setJMenuBar(menuBar);
+
+    JMenu fileMenu = new JMenu();
     fileMenu.setText(MessageManager.getString("action.file"));
+
     savemenu.setActionCommand(MessageManager.getString("action.save_image"));
     savemenu.setText(MessageManager.getString("action.save_as"));
+
+    JMenuItem pdbFile = new JMenuItem();
     pdbFile.setText(MessageManager.getString("label.pdb_file"));
     pdbFile.addActionListener(new ActionListener()
     {
@@ -59,6 +110,8 @@ public class GStructureViewer extends JInternalFrame
         pdbFile_actionPerformed(actionEvent);
       }
     });
+
+    JMenuItem png = new JMenuItem();
     png.setText("PNG");
     png.addActionListener(new ActionListener()
     {
@@ -67,6 +120,8 @@ public class GStructureViewer extends JInternalFrame
         png_actionPerformed(actionEvent);
       }
     });
+
+    JMenuItem eps = new JMenuItem();
     eps.setText("EPS");
     eps.addActionListener(new ActionListener()
     {
@@ -75,6 +130,8 @@ public class GStructureViewer extends JInternalFrame
         eps_actionPerformed(actionEvent);
       }
     });
+
+    JMenuItem viewMapping = new JMenuItem();
     viewMapping.setText(MessageManager.getString("label.view_mapping"));
     viewMapping.addActionListener(new ActionListener()
     {
@@ -85,7 +142,11 @@ public class GStructureViewer extends JInternalFrame
     });
     viewMenu.setText(MessageManager.getString("action.view"));
     chainMenu.setText(MessageManager.getString("action.show_chain"));
+
+    JMenu colourMenu = new JMenu();
     colourMenu.setText(MessageManager.getString("label.colours"));
+
+    JMenuItem backGround = new JMenuItem();
     backGround.setText(MessageManager.getString("label.background_colour")
             + "...");
     backGround.addActionListener(new ActionListener()
@@ -207,6 +268,8 @@ public class GStructureViewer extends JInternalFrame
         viewerColour_actionPerformed(actionEvent);
       }
     });
+
+    JMenu helpMenu = new JMenu();
     helpMenu.setText(MessageManager.getString("action.help"));
     helpItem.setText(MessageManager.getString("label.jmol_help"));
     helpItem.addActionListener(new ActionListener()
@@ -254,6 +317,8 @@ public class GStructureViewer extends JInternalFrame
     colourMenu.add(viewerColour);
     colourMenu.add(backGround);
 
+    ButtonGroup colourButtons = new ButtonGroup();
+
     colourButtons.add(seqColour);
     colourButtons.add(chainColour);
     colourButtons.add(chargeColour);
@@ -279,66 +344,6 @@ public class GStructureViewer extends JInternalFrame
   {
   }
 
-  JMenuBar menuBar = new JMenuBar();
-
-  JMenu fileMenu = new JMenu();
-
-  protected JMenu savemenu = new JMenu();
-
-  JMenuItem pdbFile = new JMenuItem();
-
-  JMenuItem png = new JMenuItem();
-
-  JMenuItem eps = new JMenuItem();
-
-  JMenuItem viewMapping = new JMenuItem();
-
-  protected JMenu viewMenu = new JMenu();
-
-  protected JMenu chainMenu = new JMenu();
-
-  JMenu jMenu1 = new JMenu();
-
-  protected JMenu colourMenu = new JMenu();
-
-  protected JMenu viewerActionMenu = new JMenu();
-
-  protected JMenuItem alignStructs = new JMenuItem();
-
-  JMenuItem backGround = new JMenuItem();
-
-  protected JRadioButtonMenuItem seqColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem chainColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem chargeColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem zappoColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem taylorColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem hydroColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem strandColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem helixColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem turnColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem buriedColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem purinePyrimidineColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem userColour = new JRadioButtonMenuItem();
-
-  protected JRadioButtonMenuItem viewerColour = new JRadioButtonMenuItem();
-
-  protected ButtonGroup colourButtons = new ButtonGroup();
-
-  JMenu helpMenu = new JMenu();
-
-  protected JMenuItem helpItem = new JMenuItem();
-
   public void pdbFile_actionPerformed(ActionEvent actionEvent)
   {
 
@@ -428,4 +433,14 @@ public class GStructureViewer extends JInternalFrame
   {
 
   }
+
+  // {
+  // return bindingModel;
+  // }
+
+  // public void setBindingModel(AAStructureBindingModel bindingModel)
+  // {
+  // this.bindingModel = bindingModel;
+  // }
+
 }
diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java
new file mode 100644 (file)
index 0000000..664c903
--- /dev/null
@@ -0,0 +1,364 @@
+package jalview.structures.models;
+
+import jalview.api.StructureSelectionManagerProvider;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.structure.StructureListener;
+import jalview.structure.StructureSelectionManager;
+import jalview.util.MessageManager;
+
+import java.awt.event.ComponentEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A base class to hold common function for protein structure model binding.
+ * Initial version created by refactoring JMol and Chimera binding models, but
+ * other structure viewers could in principle be accommodated in future.
+ * 
+ * @author gmcarstairs
+ *
+ */
+public abstract class AAStructureBindingModel extends
+        SequenceStructureBindingModel implements StructureListener,
+        StructureSelectionManagerProvider
+{
+
+  private StructureSelectionManager ssm;
+
+  private PDBEntry[] pdbEntry;
+
+  /*
+   * sequences mapped to each pdbentry
+   */
+  private SequenceI[][] sequence;
+
+  /*
+   * array of target chains for sequences - tied to pdbentry and sequence[]
+   */
+  private String[][] chains;
+
+  /*
+   * datasource protocol for access to PDBEntrylatest
+   */
+  String protocol = null;
+
+  protected boolean colourBySequence = true;
+
+  /**
+   * Constructor
+   * 
+   * @param ssm
+   * @param seqs
+   */
+  public AAStructureBindingModel(StructureSelectionManager ssm,
+          SequenceI[][] seqs)
+  {
+    this.ssm = ssm;
+    this.sequence = seqs;
+  }
+
+  /**
+   * Constructor
+   * 
+   * @param ssm
+   * @param pdbentry
+   * @param sequenceIs
+   * @param chains
+   * @param protocol
+   */
+  public AAStructureBindingModel(StructureSelectionManager ssm,
+          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
+          String protocol)
+  {
+    this.ssm = ssm;
+    this.sequence = sequenceIs;
+    this.chains = chains;
+    this.pdbEntry = pdbentry;
+    this.protocol = protocol;
+    if (chains == null)
+    {
+      this.chains = new String[pdbentry.length][];
+    }
+  }
+
+  public StructureSelectionManager getSsm()
+  {
+    return ssm;
+  }
+
+  /**
+   * Returns the i'th PDBEntry (or null)
+   * 
+   * @param i
+   * @return
+   */
+  public PDBEntry getPdbEntry(int i)
+  {
+    return (pdbEntry != null && pdbEntry.length > i) ? pdbEntry[i] : null;
+  }
+
+  /**
+   * Returns the number of modelled PDB file entries.
+   * 
+   * @return
+   */
+  public int getPdbCount()
+  {
+    return pdbEntry == null ? 0 : pdbEntry.length;
+  }
+
+  public SequenceI[][] getSequence()
+  {
+    return sequence;
+  }
+
+  public String[][] getChains()
+  {
+    return chains;
+  }
+
+  public String getProtocol()
+  {
+    return protocol;
+  }
+
+  // TODO may remove this if calling methods can be pulled up here
+  protected void setPdbentry(PDBEntry[] pdbentry)
+  {
+    this.pdbEntry = pdbentry;
+  }
+
+  protected void setSequence(SequenceI[][] sequence)
+  {
+    this.sequence = sequence;
+  }
+
+  protected void setChains(String[][] chains)
+  {
+    this.chains = chains;
+  }
+
+  /**
+   * Construct a title string for the viewer window based on the data Jalview
+   * knows about
+   * @param viewerName TODO
+   * @param verbose
+   * 
+   * @return
+   */
+  public String getViewerTitle(String viewerName, boolean verbose)
+  {
+    if (getSequence() == null || getSequence().length < 1
+            || getPdbCount() < 1
+            || getSequence()[0].length < 1)
+    {
+      return ("Jalview " + viewerName + " Window");
+    }
+    // TODO: give a more informative title when multiple structures are
+    // displayed.
+    StringBuilder title = new StringBuilder(64);
+    final PDBEntry pdbEntry = getPdbEntry(0);
+    title.append(viewerName + " view for " + getSequence()[0][0].getName()
+            + ":"
+            + pdbEntry.getId());
+  
+    if (verbose)
+    {
+      if (pdbEntry.getProperty() != null)
+      {
+        if (pdbEntry.getProperty().get("method") != null)
+        {
+          title.append(" Method: ");
+          title.append(pdbEntry.getProperty().get("method"));
+        }
+        if (pdbEntry.getProperty().get("chains") != null)
+        {
+          title.append(" Chain:");
+          title.append(pdbEntry.getProperty().get("chains"));
+        }
+      }
+    }
+    return title.toString();
+  }
+
+  /**
+   * Called by after closeViewer is called, to release any resources and
+   * references so they can be garbage collected. Override if needed.
+   */
+  protected void releaseUIResources()
+  {
+
+  }
+
+  public boolean isColourBySequence()
+  {
+    return colourBySequence;
+  }
+
+  public void setColourBySequence(boolean colourBySequence)
+  {
+    this.colourBySequence = colourBySequence;
+  }
+
+  protected void addSequenceAndChain(int pe, SequenceI[] seq,
+          String[] tchain)
+  {
+    if (pe < 0 || pe >= getPdbCount())
+    {
+      throw new Error(MessageManager.formatMessage(
+              "error.implementation_error_no_pdbentry_from_index",
+              new Object[]
+              { Integer.valueOf(pe).toString() }));
+    }
+    final String nullChain = "TheNullChain";
+    List<SequenceI> s = new ArrayList<SequenceI>();
+    List<String> c = new ArrayList<String>();
+    if (getChains() == null)
+    {
+      setChains(new String[getPdbCount()][]);
+    }
+    if (getSequence()[pe] != null)
+    {
+      for (int i = 0; i < getSequence()[pe].length; i++)
+      {
+        s.add(getSequence()[pe][i]);
+        if (getChains()[pe] != null)
+        {
+          if (i < getChains()[pe].length)
+          {
+            c.add(getChains()[pe][i]);
+          }
+          else
+          {
+            c.add(nullChain);
+          }
+        }
+        else
+        {
+          if (tchain != null && tchain.length > 0)
+          {
+            c.add(nullChain);
+          }
+        }
+      }
+    }
+    for (int i = 0; i < seq.length; i++)
+    {
+      if (!s.contains(seq[i]))
+      {
+        s.add(seq[i]);
+        if (tchain != null && i < tchain.length)
+        {
+          c.add(tchain[i] == null ? nullChain : tchain[i]);
+        }
+      }
+    }
+    SequenceI[] tmp = s.toArray(new SequenceI[s.size()]);
+    getSequence()[pe] = tmp;
+    if (c.size() > 0)
+    {
+      String[] tch = c.toArray(new String[c.size()]);
+      for (int i = 0; i < tch.length; i++)
+      {
+        if (tch[i] == nullChain)
+        {
+          tch[i] = null;
+        }
+      }
+      getChains()[pe] = tch;
+    }
+    else
+    {
+      getChains()[pe] = null;
+    }
+  }
+
+  /**
+   * add structures and any known sequence associations
+   * 
+   * @returns the pdb entries added to the current set.
+   */
+  public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe, SequenceI[][] seq,
+          String[][] chns)
+  {
+    List<PDBEntry> v = new ArrayList<PDBEntry>();
+    List<int[]> rtn = new ArrayList<int[]>();
+    for (int i = 0; i < getPdbCount(); i++)
+    {
+      v.add(getPdbEntry(i));
+    }
+    for (int i = 0; i < pdbe.length; i++)
+    {
+      int r = v.indexOf(pdbe[i]);
+      if (r == -1 || r >= getPdbCount())
+      {
+        rtn.add(new int[]
+        { v.size(), i });
+        v.add(pdbe[i]);
+      }
+      else
+      {
+        // just make sure the sequence/chain entries are all up to date
+        addSequenceAndChain(r, seq[i], chns[i]);
+      }
+    }
+    pdbe = v.toArray(new PDBEntry[v.size()]);
+    setPdbentry(pdbe);
+    if (rtn.size() > 0)
+    {
+      // expand the tied sequence[] and string[] arrays
+      SequenceI[][] sqs = new SequenceI[getPdbCount()][];
+      String[][] sch = new String[getPdbCount()][];
+      System.arraycopy(getSequence(), 0, sqs, 0, getSequence().length);
+      System.arraycopy(getChains(), 0, sch, 0, this.getChains().length);
+      setSequence(sqs);
+      setChains(sch);
+      pdbe = new PDBEntry[rtn.size()];
+      for (int r = 0; r < pdbe.length; r++)
+      {
+        int[] stri = (rtn.get(r));
+        // record the pdb file as a new addition
+        pdbe[r] = getPdbEntry(stri[0]);
+        // and add the new sequence/chain entries
+        addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
+      }
+    }
+    else
+    {
+      pdbe = null;
+    }
+    return pdbe;
+  }
+
+  /**
+   * Add sequences to the pe'th pdbentry's sequence set.
+   * 
+   * @param pe
+   * @param seq
+   */
+  public void addSequence(int pe, SequenceI[] seq)
+  {
+    addSequenceAndChain(pe, seq, null);
+  }
+
+  /**
+   * add the given sequences to the mapping scope for the given pdb file handle
+   * 
+   * @param pdbFile
+   *          - pdbFile identifier
+   * @param seq
+   *          - set of sequences it can be mapped to
+   */
+  public void addSequenceForStructFile(String pdbFile, SequenceI[] seq)
+  {
+    for (int pe = 0; pe < getPdbCount(); pe++)
+    {
+      if (getPdbEntry(pe).getFile().equals(pdbFile))
+      {
+        addSequence(pe, seq);
+      }
+    }
+  }
+
+}
\ No newline at end of file
index 7d023a8..d758726 100644 (file)
@@ -48,8 +48,8 @@ public class SequenceStructureBindingModel implements
 
   /**
    * 
-   * @return true if Jmol is still restoring state or loading is still going on
-   *         (see setFinsihedLoadingFromArchive)
+   * @return true if viewer is still restoring state or loading is still going
+   *         on (see setFinishedLoadingFromArchive)
    */
   @Override
   public boolean isLoadingFromArchive()
index 1736af5..858806b 100644 (file)
@@ -1,19 +1,14 @@
 package jalview.ext.rbvi.chimera;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertTrue;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.StructureViewer;
-import jalview.gui.StructureViewer.Viewer;
+import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.FormatAdapter;
 
-import java.awt.Desktop;
-import java.io.File;
-
-import org.junit.After;
 import org.junit.AfterClass;
-import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -58,25 +53,30 @@ public class JalviewChimeraView
       if (dsq.getPDBId()!=null && dsq.getPDBId().size()>0) {
         for (int q=0;q<dsq.getPDBId().size();q++) 
         {
-          new StructureViewer(af.getViewport().getStructureSelectionManager()).viewStructures(Viewer.JMOL,
+          new StructureViewer(af.getViewport()
+                  .getStructureSelectionManager()).viewStructures(
+                  ViewerType.JMOL,
                   af.getCurrentView().getAlignPanel(),
                   new PDBEntry[] { (PDBEntry)dsq.getPDBId().elementAt(q) },
                   new SequenceI[][] { new SequenceI[] { sq } });
 
-          new StructureViewer(af.getViewport().getStructureSelectionManager()).viewStructures(Viewer.CHIMERA,
+          new StructureViewer(af.getViewport()
+                  .getStructureSelectionManager()).viewStructures(
+                  ViewerType.CHIMERA,
                   af.getCurrentView().getAlignPanel(),
                   new PDBEntry[] { (PDBEntry)dsq.getPDBId().elementAt(q) },
                   new SequenceI[][] { new SequenceI[] { sq } });
+          // todo: break here means only once through this loop?
           break;
         }
         break;
       }
    }
-    try {
-      Thread.sleep(200000);
-    } catch (InterruptedException q)
-    {
-      
-    }
+    // try {
+      // why?
+//      Thread.sleep(200000);
+//    } catch (InterruptedException q)
+//    {
+    // }
   }
 }
index baf0654..0743581 100644 (file)
@@ -270,10 +270,10 @@ public class JpredJabaStructExportImport
     // write out parameters
     jalview.gui.AlignFrame nalf = null;
     assertTrue("Couldn't write out the Jar file",
-            new Jalview2XML(false).SaveAlignment(af,
+            new Jalview2XML(false).saveAlignment(af,
                     "testJPredWS_param.jar", "trial parameter writeout"));
     assertTrue("Couldn't read back the Jar file", (nalf = new Jalview2XML(
-            false).LoadJalviewAlign("testJpredWS_param.jar")) != null);
+            false).loadJalviewAlign("testJpredWS_param.jar")) != null);
     if (nalf != null)
     {
       AutoCalcSetting acs = af.getViewport().getCalcIdSettingsFor(
index 90997b1..5eeff50 100644 (file)
@@ -215,10 +215,10 @@ public class RNAStructExportImport
     // write out parameters
     jalview.gui.AlignFrame nalf = null;
     assertTrue("Couldn't write out the Jar file",
-            new Jalview2XML(false).SaveAlignment(af,
+            new Jalview2XML(false).saveAlignment(af,
                     "testRnalifold_param.jar", "trial parameter writeout"));
     assertTrue("Couldn't read back the Jar file", (nalf = new Jalview2XML(
-            false).LoadJalviewAlign("testRnalifold_param.jar")) != null);
+            false).loadJalviewAlign("testRnalifold_param.jar")) != null);
     if (nalf != null)
     {
       AutoCalcSetting acs = af.getViewport().getCalcIdSettingsFor(