/*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
*/
package jalview.ext.rbvi.chimera;
+import java.awt.Color;
+import java.net.BindException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import ext.edu.ucsf.rbvi.strucviz2.ChimeraManager;
+import ext.edu.ucsf.rbvi.strucviz2.ChimeraModel;
+import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
+import ext.edu.ucsf.rbvi.strucviz2.StructureManager.ModelType;
+
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.AtomSpec;
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;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import ext.edu.ucsf.rbvi.strucviz2.ChimeraManager;
-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 AAStructureBindingModel
+{
-public abstract class JalviewChimeraBinding extends
- SequenceStructureBindingModel implements StructureListener,
- SequenceStructureBinding, StructureSelectionManagerProvider
+ private static final boolean debug = false;
-{
private static final String PHOSPHORUS = "P";
private static final String ALPHACARBON = "CA";
private StructureManager csm;
+ /*
+ * Object through which we talk to Chimera
+ */
private ChimeraManager viewer;
- /**
+ /*
+ * Object which listens to Chimera notifications
+ */
+ private ChimeraListener chimeraListener;
+
+ /*
* 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;
- }
+ private List<String> atomsPicked = new ArrayList<String>();
- public void setFinishedInit(boolean finishedInit)
- {
- this.finishedInit = finishedInit;
- }
+ private List<String> chainNames;
- boolean allChainsSelected = false;
+ private Map<String, String> chainFile;
- /**
- * when true, try to search the associated datamodel for sequences that are
- * associated with any unknown structures in the Chimera view.
+ public String fileLoadingError;
+
+ /*
+ * Map of ChimeraModel objects keyed by PDB full local file name
*/
- private boolean associateNewStructs = false;
+ private Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<String, List<ChimeraModel>>();
- List<String> atomsPicked = new ArrayList<String>();
+ /*
+ * the default or current model displayed if the model cannot be identified
+ * from the selection message
+ */
+ private int frameNo = 0;
- public List<String> chainNames;
+ private String lastCommand;
- private Map<String, String> chainFile;
+ private boolean loadedInline;
/**
- * array of target chains for sequences - tied to pdbentry and sequence[]
+ * current set of model filenames loaded
*/
- protected String[][] chains;
-
- boolean colourBySequence = true;
-
- StringBuffer eval = new StringBuffer();
+ String[] modelFileNames = null;
- public String fileLoadingError;
+ String lastMousedOverAtomSpec;
- private Map<String, List<ChimeraModel>> chimmaps = new LinkedHashMap<String, List<ChimeraModel>>();
+ private List<String> lastReply;
- private List<String> mdlToFile = new ArrayList<String>();
+ /*
+ * incremented every time a load notification is successfully handled -
+ * lightweight mechanism for other threads to detect when they can start
+ * referring to new structures.
+ */
+ private long loadNotifiesHandled = 0;
/**
- * the default or current model displayed if the model cannot be identified
- * from the selection message
+ * 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
*/
- int frameNo = 0;
-
- String lastCommand;
-
- String lastMessage;
-
- boolean loadedInline;
-
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);
+ alreadyOpen = true;
+ modelsToMap.add(open);
}
- chimmaps.put(file, newList);
+ }
+
+ /*
+ * If Chimera doesn't yet have this model, ask it to open it, and retrieve
+ * the model name(s) added by Chimera.
+ */
+ if (!alreadyOpen)
+ {
+ viewer.openModel(file, pe.getId(), ModelType.PDB_MODEL);
+ List<ChimeraModel> newList = viewer.getModelList();
+ // JAL-1728 newList.removeAll(oldList) does not work
for (ChimeraModel cm : newList)
{
- while (mdlToFile.size() < 1 + cm.getModelNumber())
+ if (cm.getModelName().equals(pe.getId()))
{
- mdlToFile.add(new String(""));
+ modelsToMap.add(cm);
}
- mdlToFile.set(cm.getModelNumber(), file);
}
+ }
- 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);
+ 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"
}
/**
- * current set of model filenames loaded
- */
- String[] modelFileNames = null;
-
- public PDBEntry[] pdbentry;
-
- /**
- * datasource protocol for access to PDBEntrylatest
- */
- String protocol = null;
-
- StringBuffer resetLastRes = new StringBuffer();
-
- /**
- * sequences mapped to each pdbentry
+ * Constructor
+ *
+ * @param ssm
+ * @param pdbentry
+ * @param sequenceIs
+ * @param chains
+ * @param protocol
*/
- public SequenceI[][] sequence;
-
- public StructureSelectionManager ssm;
-
- private List<String> lastReply;
-
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));
}
+ /**
+ * Start a dedicated HttpServer to listen for Chimera notifications, and tell
+ * it to start listening
+ */
+ public void startChimeraListener()
+ {
+ try
+ {
+ chimeraListener = new ChimeraListener(this);
+ viewer.startListening(chimeraListener.getUri());
+ } catch (BindException e)
+ {
+ System.err.println("Failed to start Chimera listener: "
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * 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();
}
*/
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);
}
/**
}
/**
- * Close down the Jalview viewer, and (optionally) the associate Chimera
- * window.
+ * Close down the Jalview viewer and listener, 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();
}
+ if (this.chimeraListener != null)
+ {
+ chimeraListener.shutdown();
+ chimeraListener = null;
+ }
lastCommand = null;
viewer = null;
+
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;
{
// 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;
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)
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)
{
continue;
}
- if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
+ if (Comparison.isGap(asp.getCharAt(r)))
{
// no mapping to gaps in sequence
continue;
+ targetC[pdbfnum];
atomSpec[pdbfnum] = asp.getRNA() != null ? PHOSPHORUS : ALPHACARBON;
// move on to next pdb file
- s = sequence[pdbfnum].length;
+ s = seqCountForPdbFile;
break;
}
}
}
if (selectioncom.length() > 0)
{
- // TODO remove debug output
- System.out.println("Select regions:\n" + selectioncom.toString());
- System.out
- .println("Superimpose command(s):\n" + command.toString());
+ if (debug)
+ {
+ System.out.println("Select regions:\n" + selectioncom.toString());
+ System.out.println("Superimpose command(s):\n"
+ + command.toString());
+ }
allComs.append("~display all; chain @CA|P; ribbon "
+ selectioncom.toString() + ";"+command.toString());
// selcom.append("; ribbons; ");
{
selectioncom.setLength(selectioncom.length() - 1);
}
- System.out.println("Select regions:\n" + selectioncom.toString());
+ if (debug)
+ {
+ System.out.println("Select regions:\n" + selectioncom.toString());
+ }
allComs.append("; ~display all; chain @CA|P; ribbon "
+ selectioncom.toString() + "; focus");
// evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
{
if (!viewer.isChimeraLaunched())
{
- viewer.launchChimera(csm.getChimeraPaths());
+ viewer.launchChimera(StructureManager.getChimeraPaths());
}
if (!viewer.isChimeraLaunched())
{
}
/**
- * 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
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;
{
return;
}
- if (ssm == null)
+ if (getSsm() == null)
{
return;
}
}
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())
}
}
- 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)
{
// // 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()]);
}
/**
public abstract SequenceRenderer getSequenceRenderer(
AlignmentViewPanel alignment);
- // jmol/ssm only
+ /**
+ * Construct and send a command to highlight an atom.
+ *
+ * <pre>
+ * Done by generating a command like (to 'highlight' position 44)
+ * ~show #0:43.C;show #0:44.C
+ * Note this removes the highlight from the previous position.
+ * </pre>
+ */
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();
-
- viewerCommandHistory(false);
- // viewer.stopListening();
- if (resetLastRes.length() > 0)
+ StringBuilder sb = new StringBuilder();
+ sb.append(" #" + cms.get(0).getModelNumber());
+ sb.append(":" + pdbResNum);
+ if (!chain.equals(" "))
{
- eval.setLength(0);
- eval.append(resetLastRes.toString() + ";");
+ sb.append("." + chain);
}
+ String atomSpec = sb.toString();
- eval.append("display "); // +modelNum
-
- resetLastRes.setLength(0);
- resetLastRes.append("~display ");
+ StringBuilder command = new StringBuilder(32);
+ if (lastMousedOverAtomSpec != null)
{
- eval.append(" #" + (mdlNum));
- resetLastRes.append(" #" + (mdlNum));
+ command.append("~show " + lastMousedOverAtomSpec + ";");
}
- // complete select string
-
- eval.append(":" + pdbResNum);
- resetLastRes.append(":" + pdbResNum);
- if (!chain.equals(" "))
+ viewerCommandHistory(false);
+ command.append("show ").append(atomSpec);
+ String cmd = command.toString();
+ if (cmd.length() > 0)
{
- eval.append("." + chain);
- resetLastRes.append("." + chain);
+ viewer.stopListening(chimeraListener.getUri());
+ viewer.sendChimeraCommand(cmd, false);
+ viewer.startListening(chimeraListener.getUri());
}
-
- viewer.sendChimeraCommand(eval.toString(), false);
viewerCommandHistory(true);
- // viewer.startListening();
+ this.lastMousedOverAtomSpec = atomSpec;
}
}
- boolean debug = false;
-
- private void log(String message)
- {
- System.err.println("## Chimera log: " + message);
- }
-
- private void viewerCommandHistory(boolean enable)
- {
- // log("(Not yet implemented) History "
- // + ((debug || enable) ? "on" : "off"));
- }
-
- public void loadInline(String string)
+ /**
+ * Query Chimera for its current selection, and highlight it on the alignment
+ */
+ public void highlightChimeraSelection()
{
- loadedInline = true;
- // TODO: re JAL-623
- // viewer.loadInline(strModel, isAppend);
- // could do this:
- // construct fake fullPathName and fileName so we can identify the file
- // later.
- // Then, construct pass a reader for the string to Jmol.
- // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
- // fileName, null, reader, false, null, null, 0);
- // viewer.openStringInline(string);
- log("cannot load inline in Chimera, yet");
- }
+ /*
+ * Ask Chimera for its current selection
+ */
+ List<String> selection = viewer.getSelectedResidueSpecs();
- public void mouseOverStructure(int atomIndex, String strInfo)
- {
- // function to parse a mouseOver event from Chimera
- //
- int pdbResNum;
- int alocsep = strInfo.indexOf("^");
- int mdlSep = strInfo.indexOf("/");
- int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
-
- if (chainSeparator == -1)
+ /*
+ * Parse model number, residue and chain for each selected position,
+ * formatted as #0:123.A or #1.2:87.B (#model.submodel:residue.chain)
+ */
+ List<AtomSpec> atomSpecs = new ArrayList<AtomSpec>();
+ for (String atomSpec : selection)
{
- chainSeparator = strInfo.indexOf(".");
- if (mdlSep > -1 && mdlSep < chainSeparator)
+ int colonPos = atomSpec.indexOf(":");
+ if (colonPos == -1)
{
- chainSeparator1 = chainSeparator;
- chainSeparator = mdlSep;
+ continue; // malformed
}
- }
- // handle insertion codes
- if (alocsep != -1)
- {
- pdbResNum = Integer.parseInt(strInfo.substring(
- strInfo.indexOf("]") + 1, alocsep));
-
- }
- else
- {
- pdbResNum = Integer.parseInt(strInfo.substring(
- strInfo.indexOf("]") + 1, chainSeparator));
- }
- String chainId;
-
- if (strInfo.indexOf(":") > -1)
- {
- chainId = strInfo.substring(strInfo.indexOf(":") + 1,
- strInfo.indexOf("."));
- }
- else
- {
- chainId = " ";
- }
-
- String pdbfilename = modelFileNames[frameNo]; // default is first or current
- // model
- if (mdlSep > -1)
- {
- if (chainSeparator1 == -1)
- {
- chainSeparator1 = strInfo.indexOf(".", mdlSep);
+
+ int hashPos = atomSpec.indexOf("#");
+ String modelSubmodel = atomSpec.substring(hashPos + 1, colonPos);
+ int dotPos = modelSubmodel.indexOf(".");
+ int modelId = 0;
+ try {
+ modelId = Integer.valueOf(dotPos == -1 ? modelSubmodel
+ : modelSubmodel.substring(0, dotPos));
+ } catch (NumberFormatException e) {
+ // ignore, default to model 0
}
- String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
- chainSeparator1) : strInfo.substring(mdlSep + 1);
- try
+
+ String residueChain = atomSpec.substring(colonPos + 1);
+ dotPos = residueChain.indexOf(".");
+ int pdbResNum = Integer.parseInt(dotPos == -1 ? residueChain
+ : residueChain.substring(0, dotPos));
+
+ String chainId = dotPos == -1 ? "" : residueChain
+ .substring(dotPos + 1);
+
+ /*
+ * Work out the pdbfilename from the model number
+ */
+ String pdbfilename = modelFileNames[frameNo];
+ findfileloop: for (String pdbfile : this.chimeraMaps.keySet())
{
- // recover PDB filename for the model hovered over.
- int _mp = _modelFileNameMap.length - 1, mnumber = new Integer(mdlId)
- .intValue() - 1;
- while (mnumber < _modelFileNameMap[_mp])
+ for (ChimeraModel cm : chimeraMaps.get(pdbfile))
{
- _mp--;
- }
- pdbfilename = modelFileNames[_mp];
- if (pdbfilename == null)
- {
- // pdbfilename = new File(viewer.getModelFileName(mnumber))
- // .getAbsolutePath();
+ if (cm.getModelNumber() == modelId)
+ {
+ pdbfilename = pdbfile;
+ break findfileloop;
+ }
}
-
- } catch (Exception e)
- {
}
- ;
- }
- if (lastMessage == null || !lastMessage.equals(strInfo))
- {
- ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
+ atomSpecs.add(new AtomSpec(pdbfilename, chainId, pdbResNum, 0));
}
- lastMessage = strInfo;
+ /*
+ * Broadcast the selection (which may be empty, if the user just cleared all
+ * selections)
+ */
+ getSsm().mouseOverStructure(atomSpecs);
}
- public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
+ private void log(String message)
{
- /**
- * this implements the toggle label behaviour copied from the original
- * structure viewer, MCView
- */
- if (strData != null)
- {
- System.err.println("Ignoring additional pick data string " + strData);
- }
- // rewrite these selections for chimera (DNA, RNA and protein)
- 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)
- {
- mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
- }
- picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
- + mdlString + "))";
- viewerCommandHistory(false);
-
- if (!atomsPicked.contains(picked))
- {
- viewer.select(picked);
- atomsPicked.add(picked);
- }
- else
- {
- viewer.select("not " + picked);
- atomsPicked.remove(picked);
- }
- viewerCommandHistory(true);
- // TODO: in application this happens
- //
- // if (scriptWindow != null)
- // {
- // scriptWindow.sendConsoleMessage(strInfo);
- // scriptWindow.sendConsoleMessage("\n");
- // }
-
+ System.err.println("## Chimera log: " + message);
}
- // incremented every time a load notification is successfully handled -
- // lightweight mechanism for other threads to detect when they can start
- // referring to new structures.
- private long loadNotifiesHandled = 0;
-
- public long getLoadNotifiesHandled()
+ private void viewerCommandHistory(boolean enable)
{
- return loadNotifiesHandled;
+ // log("(Not yet implemented) History "
+ // + ((debug || enable) ? "on" : "off"));
}
- public void notifyFileLoaded(String fullPathName, String fileName2,
- String modelName, String errorMsg, int modelParts)
+ public long getLoadNotifiesHandled()
{
- if (errorMsg != null)
- {
- fileLoadingError = errorMsg;
- refreshGUI();
- return;
- }
- // TODO: deal sensibly with models loaded inLine:
- // modelName will be null, as will fullPathName.
-
- // the rest of this routine ignores the arguments, and simply interrogates
- // the Jmol view to find out what structures it contains, and adds them to
- // the structure selection manager.
- fileLoadingError = null;
- String[] oldmodels = modelFileNames;
- modelFileNames = null;
- chainNames = new ArrayList<String>();
- chainFile = new HashMap<String, String>();
- boolean notifyLoaded = false;
- String[] modelfilenames = getPdbFile();
- // first check if we've lost any structures
- if (oldmodels != null && oldmodels.length > 0)
- {
- int oldm = 0;
- for (int i = 0; i < oldmodels.length; i++)
- {
- for (int n = 0; n < modelfilenames.length; n++)
- {
- if (modelfilenames[n] == oldmodels[i])
- {
- oldmodels[i] = null;
- break;
- }
- }
- if (oldmodels[i] != null)
- {
- oldm++;
- }
- }
- if (oldm > 0)
- {
- String[] oldmfn = new String[oldm];
- oldm = 0;
- for (int i = 0; i < oldmodels.length; i++)
- {
- if (oldmodels[i] != null)
- {
- oldmfn[oldm++] = oldmodels[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);
- }
- }
-
- // register ourselves as a listener and notify the gui that it needs to
- // update itself.
- ssm.addStructureViewerListener(this);
-
- if (notifyLoaded)
- {
- FeatureRenderer fr = getFeatureRenderer(null);
- if (fr != null)
- {
- fr.featuresAdded();
- }
- refreshGUI();
- loadNotifiesHandled++;
- }
- setLoadingFromArchive(false);
+ return loadNotifiesHandled;
}
public void setJalviewColourScheme(ColourSchemeI cs)
return;
}
- String res;
int index;
Color col;
// Chimera expects RBG values in the range 0-1
final double normalise = 255D;
viewerCommandHistory(false);
// TODO: Switch between nucleotide or aa selection expressions
- Enumeration en = ResidueProperties.aa3Hash.keys();
StringBuilder command = new StringBuilder(128);
command.append("color white;");
- while (en.hasMoreElements())
+ for (String res : ResidueProperties.aa3Hash.keySet())
{
- res = en.nextElement().toString();
- index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
+ index = ResidueProperties.aa3Hash.get(res).intValue();
if (index > 20)
{
continue;
*/
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;
}
/**
- * 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;
}
}