2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import jalview.datamodel.DBRefEntry;
24 import jalview.datamodel.DBRefSource;
25 import jalview.datamodel.SequenceI;
26 import jalview.jsdev.RegExp;
27 import jalview.jsdev.api.RegExpInterface;
29 //import com.stevesoft.pat.Regex;
31 public class ModellerDescription
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
38 final String[] seqTypes =
39 { "sequence", "structure", "structureX", "structureN" };
41 final String[] Fields =
42 { "objectType", "objectId", "startField", "startCode", "endField",
43 "endCode", "description1", "description2", "resolutionField",
48 final int LOCALID = 1;
52 final int START_CHAIN = 3;
56 final int END_CHAIN = 5;
58 final int DESCRIPTION1 = 6;
60 final int DESCRIPTION2 = 7;
62 final int RESOLUTION = 8;
67 * 0 is free text or empty 1 is something that parses to an integer, or \@
70 { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 };
72 final char Padding[] =
73 { ' ', ' ', ' ', '.', ' ', '.', '.', '.', '.', '.' };
75 java.util.Hashtable fields = new java.util.Hashtable();
79 fields.put(Fields[TAIL], "");
88 resCode(String f, Integer v)
97 field = val.toString();
101 private resCode validResidueCode(String field)
104 RegExpInterface r = RegExp.newRegex("\\s*((([-0-9]+).?)|FIRST|LAST|@)");
106 if (!r.search(field))
108 return null; // invalid
110 String value = r.stringMatchedI(3);
113 value = r.stringMatchedI(1);
115 // Cache.log.debug("from '" + field + "' matched '" + value +
119 val = Integer.valueOf(value);
120 return new resCode(field, val); // successful numeric extraction
121 } catch (Exception e)
124 return new resCode(field, null);
127 private java.util.Hashtable parseDescription(String desc)
129 java.util.Hashtable fields = new java.util.Hashtable();
130 java.util.StringTokenizer st = new java.util.StringTokenizer(desc, ":",
135 if (st.countTokens() > 0)
137 // parse colon-fields
139 field = st.nextToken(":");
142 if (seqTypes[i].equalsIgnoreCase(field))
146 } while (++i < seqTypes.length);
148 if (i < seqTypes.length)
150 st.nextToken(); // skip ':'
151 // valid seqType for modeller
153 i = 1; // continue parsing fields
154 while (i < TAIL && st.hasMoreTokens())
156 if ((field = st.nextToken(":")) != null)
158 if (!field.equals(":"))
160 // validate residue field value
163 resCode val = validResidueCode(field);
166 fields.put(new String(Fields[i] + "num"), val);
171 // "Ignoring non-Modeller description: invalid integer-like
172 // field '" + field + "'");
173 type = -1; /* invalid field! - throw the FieldSet away */
177 fields.put(Fields[i++], field);
178 if (st.hasMoreTokens())
180 st.nextToken(); // skip token sep.
191 // slurp remaining fields
192 while (st.hasMoreTokens())
194 String tl = st.nextToken(":");
195 field += tl.equals(":") ? tl : (":" + tl);
197 fields.put(Fields[TAIL], field);
203 // object is not a proper ModellerPIR object
204 fields = new java.util.Hashtable();
205 fields.put(Fields[TAIL], new String(desc));
209 fields.put(Fields[TYPE], seqTypes[type]);
214 ModellerDescription(String desc)
220 fields = parseDescription(desc);
223 void setStartCode(int v)
226 fields.put(Fields[START] + "num", r = new resCode(v));
227 fields.put(Fields[START], r.field);
230 void setEndCode(int v)
233 fields.put(Fields[END] + "num", r = new resCode(v));
234 fields.put(Fields[END], r.field);
238 * make a possibly updated modeller field line for the sequence object
243 ModellerDescription(SequenceI seq)
246 if (seq.getDescription() != null)
248 fields = parseDescription(seq.getDescription());
251 if (isModellerFieldset())
253 // Set start and end before we update the type (in the case of a
254 // synthesized field set)
255 if (getStartCode() == null
256 || (getStartNum() != seq.getStart() && getStartCode().val != null))
258 // unset or user updated sequence start position
259 setStartCode(seq.getStart());
262 if (getEndCode() == null
263 || (getEndNum() != seq.getEnd() && getStartCode() != null && getStartCode().val != null))
265 setEndCode(seq.getEnd());
271 setStartCode(seq.getStart());
272 setEndCode(seq.getEnd());
273 fields.put(Fields[LOCALID], seq.getName()); // this may be overwritten
275 // type - decide based on evidence of PDB database references - this also
276 // sets the local reference field
277 int t = 0; // sequence
278 if (seq.getDatasetSequence() != null
279 && seq.getDatasetSequence().getDBRef() != null)
281 DBRefEntry[] dbr = seq.getDatasetSequence().getDBRef();
283 for (i = 0, j = dbr.length; i < j; i++)
287 // JBPNote PDB dbRefEntry needs properties to propagate onto
289 // JBPNote Need to get info from the user about whether the sequence
290 // is the one being modelled, or if it is a template.
291 if (dbr[i].getSource().equals(DBRefSource.PDB))
293 fields.put(Fields[LOCALID], dbr[i].getAccessionId());
300 fields.put(Fields[TYPE], seqTypes[t]);
306 * Indicate if fields parsed to a modeller-like colon-separated value line
310 boolean isModellerFieldset()
312 return (fields.containsKey(Fields[TYPE]));
315 String getDescriptionLine()
318 int lastfield = Fields.length - 1;
320 if (isModellerFieldset())
323 // try to write a minimal modeller field set, so..
325 // find the last valid field in the entry
327 for (; lastfield > 6; lastfield--)
329 if (fields.containsKey(Fields[lastfield]))
335 for (int i = 0; i < lastfield; i++)
337 value = (String) fields.get(Fields[i]);
338 if (value != null && value.length() > 0)
340 desc += ((String) fields.get(Fields[i])) + ":";
344 desc += Padding[i] + ":";
348 // just return the last field if no others were defined.
349 if (fields.containsKey(Fields[lastfield]))
351 desc += (String) fields.get(Fields[lastfield]);
363 resCode val = getStartCode();
364 if (val != null && val.val != null)
366 return val.val.intValue();
371 resCode getStartCode()
373 if (isModellerFieldset() && fields.containsKey(Fields[START] + "num"))
375 return (resCode) fields.get(Fields[START] + "num");
382 if (isModellerFieldset() && fields.containsKey(Fields[END] + "num"))
384 return (resCode) fields.get(Fields[END] + "num");
392 resCode val = getEndCode();
393 if (val != null && val.val != null)
395 return val.val.intValue();
401 * returns true if sequence object was modifed with a valid modellerField set
407 boolean updateSequenceI(SequenceI newSeq)
409 if (isModellerFieldset())
411 resCode rc = getStartCode();
412 if (rc != null && rc.val != null)
414 newSeq.setStart(getStartNum());
421 if (rc != null && rc.val != null)
423 newSeq.setEnd(getEndNum());
427 newSeq.setEnd(newSeq.getStart() + newSeq.getLength());