JAL-1761 backbone type parameter for configuring which atoms are used for superpositi...
[jalview.git] / src / jalview / structure / StructureCommandsBase.java
1 package jalview.structure;
2
3 import java.awt.Color;
4 import java.util.ArrayList;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Map.Entry;
8
9 /**
10  * A base class holding methods useful to all classes that implement commands
11  * for structure viewers
12  * 
13  * @author gmcarstairs
14  *
15  */
16 public abstract class StructureCommandsBase implements StructureCommandsI
17 {
18   public static final String NAMESPACE_PREFIX = "jv_";
19
20   private static final String CMD_SEPARATOR = ";";
21
22   /**
23    * Returns something that separates concatenated commands
24    * 
25    * @return
26    */
27   protected String getCommandSeparator()
28   {
29     return CMD_SEPARATOR;
30   }
31
32   /**
33    * Returns the lowest model number used by the structure viewer
34    * 
35    * @return
36    */
37   @Override
38   public int getModelStartNo()
39   {
40     return 0;
41   }
42
43   /**
44    * Helper method to add one contiguous range to the AtomSpec model for the given
45    * value (creating the model if necessary). As used by Jalview, {@code value} is
46    * <ul>
47    * <li>a colour, when building a 'colour structure by sequence' command</li>
48    * <li>a feature value, when building a 'set Chimera attributes from features'
49    * command</li>
50    * </ul>
51    * 
52    * @param map
53    * @param value
54    * @param model
55    * @param startPos
56    * @param endPos
57    * @param chain
58    */
59   public static final void addAtomSpecRange(Map<Object, AtomSpecModel> map,
60           Object value, String model, int startPos, int endPos,
61           String chain)
62   {
63     /*
64      * Get/initialize map of data for the colour
65      */
66     AtomSpecModel atomSpec = map.get(value);
67     if (atomSpec == null)
68     {
69       atomSpec = new AtomSpecModel();
70       map.put(value, atomSpec);
71     }
72   
73     atomSpec.addRange(model, startPos, endPos, chain);
74   }
75
76   /**
77    * Makes a structure viewer attribute name for a Jalview feature type by
78    * prefixing it with "jv_", and replacing any non-alphanumeric characters with
79    * an underscore
80    * 
81    * @param featureType
82    * @return
83    */
84   protected String makeAttributeName(String featureType)
85   {
86     StringBuilder sb = new StringBuilder();
87     if (featureType != null)
88     {
89       for (char c : featureType.toCharArray())
90       {
91         sb.append(Character.isLetterOrDigit(c) ? c : '_');
92       }
93     }
94     String attName = NAMESPACE_PREFIX + sb.toString();
95     return attName;
96   }
97
98   /**
99    * Traverse the map of colours/models/chains/positions to construct a list of
100    * 'color' commands (one per distinct colour used). The format of each command
101    * is specific to the structure viewer.
102    * <p>
103    * The default implementation returns a single command containing one command
104    * per colour, concatenated.
105    * 
106    * @param colourMap
107    * @return
108    */
109   @Override
110   public List<StructureCommandI> colourBySequence(
111           Map<Object, AtomSpecModel> colourMap)
112   {
113     List<StructureCommandI> commands = new ArrayList<>();
114     StringBuilder sb = new StringBuilder(colourMap.size() * 20);
115     boolean first = true;
116     for (Object key : colourMap.keySet())
117     {
118       Color colour = (Color) key;
119       final AtomSpecModel colourData = colourMap.get(colour);
120       StructureCommandI command = getColourCommand(colourData, colour);
121       if (!first)
122       {
123         sb.append(getCommandSeparator());
124       }
125       first = false;
126       sb.append(command.getCommand());
127     }
128
129     commands.add(new StructureCommand(sb.toString()));
130     return commands;
131   }
132
133   /**
134    * Returns a command to colour the atoms represented by {@code atomSpecModel}
135    * with the colour specified by {@code colourCode}.
136    * 
137    * @param atomSpecModel
138    * @param colour
139    * @return
140    */
141   protected StructureCommandI getColourCommand(AtomSpecModel atomSpecModel,
142           Color colour)
143   {
144     String atomSpec = getAtomSpec(atomSpecModel, AtomSpecType.RESIDUE_ONLY);
145     return colourResidues(atomSpec, colour);
146   }
147
148   /**
149    * Returns a command to colour the atoms described (in viewer command syntax)
150    * by {@code atomSpec} with the colour specified by {@code colourCode}
151    * 
152    * @param atomSpec
153    * @param colour
154    * @return
155    */
156   protected abstract StructureCommandI colourResidues(String atomSpec,
157           Color colour);
158
159   @Override
160   public List<StructureCommandI> colourByResidues(
161           Map<String, Color> colours)
162   {
163     List<StructureCommandI> commands = new ArrayList<>();
164     for (Entry<String, Color> entry : colours.entrySet())
165     {
166       commands.add(colourResidue(entry.getKey(), entry.getValue()));
167     }
168     return commands;
169   }
170
171   private StructureCommandI colourResidue(String resName, Color col)
172   {
173     String atomSpec = getResidueSpec(resName);
174     return colourResidues(atomSpec, col);
175   }
176
177   /**
178    * Helper method to append one start-end range to an atomspec string
179    * 
180    * @param sb
181    * @param start
182    * @param end
183    * @param chain
184    * @param firstPositionForModel
185    */
186   protected void appendRange(StringBuilder sb, int start, int end,
187           String chain, boolean firstPositionForModel, boolean isChimeraX)
188   {
189     if (!firstPositionForModel)
190     {
191       sb.append(",");
192     }
193     if (end == start)
194     {
195       sb.append(start);
196     }
197     else
198     {
199       sb.append(start).append("-").append(end);
200     }
201
202     if (!isChimeraX)
203     {
204       sb.append(".");
205       if (!" ".equals(chain))
206       {
207         sb.append(chain);
208       }
209     }
210   }
211
212   /**
213    * Returns the atom specifier meaning all occurrences of the given residue
214    * 
215    * @param residue
216    * @return
217    */
218   protected abstract String getResidueSpec(String residue);
219
220   @Override
221   public List<StructureCommandI> setAttributes(
222           Map<String, Map<Object, AtomSpecModel>> featureValues)
223   {
224     // default does nothing, override where this is implemented
225     return null;
226   }
227
228   @Override
229   public List<StructureCommandI> startNotifications(String uri)
230   {
231     return null;
232   }
233
234   @Override
235   public List<StructureCommandI> stopNotifications()
236   {
237     return null;
238   }
239
240   @Override
241   public StructureCommandI getSelectedResidues()
242   {
243     return null;
244   }
245
246   @Override
247   public StructureCommandI listResidueAttributes()
248   {
249     return null;
250   }
251
252   @Override
253   public StructureCommandI getResidueAttributes(String attName)
254   {
255     return null;
256   }
257 }