JAL-3551 working proof of concept of Jalview driving PyMOL
[jalview.git] / src / jalview / ext / pymol / PymolCommands.java
1 package jalview.ext.pymol;
2
3 import jalview.structure.AtomSpecModel;
4 import jalview.structure.StructureCommand;
5 import jalview.structure.StructureCommandI;
6 import jalview.structure.StructureCommandsBase;
7
8 import java.awt.Color;
9 import java.util.ArrayList;
10 import java.util.List;
11
12 /**
13  * A class that generates commands to send to PyMol
14  * 
15  * @see https://pymolwiki.org/index.php/Category:Commands
16  */
17 public class PymolCommands extends StructureCommandsBase
18 {
19   private static final StructureCommandI COLOUR_BY_CHAIN = new StructureCommand(
20           "util.cbc");
21
22   /*
23    * because the xml-rpc interface can only accept one command at a time, we can't
24    * concatenate commands and must instead form and send them individually
25    */
26   private static final List<StructureCommandI> COLOR_BY_CHARGE = new ArrayList<>();
27
28   private static final List<StructureCommandI> SHOW_BACKBONE = new ArrayList<>();
29
30   static {
31     COLOR_BY_CHARGE.add(new StructureCommand("color", "white", "*"));
32     COLOR_BY_CHARGE
33             .add(new StructureCommand("color", "red", "resn ASP resn GLU"));
34     COLOR_BY_CHARGE.add(
35             new StructureCommand("color", "blue", "resn LYS resn ARG"));
36     COLOR_BY_CHARGE.add(new StructureCommand("color"));
37     SHOW_BACKBONE.add(new StructureCommand("hide", "everything"));
38     SHOW_BACKBONE.add(new StructureCommand("show", "ribbon"));
39   }
40
41   @Override
42   public StructureCommandI colourByChain()
43   {
44     // https://pymolwiki.org/index.php/CBC
45     // TODO this doesn't execute as an xml-rpc command
46     return COLOUR_BY_CHAIN;
47   }
48
49   @Override
50   public List<StructureCommandI> colourByCharge()
51   {
52     return COLOR_BY_CHARGE;
53   }
54
55   @Override
56   public StructureCommandI setBackgroundColour(Color col)
57   {
58     // https://pymolwiki.org/index.php/Bg_Color
59     return new StructureCommand("bg_color", getColourString(col));
60   }
61
62   /**
63    * Returns a colour formatted suitable for use in viewer command syntax. For
64    * example, red is {@code "0xff0000"}.
65    * 
66    * @param c
67    * @return
68    */
69   protected String getColourString(Color c)
70   {
71     return String.format("0x%02x%02x%02x", c.getRed(), c.getGreen(),
72             c.getBlue());
73   }
74
75   @Override
76   public StructureCommandI focusView()
77   {
78     // TODO what?
79     return null;
80   }
81
82   @Override
83   public List<StructureCommandI> showChains(List<String> toShow)
84   {
85     // https://pymolwiki.org/index.php/Show
86     List<StructureCommandI> commands = new ArrayList<>();
87     commands.add(new StructureCommand("hide", "everything"));
88     commands.add(new StructureCommand("show", "lines"));
89     StringBuilder chains = new StringBuilder();
90     for (String chain : toShow)
91     {
92       chains.append(" chain ").append(chain);
93     }
94     commands.add(new StructureCommand("show", "cartoon", chains.toString()));
95     return commands;
96   }
97
98   @Override
99   public List<StructureCommandI> superposeStructures(AtomSpecModel refAtoms,
100           AtomSpecModel atomSpec)
101   {
102     // https://pymolwiki.org/index.php/Super
103     List<StructureCommandI> commands = new ArrayList<>();
104     String refAtomsAlphaOnly = getAtomSpec(refAtoms, true);
105     String atomSpec2AlphaOnly = getAtomSpec(atomSpec, true);
106     commands.add(new StructureCommand("super", refAtomsAlphaOnly,
107             atomSpec2AlphaOnly));
108
109     /*
110      * and show superposed residues as cartoon
111      */
112     String refAtomsAll = getAtomSpec(refAtoms, false);
113     String atomSpec2All = getAtomSpec(atomSpec, false);
114     commands.add(new StructureCommand("show", "cartoon",
115             refAtomsAll + " " + atomSpec2All));
116
117     return commands;
118   }
119
120   @Override
121   public StructureCommandI openCommandFile(String path)
122   {
123     // where is this documented by PyMol?
124     // todo : xml-rpc answers 'method "@" is not supported'
125     return new StructureCommand("@" + path); // should be .pml
126   }
127
128   @Override
129   public StructureCommandI saveSession(String filepath)
130   {
131     // https://pymolwiki.org/index.php/Save#EXAMPLES
132     return new StructureCommand("save", filepath); // should be .pse
133   }
134
135   /**
136    * Returns a selection string in PyMOL 'selection macro' format:
137    * 
138    * <pre>
139    * modelId// chain/residues/
140    * </pre>
141    * 
142    * If more than one chain, makes a selection expression for each, and they are
143    * separated by spaces.
144    * 
145    * @see https://pymolwiki.org/index.php/Selection_Macros
146    */
147   @Override
148   public String getAtomSpec(AtomSpecModel model, boolean alphaOnly)
149   {
150     StringBuilder sb = new StringBuilder(64);
151     boolean first = true;
152     for (String modelId : model.getModels())
153     {
154       for (String chain : model.getChains(modelId))
155       {
156         if (!first)
157         {
158           sb.append(" ");
159         }
160         first = false;
161         List<int[]> rangeList = model.getRanges(modelId, chain);
162         chain = chain.trim();
163         sb.append(modelId).append("//").append(chain).append("/");
164         boolean firstRange = true;
165         for (int[] range : rangeList)
166         {
167           if (!firstRange)
168           {
169             sb.append("+");
170           }
171           firstRange = false;
172           sb.append(String.valueOf(range[0]));
173           if (range[0] != range[1])
174           {
175             sb.append("-").append(String.valueOf(range[1]));
176           }
177         }
178         sb.append("/");
179         if (alphaOnly)
180         {
181           sb.append("CA");
182         }
183       }
184     }
185     return sb.toString();
186   }
187
188   @Override
189   public List<StructureCommandI> showBackbone()
190   {
191     return SHOW_BACKBONE;
192   }
193
194   @Override
195   protected StructureCommandI getColourCommand(String atomSpec, Color colour)
196   {
197     // https://pymolwiki.org/index.php/Color
198     return new StructureCommand("color", getColourString(colour), atomSpec);
199   }
200
201   @Override
202   protected String getResidueSpec(String residue)
203   {
204     // https://pymolwiki.org/index.php/Selection_Algebra
205     return "resn " + residue;
206   }
207
208   @Override
209   public StructureCommandI loadFile(String file)
210   {
211     return new StructureCommand("load", file);
212   }
213
214 }