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.SequenceI;
25 import jalview.util.Platform;
27 import java.util.List;
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 = { "sequence", "structure", "structureX",
41 final String[] Fields = { "objectType", "objectId", "startField",
42 "startCode", "endField", "endCode", "description1", "description2",
43 "resolutionField", "tailField" };
47 final int LOCALID = 1;
51 final int START_CHAIN = 3;
55 final int END_CHAIN = 5;
57 final int DESCRIPTION1 = 6;
59 final int DESCRIPTION2 = 7;
61 final int RESOLUTION = 8;
66 * 0 is free text or empty 1 is something that parses to an integer, or \@
68 final int Types[] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 };
70 final char Padding[] = { ' ', ' ', ' ', '.', ' ', '.', '.', '.', '.',
73 java.util.Hashtable fields = new java.util.Hashtable();
77 fields.put(Fields[TAIL], "");
86 resCode(String f, Integer v)
94 val = Integer.valueOf(v);
95 field = val.toString();
99 private static Regex VALIDATION_REGEX;
101 private static Regex getRegex()
103 return (VALIDATION_REGEX == null
104 ? VALIDATION_REGEX = Platform
105 .newRegex("\\s*((([-0-9]+).?)|FIRST|LAST|@)", null)
109 private resCode validResidueCode(String field)
112 Regex r = getRegex();
113 if (!r.search(field))
115 return null; // invalid
117 String value = r.stringMatched(3);
120 value = r.stringMatched(1);
122 // jalview.bin.Cache.log.debug("from '" + field + "' matched '" + value +
126 val = Integer.valueOf(value);
127 return new resCode(field, val); // successful numeric extraction
128 } catch (Exception e)
131 return new resCode(field, null);
134 private java.util.Hashtable parseDescription(String desc)
136 java.util.Hashtable fields = new java.util.Hashtable();
137 java.util.StringTokenizer st = new java.util.StringTokenizer(desc, ":",
142 if (st.countTokens() > 0)
144 // parse colon-fields
146 field = st.nextToken(":");
149 if (seqTypes[i].equalsIgnoreCase(field))
153 } while (++i < seqTypes.length);
155 if (i < seqTypes.length)
157 st.nextToken(); // skip ':'
158 // valid seqType for modeller
160 i = 1; // continue parsing fields
161 while (i < TAIL && st.hasMoreTokens())
163 if ((field = st.nextToken(":")) != null)
165 if (!field.equals(":"))
167 // validate residue field value
170 resCode val = validResidueCode(field);
173 fields.put(new String(Fields[i] + "num"), val);
177 // jalview.bin.Cache.log.debug(
178 // "Ignoring non-Modeller description: invalid integer-like
179 // field '" + field + "'");
180 type = -1; /* invalid field! - throw the FieldSet away */
184 fields.put(Fields[i++], field);
185 if (st.hasMoreTokens())
187 st.nextToken(); // skip token sep.
198 // slurp remaining fields
199 while (st.hasMoreTokens())
201 String tl = st.nextToken(":");
202 field += tl.equals(":") ? tl : (":" + tl);
204 fields.put(Fields[TAIL], field);
210 // object is not a proper ModellerPIR object
211 fields = new java.util.Hashtable();
212 fields.put(Fields[TAIL], new String(desc));
216 fields.put(Fields[TYPE], seqTypes[type]);
221 ModellerDescription(String desc)
227 fields = parseDescription(desc);
230 void setStartCode(int v)
233 fields.put(Fields[START] + "num", r = new resCode(v));
234 fields.put(Fields[START], r.field);
237 void setEndCode(int v)
240 fields.put(Fields[END] + "num", r = new resCode(v));
241 fields.put(Fields[END], r.field);
245 * make a possibly updated modeller field line for the sequence object
250 ModellerDescription(SequenceI seq)
253 if (seq.getDescription() != null)
255 fields = parseDescription(seq.getDescription());
258 if (isModellerFieldset())
260 // Set start and end before we update the type (in the case of a
261 // synthesized field set)
262 if (getStartCode() == null || (getStartNum() != seq.getStart()
263 && getStartCode().val != null))
265 // unset or user updated sequence start position
266 setStartCode(seq.getStart());
269 if (getEndCode() == null || (getEndNum() != seq.getEnd()
270 && getStartCode() != null && getStartCode().val != null))
272 setEndCode(seq.getEnd());
278 setStartCode(seq.getStart());
279 setEndCode(seq.getEnd());
280 fields.put(Fields[LOCALID], seq.getName()); // this may be overwritten
282 // type - decide based on evidence of PDB database references - this also
283 // sets the local reference field
284 int t = 0; // sequence
285 if (seq.getDatasetSequence() != null
286 && seq.getDatasetSequence().getDBRefs() != null)
288 List<DBRefEntry> dbr = seq.getDatasetSequence().getDBRefs();
289 for (int i = 0, ni = dbr.size(); i < ni; i++)
291 DBRefEntry dbri = dbr.get(i);
294 // JBPNote PDB dbRefEntry needs properties to propagate onto
296 // JBPNote Need to get info from the user about whether the sequence
297 // is the one being modelled, or if it is a template.
299 .equals(jalview.datamodel.DBRefSource.PDB))
301 fields.put(Fields[LOCALID], dbri.getAccessionId());
308 fields.put(Fields[TYPE], seqTypes[t]);
314 * Indicate if fields parsed to a modeller-like colon-separated value line
318 boolean isModellerFieldset()
320 return (fields.containsKey(Fields[TYPE]));
323 String getDescriptionLine()
326 int lastfield = Fields.length - 1;
328 if (isModellerFieldset())
331 // try to write a minimal modeller field set, so..
333 // find the last valid field in the entry
335 for (; lastfield > 6; lastfield--)
337 if (fields.containsKey(Fields[lastfield]))
343 for (int i = 0; i < lastfield; i++)
345 value = (String) fields.get(Fields[i]);
346 if (value != null && value.length() > 0)
348 desc += ((String) fields.get(Fields[i])) + ":";
352 desc += Padding[i] + ":";
356 // just return the last field if no others were defined.
357 if (fields.containsKey(Fields[lastfield]))
359 desc += (String) fields.get(Fields[lastfield]);
371 resCode val = getStartCode();
372 if (val != null && val.val != null)
374 return val.val.intValue();
379 resCode getStartCode()
381 if (isModellerFieldset() && fields.containsKey(Fields[START] + "num"))
383 return (resCode) fields.get(Fields[START] + "num");
390 if (isModellerFieldset() && fields.containsKey(Fields[END] + "num"))
392 return (resCode) fields.get(Fields[END] + "num");
400 resCode val = getEndCode();
401 if (val != null && val.val != null)
403 return val.val.intValue();
409 * returns true if sequence object was modifed with a valid modellerField set
415 boolean updateSequenceI(SequenceI newSeq)
417 if (isModellerFieldset())
419 resCode rc = getStartCode();
420 if (rc != null && rc.val != null)
422 newSeq.setStart(getStartNum());
429 if (rc != null && rc.val != null)
431 newSeq.setEnd(getEndNum());
435 newSeq.setEnd(newSeq.getStart() + newSeq.getLength());