Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
ModellerDescription | 31 | 123 | 67 | ||
ModellerDescription.resCode | 80 | 4 | 2 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
7 | * Jalview is free software: you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License | |
9 | * as published by the Free Software Foundation, either version 3 | |
10 | * of the License, or (at your option) any later version. | |
11 | * | |
12 | * Jalview is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty | |
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
15 | * PURPOSE. See the GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with Jalview. If not, see <http://www.gnu.org/licenses/>. | |
19 | * The Jalview Authors are detailed in the 'AUTHORS' file. | |
20 | */ | |
21 | package jalview.io; | |
22 | ||
23 | import jalview.bin.Cache; | |
24 | import jalview.datamodel.DBRefEntry; | |
25 | import jalview.datamodel.SequenceI; | |
26 | ||
27 | import java.util.List; | |
28 | ||
29 | import com.stevesoft.pat.Regex; | |
30 | ||
31 | public class ModellerDescription | |
32 | { | |
33 | /** | |
34 | * Translates between a String containing a set of colon-separated values on a | |
35 | * single line, and sequence start/end and other properties. See PIRFile IO | |
36 | * for its use. | |
37 | */ | |
38 | final String[] seqTypes = { "sequence", "structure", "structureX", | |
39 | "structureN" }; | |
40 | ||
41 | final String[] Fields = { "objectType", "objectId", "startField", | |
42 | "startCode", "endField", "endCode", "description1", "description2", | |
43 | "resolutionField", "tailField" }; | |
44 | ||
45 | final int TYPE = 0; | |
46 | ||
47 | final int LOCALID = 1; | |
48 | ||
49 | final int START = 2; | |
50 | ||
51 | final int START_CHAIN = 3; | |
52 | ||
53 | final int END = 4; | |
54 | ||
55 | final int END_CHAIN = 5; | |
56 | ||
57 | final int DESCRIPTION1 = 6; | |
58 | ||
59 | final int DESCRIPTION2 = 7; | |
60 | ||
61 | final int RESOLUTION = 8; | |
62 | ||
63 | final int TAIL = 9; | |
64 | ||
65 | /** | |
66 | * 0 is free text or empty 1 is something that parses to an integer, or \@ | |
67 | */ | |
68 | final int Types[] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 }; | |
69 | ||
70 | final char Padding[] = { ' ', ' ', ' ', '.', ' ', '.', '.', '.', '.', | |
71 | '.' }; | |
72 | ||
73 | java.util.Hashtable fields = new java.util.Hashtable(); | |
74 | ||
75 | 0 | ModellerDescription() |
76 | { | |
77 | 0 | fields.put(Fields[TAIL], ""); |
78 | } | |
79 | ||
80 | class resCode | |
81 | { | |
82 | Integer val; | |
83 | ||
84 | String field; | |
85 | ||
86 | 0 | resCode(String f, Integer v) |
87 | { | |
88 | 0 | val = v; |
89 | 0 | field = f; |
90 | } | |
91 | ||
92 | 0 | resCode(int v) |
93 | { | |
94 | 0 | val = Integer.valueOf(v); |
95 | 0 | field = val.toString(); |
96 | } | |
97 | }; | |
98 | ||
99 | 0 | private resCode validResidueCode(String field) |
100 | { | |
101 | 0 | Integer val = null; |
102 | 0 | Regex r = new Regex("\\s*((([-0-9]+).?)|FIRST|LAST|@)"); |
103 | ||
104 | 0 | if (!r.search(field)) |
105 | { | |
106 | 0 | return null; // invalid |
107 | } | |
108 | 0 | String value = r.stringMatched(3); |
109 | 0 | if (value == null) |
110 | { | |
111 | 0 | value = r.stringMatched(1); |
112 | } | |
113 | // Cache.debug("from '" + field + "' matched '" + value + | |
114 | // "'"); | |
115 | 0 | try |
116 | { | |
117 | 0 | val = Integer.valueOf(value); |
118 | 0 | return new resCode(field, val); // successful numeric extraction |
119 | } catch (Exception e) | |
120 | { | |
121 | } | |
122 | 0 | return new resCode(field, null); |
123 | } | |
124 | ||
125 | 15 | private java.util.Hashtable parseDescription(String desc) |
126 | { | |
127 | 15 | java.util.Hashtable fields = new java.util.Hashtable(); |
128 | 15 | java.util.StringTokenizer st = new java.util.StringTokenizer(desc, ":", |
129 | true); | |
130 | ||
131 | 15 | String field; |
132 | 15 | int type = -1; |
133 | 15 | if (st.countTokens() > 0) |
134 | { | |
135 | // parse colon-fields | |
136 | 15 | int i = 0; |
137 | 15 | field = st.nextToken(":"); |
138 | 15 | do |
139 | { | |
140 | 60 | if (seqTypes[i].equalsIgnoreCase(field)) |
141 | { | |
142 | 0 | break; |
143 | } | |
144 | 60 | } while (++i < seqTypes.length); |
145 | ||
146 | 15 | if (i < seqTypes.length) |
147 | { | |
148 | 0 | st.nextToken(); // skip ':' |
149 | // valid seqType for modeller | |
150 | 0 | type = i; |
151 | 0 | i = 1; // continue parsing fields |
152 | 0 | while (i < TAIL && st.hasMoreTokens()) |
153 | { | |
154 | 0 | if ((field = st.nextToken(":")) != null) |
155 | { | |
156 | 0 | if (!field.equals(":")) |
157 | { | |
158 | // validate residue field value | |
159 | 0 | if (Types[i] == 1) |
160 | { | |
161 | 0 | resCode val = validResidueCode(field); |
162 | 0 | if (val != null) |
163 | { | |
164 | 0 | fields.put(new String(Fields[i] + "num"), val); |
165 | } | |
166 | else | |
167 | { | |
168 | // Cache.debug( | |
169 | // "Ignoring non-Modeller description: invalid integer-like | |
170 | // field '" + field + "'"); | |
171 | 0 | type = -1; /* invalid field! - throw the FieldSet away */ |
172 | } | |
173 | 0 | ; |
174 | } | |
175 | 0 | fields.put(Fields[i++], field); |
176 | 0 | if (st.hasMoreTokens()) |
177 | { | |
178 | 0 | st.nextToken(); // skip token sep. |
179 | } | |
180 | } | |
181 | else | |
182 | { | |
183 | 0 | i++; |
184 | } | |
185 | } | |
186 | } | |
187 | 0 | if (i == TAIL) |
188 | { | |
189 | // slurp remaining fields | |
190 | 0 | while (st.hasMoreTokens()) |
191 | { | |
192 | 0 | String tl = st.nextToken(":"); |
193 | 0 | field += tl.equals(":") ? tl : (":" + tl); |
194 | } | |
195 | 0 | fields.put(Fields[TAIL], field); |
196 | } | |
197 | } | |
198 | } | |
199 | 15 | if (type == -1) |
200 | { | |
201 | // object is not a proper ModellerPIR object | |
202 | 15 | fields = new java.util.Hashtable(); |
203 | 15 | fields.put(Fields[TAIL], new String(desc)); |
204 | } | |
205 | else | |
206 | { | |
207 | 0 | fields.put(Fields[TYPE], seqTypes[type]); |
208 | } | |
209 | 15 | return fields; |
210 | } | |
211 | ||
212 | 15 | ModellerDescription(String desc) |
213 | { | |
214 | 15 | if (desc == null) |
215 | { | |
216 | 0 | desc = ""; |
217 | } | |
218 | 15 | fields = parseDescription(desc); |
219 | } | |
220 | ||
221 | 0 | void setStartCode(int v) |
222 | { | |
223 | 0 | resCode r; |
224 | 0 | fields.put(Fields[START] + "num", r = new resCode(v)); |
225 | 0 | fields.put(Fields[START], r.field); |
226 | } | |
227 | ||
228 | 0 | void setEndCode(int v) |
229 | { | |
230 | 0 | resCode r; |
231 | 0 | fields.put(Fields[END] + "num", r = new resCode(v)); |
232 | 0 | fields.put(Fields[END], r.field); |
233 | } | |
234 | ||
235 | /** | |
236 | * make a possibly updated modeller field line for the sequence object | |
237 | * | |
238 | * @param seq | |
239 | * SequenceI | |
240 | */ | |
241 | 0 | ModellerDescription(SequenceI seq) |
242 | { | |
243 | ||
244 | 0 | if (seq.getDescription() != null) |
245 | { | |
246 | 0 | fields = parseDescription(seq.getDescription()); |
247 | } | |
248 | ||
249 | 0 | if (isModellerFieldset()) |
250 | { | |
251 | // Set start and end before we update the type (in the case of a | |
252 | // synthesized field set) | |
253 | 0 | if (getStartCode() == null || (getStartNum() != seq.getStart() |
254 | && getStartCode().val != null)) | |
255 | { | |
256 | // unset or user updated sequence start position | |
257 | 0 | setStartCode(seq.getStart()); |
258 | } | |
259 | ||
260 | 0 | if (getEndCode() == null || (getEndNum() != seq.getEnd() |
261 | && getStartCode() != null && getStartCode().val != null)) | |
262 | { | |
263 | 0 | setEndCode(seq.getEnd()); |
264 | } | |
265 | } | |
266 | else | |
267 | { | |
268 | // synthesize fields | |
269 | 0 | setStartCode(seq.getStart()); |
270 | 0 | setEndCode(seq.getEnd()); |
271 | 0 | fields.put(Fields[LOCALID], seq.getName()); // this may be overwritten |
272 | // below... | |
273 | // type - decide based on evidence of PDB database references - this also | |
274 | // sets the local reference field | |
275 | 0 | int t = 0; // sequence |
276 | 0 | if (seq.getDatasetSequence() != null |
277 | && seq.getDatasetSequence().getDBRefs() != null) | |
278 | { | |
279 | 0 | List<DBRefEntry> dbr = seq.getDatasetSequence().getDBRefs(); |
280 | 0 | for (int i = 0, ni = dbr.size(); i < ni; i++) |
281 | { | |
282 | 0 | DBRefEntry dbri = dbr.get(i); |
283 | 0 | if (dbri != null) |
284 | { | |
285 | // JBPNote PDB dbRefEntry needs properties to propagate onto | |
286 | // ModellerField | |
287 | // JBPNote Need to get info from the user about whether the sequence | |
288 | // is the one being modelled, or if it is a template. | |
289 | 0 | if (dbri.getSource().equals(jalview.datamodel.DBRefSource.PDB)) |
290 | { | |
291 | 0 | fields.put(Fields[LOCALID], dbri.getAccessionId()); |
292 | 0 | t = 2; |
293 | 0 | break; |
294 | } | |
295 | } | |
296 | } | |
297 | } | |
298 | 0 | fields.put(Fields[TYPE], seqTypes[t]); |
299 | } | |
300 | ||
301 | } | |
302 | ||
303 | /** | |
304 | * Indicate if fields parsed to a modeller-like colon-separated value line | |
305 | * | |
306 | * @return boolean | |
307 | */ | |
308 | 15 | boolean isModellerFieldset() |
309 | { | |
310 | 15 | return (fields.containsKey(Fields[TYPE])); |
311 | } | |
312 | ||
313 | 0 | String getDescriptionLine() |
314 | { | |
315 | 0 | String desc = ""; |
316 | 0 | int lastfield = Fields.length - 1; |
317 | ||
318 | 0 | if (isModellerFieldset()) |
319 | { | |
320 | 0 | String value; |
321 | // try to write a minimal modeller field set, so.. | |
322 | ||
323 | // find the last valid field in the entry | |
324 | ||
325 | 0 | for (; lastfield > 6; lastfield--) |
326 | { | |
327 | 0 | if (fields.containsKey(Fields[lastfield])) |
328 | { | |
329 | 0 | break; |
330 | } | |
331 | } | |
332 | ||
333 | 0 | for (int i = 0; i < lastfield; i++) |
334 | { | |
335 | 0 | value = (String) fields.get(Fields[i]); |
336 | 0 | if (value != null && value.length() > 0) |
337 | { | |
338 | 0 | desc += ((String) fields.get(Fields[i])) + ":"; |
339 | } | |
340 | else | |
341 | { | |
342 | 0 | desc += Padding[i] + ":"; |
343 | } | |
344 | } | |
345 | } | |
346 | // just return the last field if no others were defined. | |
347 | 0 | if (fields.containsKey(Fields[lastfield])) |
348 | { | |
349 | 0 | desc += (String) fields.get(Fields[lastfield]); |
350 | } | |
351 | else | |
352 | { | |
353 | 0 | desc += "."; |
354 | } | |
355 | 0 | return desc; |
356 | } | |
357 | ||
358 | 0 | int getStartNum() |
359 | { | |
360 | 0 | int start = 0; |
361 | 0 | resCode val = getStartCode(); |
362 | 0 | if (val != null && val.val != null) |
363 | { | |
364 | 0 | return val.val.intValue(); |
365 | } | |
366 | 0 | return start; |
367 | } | |
368 | ||
369 | 0 | resCode getStartCode() |
370 | { | |
371 | 0 | if (isModellerFieldset() && fields.containsKey(Fields[START] + "num")) |
372 | { | |
373 | 0 | return (resCode) fields.get(Fields[START] + "num"); |
374 | } | |
375 | 0 | return null; |
376 | } | |
377 | ||
378 | 0 | resCode getEndCode() |
379 | { | |
380 | 0 | if (isModellerFieldset() && fields.containsKey(Fields[END] + "num")) |
381 | { | |
382 | 0 | return (resCode) fields.get(Fields[END] + "num"); |
383 | } | |
384 | 0 | return null; |
385 | } | |
386 | ||
387 | 0 | int getEndNum() |
388 | { | |
389 | 0 | int end = 0; |
390 | 0 | resCode val = getEndCode(); |
391 | 0 | if (val != null && val.val != null) |
392 | { | |
393 | 0 | return val.val.intValue(); |
394 | } | |
395 | 0 | return end; |
396 | } | |
397 | ||
398 | /** | |
399 | * returns true if sequence object was modifed with a valid modellerField set | |
400 | * | |
401 | * @param newSeq | |
402 | * SequenceI | |
403 | * @return boolean | |
404 | */ | |
405 | 15 | boolean updateSequenceI(SequenceI newSeq) |
406 | { | |
407 | 15 | if (isModellerFieldset()) |
408 | { | |
409 | 0 | resCode rc = getStartCode(); |
410 | 0 | if (rc != null && rc.val != null) |
411 | { | |
412 | 0 | newSeq.setStart(getStartNum()); |
413 | } | |
414 | else | |
415 | { | |
416 | 0 | newSeq.setStart(1); |
417 | } | |
418 | 0 | rc = getEndCode(); |
419 | 0 | if (rc != null && rc.val != null) |
420 | { | |
421 | 0 | newSeq.setEnd(getEndNum()); |
422 | } | |
423 | else | |
424 | { | |
425 | 0 | newSeq.setEnd(newSeq.getStart() + newSeq.getLength()); |
426 | } | |
427 | 0 | return true; |
428 | } | |
429 | 15 | return false; |
430 | } | |
431 | } |