X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fext%2Frbvi%2Fchimera%2FJalviewChimeraBinding.java;h=d7bcc6602d87e8b182914ede95f8b83e533ace3b;hb=2ab7b9b152018bb808693218ad88dc3778166492;hp=9a570fc46ed1d195904c8a73b831768c07c521bc;hpb=799c26111d6936a2e70cb5f1fd7d7312311e6db9;p=jalview.git diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index 9a570fc..d7bcc66 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -20,30 +20,26 @@ */ package jalview.ext.rbvi.chimera; -import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; -import jalview.api.FeatureRenderer; -import jalview.api.SequenceRenderer; import jalview.api.structures.JalviewStructureDisplayI; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; -import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; +import jalview.gui.Preferences; +import jalview.gui.StructureViewer.ViewerType; import jalview.httpserver.AbstractRequestHandler; import jalview.io.DataSourceType; -import jalview.schemes.ColourSchemeI; -import jalview.schemes.ResidueProperties; import jalview.structure.AtomSpec; import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; import jalview.structures.models.AAStructureBindingModel; import jalview.util.MessageManager; -import java.awt.Color; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -52,7 +48,7 @@ import java.net.BindException; import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; -import java.util.Hashtable; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -69,23 +65,16 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel // Chimera clause to exclude alternate locations in atom selection private static final String NO_ALTLOCS = "&~@.B-Z&~@.2-9"; - private static final String COLOURING_CHIMERA = MessageManager - .getString("status.colouring_chimera"); - private static final boolean debug = false; private static final String PHOSPHORUS = "P"; private static final String ALPHACARBON = "CA"; - private List chainNames = new ArrayList(); - - private Hashtable chainFile = new Hashtable(); - /* * Object through which we talk to Chimera */ - private ChimeraManager viewer; + private ChimeraManager chimeraManager; /* * Object which listens to Chimera notifications @@ -108,7 +97,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel /* * Map of ChimeraModel objects keyed by PDB full local file name */ - private Map> chimeraMaps = new LinkedHashMap>(); + private Map> chimeraMaps = new LinkedHashMap<>(); String lastHighlightCommand; @@ -124,8 +113,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel /** * 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. + * 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 @@ -135,8 +124,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel String file = pe.getFile(); try { - List modelsToMap = new ArrayList(); - List oldList = viewer.getModelList(); + List modelsToMap = new ArrayList<>(); + List oldList = chimeraManager.getModelList(); boolean alreadyOpen = false; /* @@ -157,14 +146,33 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ if (!alreadyOpen) { - viewer.openModel(file, pe.getId(), ModelType.PDB_MODEL); - List newList = viewer.getModelList(); - // JAL-1728 newList.removeAll(oldList) does not work - for (ChimeraModel cm : newList) + chimeraManager.openModel(file, pe.getId(), ModelType.PDB_MODEL); + if (chimeraManager.isChimeraX()) + { + /* + * ChimeraX hack: force chimera model name to pdbId + */ + int modelNumber = chimeraMaps.size() + 1; + String command = "setattr #" + modelNumber + " models name " + + pe.getId(); + executeCommand(command, false); + modelsToMap.add(new ChimeraModel(pe.getId(), ModelType.PDB_MODEL, + modelNumber, 0)); + } + else { - if (cm.getModelName().equals(pe.getId())) + /* + * Chimera: query for actual models and find the one with + * matching model name - set in viewer.openModel() + */ + List newList = chimeraManager.getModelList(); + // JAL-1728 newList.removeAll(oldList) does not work + for (ChimeraModel cm : newList) { - modelsToMap.add(cm); + if (cm.getModelName().equals(pe.getId())) + { + modelsToMap.add(cm); + } } } } @@ -174,13 +182,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel if (getSsm() != null) { getSsm().addStructureViewerListener(this); - // ssm.addSelectionListener(this); - FeatureRenderer fr = getFeatureRenderer(null); - if (fr != null) - { - fr.featuresAdded(); - } - refreshGUI(); } return true; } catch (Exception q) @@ -201,20 +202,24 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * @param protocol */ public JalviewChimeraBinding(StructureSelectionManager ssm, - PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol) + PDBEntry[] pdbentry, SequenceI[][] sequenceIs, + DataSourceType protocol) { super(ssm, pdbentry, sequenceIs, protocol); - viewer = new ChimeraManager(new StructureManager(true)); + chimeraManager = new ChimeraManager(new StructureManager(true)); + String viewerType = Cache.getProperty(Preferences.STRUCTURE_DISPLAY); + chimeraManager.setChimeraX(ViewerType.CHIMERAX.name().equals(viewerType)); + setStructureCommands(new ChimeraCommands()); } /** - * Starts a thread that waits for the Chimera process to finish, so that we - * can then close the associated resources. This avoids leaving orphaned - * Chimera viewer panels in Jalview if the user closes Chimera. + * Starts a thread that waits for the Chimera process to finish, so that we can + * then close the associated resources. This avoids leaving orphaned Chimera + * viewer panels in Jalview if the user closes Chimera. */ protected void startChimeraProcessMonitor() { - final Process p = viewer.getChimeraProcess(); + final Process p = chimeraManager.getChimeraProcess(); chimeraMonitor = new Thread(new Runnable() { @@ -239,57 +244,20 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /** - * Start a dedicated HttpServer to listen for Chimera notifications, and tell - * it to start listening + * 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()); + chimeraManager.startListening(chimeraListener.getUri()); } catch (BindException e) { - System.err.println("Failed to start Chimera listener: " - + e.getMessage()); - } - } - - /** - * Tells Chimera to display only the specified chains - * - * @param toshow - */ - public void showChains(List toshow) - { - /* - * Construct a chimera command like - * - * ~display #*;~ribbon #*;ribbon :.A,:.B - */ - StringBuilder cmd = new StringBuilder(64); - boolean first = true; - for (String chain : toshow) - { - int modelNumber = getModelNoForChain(chain); - String showChainCmd = modelNumber == -1 ? "" : modelNumber + ":." - + chain.split(":")[1]; - if (!first) - { - cmd.append(","); - } - cmd.append(showChainCmd); - first = false; + System.err.println( + "Failed to start Chimera listener: " + e.getMessage()); } - - /* - * could append ";focus" to this command to resize the display to fill the - * window, but it looks more helpful not to (easier to relate chains to the - * whole) - */ - final String command = "~display #*; ~ribbon #*; ribbon :" - + cmd.toString(); - sendChimeraCommand(command, false); } /** @@ -298,17 +266,17 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ public void closeViewer(boolean closeChimera) { - getSsm().removeStructureViewerListener(this, this.getPdbFile()); + getSsm().removeStructureViewerListener(this, this.getStructureFiles()); if (closeChimera) { - viewer.exitChimera(); + chimeraManager.exitChimera(); } if (this.chimeraListener != null) { chimeraListener.shutdown(); chimeraListener = null; } - viewer = null; + chimeraManager = null; if (chimeraMonitor != null) { @@ -317,39 +285,15 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel releaseUIResources(); } - @Override - public void colourByChain() - { - colourBySequence = false; - sendAsynchronousCommand("rainbow chain", COLOURING_CHIMERA); - } - - /** - * Constructs and sends a Chimera command to colour by charge - *
    - *
  • Aspartic acid and Glutamic acid (negative charge) red
  • - *
  • Lysine and Arginine (positive charge) blue
  • - *
  • Cysteine - yellow
  • - *
  • all others - white
  • - *
