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