/*
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
* Jalview is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* Jalview is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jalview. If not, see .
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
package jalview.ext.pymol;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import jalview.structure.AtomSpecModel;
import jalview.structure.StructureCommand;
import jalview.structure.StructureCommandI;
import jalview.structure.StructureCommandsBase;
/**
* A class that generates commands to send to PyMol over its XML-RPC interface.
*
* Note that because the xml-rpc interface can only accept one command at a
* time, we can't concatenate commands, and must instead form and send them
* individually.
*
* @see https://pymolwiki.org/index.php/Category:Commands
* @see https://pymolwiki.org/index.php/RPC
*/
public class PymolCommands extends StructureCommandsBase
{
// https://pymol.org/dokuwiki/doku.php?id=command:zoom
// not currently documented on
// https://pymolwiki.org/index.php/Category:Commands
private static final StructureCommand FOCUS_VIEW = new StructureCommand(
"zoom");
// https://pymolwiki.org/index.php/Quit
private static final StructureCommand CLOSE_PYMOL = new StructureCommand(
"quit");
// not currently documented on
// https://pymolwiki.org/index.php/Category:Commands
private static final StructureCommand COLOUR_BY_CHAIN = new StructureCommand(
"spectrum", "chain");
private static final List COLOR_BY_CHARGE = Arrays
.asList(new StructureCommand("color", "white", "*"),
new StructureCommand("color", "red", "resn ASP resn GLU"),
new StructureCommand("color", "blue",
"resn LYS resn ARG"),
new StructureCommand("color", "yellow", "resn CYS"));
private static final List SHOW_BACKBONE = Arrays
.asList(new StructureCommand("hide", "everything"),
new StructureCommand("show", "ribbon"));
@Override
public StructureCommandI colourByChain()
{
return COLOUR_BY_CHAIN;
}
@Override
public List colourByCharge()
{
return COLOR_BY_CHARGE;
}
@Override
public StructureCommandI setBackgroundColour(Color col)
{
// https://pymolwiki.org/index.php/Bg_Color
return new StructureCommand("bg_color", getColourString(col));
}
/**
* Returns a colour formatted suitable for use in viewer command syntax. For
* example, red is {@code "0xff0000"}.
*
* @param c
* @return
*/
protected String getColourString(Color c)
{
return String.format("0x%02x%02x%02x", c.getRed(), c.getGreen(),
c.getBlue());
}
@Override
public StructureCommandI focusView()
{
return FOCUS_VIEW;
}
@Override
public List showChains(List toShow)
{
// https://pymolwiki.org/index.php/Show
List commands = new ArrayList<>();
commands.add(new StructureCommand("hide", "everything"));
commands.add(new StructureCommand("show", "lines"));
StringBuilder chains = new StringBuilder();
for (String chain : toShow)
{
chains.append(" chain ").append(chain);
}
commands.add(
new StructureCommand("show", "cartoon", chains.toString()));
return commands;
}
@Override
public List superposeStructures(AtomSpecModel refAtoms,
AtomSpecModel atomSpec, AtomSpecType specType)
{
// https://pymolwiki.org/index.php/Super
List commands = new ArrayList<>();
String refAtomsAlphaOnly = "(" + getAtomSpec(refAtoms, specType)
+ " and (altloc '' or altloc 'a'))";
String atomSpec2AlphaOnly = "(" + getAtomSpec(atomSpec, specType)
+ " and (altloc '' or altloc 'a'))";
// pair_fit mobile -> reference
// crashes when undo is enabled on 2.5.2 (incentive)
commands.add(new StructureCommand("undo_disable"));
commands.add(new StructureCommand("pair_fit", atomSpec2AlphaOnly,
refAtomsAlphaOnly));
commands.add(new StructureCommand("undo_enable"));
/*
* and show superposed residues as cartoon
*/
String refAtomsAll = getAtomSpec(refAtoms, AtomSpecType.RESIDUE_ONLY);
String atomSpec2All = getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY);
commands.add(new StructureCommand("show", "cartoon",
refAtomsAll + " " + atomSpec2All));
return commands;
}
@Override
public StructureCommandI openCommandFile(String path)
{
// https://pymolwiki.org/index.php/Run
return new StructureCommand("run", path); // should be .pml
}
@Override
public StructureCommandI saveSession(String filepath)
{
// https://pymolwiki.org/index.php/Save#EXAMPLES
return new StructureCommand("save", filepath); // should be .pse
}
/**
* Returns a selection string in PyMOL 'selection macro' format:
*
*
* modelId// chain/residues/
*
*
* If more than one chain, makes a selection expression for each, and they are
* separated by spaces.
*
* @see https://pymolwiki.org/index.php/Selection_Macros
*/
@Override
public String getAtomSpec(AtomSpecModel model, AtomSpecType specType)
{
StringBuilder sb = new StringBuilder(64);
boolean first = true;
for (String modelId : model.getModels())
{
for (String chain : model.getChains(modelId))
{
if (!first)
{
sb.append(" ");
}
first = false;
List rangeList = model.getRanges(modelId, chain);
chain = chain.trim();
sb.append(modelId).append("//").append(chain).append("/");
boolean firstRange = true;
for (int[] range : rangeList)
{
if (!firstRange)
{
sb.append("+");
}
firstRange = false;
sb.append(String.valueOf(range[0]));
if (range[0] != range[1])
{
sb.append("-").append(String.valueOf(range[1]));
}
}
sb.append("/");
if (specType == AtomSpecType.ALPHA)
{
sb.append("CA");
}
if (specType == AtomSpecType.PHOSPHATE)
{
sb.append("P");
}
}
}
return sb.toString();
}
@Override
public List showBackbone()
{
return SHOW_BACKBONE;
}
@Override
protected StructureCommandI colourResidues(String atomSpec, Color colour)
{
// https://pymolwiki.org/index.php/Color
return new StructureCommand("color", getColourString(colour), atomSpec);
}
@Override
protected String getResidueSpec(String residue)
{
// https://pymolwiki.org/index.php/Selection_Algebra
return "resn " + residue;
}
@Override
public StructureCommandI loadFile(String file)
{
return new StructureCommand("load", file);
}
/**
* Overrides the default implementation (which generates concatenated
* commands) to generate one per colour (because the XML-RPC interface to
* PyMOL only accepts one command at a time)
*
* @param colourMap
* @return
*/
@Override
public List colourBySequence(
Map