Line |
Branch |
Exec |
Source |
1 |
|
|
/* BEGIN software license |
2 |
|
|
* |
3 |
|
|
* MsXpertSuite - mass spectrometry software suite |
4 |
|
|
* ----------------------------------------------- |
5 |
|
|
* Copyright(C) 2009,...,2018 Filippo Rusconi |
6 |
|
|
* |
7 |
|
|
* http://www.msxpertsuite.org |
8 |
|
|
* |
9 |
|
|
* This file is part of the MsXpertSuite project. |
10 |
|
|
* |
11 |
|
|
* The MsXpertSuite project is the successor of the massXpert project. This |
12 |
|
|
* project now includes various independent modules: |
13 |
|
|
* |
14 |
|
|
* - massXpert, model polymer chemistries and simulate mass spectrometric data; |
15 |
|
|
* - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; |
16 |
|
|
* |
17 |
|
|
* This program is free software: you can redistribute it and/or modify |
18 |
|
|
* it under the terms of the GNU General Public License as published by |
19 |
|
|
* the Free Software Foundation, either version 3 of the License, or |
20 |
|
|
* (at your option) any later version. |
21 |
|
|
* |
22 |
|
|
* This program is distributed in the hope that it will be useful, |
23 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
24 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
25 |
|
|
* GNU General Public License for more details. |
26 |
|
|
* |
27 |
|
|
* You should have received a copy of the GNU General Public License |
28 |
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
29 |
|
|
* |
30 |
|
|
* END software license |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
|
34 |
|
|
/////////////////////// Local includes |
35 |
|
|
#include "PolChemDefEntity.hpp" |
36 |
|
|
#include "globals.hpp" |
37 |
|
|
#include "Modif.hpp" |
38 |
|
|
#include "PolChemDef.hpp" |
39 |
|
|
#include "Monomer.hpp" |
40 |
|
|
#include <qdebug.h> |
41 |
|
|
|
42 |
|
|
namespace MsXpS |
43 |
|
|
{ |
44 |
|
|
|
45 |
|
|
namespace libXpertMass |
46 |
|
|
{ |
47 |
|
|
|
48 |
|
|
|
49 |
|
|
/*! |
50 |
|
|
\class MsXpS::libXpertMass::Modif |
51 |
|
|
\inmodule libXpertMass |
52 |
|
|
\ingroup PolChemDefBuildingdBlocks |
53 |
|
|
\inheaderfile Modif.hpp |
54 |
|
|
|
55 |
|
|
\brief The Modif class provides abstractions to work with |
56 |
|
|
chemical modifications. |
57 |
|
|
|
58 |
|
|
The Modif class provides a chemical modification that can be set to any monomer |
59 |
|
|
in a polymer sequence or to any one of the polymer sequence ends.In the protein |
60 |
|
|
world, chemical modifications of proteins that occur in the living cell are |
61 |
|
|
called post-translational modifications.This class aims at modelling, among |
62 |
|
|
others, such modifications. |
63 |
|
|
|
64 |
|
|
The chemical reaction described by the Modif class is encoded as an |
65 |
|
|
actionformula (see \l{Formula}). |
66 |
|
|
*/ |
67 |
|
|
|
68 |
|
|
/*! |
69 |
|
|
\variable int MsXpS::libXpertMass::Modif::m_targets |
70 |
|
|
|
71 |
|
|
\brief String that holds a list of all the target monomers of this |
72 |
|
|
modification. |
73 |
|
|
|
74 |
|
|
If there are more than one target, the targets (monomer codes) |
75 |
|
|
must be separated by ';' characters. |
76 |
|
|
|
77 |
|
|
If any monomer in the polymer chemistry definition might be modified by this |
78 |
|
|
Modif object, then, the "*" string can be used to indicate so. |
79 |
|
|
*/ |
80 |
|
|
|
81 |
|
|
/*! |
82 |
|
|
\variable int MsXpS::libXpertMass::Modif::m_maxCount |
83 |
|
|
|
84 |
|
|
\brief Value indicating the maximum number of times this modification |
85 |
|
|
can be set to a target entity (monomer or polymer). |
86 |
|
|
*/ |
87 |
|
|
|
88 |
|
|
|
89 |
|
4 |
Modif::Modif(PolChemDefCstSPtr pol_chem_def_csp, |
90 |
|
|
const QDomElement &element, |
91 |
|
4 |
[[maybe_unused]] int version) |
92 |
5/10
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 4 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 4 times.
✗ Branch 19 not taken.
|
4 |
: PolChemDefEntity(pol_chem_def_csp, "NOT_SET") |
93 |
|
|
{ |
94 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
|
4 |
if(element.tagName() != "mdf") |
95 |
|
✗ |
return; |
96 |
|
|
|
97 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
QDomElement child; |
98 |
|
|
|
99 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
|
4 |
if(element.tagName() != "mdf") |
100 |
|
✗ |
return; |
101 |
|
|
|
102 |
3/6
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 |
child = element.firstChildElement("name"); |
103 |
|
|
|
104 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 |
if(child.isNull()) |
105 |
|
✗ |
return; |
106 |
|
|
|
107 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
m_name = child.text(); |
108 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 |
if(m_name.isEmpty()) |
109 |
|
✗ |
return; |
110 |
|
|
|
111 |
3/6
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 |
child = child.nextSiblingElement("formula"); |
112 |
|
|
|
113 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 |
if(child.isNull()) |
114 |
|
✗ |
return; |
115 |
|
|
|
116 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 |
if(!Formula::renderXmlFormulaElement(child)) |
117 |
|
✗ |
return; |
118 |
|
|
|
119 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 |
if(!calculateMasses()) |
120 |
|
✗ |
return; |
121 |
|
|
|
122 |
3/6
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 |
child = child.nextSiblingElement("targets"); |
123 |
|
|
|
124 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 |
if(child.isNull()) |
125 |
|
✗ |
return; |
126 |
|
|
|
127 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
m_targets = child.text(); |
128 |
|
|
|
129 |
3/6
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 |
child = child.nextSiblingElement("maxcount"); |
130 |
|
|
|
131 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 |
if(child.isNull()) |
132 |
|
✗ |
return; |
133 |
|
|
|
134 |
|
4 |
bool ok = false; |
135 |
|
|
|
136 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 |
m_maxCount = child.text().toInt(&ok); |
137 |
|
|
|
138 |
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
4 |
if(!m_maxCount && !ok) |
139 |
|
✗ |
return; |
140 |
|
|
|
141 |
|
|
// The validation will take care of checking that the <targets> |
142 |
|
|
// element did have correct text inside and that <maxcount> be |
143 |
|
|
// correct also. |
144 |
|
|
|
145 |
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 |
if(!validate()) |
146 |
|
✗ |
qDebug("The Modif being constructed failed to validate."); |
147 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
} |
148 |
|
|
|
149 |
|
|
/*! |
150 |
|
|
\brief Constructs a modification. |
151 |
|
|
|
152 |
|
|
A Modif instance cannot be of any use if it is not associated logically to a |
153 |
|
|
polymer chemistry definition (\a pol_chem_def_csp). The formula is defined by |
154 |
|
|
its \a name and its \a formula as as string (that defaults to empty in this |
155 |
|
|
constructor). |
156 |
|
|
|
157 |
|
|
Being able to construct a Modif without a formula string is necessary when Modif |
158 |
|
|
objects are intialized piecemeal upon reading XML elements that describe the |
159 |
|
|
Modif. |
160 |
|
|
|
161 |
|
|
The \a formula might be a simple formula ("O", for an oxydation) or an |
162 |
|
|
actionformula, if that is required to best characterize the modification |
163 |
|
|
("-H20+CH3COOH", for example, for an acetylation). The formula string can also |
164 |
|
|
have a title, like "\"Acetylation\"-H20+CH3COOH". |
165 |
|
|
|
166 |
|
|
The Ponderable base class' mono and avg masses are initialized to (0,0). |
167 |
|
|
|
168 |
|
|
The targets (m_targets) is set to "all", that is \c "*" and the maximum count |
169 |
|
|
that this modification can bet set to a target is set to \c 1 by default, like a |
170 |
|
|
Seryl residue can only be phosphorylated once, for example. |
171 |
|
|
|
172 |
|
|
If \a pol_chem_def_csp and \a modif_name are usable, then \c this modification |
173 |
|
|
is initialized by looking into the polymer chemistry definition's list of Modif |
174 |
|
|
instances and using the found Modif that has the same name as \a modif_name. |
175 |
|
|
*/ |
176 |
|
10508 |
Modif::Modif(PolChemDefCstSPtr pol_chem_def_csp, |
177 |
|
|
QString modif_name, |
178 |
|
10508 |
QString formula_string) |
179 |
|
|
: PolChemDefEntity(pol_chem_def_csp, modif_name), |
180 |
|
|
Formula(formula_string), |
181 |
|
|
Ponderable(0, 0), |
182 |
|
10508 |
m_targets("*"), |
183 |
5/10
✓ Branch 2 taken 10508 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 10508 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 10508 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 10508 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 10508 times.
✗ Branch 16 not taken.
|
10508 |
m_maxCount(1) |
184 |
|
|
{ |
185 |
|
|
// By default a modification will target any monomer. By default |
186 |
|
|
// the modification will be able to modify an entity only once at maximum, |
187 |
|
|
// like a Seryl may be phosphorylated only once. |
188 |
|
|
|
189 |
6/8
✓ Branch 1 taken 10508 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10508 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10448 times.
✓ Branch 7 taken 60 times.
✓ Branch 8 taken 10448 times.
✓ Branch 9 taken 60 times.
|
21016 |
if(pol_chem_def_csp != nullptr && pol_chem_def_csp.get() != nullptr && |
190 |
|
10508 |
formula_string.isEmpty()) |
191 |
|
|
{ |
192 |
|
|
[[maybe_unused]] bool result; |
193 |
1/2
✓ Branch 2 taken 10448 times.
✗ Branch 3 not taken.
|
10448 |
result = pol_chem_def_csp->referenceModifByName(modif_name, this); |
194 |
|
|
|
195 |
|
|
// if(!result) |
196 |
|
|
// qWarning() << "Modification by name" << modif_name |
197 |
|
|
// << "is not known to the polymer chemistry definition."; |
198 |
|
|
} |
199 |
|
10508 |
} |
200 |
|
|
|
201 |
|
|
|
202 |
|
|
/*! |
203 |
|
|
\brief Constructs a Modif object as a copy of \a other. |
204 |
|
|
*/ |
205 |
|
2160 |
Modif::Modif(const Modif &other) |
206 |
|
|
: PolChemDefEntity(other), |
207 |
|
|
Formula(other), |
208 |
|
|
Ponderable(other), |
209 |
|
|
PropListHolder(other), |
210 |
|
2160 |
m_targets(other.m_targets), |
211 |
3/6
✓ Branch 2 taken 2160 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2160 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2160 times.
✗ Branch 9 not taken.
|
2160 |
m_maxCount(other.m_maxCount) |
212 |
|
|
{ |
213 |
|
2160 |
} |
214 |
|
|
|
215 |
|
|
/*! |
216 |
|
|
\brief Destructs this Modif. |
217 |
|
|
*/ |
218 |
|
4976 |
Modif::~Modif() |
219 |
|
|
{ |
220 |
|
4976 |
} |
221 |
|
|
|
222 |
|
|
|
223 |
|
|
/*! |
224 |
|
|
\brief Assigns \a other to this modification. |
225 |
|
|
|
226 |
|
|
Returns a reference to this modification. |
227 |
|
|
*/ |
228 |
|
|
Modif & |
229 |
|
128 |
Modif::operator=(const Modif &other) |
230 |
|
|
{ |
231 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 |
if(&other == this) |
232 |
|
✗ |
return *this; |
233 |
|
|
|
234 |
|
128 |
PolChemDefEntity::operator=(other); |
235 |
|
128 |
Formula::operator=(other); |
236 |
|
128 |
Ponderable::operator=(other); |
237 |
|
128 |
PropListHolder::operator=(other); |
238 |
|
|
|
239 |
|
128 |
return *this; |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
|
243 |
|
|
/*! Resets this modification to an empty object. |
244 |
|
|
*/ |
245 |
|
|
void |
246 |
|
✗ |
Modif::reset() |
247 |
|
|
{ |
248 |
|
✗ |
m_name = "NOT_SET"; |
249 |
|
|
|
250 |
|
✗ |
m_formula.clear(); |
251 |
|
✗ |
m_plusFormula.clear(); |
252 |
|
✗ |
m_minusFormula.clear(); |
253 |
|
|
|
254 |
|
|
// When m_targets is empty, the modification cannot modify |
255 |
|
|
// anything. Useful for testing purposes. |
256 |
|
✗ |
m_targets.clear(); |
257 |
|
✗ |
m_maxCount = 1; |
258 |
|
|
|
259 |
|
✗ |
m_mono = 0; |
260 |
|
✗ |
m_avg = 0; |
261 |
|
|
|
262 |
|
✗ |
while(!m_propList.isEmpty()) |
263 |
|
✗ |
delete m_propList.takeFirst(); |
264 |
|
✗ |
} |
265 |
|
|
|
266 |
|
|
/*! |
267 |
|
|
\brief Sets the \a targets for this modification. |
268 |
|
|
|
269 |
|
|
Setting \e{targets} means specifying which target might be modified using |
270 |
|
|
this modification. For example, for \c Phosphorylation, in protein chemistry, |
271 |
|
|
one would define targets as \c Serine, \c Threonine, \c Tyrosine (there are |
272 |
|
|
other targets, but very rarely encountered). |
273 |
|
|
|
274 |
|
|
Multiple targets are separated using ';'. |
275 |
|
|
|
276 |
|
|
*/ |
277 |
|
|
QString & |
278 |
|
24 |
Modif::setTargets(QString targets) |
279 |
|
|
{ |
280 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
|
24 |
if(targets.isEmpty()) |
281 |
|
|
{ |
282 |
|
✗ |
m_targets.clear(); |
283 |
|
✗ |
return m_targets; |
284 |
|
|
} |
285 |
|
|
|
286 |
|
|
// qDebug() << __FILE__ << __LINE__ |
287 |
|
|
// << "Before unspacification" << targets; |
288 |
|
|
|
289 |
|
|
// Remove any space from 'targets'. |
290 |
|
24 |
m_targets = unspacifyString(targets); |
291 |
|
|
|
292 |
|
|
// qDebug() << __FILE__ << __LINE__ |
293 |
|
|
// << "After unspacification" << m_targets; |
294 |
|
|
|
295 |
|
|
// Validate and simplify: true is by default the bool param. |
296 |
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 20 times.
|
24 |
if(!validateTargets()) |
297 |
|
4 |
m_targets = QString(); |
298 |
|
|
|
299 |
|
24 |
return m_targets; |
300 |
|
|
} |
301 |
|
|
|
302 |
|
|
/*! |
303 |
|
|
\brief Returns the tagets of this modification. |
304 |
|
|
*/ |
305 |
|
|
QString |
306 |
|
32 |
Modif::targets() const |
307 |
|
|
{ |
308 |
|
32 |
return m_targets; |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
/*! |
312 |
|
|
\brief Returns the tagets of this modification in the form a string list. |
313 |
|
|
|
314 |
|
|
The member m_targets string is split using ';' as a delimitor, the |
315 |
|
|
obtained list of strings is set to \a string_list and the size of the list is |
316 |
|
|
returned. |
317 |
|
|
*/ |
318 |
|
|
int |
319 |
|
✗ |
Modif::targets(QStringList &string_list) const |
320 |
|
|
{ |
321 |
|
|
// Return a string list after splitting at ';'. |
322 |
|
|
|
323 |
|
✗ |
string_list.clear(); |
324 |
|
|
|
325 |
|
✗ |
string_list = m_targets.split(';', Qt::SkipEmptyParts, Qt::CaseSensitive); |
326 |
|
✗ |
return string_list.size(); |
327 |
|
|
} |
328 |
|
|
|
329 |
|
|
/*! |
330 |
|
|
\brief Returns true if monomer \a code is found among the targets of this |
331 |
|
|
modifications, false otherwise. |
332 |
|
|
*/ |
333 |
|
|
bool |
334 |
|
44 |
Modif::hasMonomerTarget(QString code) const |
335 |
|
|
{ |
336 |
2/2
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 16 times.
|
44 |
if(m_targets == "*") |
337 |
|
28 |
return true; |
338 |
|
|
|
339 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 |
if(m_targets == "!") |
340 |
|
✗ |
return false; |
341 |
|
|
|
342 |
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
32 |
QString delimitedCode = QString(";%1;").arg(code); |
343 |
|
|
|
344 |
|
|
// The m_targets string is in the form ";code;code;code;". |
345 |
|
|
|
346 |
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 |
return m_targets.contains(delimitedCode, Qt::CaseSensitive); |
347 |
|
16 |
} |
348 |
|
|
|
349 |
|
|
/*! |
350 |
|
|
\brief Validates the target of this modification. |
351 |
|
|
|
352 |
|
|
The target list is split using ';' as a delimiter. If '*' is found and \a |
353 |
|
|
simplify is true, the function returns true immediately (as all the |
354 |
|
|
monomers in the polymer chemistry definition might be a target of this |
355 |
|
|
modification). |
356 |
|
|
|
357 |
|
|
If at least one target is found, then each target is a monomer |
358 |
|
|
code and that code is looked for in the member polymer chemistry definition list |
359 |
|
|
of monomers. If the code is found, that code is added to a temporary string. If |
360 |
|
|
the code is not found, m_targets is set to that temporary string (only having in |
361 |
|
|
it monomer codes found in the polymer chemistry definition's list of monomers) |
362 |
|
|
and the function returns false. |
363 |
|
|
|
364 |
|
|
Returns true if the targets of this modification all validated successfully. |
365 |
|
|
*/ |
366 |
|
|
bool |
367 |
|
12188 |
Modif::validateTargets(bool simplify) |
368 |
|
|
{ |
369 |
|
|
// A targets string cannot contain both a '*' and a '!' |
370 |
|
|
// character. We check that immediately. |
371 |
6/10
✓ Branch 2 taken 12188 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1184 times.
✓ Branch 5 taken 11004 times.
✓ Branch 8 taken 1184 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1184 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12188 times.
|
12188 |
if(m_targets.contains('*') && m_targets.contains('!')) |
372 |
|
✗ |
return false; |
373 |
|
|
|
374 |
1/2
✓ Branch 2 taken 12188 times.
✗ Branch 3 not taken.
|
12188 |
QList<Monomer *> monomerList = mcsp_polChemDef->monomerList(); |
375 |
|
|
|
376 |
|
12188 |
QString result; |
377 |
|
|
|
378 |
|
|
// If the m_targets is empty, this is an error, because we cannot |
379 |
|
|
// know what's to be done with the modification. |
380 |
|
|
|
381 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12188 times.
|
12188 |
if(m_targets.isEmpty()) |
382 |
|
|
{ |
383 |
|
✗ |
return false; |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
// A targets string looks like "Ser ; Thr ; Tyr". |
387 |
|
|
QStringList stringList = |
388 |
1/2
✓ Branch 3 taken 12188 times.
✗ Branch 4 not taken.
|
12188 |
m_targets.split(';', Qt::SkipEmptyParts, Qt::CaseSensitive); |
389 |
|
|
|
390 |
2/2
✓ Branch 1 taken 20432 times.
✓ Branch 2 taken 11000 times.
|
31432 |
for(int iter = 0; iter < stringList.size(); ++iter) |
391 |
|
|
{ |
392 |
|
20432 |
QString currentString = stringList.at(iter); |
393 |
|
|
|
394 |
|
|
// There are two character that might be encountered: '*' is the |
395 |
|
|
// equivalent of "all the monomers in the definition"; '!' is |
396 |
|
|
// equivalent to "none of the monomers in the definition". But |
397 |
|
|
// it is not possible that both * and ! be present in the same |
398 |
|
|
// targets string. |
399 |
|
|
|
400 |
5/6
✓ Branch 1 taken 19248 times.
✓ Branch 2 taken 1184 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 19248 times.
✓ Branch 6 taken 1184 times.
✓ Branch 7 taken 19248 times.
|
20432 |
if(currentString == "*" || currentString == "!") |
401 |
|
|
{ |
402 |
|
|
// Simplification asked: if '*' is found then it can be |
403 |
|
|
// there alone. Same for '!'. '*' means that any monomer in |
404 |
|
|
// the definition might be modified with this modification, |
405 |
|
|
// '!' means that none of the monomers might be modified. |
406 |
|
|
|
407 |
1/2
✓ Branch 0 taken 1184 times.
✗ Branch 1 not taken.
|
1184 |
if(simplify) |
408 |
|
|
{ |
409 |
|
1184 |
m_targets = currentString; |
410 |
|
|
|
411 |
|
1184 |
return true; |
412 |
|
|
} |
413 |
|
|
else |
414 |
|
|
{ |
415 |
|
✗ |
result.append(QString("%1;").arg(currentString)); |
416 |
|
|
} |
417 |
|
|
|
418 |
|
✗ |
continue; |
419 |
|
|
} |
420 |
|
|
|
421 |
|
|
// At this point, we have something to check as a monomer code: |
422 |
|
|
|
423 |
3/4
✓ Branch 1 taken 19248 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 19244 times.
|
19248 |
if(Monomer::isCodeInList(currentString, monomerList) == -1) |
424 |
|
|
{ |
425 |
3/6
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 |
qDebug() << "Monomer code is not known:" << currentString; |
426 |
|
|
|
427 |
|
4 |
m_targets = result; |
428 |
|
|
|
429 |
|
4 |
return false; |
430 |
|
|
} |
431 |
|
|
else |
432 |
|
|
{ |
433 |
|
|
// Want the string to be ;code;code;code;(notice the first |
434 |
|
|
// and last ';'), so that we can later ask easily if ;Lys; |
435 |
|
|
// is found in the targets string, without risking to also |
436 |
|
|
// match ;Ly;. |
437 |
2/2
✓ Branch 1 taken 11004 times.
✓ Branch 2 taken 8240 times.
|
19244 |
if(!result.size()) |
438 |
3/6
✓ Branch 1 taken 11004 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11004 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 11004 times.
✗ Branch 8 not taken.
|
22008 |
result.append(QString(";%1;").arg(currentString)); |
439 |
|
|
else |
440 |
3/6
✓ Branch 1 taken 8240 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8240 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8240 times.
✗ Branch 8 not taken.
|
16480 |
result.append(QString("%1;").arg(currentString)); |
441 |
|
|
} |
442 |
2/3
✓ Branch 1 taken 19244 times.
✓ Branch 2 taken 1188 times.
✗ Branch 3 not taken.
|
20432 |
} |
443 |
|
|
|
444 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11000 times.
|
11000 |
if(result.isEmpty()) |
445 |
|
✗ |
return false; |
446 |
|
|
|
447 |
|
11000 |
m_targets = result; |
448 |
|
|
|
449 |
|
11000 |
return true; |
450 |
|
12188 |
} |
451 |
|
|
|
452 |
|
|
|
453 |
|
|
/*! |
454 |
|
|
\brief Set the maximum count of times that this modification might be set to |
455 |
|
|
a target to \a value. |
456 |
|
|
*/ |
457 |
|
|
void |
458 |
|
✗ |
Modif::setMaxCount(int value) |
459 |
|
|
{ |
460 |
|
✗ |
Q_ASSERT(value > 0); |
461 |
|
|
|
462 |
|
✗ |
m_maxCount = value; |
463 |
|
✗ |
} |
464 |
|
|
|
465 |
|
|
/*! |
466 |
|
|
\brief Returns the maximum count of times that this modification might be |
467 |
|
|
set to a target. |
468 |
|
|
*/ |
469 |
|
|
int |
470 |
|
56 |
Modif::maxCount() const |
471 |
|
|
{ |
472 |
|
56 |
return m_maxCount; |
473 |
|
|
} |
474 |
|
|
|
475 |
|
|
/* |
476 |
|
|
\brief Returns the formula describing this modification. |
477 |
|
|
*/ |
478 |
|
|
QString |
479 |
|
32 |
Modif::formula() const |
480 |
|
|
{ |
481 |
|
32 |
return Formula::toString(); |
482 |
|
|
} |
483 |
|
|
|
484 |
|
|
/*! |
485 |
|
|
\brief Returns the index of \c this modification in the member |
486 |
|
|
polymer chemistry definition's list of modifications, -1 otherwise |
487 |
|
|
*/ |
488 |
|
|
int |
489 |
|
4 |
Modif::isNameKnown() |
490 |
|
|
{ |
491 |
|
4 |
const QList<Modif *> &refList = mcsp_polChemDef->modifList(); |
492 |
|
|
|
493 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 |
if(m_name.isEmpty()) |
494 |
|
✗ |
return -1; |
495 |
|
|
|
496 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
for(int iter = 0; iter < refList.size(); ++iter) |
497 |
|
|
{ |
498 |
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 |
if(refList.at(iter)->m_name == m_name) |
499 |
|
4 |
return iter; |
500 |
|
|
} |
501 |
|
|
|
502 |
|
✗ |
return -1; |
503 |
|
|
} |
504 |
|
|
|
505 |
|
|
|
506 |
|
|
/*! |
507 |
|
|
\brief Searches for a modification by name \a name in the reference list \a |
508 |
|
|
refList. |
509 |
|
|
|
510 |
|
|
If a modification is found, and \a other is non-nullptr, the found modif is |
511 |
|
|
copied to \a other. |
512 |
|
|
|
513 |
|
|
Returns true if the modification was found, false otherwise. |
514 |
|
|
*/ |
515 |
|
|
int |
516 |
|
2056 |
Modif::isNameInList(const QString &name, |
517 |
|
|
const QList<Modif *> &refList, |
518 |
|
|
Modif *other) |
519 |
|
|
{ |
520 |
|
2056 |
Modif *iter_modif_p = 0; |
521 |
|
|
|
522 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2056 times.
|
2056 |
if(name.isEmpty()) |
523 |
|
✗ |
return -1; |
524 |
|
|
|
525 |
|
|
// qDebug() << "Looking for modif by name" << name; |
526 |
|
|
|
527 |
1/2
✓ Branch 1 taken 26840 times.
✗ Branch 2 not taken.
|
26840 |
for(int iter = 0; iter < refList.size(); ++iter) |
528 |
|
|
{ |
529 |
|
26840 |
iter_modif_p = refList.at(iter); |
530 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26840 times.
|
26840 |
Q_ASSERT(iter_modif_p); |
531 |
|
|
|
532 |
2/2
✓ Branch 1 taken 2056 times.
✓ Branch 2 taken 24784 times.
|
26840 |
if(iter_modif_p->m_name == name) |
533 |
|
|
{ |
534 |
1/2
✓ Branch 1 taken 2056 times.
✗ Branch 2 not taken.
|
2056 |
Modif test_modif(*iter_modif_p); |
535 |
|
|
|
536 |
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 1964 times.
|
2056 |
if(other) |
537 |
|
|
{ |
538 |
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
|
92 |
*other = *iter_modif_p; |
539 |
|
|
} |
540 |
|
2056 |
return iter; |
541 |
|
2056 |
} |
542 |
|
|
} |
543 |
|
|
|
544 |
|
✗ |
return -1; |
545 |
|
|
} |
546 |
|
|
|
547 |
|
|
|
548 |
|
|
/*! |
549 |
|
|
\brief Validates this modification. |
550 |
|
|
|
551 |
|
|
The modification validates successfully if: |
552 |
|
|
|
553 |
|
|
\list |
554 |
|
|
\li The member polymer chemistry definition must be set |
555 |
|
|
\li The name is not empty |
556 |
|
|
\li The formula validates successfully |
557 |
|
|
\li The targets validate successfully |
558 |
|
|
\li The m_maxCount member is greater than 0 |
559 |
|
|
\endlist |
560 |
|
|
|
561 |
|
|
Returns true if the modification validates successfully, false otherwise. |
562 |
|
|
*/ |
563 |
|
|
bool |
564 |
|
12164 |
Modif::validate() |
565 |
|
|
{ |
566 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12164 times.
|
12164 |
if(mcsp_polChemDef == nullptr) |
567 |
|
✗ |
return false; |
568 |
|
|
|
569 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12164 times.
|
12164 |
if(m_name.isEmpty()) |
570 |
|
✗ |
return false; |
571 |
|
|
|
572 |
1/2
✓ Branch 1 taken 12164 times.
✗ Branch 2 not taken.
|
12164 |
Formula formula(m_formula); |
573 |
|
|
|
574 |
|
|
IsotopicDataCstSPtr isotopic_data_csp = |
575 |
1/2
✓ Branch 2 taken 12164 times.
✗ Branch 3 not taken.
|
12164 |
mcsp_polChemDef->getIsotopicDataCstSPtr(); |
576 |
|
|
|
577 |
2/4
✓ Branch 2 taken 12164 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 12164 times.
|
12164 |
if(!formula.validate(isotopic_data_csp)) |
578 |
|
|
{ |
579 |
|
✗ |
qDebug() << "The formula failed to validate."; |
580 |
|
|
|
581 |
|
✗ |
return false; |
582 |
|
|
} |
583 |
|
|
|
584 |
2/4
✓ Branch 1 taken 12164 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12164 times.
|
12164 |
if(!validateTargets()) |
585 |
|
|
{ |
586 |
|
✗ |
qDebug() << "The targets failed to validate."; |
587 |
|
✗ |
return false; |
588 |
|
|
} |
589 |
|
|
|
590 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12164 times.
|
12164 |
if(m_maxCount <= 0) |
591 |
|
✗ |
return false; |
592 |
|
|
|
593 |
|
12164 |
return true; |
594 |
|
12164 |
} |
595 |
|
|
|
596 |
|
|
|
597 |
|
|
/*! |
598 |
|
|
\brief Calculates the net masses of this modification. |
599 |
|
|
|
600 |
|
|
The masses of the modification are the masses (monoisotopic and average) that |
601 |
|
|
are added to the target as a result of that target being modified with this |
602 |
|
|
modification. |
603 |
|
|
|
604 |
|
|
The calculated masses are set to the Ponderable base class' m_mono and m_avg |
605 |
|
|
members. |
606 |
|
|
|
607 |
|
|
Returns true if the mass calculations were successful, false otherwise. |
608 |
|
|
|
609 |
|
|
\sa Formula::accountMasses() |
610 |
|
|
*/ |
611 |
|
|
bool |
612 |
|
10332 |
Modif::calculateMasses() |
613 |
|
|
{ |
614 |
|
|
IsotopicDataCstSPtr isotopic_data_csp = |
615 |
1/2
✓ Branch 2 taken 10332 times.
✗ Branch 3 not taken.
|
10332 |
mcsp_polChemDef->getIsotopicDataCstSPtr(); |
616 |
|
|
|
617 |
|
10332 |
m_mono = 0; |
618 |
|
10332 |
m_avg = 0; |
619 |
|
|
|
620 |
|
|
// qDebug() << "Right before accounting modif formula masses for formula:" |
621 |
|
|
// << m_formula; |
622 |
|
|
|
623 |
2/4
✓ Branch 2 taken 10332 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 10332 times.
|
10332 |
if(!Formula::accountMasses(isotopic_data_csp, &m_mono, &m_avg)) |
624 |
|
|
{ |
625 |
|
✗ |
qDebug() << "Failed accounting masses for modif:" << m_name |
626 |
|
✗ |
<< "and formula:" << m_formula; |
627 |
|
✗ |
return false; |
628 |
|
|
} |
629 |
|
|
|
630 |
|
|
// qDebug() << "Right after accounting modif formula masses for formula:" |
631 |
|
|
// << m_formula << m_mono << "-" << m_avg; |
632 |
|
|
|
633 |
|
10332 |
return true; |
634 |
|
10332 |
} |
635 |
|
|
|
636 |
|
|
|
637 |
|
|
/*! |
638 |
|
|
\brief Adds to \a mono and \a avg the corresponding mass of this |
639 |
|
|
modification. |
640 |
|
|
|
641 |
|
|
The m_mono and m_avg masses are added to the arguments. The masses are |
642 |
|
|
compounded by factor \a times before the addition. |
643 |
|
|
|
644 |
|
|
Returns true. |
645 |
|
|
*/ |
646 |
|
|
bool |
647 |
|
2036 |
Modif::accountMasses(double *mono, double *avg, int times) |
648 |
|
|
{ |
649 |
1/2
✓ Branch 0 taken 2036 times.
✗ Branch 1 not taken.
|
2036 |
if(mono) |
650 |
|
2036 |
*mono += m_mono * times; |
651 |
|
|
|
652 |
1/2
✓ Branch 0 taken 2036 times.
✗ Branch 1 not taken.
|
2036 |
if(avg) |
653 |
|
2036 |
*avg += m_avg * times; |
654 |
|
|
|
655 |
|
2036 |
return true; |
656 |
|
|
} |
657 |
|
|
|
658 |
|
|
|
659 |
|
|
/*! |
660 |
|
|
\brief Parses the modification XML \a element specifically for \a version. |
661 |
|
|
|
662 |
|
|
Parses the modif \c mdf XML element passed as argument and for each |
663 |
|
|
encountered data will set the data to this modif (this is |
664 |
|
|
called XML rendering).The parsing is delegated to a function that is specific |
665 |
|
|
for \a version of the polymer chemistry definition. |
666 |
|
|
|
667 |
|
|
The \c mdf XML element is found in the polymer chemistry definition and has |
668 |
|
|
the following form: |
669 |
|
|
|
670 |
|
|
|
671 |
|
|
\code |
672 |
|
|
<mdf> |
673 |
|
|
<name>Acetylation</name> |
674 |
|
|
<formula>C2H2O1</formula> |
675 |
|
|
<targets>;K;</targets> |
676 |
|
|
<maxcount>1</maxcount> |
677 |
|
|
</mdf> |
678 |
|
|
<mdf> |
679 |
|
|
<name>AmidationAsp</name> |
680 |
|
|
<formula>H1N1-O1</formula> |
681 |
|
|
<targets>;D;</targets> |
682 |
|
|
<maxcount>1</maxcount> |
683 |
|
|
</mdf> |
684 |
|
|
\endcode |
685 |
|
|
|
686 |
|
|
After setting all the data, this modification calculates it masses and |
687 |
|
|
validates itself. If any of these steps fails, the error is reported |
688 |
|
|
by returning false. |
689 |
|
|
|
690 |
|
|
Returns true if parsing was successful, false otherwise. |
691 |
|
|
*/ |
692 |
|
|
bool |
693 |
|
10192 |
Modif::renderXmlMdfElement(const QDomElement &element, int version) |
694 |
|
|
{ |
695 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 10192 times.
|
10192 |
if(element.tagName() != "mdf") |
696 |
|
✗ |
return false; |
697 |
|
|
|
698 |
1/2
✓ Branch 0 taken 10192 times.
✗ Branch 1 not taken.
|
10192 |
if(version == 1) |
699 |
|
|
{ |
700 |
|
|
// no-op |
701 |
|
10192 |
version = 1; |
702 |
|
|
} |
703 |
|
|
|
704 |
1/2
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
|
10192 |
QDomElement child; |
705 |
|
|
|
706 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 10192 times.
|
10192 |
if(element.tagName() != "mdf") |
707 |
|
✗ |
return false; |
708 |
|
|
|
709 |
3/6
✓ Branch 2 taken 10192 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10192 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10192 times.
✗ Branch 9 not taken.
|
10192 |
child = element.firstChildElement("name"); |
710 |
|
|
|
711 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10192 times.
|
10192 |
if(child.isNull()) |
712 |
|
✗ |
return false; |
713 |
|
|
|
714 |
1/2
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
|
10192 |
m_name = child.text(); |
715 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10192 times.
|
10192 |
if(m_name.isEmpty()) |
716 |
|
✗ |
return false; |
717 |
|
|
|
718 |
3/6
✓ Branch 2 taken 10192 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10192 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10192 times.
✗ Branch 9 not taken.
|
10192 |
child = child.nextSiblingElement("formula"); |
719 |
|
|
|
720 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10192 times.
|
10192 |
if(child.isNull()) |
721 |
|
✗ |
return false; |
722 |
|
|
|
723 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10192 times.
|
10192 |
if(!Formula::renderXmlFormulaElement(child)) |
724 |
|
✗ |
return false; |
725 |
|
|
|
726 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10192 times.
|
10192 |
if(!calculateMasses()) |
727 |
|
|
{ |
728 |
|
✗ |
qDebug() << "Failed accounting masses for modif: " << m_name |
729 |
|
✗ |
<< "with formula:" << m_formula; |
730 |
|
✗ |
return false; |
731 |
|
|
} |
732 |
|
|
|
733 |
3/6
✓ Branch 2 taken 10192 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10192 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10192 times.
✗ Branch 9 not taken.
|
10192 |
child = child.nextSiblingElement("targets"); |
734 |
|
|
|
735 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10192 times.
|
10192 |
if(child.isNull()) |
736 |
|
✗ |
return false; |
737 |
|
|
|
738 |
1/2
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
|
10192 |
m_targets = child.text(); |
739 |
|
|
|
740 |
3/6
✓ Branch 2 taken 10192 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10192 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10192 times.
✗ Branch 9 not taken.
|
10192 |
child = child.nextSiblingElement("maxcount"); |
741 |
|
|
|
742 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10192 times.
|
10192 |
if(child.isNull()) |
743 |
|
✗ |
return false; |
744 |
|
|
|
745 |
|
10192 |
bool ok = false; |
746 |
|
|
|
747 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10192 times.
✗ Branch 5 not taken.
|
10192 |
m_maxCount = child.text().toInt(&ok); |
748 |
|
|
|
749 |
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
10192 |
if(!m_maxCount && !ok) |
750 |
|
✗ |
return false; |
751 |
|
|
|
752 |
|
|
// The validation will take care of checking that the <targets> |
753 |
|
|
// element did have correct text inside and that <maxcount> be |
754 |
|
|
// correct also. |
755 |
|
|
|
756 |
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10192 times.
|
10192 |
if(!validate()) |
757 |
|
✗ |
return false; |
758 |
|
|
|
759 |
|
10192 |
return true; |
760 |
|
10192 |
} |
761 |
|
|
|
762 |
|
|
|
763 |
|
|
/*! |
764 |
|
|
\brief Formats this modification's data as a string suitable to be used as a |
765 |
|
|
\c mdf XML element in the polymer chemistry definition. |
766 |
|
|
|
767 |
|
|
The typical modification element that is generated in this function looks |
768 |
|
|
like this: |
769 |
|
|
|
770 |
|
|
\code |
771 |
|
|
<mdf> |
772 |
|
|
<name>Acetylation</name> |
773 |
|
|
<formula>C2H2O1</formula> |
774 |
|
|
<targets>;K;</targets> |
775 |
|
|
<maxcount>1</maxcount> |
776 |
|
|
</mdf> |
777 |
|
|
<mdf> |
778 |
|
|
<name>AmidationAsp</name> |
779 |
|
|
<formula>H1N1-O1</formula> |
780 |
|
|
<targets>;D;</targets> |
781 |
|
|
<maxcount>1</maxcount> |
782 |
|
|
</mdf> |
783 |
|
|
\endcode |
784 |
|
|
|
785 |
|
|
The formatting of the XML element takes into account \a offset and \a |
786 |
|
|
indent by prepending the string with \a offset * \a indent character substring. |
787 |
|
|
|
788 |
|
|
\a indent defaults to two spaces. |
789 |
|
|
|
790 |
|
|
Returns a dynamically allocated string that needs to be freed after |
791 |
|
|
use. |
792 |
|
|
*/ |
793 |
|
|
QString * |
794 |
|
112 |
Modif::formatXmlMdfElement(int offset, const QString &indent) |
795 |
|
|
{ |
796 |
|
|
int newOffset; |
797 |
|
112 |
int iter = 0; |
798 |
|
|
|
799 |
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
112 |
QString lead(""); |
800 |
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
112 |
QString *string = new QString(); |
801 |
|
|
|
802 |
|
|
// Prepare the lead. |
803 |
|
112 |
newOffset = offset; |
804 |
2/2
✓ Branch 0 taken 316 times.
✓ Branch 1 taken 112 times.
|
428 |
while(iter < newOffset) |
805 |
|
|
{ |
806 |
1/2
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
|
316 |
lead += indent; |
807 |
|
316 |
++iter; |
808 |
|
|
} |
809 |
|
|
|
810 |
|
|
/* We are willing to create an <modif> node that should look like this: |
811 |
|
|
* |
812 |
|
|
<mdf> |
813 |
|
|
<name>Phosphorylation</name> |
814 |
|
|
<formula>-H+H2PO3</formula> |
815 |
|
|
<targets>S;T;Y</targets> |
816 |
|
|
<maxcount>1</maxcount> |
817 |
|
|
</mdf> |
818 |
|
|
* |
819 |
|
|
*/ |
820 |
|
|
|
821 |
3/6
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
|
224 |
*string += QString("%1<mdf>\n").arg(lead); |
822 |
|
|
|
823 |
|
|
// Prepare the lead. |
824 |
|
112 |
++newOffset; |
825 |
|
112 |
lead.clear(); |
826 |
|
112 |
iter = 0; |
827 |
2/2
✓ Branch 0 taken 428 times.
✓ Branch 1 taken 112 times.
|
540 |
while(iter < newOffset) |
828 |
|
|
{ |
829 |
1/2
✓ Branch 1 taken 428 times.
✗ Branch 2 not taken.
|
428 |
lead += indent; |
830 |
|
428 |
++iter; |
831 |
|
|
} |
832 |
|
|
|
833 |
|
|
// Continue with indented elements. |
834 |
|
|
|
835 |
4/8
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 112 times.
✗ Branch 11 not taken.
|
336 |
*string += QString("%1<name>%2</name>\n").arg(lead).arg(m_name); |
836 |
|
|
|
837 |
4/8
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 112 times.
✗ Branch 11 not taken.
|
336 |
*string += QString("%1<formula>%2</formula>\n").arg(lead).arg(m_formula); |
838 |
|
|
|
839 |
4/8
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 112 times.
✗ Branch 11 not taken.
|
336 |
*string += QString("%1<targets>%2</targets>\n").arg(lead).arg(m_targets); |
840 |
|
|
|
841 |
4/8
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 112 times.
✗ Branch 11 not taken.
|
336 |
*string += QString("%1<maxcount>%2</maxcount>\n").arg(lead).arg(m_maxCount); |
842 |
|
|
|
843 |
|
|
// Prepare the lead for the closing element. |
844 |
|
112 |
--newOffset; |
845 |
|
112 |
lead.clear(); |
846 |
|
112 |
iter = 0; |
847 |
2/2
✓ Branch 0 taken 316 times.
✓ Branch 1 taken 112 times.
|
428 |
while(iter < newOffset) |
848 |
|
|
{ |
849 |
1/2
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
|
316 |
lead += indent; |
850 |
|
316 |
++iter; |
851 |
|
|
} |
852 |
|
|
|
853 |
3/6
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
|
224 |
*string += QString("%1</mdf>\n").arg(lead); |
854 |
|
|
|
855 |
|
112 |
return string; |
856 |
|
112 |
} |
857 |
|
|
|
858 |
|
|
|
859 |
|
|
/*! |
860 |
|
|
\brief Outputs a string representing this modification using qDebug(). |
861 |
|
|
*/ |
862 |
|
|
void |
863 |
|
✗ |
Modif::debugPutStdErr() |
864 |
|
|
{ |
865 |
|
✗ |
qDebug() << m_name << m_formula << m_targets; |
866 |
|
✗ |
} |
867 |
|
|
|
868 |
|
|
|
869 |
|
|
//////////////////////// ModifProp //////////////////////// |
870 |
|
|
//////////////////////// ModifProp //////////////////////// |
871 |
|
|
|
872 |
|
|
|
873 |
|
|
/*! |
874 |
|
|
\class MsXpS::libXpertMass::ModifProp |
875 |
|
|
\inmodule libXpertMass |
876 |
|
|
\ingroup ThePropSystem |
877 |
|
|
|
878 |
|
|
\brief The ModifProp class provides a Prop instance of which the member data |
879 |
|
|
points to a dynamically allocated \l Modif instance. |
880 |
|
|
|
881 |
|
|
The member datum \l m_name is set to "MODIF". |
882 |
|
|
*/ |
883 |
|
|
|
884 |
|
|
/*! |
885 |
|
|
\brief Constructs a ModifProp instance using \a modif. |
886 |
|
|
|
887 |
|
|
The \a modif pointer is set to the \l mpa_data member. |
888 |
|
|
*/ |
889 |
|
✗ |
ModifProp::ModifProp(Modif *modif) : Prop("MODIF") |
890 |
|
|
{ |
891 |
|
✗ |
mpa_data = static_cast<void *>(modif); |
892 |
|
✗ |
} |
893 |
|
|
|
894 |
|
|
|
895 |
|
|
/*! |
896 |
|
|
\brief Constructs a ModifProp instance as a copy of \a other. |
897 |
|
|
*/ |
898 |
|
✗ |
ModifProp::ModifProp(const ModifProp &other) : Prop(other) |
899 |
|
|
{ |
900 |
|
✗ |
if(other.mpa_data != nullptr) |
901 |
|
|
{ |
902 |
|
✗ |
Modif *modif = static_cast<Modif *>(other.mpa_data); |
903 |
|
|
|
904 |
|
✗ |
mpa_data = static_cast<void *>(new Modif(*modif)); |
905 |
|
|
} |
906 |
|
|
else |
907 |
|
✗ |
mpa_data = nullptr; |
908 |
|
✗ |
} |
909 |
|
|
|
910 |
|
|
/*! |
911 |
|
|
\brief Destructs this ModifProp instance. |
912 |
|
|
|
913 |
|
|
The deletion of the data are delegated to \l deleteData(). |
914 |
|
|
*/ |
915 |
|
✗ |
ModifProp::~ModifProp() |
916 |
|
|
{ |
917 |
|
✗ |
deleteData(); |
918 |
|
✗ |
} |
919 |
|
|
|
920 |
|
|
/*! |
921 |
|
|
\brief Deletes the member data. |
922 |
|
|
*/ |
923 |
|
|
void |
924 |
|
✗ |
ModifProp::deleteData() |
925 |
|
|
{ |
926 |
|
✗ |
if(mpa_data != nullptr) |
927 |
|
|
{ |
928 |
|
✗ |
delete static_cast<Modif *>(mpa_data); |
929 |
|
✗ |
mpa_data = nullptr; |
930 |
|
|
} |
931 |
|
✗ |
} |
932 |
|
|
|
933 |
|
|
/*! |
934 |
|
|
\brief Assigns \a other to this ModifProp instance. |
935 |
|
|
|
936 |
|
|
The member data are first deleted and then set to a copy of those in \a other. |
937 |
|
|
*/ |
938 |
|
|
ModifProp & |
939 |
|
✗ |
ModifProp::operator=(const ModifProp &other) |
940 |
|
|
{ |
941 |
|
✗ |
if(&other == this) |
942 |
|
✗ |
return *this; |
943 |
|
|
|
944 |
|
✗ |
Prop::operator=(other); |
945 |
|
|
|
946 |
|
✗ |
if(mpa_data != nullptr) |
947 |
|
✗ |
deleteData(); |
948 |
|
|
|
949 |
|
✗ |
if(other.mpa_data) |
950 |
|
|
{ |
951 |
|
✗ |
Modif *modif = static_cast<Modif *>(other.mpa_data); |
952 |
|
|
|
953 |
|
✗ |
mpa_data = static_cast<void *>(new Modif(*modif)); |
954 |
|
|
} |
955 |
|
|
else |
956 |
|
✗ |
mpa_data = nullptr; |
957 |
|
|
|
958 |
|
✗ |
return *this; |
959 |
|
|
} |
960 |
|
|
|
961 |
|
|
/*! |
962 |
|
|
\brief Returns true if this and the \a other modifications are identical, |
963 |
|
|
false otherwise. |
964 |
|
|
*/ |
965 |
|
|
bool |
966 |
|
72 |
Modif::operator==(const Modif &other) |
967 |
|
|
{ |
968 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
|
72 |
if(&other == this) |
969 |
|
✗ |
return true; |
970 |
|
|
|
971 |
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 64 times.
|
72 |
if(PolChemDefEntity::operator!=(other)) |
972 |
|
8 |
return false; |
973 |
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 56 times.
|
64 |
if(Formula::operator!=(other)) |
974 |
|
8 |
return false; |
975 |
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 48 times.
|
56 |
if(Ponderable::operator!=(other)) |
976 |
|
8 |
return false; |
977 |
|
|
|
978 |
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 40 times.
|
48 |
if(m_targets != other.m_targets) |
979 |
|
8 |
return false; |
980 |
|
|
|
981 |
|
40 |
return true; |
982 |
|
|
} |
983 |
|
|
|
984 |
|
|
/*! |
985 |
|
|
\brief Returns true if this and the \a other modifications differ, |
986 |
|
|
false otherwise. |
987 |
|
|
|
988 |
|
|
Returns the negated result of operator==(). |
989 |
|
|
*/ |
990 |
|
|
bool |
991 |
|
36 |
Modif::operator!=(const Modif &other) |
992 |
|
|
{ |
993 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 |
if(&other == this) |
994 |
|
✗ |
return false; |
995 |
|
|
|
996 |
|
36 |
return !operator==(other); |
997 |
|
|
} |
998 |
|
|
|
999 |
|
|
|
1000 |
|
|
/*! |
1001 |
|
|
\brief Duplicates this ModifProp instance and returns its pointer. |
1002 |
|
|
*/ |
1003 |
|
|
ModifProp * |
1004 |
|
✗ |
ModifProp::cloneOut() const |
1005 |
|
|
{ |
1006 |
|
✗ |
ModifProp *new_p = new ModifProp(*this); |
1007 |
|
|
|
1008 |
|
✗ |
return new_p; |
1009 |
|
|
} |
1010 |
|
|
|
1011 |
|
|
|
1012 |
|
|
/*! |
1013 |
|
|
\brief Parses the property XML \a element using a \a{version}ed |
1014 |
|
|
function. |
1015 |
|
|
|
1016 |
|
|
The element looks like this: |
1017 |
|
|
|
1018 |
|
|
\code |
1019 |
|
|
<prop> |
1020 |
|
|
<name>MODIF</name> |
1021 |
|
|
<data>Phosphorylation</data> // That is the Modif name |
1022 |
|
|
<data>-H+H2PO3</data> // -------------------- formula |
1023 |
|
|
<data>S;T;Y</data> // -------------------- targets |
1024 |
|
|
</prop> |
1025 |
|
|
\endcode |
1026 |
|
|
|
1027 |
|
|
As the data in \a element are parsed they are set to the member data, thus |
1028 |
|
|
essentially initializing the Modif object pointed to by the member data. |
1029 |
|
|
|
1030 |
|
|
Returns true if parsing was successful, false otherwise. |
1031 |
|
|
*/ |
1032 |
|
|
bool |
1033 |
|
✗ |
ModifProp::renderXmlElement(const QDomElement &element, int version) |
1034 |
|
|
{ |
1035 |
|
✗ |
if(element.tagName() != "prop") |
1036 |
|
✗ |
return false; |
1037 |
|
|
|
1038 |
|
✗ |
if(version == 1) |
1039 |
|
|
{ |
1040 |
|
|
// no-op |
1041 |
|
✗ |
version = 1; |
1042 |
|
|
} |
1043 |
|
|
|
1044 |
|
✗ |
QDomElement child; |
1045 |
|
|
|
1046 |
|
|
// The element looks like this: |
1047 |
|
|
// |
1048 |
|
|
// <prop> |
1049 |
|
|
// <name>MODIF</name> |
1050 |
|
|
// <data>Phosphorylation</data> // That is the Modif name |
1051 |
|
|
// <data>-H+H2PO3</data> // -------------------- formula |
1052 |
|
|
// <data>S;T;Y</data> // -------------------- targets |
1053 |
|
|
// </prop> |
1054 |
|
|
|
1055 |
|
|
|
1056 |
|
✗ |
if(element.tagName() != "prop") |
1057 |
|
✗ |
return false; |
1058 |
|
|
|
1059 |
|
✗ |
child = element.firstChildElement("name"); |
1060 |
|
|
|
1061 |
|
✗ |
if(child.isNull()) |
1062 |
|
✗ |
return false; |
1063 |
|
|
|
1064 |
|
✗ |
m_name = child.text(); |
1065 |
|
|
|
1066 |
|
✗ |
if(m_name != "MODIF") |
1067 |
|
✗ |
return false; |
1068 |
|
|
|
1069 |
|
|
// And now we have to manage the prop's data elements. When this |
1070 |
|
|
// ModifProp object was allocated, one Modif was allocated and |
1071 |
|
|
// set as the data of the Prop. Get to it. |
1072 |
|
|
|
1073 |
|
✗ |
Modif *modif = static_cast<Modif *>(mpa_data); |
1074 |
|
|
|
1075 |
|
|
// Next sibling is the modif's name data. |
1076 |
|
|
|
1077 |
|
✗ |
child = child.nextSiblingElement("data"); |
1078 |
|
|
|
1079 |
|
✗ |
if(child.isNull()) |
1080 |
|
✗ |
return false; |
1081 |
|
|
|
1082 |
|
✗ |
modif->setName(child.text()); |
1083 |
|
|
|
1084 |
|
|
// Next sibling is the modif's formula data. |
1085 |
|
|
|
1086 |
|
✗ |
child = child.nextSiblingElement("data"); |
1087 |
|
|
|
1088 |
|
✗ |
if(child.isNull()) |
1089 |
|
✗ |
return false; |
1090 |
|
|
|
1091 |
|
✗ |
modif->setFormula(child.text()); |
1092 |
|
|
|
1093 |
|
✗ |
if(!modif->calculateMasses()) |
1094 |
|
|
{ |
1095 |
|
✗ |
qDebug() << __FILE__ << __LINE__ |
1096 |
|
✗ |
<< "Failed to calculate masses for modification:" |
1097 |
|
✗ |
<< modif->name(); |
1098 |
|
✗ |
return false; |
1099 |
|
|
} |
1100 |
|
|
|
1101 |
|
|
// Next sibling is the modif's targets data. |
1102 |
|
|
|
1103 |
|
✗ |
child = child.nextSiblingElement("data"); |
1104 |
|
|
|
1105 |
|
✗ |
if(child.isNull()) |
1106 |
|
✗ |
return false; |
1107 |
|
|
|
1108 |
|
✗ |
modif->setTargets(child.text()); |
1109 |
|
|
|
1110 |
|
|
// The validation will take care of checking that the <targets> |
1111 |
|
|
// element did have correct text inside. |
1112 |
|
|
|
1113 |
|
✗ |
if(!modif->validate()) |
1114 |
|
✗ |
return false; |
1115 |
|
|
|
1116 |
|
✗ |
return true; |
1117 |
|
✗ |
} |
1118 |
|
|
|
1119 |
|
|
|
1120 |
|
|
/*! |
1121 |
|
|
\brief Formats a string suitable to use as an XML element. |
1122 |
|
|
|
1123 |
|
|
Formats a string suitable to be used as an XML element in an XML file (a |
1124 |
|
|
polymer sequence file, for example). Typical ModifProp elements that might be |
1125 |
|
|
generated in this function look like this: |
1126 |
|
|
|
1127 |
|
|
\code |
1128 |
|
|
<prop> |
1129 |
|
|
<name>MODIF</name> |
1130 |
|
|
<data>Phosphorylation</data> // That is the Modif name |
1131 |
|
|
<data>-H+H2PO3</data> // -------------------- formula |
1132 |
|
|
<data>S;T;Y</data> // -------------------- targets |
1133 |
|
|
</prop> |
1134 |
|
|
\endcode |
1135 |
|
|
|
1136 |
|
|
\a offset times the \a indent string must be used as a lead in the |
1137 |
|
|
formatting of elements. |
1138 |
|
|
|
1139 |
|
|
Returns a dynamically allocated string that needs to be freed after use. |
1140 |
|
|
*/ |
1141 |
|
|
QString * |
1142 |
|
✗ |
ModifProp::formatXmlElement(int offset, const QString &indent) |
1143 |
|
|
{ |
1144 |
|
|
int newOffset; |
1145 |
|
✗ |
int iter = 0; |
1146 |
|
|
|
1147 |
|
✗ |
QString lead(""); |
1148 |
|
✗ |
QString *string = new QString(); |
1149 |
|
|
|
1150 |
|
|
// Prepare the lead. |
1151 |
|
✗ |
newOffset = offset; |
1152 |
|
✗ |
while(iter < newOffset) |
1153 |
|
|
{ |
1154 |
|
✗ |
lead += indent; |
1155 |
|
✗ |
++iter; |
1156 |
|
|
} |
1157 |
|
|
|
1158 |
|
|
// The property has its data member that points to a Modif. Thus |
1159 |
|
|
// the formatting of the element should produce something like this: |
1160 |
|
|
// |
1161 |
|
|
// <prop> |
1162 |
|
|
// <name>MODIF</name> |
1163 |
|
|
// <data>Phosphorylation</data> // That is the Modif name |
1164 |
|
|
// <data>-H+H2PO3</data> // -------------------- formula |
1165 |
|
|
// <data>S;T;Y</data> // -------------------- targets |
1166 |
|
|
// </prop> |
1167 |
|
|
|
1168 |
|
✗ |
*string += QString("%1<prop>\n").arg(lead); |
1169 |
|
|
|
1170 |
|
|
// Prepare the lead. |
1171 |
|
✗ |
++newOffset; |
1172 |
|
✗ |
lead.clear(); |
1173 |
|
✗ |
iter = 0; |
1174 |
|
✗ |
while(iter < newOffset) |
1175 |
|
|
{ |
1176 |
|
✗ |
lead += indent; |
1177 |
|
✗ |
++iter; |
1178 |
|
|
} |
1179 |
|
|
|
1180 |
|
|
// Continue with indented elements. |
1181 |
|
|
|
1182 |
|
✗ |
*string += QString("%1<name>%2</name>\n").arg(lead).arg(m_name); |
1183 |
|
|
|
1184 |
|
✗ |
*string += QString("%1<data>%2</data>\n") |
1185 |
|
✗ |
.arg(lead) |
1186 |
|
✗ |
.arg(static_cast<Modif *>(mpa_data)->name()); |
1187 |
|
|
|
1188 |
|
✗ |
*string += QString("%1<data>%2</data>\n") |
1189 |
|
✗ |
.arg(lead) |
1190 |
|
✗ |
.arg(static_cast<Modif *>(mpa_data)->formula()); |
1191 |
|
|
|
1192 |
|
✗ |
*string += QString("%1<data>%2</data>\n") |
1193 |
|
✗ |
.arg(lead) |
1194 |
|
✗ |
.arg(static_cast<Modif *>(mpa_data)->targets()); |
1195 |
|
|
|
1196 |
|
|
// Prepare the lead for the closing element. |
1197 |
|
✗ |
--newOffset; |
1198 |
|
✗ |
lead.clear(); |
1199 |
|
✗ |
iter = 0; |
1200 |
|
✗ |
while(iter < newOffset) |
1201 |
|
|
{ |
1202 |
|
✗ |
lead += indent; |
1203 |
|
✗ |
++iter; |
1204 |
|
|
} |
1205 |
|
|
|
1206 |
|
✗ |
*string += QString("%1</prop>\n").arg(lead); |
1207 |
|
|
|
1208 |
|
✗ |
return string; |
1209 |
|
✗ |
} |
1210 |
|
|
|
1211 |
|
|
} // namespace libXpertMass |
1212 |
|
|
|
1213 |
|
|
} // namespace MsXpS |
1214 |
|
|
|