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