Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 16:11:35 GMT
  2. Package jalview.io

File ModellerDescription.java

 

Coverage histogram

../../img/srcFileCovDistChart2.png
54% of files have more coverage

Code metrics

78
128
17
2
442
324
71
0.55
7.53
8.5
4.18

Classes

Class Line # Actions
ModellerDescription 32 124 69
0.1428571514.3%
ModellerDescription.resCode 81 4 2
0.00%
 

Contributing tests

This file is covered by 1 test. .

Source view

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