package jalview.gui; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import jalview.api.AlignmentViewPanel; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.ext.pymol.PymolCommands; import jalview.ext.pymol.PymolManager; import jalview.gui.StructureViewer.ViewerType; import jalview.structure.AtomSpec; import jalview.structure.StructureCommand; import jalview.structure.StructureCommandI; import jalview.structure.StructureSelectionManager; import jalview.structures.models.AAStructureBindingModel; public class PymolBindingModel extends AAStructureBindingModel { /* * format for labels shown on structures when mousing over sequence; * see https://pymolwiki.org/index.php/Label#examples * left not final so customisable e.g. with a Groovy script */ private static String LABEL_FORMAT = "\"%s %s\" % (resn,resi)"; private PymolManager pymolManager; private Thread pymolMonitor; /* * full paths to structure files opened in PyMOL */ List structureFiles = new ArrayList<>(); /* * lookup from file path to PyMOL object name */ Map pymolObjects = new HashMap<>(); private String lastLabelSpec; /** * Constructor * * @param viewer * @param ssm * @param pdbentry * @param sequenceIs */ public PymolBindingModel(StructureViewerBase viewer, StructureSelectionManager ssm, PDBEntry[] pdbentry, SequenceI[][] sequenceIs) { super(ssm, pdbentry, sequenceIs, null); pymolManager = new PymolManager(); setStructureCommands(new PymolCommands()); setViewer(viewer); } @Override public String[] getStructureFiles() { return structureFiles.toArray(new String[structureFiles.size()]); } @Override public void highlightAtoms(List atoms) { /* * https://pymolwiki.org/index.php/Label#examples */ StringBuilder sb = new StringBuilder(); for (AtomSpec atom : atoms) { // todo promote to StructureCommandsI.showLabel() // todo handle CA|P correctly String modelId = getModelIdForFile(atom.getPdbFile()); sb.append(String.format(" %s//%s/%d/CA", modelId, atom.getChain(), atom.getPdbResNum())); } String labelSpec = sb.toString(); if (labelSpec.equals(lastLabelSpec)) { return; } StructureCommandI command = new StructureCommand("label", labelSpec, LABEL_FORMAT); executeCommand(command, false); /* * and remove the label(s) previously shown */ if (lastLabelSpec != null) { command = new StructureCommand("label", lastLabelSpec, ""); executeCommand(command, false); } lastLabelSpec = labelSpec; } @Override public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment) { // pull up? return new SequenceRenderer(alignment.getAlignViewport()); } @Override protected List executeCommand(StructureCommandI command, boolean getReply) { // System.out.println(command.toString()); // debug return pymolManager.sendCommand(command, getReply); } @Override protected String getModelIdForFile(String file) { return pymolObjects.containsKey(file) ? pymolObjects.get(file) : ""; } @Override protected ViewerType getViewerType() { return ViewerType.PYMOL; } @Override public boolean isViewerRunning() { return pymolManager.isPymolLaunched(); } @Override public void closeViewer(boolean closePymol) { super.closeViewer(closePymol); if (closePymol) { pymolManager.exitPymol(); } pymolManager = null; if (pymolMonitor != null) { pymolMonitor.interrupt(); } } public boolean openSession(String pymolSessionFile) { StructureCommandI cmd = getCommandGenerator() .loadFile(pymolSessionFile); executeCommand(cmd, false); return true; } public boolean launchPymol() { if (pymolManager.isPymolLaunched()) { return true; } boolean launched = pymolManager.launchPymol(); if (launched) { // start listening for PyMOL selections - how?? } else { System.err.println("Failed to launch PyMOL!"); } return launched; } public void openFile(PDBEntry pe) { // todo : check not already open, remap / rename, etc String file = pe.getFile(); StructureCommandI cmd = getCommandGenerator().loadFile(file); /* * a second parameter sets the pdbid as the loaded PyMOL object name */ String pdbId = pe.getId(); cmd.addParameter(pdbId); executeCommand(cmd, false); pymolObjects.put(file, pdbId); if (!structureFiles.contains(file)) { structureFiles.add(file); } if (getSsm() != null) { getSsm().addStructureViewerListener(this); } } @Override protected String getModelId(int pdbfnum, String file) { return file; } /** * Returns the file extension to use for a saved viewer session file (.pse) * * @return * @see https://pymolwiki.org/index.php/Save */ @Override public String getSessionFileExtension() { return ".pse"; } }