- */ - @Override - public void colourByCharge() - { - colourBySequence = false; - String command = "color white;color red ::ASP;color red ::GLU;color blue ::LYS;color blue ::ARG;color yellow ::CYS"; - sendAsynchronousCommand(command, COLOURING_CHIMERA); - } - /** * {@inheritDoc} */ @Override public String superposeStructures(AlignmentI[] _alignment, - int[] _refStructure, ColumnSelection[] _hiddenCols) + int[] _refStructure, HiddenColumns[] _hiddenCols) { StringBuilder allComs = new StringBuilder(128); - String[] files = getPdbFile(); + String[] files = getStructureFiles(); if (!waitForFileLoad(files)) { @@ -358,11 +302,12 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel refreshPdbEntries(); StringBuilder selectioncom = new StringBuilder(256); + boolean chimeraX = chimeraManager.isChimeraX(); for (int a = 0; a < _alignment.length; a++) { int refStructure = _refStructure[a]; AlignmentI alignment = _alignment[a]; - ColumnSelection hiddenCols = _hiddenCols[a]; + HiddenColumns hiddenCols = _hiddenCols[a]; if (refStructure >= files.length) { @@ -418,10 +363,16 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel String[] selcom = new String[files.length]; for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { + final int modelNo = pdbfnum + (chimeraX ? 1 : 0); + // todo correct resolution to model number String chainCd = "." + structures[pdbfnum].chain; int lpos = -1; boolean run = false; StringBuilder molsel = new StringBuilder(); + if (chimeraX) + { + molsel.append("/" + structures[pdbfnum].chain + ":"); + } int nextColumnMatch = matched.nextSetBit(0); while (nextColumnMatch != -1) @@ -435,7 +386,10 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel if (lpos != -1) { molsel.append(String.valueOf(lpos)); - molsel.append(chainCd); + if (!chimeraX) + { + molsel.append(chainCd); + } molsel.append(","); } run = false; @@ -465,18 +419,24 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel if (lpos != -1) { molsel.append(String.valueOf(lpos)); - molsel.append(chainCd); + if (!chimeraX) + { + molsel.append(chainCd); + } } if (molsel.length() > 1) { selcom[pdbfnum] = molsel.toString(); - selectioncom.append("#").append(String.valueOf(pdbfnum)) - .append(":"); + selectioncom.append("#").append(String.valueOf(modelNo)); + if (!chimeraX) + { + selectioncom.append(":"); + } selectioncom.append(selcom[pdbfnum]); - selectioncom.append(" "); + // selectioncom.append(" "); if (pdbfnum < files.length - 1) { - selectioncom.append("| "); + selectioncom.append("|"); } } else @@ -488,6 +448,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel StringBuilder command = new StringBuilder(256); for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { + final int modelNo = pdbfnum + (chimeraX ? 1 : 0); if (pdbfnum == refStructure || selcom[pdbfnum] == null || selcom[refStructure] == null) { @@ -507,29 +468,57 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * @see * https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/midas/match.html */ - command.append("match ").append(getModelSpec(pdbfnum)).append(":"); + command.append(chimeraX ? "align " : "match "); + command.append(getModelSpec(modelNo)); + if (!chimeraX) + { + command.append(":"); + } command.append(selcom[pdbfnum]); command.append("@").append( structures[pdbfnum].isRna ? PHOSPHORUS : ALPHACARBON); - // JAL-1757 exclude alternate CA locations - command.append(NO_ALTLOCS); - command.append(" ").append(getModelSpec(refStructure)).append(":"); + // JAL-1757 exclude alternate CA locations - ChimeraX syntax tbd + if (!chimeraX) + { + command.append(NO_ALTLOCS); + } + command.append(chimeraX ? " toAtoms " : " ") + .append(getModelSpec(refStructure + (chimeraX ? 1 : 0))); + if (!chimeraX) + { + command.append(":"); + } command.append(selcom[refStructure]); command.append("@").append( structures[refStructure].isRna ? PHOSPHORUS : ALPHACARBON); - command.append(NO_ALTLOCS); + if (!chimeraX) + { + command.append(NO_ALTLOCS); + } } if (selectioncom.length() > 0) { if (debug) { System.out.println("Select regions:\n" + selectioncom.toString()); - System.out.println("Superimpose command(s):\n" - + command.toString()); + System.out.println( + "Superimpose command(s):\n" + command.toString()); } - allComs.append("~display all; chain @CA|P; ribbon ") - .append(selectioncom.toString()) - .append(";" + command.toString()); + // allComs.append("~display all; "); + // if (chimeraX) + // { + // allComs.append("show ").append(selectioncom.toString()) + // .append(" pbonds"); + // } + // else + // { + // allComs.append("chain @CA|P; ribbon "); + // allComs.append(selectioncom.toString()); + // } + if (allComs.length() > 0) { + allComs.append(";"); + } + allComs.append(command.toString()); } } @@ -545,9 +534,20 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { System.out.println("Select regions:\n" + selectioncom.toString()); } - allComs.append("; ~display all; chain @CA|P; ribbon ") - .append(selectioncom.toString()).append("; focus"); - List chimeraReplies = sendChimeraCommand(allComs.toString(), + allComs.append(";~display all; "); + if (chimeraX) + { + allComs.append("show @CA|P pbonds; show ") + .append(selectioncom.toString()).append(" ribbons; view"); + } + else + { + allComs.append("chain @CA|P; ribbon ; focus"); + allComs.append(selectioncom.toString()); + } + // allComs.append("; ~display all; chain @CA|P; ribbon ") + // .append(selectioncom.toString()).append("; focus"); + List chimeraReplies = executeCommand(allComs.toString(), true); for (String reply : chimeraReplies) { @@ -577,7 +577,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { if (pdbfnum < 0 || pdbfnum >= getPdbCount()) { - return ""; + return "#" + pdbfnum; // temp hack for ChimeraX } /* @@ -586,7 +586,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * to the Chimera command 'list models type molecule', see * ChimeraManager.getModelList(). */ - List maps = chimeraMaps.get(getPdbFile()[pdbfnum]); + List maps = chimeraMaps.get(getStructureFiles()[pdbfnum]); boolean hasSubModels = maps != null && maps.size() > 1; return "#" + String.valueOf(pdbfnum) + (hasSubModels ? ".1" : ""); } @@ -600,13 +600,13 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ public boolean launchChimera() { - if (viewer.isChimeraLaunched()) + if (chimeraManager.isChimeraLaunched()) { return true; } - boolean launched = viewer.launchChimera(StructureManager - .getChimeraPaths()); + boolean launched = chimeraManager.launchChimera( + StructureManager.getChimeraPaths(chimeraManager.isChimeraX())); if (launched) { startChimeraProcessMonitor(); @@ -626,7 +626,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ public boolean isChimeraRunning() { - return viewer.isChimeraLaunched(); + return chimeraManager.isChimeraLaunched(); } /** @@ -638,10 +638,11 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * @param command * @param getResponse */ - public List sendChimeraCommand(final String command, + @Override + public List executeCommand(final String command, boolean getResponse) { - if (viewer == null) + if (chimeraManager == null || command == null) { // ? thread running after viewer shut down return null; @@ -651,7 +652,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel if (true /*lastCommand == null || !lastCommand.equals(command)*/) { // trim command or it may never find a match in the replyLog!! - List lastReply = viewer.sendChimeraCommand(command.trim(), + List lastReply = chimeraManager.sendChimeraCommand(command.trim(), getResponse); if (getResponse) { @@ -679,52 +680,18 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel String progressMsg); /** - * Sends a set of colour commands to the structure viewer - * - * @param colourBySequenceCommands - */ - @Override - protected void colourBySequence( - StructureMappingcommandSet[] colourBySequenceCommands) - { - for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands) - { - for (String command : cpdbbyseq.commands) - { - sendAsynchronousCommand(command, COLOURING_CHIMERA); - } - } - } - - /** - * @param files - * @param sr - * @param fr - * @param viewport - * @return - */ - @Override - protected StructureMappingcommandSet[] getColourBySequenceCommands( - String[] files, SequenceRenderer sr, FeatureRenderer fr, - AlignViewportI viewport) - { - return ChimeraCommands.getColourBySequenceCommand(getSsm(), files, - getSequence(), sr, fr, viewport); - } - - /** * @param command */ protected void executeWhenReady(String command) { waitForChimera(); - sendChimeraCommand(command, false); + executeCommand(command, false); waitForChimera(); } private void waitForChimera() { - while (viewer != null && viewer.isBusy()) + while (chimeraManager != null && chimeraManager.isBusy()) { try { @@ -752,25 +719,23 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ private int _modelFileNameMap[]; - // //////////////////////////////// // /StructureListener @Override - public synchronized String[] getPdbFile() + public synchronized String[] getStructureFiles() { - if (viewer == null) + if (chimeraManager == null) { return new String[0]; } - return chimeraMaps.keySet().toArray( - modelFileNames = new String[chimeraMaps.size()]); + return chimeraMaps.keySet() + .toArray(modelFileNames = new String[chimeraMaps.size()]); } /** - * Construct and send a command to highlight zero, one or more atoms. We do - * this by sending an "rlabel" command to show the residue label at that - * position. + * Construct and send a command to highlight zero, one or more atoms. We do this + * by sending an "rlabel" command to show the residue label at that position. */ @Override public void highlightAtoms(List atoms) @@ -780,6 +745,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel return; } + boolean forChimeraX = chimeraManager.isChimeraX(); StringBuilder cmd = new StringBuilder(128); boolean first = true; boolean found = false; @@ -794,18 +760,26 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { if (first) { - cmd.append("rlabel #").append(cms.get(0).getModelNumber()) - .append(":"); + cmd.append(forChimeraX ? "label #" : "rlabel #"); } else { cmd.append(","); } first = false; - cmd.append(pdbResNum); - if (!chain.equals(" ")) + if (forChimeraX) { - cmd.append(".").append(chain); + cmd.append(cms.get(0).getModelNumber()) + .append("/").append(chain).append(":").append(pdbResNum); + } + else + { + cmd.append(cms.get(0).getModelNumber()) + .append(":").append(pdbResNum); + if (!chain.equals(" ") && !forChimeraX) + { + cmd.append(".").append(chain); + } } found = true; } @@ -825,11 +799,11 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ if (lastHighlightCommand != null) { - viewer.sendChimeraCommand("~" + lastHighlightCommand, false); + chimeraManager.sendChimeraCommand("~" + lastHighlightCommand, false); } if (found) { - viewer.sendChimeraCommand(command, false); + chimeraManager.sendChimeraCommand(command, false); } this.lastHighlightCommand = command; } @@ -842,13 +816,14 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel /* * Ask Chimera for its current selection */ - List selection = viewer.getSelectedResidueSpecs(); + List selection = chimeraManager.getSelectedResidueSpecs(); /* * 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 atomSpecs = convertStructureResiduesToAlignment(selection); + List atomSpecs = convertStructureResiduesToAlignment( + selection); /* * Broadcast the selection (which may be empty, if the user just cleared all @@ -867,12 +842,13 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel protected List convertStructureResiduesToAlignment( List structureSelection) { - List atomSpecs = new ArrayList(); + boolean chimeraX = chimeraManager.isChimeraX(); + List atomSpecs = new ArrayList<>(); for (String atomSpec : structureSelection) { try { - AtomSpec spec = AtomSpec.fromChimeraAtomspec(atomSpec); + AtomSpec spec = AtomSpec.fromChimeraAtomspec(atomSpec, chimeraX); String pdbfilename = getPdbFileForModel(spec.getModelNumber()); spec.setPdbFile(pdbfilename); atomSpecs.add(spec); @@ -924,37 +900,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel return loadNotifiesHandled; } - @Override - public void setJalviewColourScheme(ColourSchemeI cs) - { - colourBySequence = false; - - if (cs == null) - { - return; - } - - // Chimera expects RBG values in the range 0-1 - final double normalise = 255D; - viewerCommandHistory(false); - StringBuilder command = new StringBuilder(128); - - List residueSet = ResidueProperties.getResidues(isNucleotide(), - false); - for (String resName : residueSet) - { - char res = resName.length() == 3 ? ResidueProperties - .getSingleCharacterCode(resName) : resName.charAt(0); - Color col = cs.findColour(res, 0, null, null, 0f); - command.append("color " + col.getRed() / normalise + "," - + col.getGreen() / normalise + "," + col.getBlue() - / normalise + " ::" + resName + ";"); - } - - sendAsynchronousCommand(command.toString(), COLOURING_CHIMERA); - viewerCommandHistory(true); - } - /** * called when the binding thinks the UI needs to be refreshed after a Chimera * state change. this could be because structures were loaded, or because an @@ -992,26 +937,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /** - * Send the Chimera 'background solid " command. - * - * @see https - * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/background - * .html - * @param col - */ - @Override - public void setBackgroundColour(Color col) - { - viewerCommandHistory(false); - double normalise = 255D; - final String command = "background solid " + col.getRed() / normalise - + "," + col.getGreen() / normalise + "," + col.getBlue() - / normalise + ";"; - viewer.sendChimeraCommand(command, false); - viewerCommandHistory(true); - } - - /** * Ask Chimera to save its session to the given file. Returns true if * successful, else false. * @@ -1022,7 +947,12 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { if (isChimeraRunning()) { - List reply = viewer.sendChimeraCommand("save " + filepath, + /* + * Chimera: https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/save.html + * ChimeraX: https://www.cgl.ucsf.edu/chimerax/docs/user/commands/save.html + */ + String command = isChimeraX() ? "save session " : "save "; + List reply = chimeraManager.sendChimeraCommand(command + filepath, true); if (reply.contains("Session written")) { @@ -1039,39 +969,24 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel /** * 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. + * The filename must have a .py (Chimera) or .cxs (ChimeraX) extension for + * this command to work. * * @param filepath * @return */ public boolean openSession(String filepath) { - sendChimeraCommand("open " + filepath, true); + /* + * Chimera: https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/open.html + * ChimeraX: https://www.cgl.ucsf.edu/chimerax/docs/user/commands/open.html + */ + executeCommand("open " + filepath, true); // todo: test for failure - how? return true; } /** - * Returns a list of chains mapped in this viewer. Note this list is not - * currently scoped per structure. - * - * @return - */ - @Override - public List getChainNames() - { - return chainNames; - } - - /** - * Send a 'focus' command to Chimera to recentre the visible display - */ - public void focusView() - { - sendChimeraCommand("focus", false); - } - - /** * Send a 'show' command for all atoms in the currently selected columns * * TODO: pull up to abstract structure viewer interface @@ -1110,17 +1025,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { // TODO refactor as required to pull up to an interface AlignmentI alignment = avp.getAlignment(); - FeatureRenderer fr = getFeatureRenderer(avp); - /* - * fr is null if feature display is turned off - */ - if (fr == null) - { - return 0; - } - - String[] files = getPdbFile(); + String[] files = getStructureFiles(); if (files == null) { return 0; @@ -1128,7 +1034,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel StructureMappingcommandSet commandSet = ChimeraCommands .getSetAttributeCommandsForFeatures(getSsm(), files, - getSequence(), fr, alignment); + getSequence(), avp, chimeraManager.isChimeraX()); String[] commands = commandSet.commands; if (commands.length > 10) { @@ -1145,17 +1051,18 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /** - * Write commands to a temporary file, and send a command to Chimera to open - * the file as a commands script. For use when sending a large number of - * separate commands would overload the REST interface mechanism. + * Write commands to a temporary file, and send a command to Chimera to open the + * file as a commands script. For use when sending a large number of separate + * commands would overload the REST interface mechanism. * * @param commands */ protected void sendCommandsByFile(String[] commands) { + boolean toChimeraX = chimeraManager.isChimeraX(); try { - File tmp = File.createTempFile("chim", ".com"); + File tmp = File.createTempFile("chim", toChimeraX ? ".cxc" : ".com"); tmp.deleteOnExit(); PrintWriter out = new PrintWriter(new FileOutputStream(tmp)); for (String command : commands) @@ -1165,12 +1072,12 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel out.flush(); out.close(); String path = tmp.getAbsolutePath(); - sendAsynchronousCommand("open cmd:" + path, null); + String command = "open " + (toChimeraX ? "" : "cmd:") + path; + sendAsynchronousCommand(command, null); } catch (IOException e) { - System.err - .println("Sending commands to Chimera via file failed with " - + e.getMessage()); + System.err.println("Sending commands to Chimera via file failed with " + + e.getMessage()); } } @@ -1195,7 +1102,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel // fails for 'average.bfactor' (which is bad): String cmd = "list residues attr '" + attName + "'"; - List residues = sendChimeraCommand(cmd, true); + List residues = executeCommand(cmd, true); boolean featureAdded = createFeaturesForAttributes(attName, residues); if (featureAdded) @@ -1224,6 +1131,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { boolean featureAdded = false; String featureGroup = getViewerFeatureGroup(); + boolean chimeraX = chimeraManager.isChimeraX(); for (String residue : residues) { @@ -1247,7 +1155,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel try { - spec = AtomSpec.fromChimeraAtomspec(atomSpec); + spec = AtomSpec.fromChimeraAtomspec(atomSpec, chimeraX); } catch (IllegalArgumentException e) { System.err.println("Problem parsing atomspec " + atomSpec); @@ -1308,24 +1216,42 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel return CHIMERA_FEATURE_GROUP; } - - public Hashtable getChainFile() + @Override + public int getModelNoForFile(String pdbFile) { - return chainFile; + List foundModels = chimeraMaps.get(pdbFile); + if (foundModels != null && !foundModels.isEmpty()) + { + return foundModels.get(0).getModelNumber(); + } + return -1; } - public List getChimeraModelByChain(String chain) + /** + * Answers a (possibly empty) list of attribute names in Chimera[X], excluding + * any which were added from Jalview + * + * @return + */ + public List getChimeraAttributes() { - return chimeraMaps.get(chainFile.get(chain)); + List atts = chimeraManager.getAttrList(); + Iterator it = atts.iterator(); + while (it.hasNext()) + { + if (it.next().startsWith(ChimeraCommands.NAMESPACE_PREFIX)) + { + /* + * attribute added from Jalview - exclude it + */ + it.remove(); + } + } + return atts; } - public int getModelNoForChain(String chain) + public boolean isChimeraX() { - List foundModels = getChimeraModelByChain(chain); - if (foundModels != null && !foundModels.isEmpty()) - { - return foundModels.get(0).getModelNumber(); - } - return -1; + return chimeraManager.isChimeraX(); } }