GCC Code Coverage Report


./
File: src/XpertMass/Monomer.cpp
Date: 2024-08-24 11:26:06
Lines:
237/372
63.7%
Functions:
28/33
84.8%
Branches:
194/568
34.2%

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 "Monomer.hpp"
36 #include "PolChemDef.hpp"
37
38
39 namespace MsXpS
40 {
41
42 namespace libXpertMass
43 {
44
45
46 /*!
47 \class MsXpS::libXpertMass::Monomer
48 \inmodule libXpertMass
49 \ingroup PolChemDefBuildingdBlocks
50 \inheaderfile Monomer.hpp
51
52 \brief The Monomer class provides abstractions to work with monomers.
53
54 In libmass, a momomer is an entity that is part of a polymer chemistry
55 definition. A monomer models a chemical entity that is part of a polymer.
56
57 In protein chemistry, that would be a \e{residue}, that is, an amino-acid that
58 has been polymerized into a residue chain (that is, a protein, or a peptide).
59 The chemical reaction that polymerizez an amino acid into an elongating protein
60 structure is a condensation, with loss of H2O from the amino acid to actually
61 lead to a what is called a \e{residue} of a monomer, or for short a \e{residue}.
62
63 \note The monomer, that is partly defined by its formula, has the formula of the
64 \e{residue}, not of the amino acid. This is always true, whatever the polymer
65 chemistry definition at hand: protein, saccharide, nucleic acid.
66 */
67
68
69 /*!
70 \variable int MsXpS::libXpertMass::Monomer::m_code
71
72 \brief The code of the monomer, like K for lysine, A for adenine.
73 */
74
75 /*!
76 \variable int MsXpS::libXpertMass::Monomer::mpa_modifList
77
78 \brief Allocated list of MsXpS::libXpertMass::Modif objects.
79 */
80
81
82 /*!
83 \brief Constructs a monomer with its member data set to \a name, \a code, \a
84 formula.
85
86 The \a pol_chem_def_csp polymer chemistry definition is set to the
87 PolChemDefEntity base class' member.
88 */
89 38728 Monomer::Monomer(PolChemDefCstSPtr pol_chem_def_csp,
90 QString name,
91 QString code,
92 38728 QString formula)
93 : PolChemDefEntity(pol_chem_def_csp, name),
94 Formula(formula),
95 Ponderable(0, 0),
96
4/8
✓ Branch 2 taken 38728 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 38728 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 38728 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 38728 times.
✗ Branch 13 not taken.
38728 m_code(code)
97 {
98 38728 mpa_modifList = 0;
99 38728 }
100
101 /*!
102 \brief Constructs a monomer as a copy of \a other.
103 */
104 20 Monomer::Monomer(const Monomer &other)
105 : PolChemDefEntity(other),
106 20 Formula(other.m_formula),
107 Ponderable(other),
108
3/6
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 20 times.
✗ Branch 9 not taken.
20 PropListHolder(other)
109 {
110 20 m_code = other.m_code;
111
112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if(mpa_modifList != nullptr)
113 qDeleteAll(*mpa_modifList);
114
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if(other.mpa_modifList != nullptr)
116 {
117 if(mpa_modifList == nullptr)
118 mpa_modifList = new QList<Modif *>();
119
120 for(int iter = 0; iter < other.mpa_modifList->size(); ++iter)
121 {
122 Modif *modif = new Modif(*other.mpa_modifList->at(iter));
123 mpa_modifList->append(modif);
124 }
125 }
126 else
127 {
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 delete(mpa_modifList);
129
130 20 mpa_modifList = nullptr;
131 }
132 20 }
133
134
135 /*!
136 \brief Destroys the monomer.
137 */
138 121864 Monomer::~Monomer()
139 {
140 121864 }
141
142 /*!
143 \brief Assigns \a other's member data to this monomer.
144
145 The copy is deep, in particular with the mpa_modifList being copied.
146
147 Returns a reference to this monomer.
148 */
149 Monomer &
150 30384 Monomer::operator=(const Monomer &other)
151 {
152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30384 times.
30384 if(&other == this)
153 return *this;
154
155 30384 PolChemDefEntity::operator=(other);
156 30384 Formula::operator=(other);
157 30384 Ponderable::operator=(other);
158 30384 PropListHolder::operator=(other);
159
160 30384 m_code = other.m_code;
161
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30384 times.
30384 if(mpa_modifList != nullptr)
163 qDeleteAll(*mpa_modifList);
164
165
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30384 times.
30384 if(other.mpa_modifList != nullptr)
166 {
167 if(mpa_modifList == nullptr)
168 mpa_modifList = new QList<Modif *>();
169
170 for(int iter = 0; iter < other.mpa_modifList->size(); ++iter)
171 {
172 Modif *modif = new Modif(*other.mpa_modifList->at(iter));
173 mpa_modifList->append(modif);
174 }
175 }
176 else
177 {
178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30384 times.
30384 delete(mpa_modifList);
179
180 30384 mpa_modifList = nullptr;
181 }
182
183 30384 return *this;
184 }
185
186
187 /*!
188 \brief Returns true if this monomer and \a other are identical, false
189 otherwise.
190
191 The comparison involves also the comparison of the Modif objects in
192 mpa_modifList.
193 */
194 bool
195 2584 Monomer::operator==(const Monomer &other) const
196 {
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2584 times.
2584 if(&other == this)
198 return true;
199
200
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2576 times.
2584 if(PolChemDefEntity::operator!=(other))
201 8 return false;
202
203
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2568 times.
2576 if(Formula::operator!=(other))
204 8 return false;
205
206
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2560 times.
2568 if(Ponderable::operator!=(other))
207 8 return false;
208
209
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2552 times.
2560 if(m_code != other.m_code)
210 8 return false;
211
212
213
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2552 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2552 if(mpa_modifList != nullptr && other.mpa_modifList != nullptr)
214 {
215 if(mpa_modifList->size() != other.mpa_modifList->size())
216 return false;
217
218 for(int iter = 0; iter < mpa_modifList->size(); ++iter)
219 {
220 if(*mpa_modifList->at(iter) != *other.mpa_modifList->at(iter))
221 return false;
222 }
223 }
224
2/4
✓ Branch 0 taken 2552 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2552 times.
✗ Branch 3 not taken.
2552 else if(mpa_modifList == nullptr && other.mpa_modifList == nullptr)
225 2552 return true;
226 else
227 // Both objects have not the same modifList status.
228 return false;
229
230 return true;
231 }
232
233
234 /*!
235 \brief Returns true if \c this monomer and \a other differ, false
236 otherwise.
237
238 Returns the negated result of operator==(other).
239 */
240 bool
241 2548 Monomer::operator!=(const Monomer &other) const
242 {
243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2548 times.
2548 if(&other == this)
244 return false;
245
246 2548 return !operator==(other);
247 }
248
249 /*!
250 \brief Sets the code to \a code
251
252 */
253 void
254 4 Monomer::setCode(const QString &code)
255 {
256 4 m_code = code;
257 4 }
258
259
260 /*!
261 \brief Returns the code
262 */
263 QString
264 13072 Monomer::code() const
265 {
266 13072 return m_code;
267 }
268
269
270 /*!
271 \brief Checks the code's syntactic validity.
272
273 The monomer code is verified and has to verify these criteria:
274
275 \list
276 \li It must be non-empty
277 \li Its character length has to be less or equal to the code length parameter
278 in the polymer chemistry definition (see PolChemDef::m_codeLength)
279 \li The first character is uppercase
280 \li All the remaining characters are lowercase
281 \endlist
282
283 Returns true if the code syntax checked successfully, false otherwise.
284
285 \sa validate()
286 */
287 bool
288 8260 Monomer::checkCodeSyntax() const
289 {
290 // The code has to be at least one character long.
291 // The first letter in the code has to be uppercase.
292 // All the remaining authorized characters have to be
293 // lowercase.
294 8260 int codeLength = mcsp_polChemDef->codeLength();
295
296
5/6
✓ Branch 1 taken 8260 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 8252 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 8252 times.
8260 if(m_code.length() < 1 || m_code.length() > codeLength)
297 8 return false;
298
299 // Note that the actual monomer code length might be less than the
300 // codeLength member datum in the polymer chemistry
301 // definition. Which is why we have to make sure we test that before
302 // risking to access a character ouf of bonds of the m_code string.
303
304
2/2
✓ Branch 1 taken 8252 times.
✓ Branch 2 taken 8252 times.
16504 for(int iter = 0; iter < m_code.size(); ++iter)
305 {
306 // Test that the m_code length is not greater than codeLength.
307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8252 times.
8252 if(iter + 1 > codeLength)
308 return false;
309
310 // And now check the character syntax.
311 8252 QChar curChar = m_code.at(iter);
312
313
1/2
✓ Branch 0 taken 8252 times.
✗ Branch 1 not taken.
8252 if(iter == 0)
314 {
315
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8252 times.
8252 if(curChar.category() != QChar::Letter_Uppercase)
316 return false;
317 }
318 else if(curChar.category() == QChar::Letter_Uppercase)
319 return false;
320 }
321
322 8252 return true;
323 }
324
325 /*!
326 \brief Tells if a monomer by this monomer's code is known in the polymer
327 chemistry definition.
328
329 The monomers in the list of monomers of the polymer chemistry definition
330 (mcsp_polChemDef) are searched through for this monomer's code (m_code).
331
332 Returns the index of the found monomer or -1 either if m_code is empty or if
333 the monomer was not found.
334 */
335 int
336 12 Monomer::isCodeKnown() const
337 {
338 12 const QList<Monomer *> &refList = mcsp_polChemDef->monomerList();
339
340
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if(m_code.isEmpty())
341 return -1;
342
343
2/2
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 4 times.
224 for(int iter = 0; iter < refList.size(); ++iter)
344 {
345
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 212 times.
220 if(refList.at(iter)->m_code == m_code)
346 8 return iter;
347 }
348
349 4 return -1;
350 }
351
352
353 /*!
354 \brief Tells if a monomer by the monomer \a code is in \a refList.
355
356 The monomers in \a refList are searched through for the monomer \a code.
357
358 If a monomer is found and \a monomer_p is non-nullptr, the monomer pointed
359 to by \a monomer_p is set to the contents of the found monomer.
360
361 Returns the index of the found monomer or -1 either if m_code is empty or if
362 the monomer was not found.
363 */
364 int
365 57484 Monomer::isCodeInList(const QString &code,
366 const QList<Monomer *> &refList,
367 Monomer *monomer_p)
368 {
369 57484 Monomer *iter_monomer_p = nullptr;
370
371
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 57484 times.
57484 if(code.isEmpty())
372 return -1;
373
374
2/2
✓ Branch 1 taken 629220 times.
✓ Branch 2 taken 8 times.
629228 for(int iter = 0; iter < refList.size(); ++iter)
375 {
376 629220 iter_monomer_p = refList.at(iter);
377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 629220 times.
629220 Q_ASSERT(iter_monomer_p);
378
379
2/2
✓ Branch 1 taken 57476 times.
✓ Branch 2 taken 571744 times.
629220 if(iter_monomer_p->m_code == code)
380 {
381 // qDebug() << "Found the monomer in the reference list by code:" <<
382 // str;
383
384
2/2
✓ Branch 0 taken 30384 times.
✓ Branch 1 taken 27092 times.
57476 if(monomer_p)
385 30384 *monomer_p = *iter_monomer_p;
386
387 57476 return iter;
388 }
389 }
390
391 8 return -1;
392 }
393
394
395 /*!
396 \brief Tells if a monomer by this monomer's name is known in the polymer
397 chemistry definition.
398
399 The monomers in the list of monomers of the polymer chemistry definition
400 (mcsp_polChemDef) are searched through for this monomer's name (m_name).
401
402 Returns the index of the found monomer or -1 either if m_name is empty or if
403 the monomer was not found.
404 */
405 int
406 16 Monomer::isNameKnown() const
407 {
408 16 const QList<Monomer *> &refList = mcsp_polChemDef->monomerList();
409
410
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if(m_name.isEmpty())
411 return -1;
412
413
2/2
✓ Branch 1 taken 288 times.
✓ Branch 2 taken 4 times.
292 for(int iter = 0; iter < refList.size(); ++iter)
414 {
415
2/2
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 276 times.
288 if(refList.at(iter)->m_name == m_name)
416 12 return iter;
417 }
418
419 4 return -1;
420 }
421
422
423 /*!
424 \brief Tells if a monomer by the monomer \a name is in \a refList.
425
426 The monomers in \a refList are searched through for the monomer \a name.
427
428 If a monomer is found and \a monomer_p is non-nullptr, the monomer pointed
429 to by \a monomer_p is set to the contents of the found monomer.
430
431 Returns the index of the found monomer or -1 either if m_name is empty or if
432 the monomer was not found.
433 */
434 int
435 16 Monomer::isNameInList(const QString &name,
436 const QList<Monomer *> &refList,
437 Monomer *monomer_p)
438 {
439 16 Monomer *monomer = 0;
440
441
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if(name.isEmpty())
442 return -1;
443
444
2/2
✓ Branch 1 taken 288 times.
✓ Branch 2 taken 4 times.
292 for(int iter = 0; iter < refList.size(); ++iter)
445 {
446 288 monomer = refList.at(iter);
447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 288 times.
288 Q_ASSERT(monomer != 0);
448
449
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 276 times.
288 if(monomer->m_name == name)
450 {
451
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(monomer_p != 0)
452 *monomer_p = *monomer;
453
454 12 return iter;
455 }
456 }
457
458 4 return -1;
459 }
460
461 /*!
462 \brief Returns the modification list
463
464 */
465 QList<Modif *> *
466 8 Monomer::modifList() const
467 {
468 8 return mpa_modifList;
469 }
470
471 /*
472 \brief Return the formula of this monomer as a string.
473 */
474 QString
475 64 Monomer::formula() const
476 {
477 64 return Formula::toString();
478 }
479
480
481 /*
482 \brief Returns true if this monomer is a target of Modif \a modif, false
483 otherwise.
484 */
485 bool
486 44 Monomer::isModifTarget(const Modif &modif) const
487 {
488 // Pure convenience function.
489
490
1/2
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
44 return modif.hasMonomerTarget(m_code);
491 }
492
493 /*!
494 \brief Modifies this monomer using \a modif.
495
496 The two verifications that are done:
497
498 \list
499 \li This monomer must be a \a modif target;
500 \li The count of \a modif modifications in this monomer must be at most the
501 authorized count - 1, to accomodate this new modification [see
502 Modif::maxCount()].
503 \endlist
504
505 The two restriction above can be overridden by setting \a override to true.
506
507 If errors are encountered, these are reported as strings in \a errorList.
508
509 The \a{modif}'s ownership is taken by this monomer.
510
511 Returns true on success, false otherwise.
512 */
513 bool
514 32 Monomer::modify(Modif *modif, bool override, QStringList &errorList)
515 {
516 // Will take ownership of the modif.
517
518 // We have to check two things:
519
520 // 1. That *this monomer is actually a target of the modification
521 // at hand(or that we can override limitations);
522
523 // 2. That *this monomer can still accommodate one such 'modif'
524 // more (that is the count of 'modif' for *this mononomer is
525 // correct for adding one more.
526
527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 Q_ASSERT(modif);
528
529
5/6
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 28 times.
32 if(!isModifTarget(*modif) && !override)
530 {
531 // This monomer is not a target for the modif, and no override
532 // is allowed.
533
534
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 errorList << QObject::tr(
535 "\t%1 not target of modif %2 "
536 "(no overriding allowed)")
537
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 .arg(m_name)
538
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
4 .arg(modif->name());
539
540 4 return false;
541 }
542
543
2/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
28 int count = modifCount(modif->name());
544
545
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
28 if(count >= modif->maxCount() && !override)
546 {
547 // This monomer has already the maximum count of 'modif' objects.
548
549 errorList << QObject::tr(
550 "\t%1 already modified %2 times "
551 "(no overriding allowed)")
552 .arg(m_name)
553 .arg(count);
554
555 return false;
556 }
557
558 // We are going to add one modification to the list of
559 // modifications. Note however, that if the monomer had never been
560 // modified(or all of its modifications had been removed), then its
561 // modifList should be 0. We must allocate it.
562
563
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if(!mpa_modifList)
564 28 mpa_modifList = new QList<Modif *>();
565
566 28 mpa_modifList->append(modif);
567
568 28 return true;
569 }
570
571
572 /*!
573 * \brief Modifies this monomer using a newly heap-allocated copy of \a modif.
574 *
575 * The two verifications that are done:
576 *
577 * \list
578 * \li This monomer must be a \a modif target;
579 * \li The count of \a modif modifications in this monomer must be at most the
580 * authorized count - 1, to accomodate this new modification [see
581 * Modif::maxCount()].
582 * \endlist
583 *
584 * The two restriction above can be overridden by setting \a override to true.
585 *
586 * If errors are encountered, these are reported as strings in \a errorList.
587 *
588 * Returns true on success, false otherwise.
589 */
590 bool
591 Monomer::modify(const Modif &modif, bool override, QStringList &errorList)
592 {
593 // Will take ownership of the modif.
594
595 // We have to check two things:
596
597 // 1. That *this monomer is actually a target of the modification
598 // at hand(or that we can override limitations);
599
600 // 2. That *this monomer can still accommodate one such 'modif'
601 // more (that is the count of 'modif' for *this mononomer is
602 // correct for adding one more.
603
604 if(!isModifTarget(modif) && !override)
605 {
606 // This monomer is not a target for the modif, and no override
607 // is allowed.
608
609 errorList << QObject::tr(
610 "\t%1 not target of modif %2 "
611 "(no overriding allowed)")
612 .arg(m_name)
613 .arg(modif.name());
614
615 return false;
616 }
617
618 int count = modifCount(modif.name());
619
620 if(count >= modif.maxCount() && !override)
621 {
622 // This monomer has already the maximum count of 'modif' objects.
623
624 errorList << QObject::tr(
625 "\t%1 already modified %2 times "
626 "(no overriding allowed)")
627 .arg(m_name)
628 .arg(count);
629
630 return false;
631 }
632
633 // We are going to add one modification to the list of
634 // modifications. Note however, that if the monomer had never been
635 // modified(or all of its modifications had been removed), then its
636 // modifList should be 0. We must allocate it.
637
638 if(!mpa_modifList)
639 mpa_modifList = new QList<Modif *>();
640
641 mpa_modifList->append(new Modif(modif));
642
643 return true;
644 }
645
646 /*!
647 \brief Removes \a modif from this monomer.
648
649 The member list of modifications must exist (it is a heap-allocated list that
650 is allocated upon the first modification of the monomer) and must be non-empty.
651
652 Returns true.
653 */
654 bool
655 4 Monomer::unmodify(Modif *modif)
656 {
657 // The unmodification pertains to the single 'modif' object.
658
659 // We are given the address of a specific modif to remove, thus it
660 // cannot be that the list of modifs be 0 or empty.
661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 Q_ASSERT(mpa_modifList);
662
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 Q_ASSERT(mpa_modifList->size());
663
664 // Will remove only one item, even if we call removeAll() because
665 // there is only one 'modif' pointer to Modif.
666 4 int ret = mpa_modifList->removeAll(modif);
667
668 // Only one item should have been found in the list.
669
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(ret != 1)
670 qFatal("Programming error");
671
672 // If we removed the last item, free the list.
673
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if(!mpa_modifList->size())
674 {
675
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 delete mpa_modifList;
676
677 4 mpa_modifList = 0;
678 }
679
680 4 return true;
681 }
682
683
684 /*!
685 \brief Removes \e{all} the modification from this monomer.
686
687 Returns true.
688 */
689 bool
690 Monomer::unmodify()
691 {
692 if(mpa_modifList)
693 {
694 qDeleteAll(*mpa_modifList);
695
696 delete mpa_modifList;
697 }
698
699 return true;
700 }
701
702
703 /*!
704 \brief Returns true if this monomer has at least one modification, false
705 otherwise.
706 */
707 bool
708 648 Monomer::isModified() const
709 {
710
5/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 644 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 644 times.
648 if(mpa_modifList && mpa_modifList->size())
711 4 return true;
712
713 644 return false;
714 }
715
716 /*!
717 \brief Returns the count of modifications by name \a modif_name in this
718 monomer.
719 */
720 int
721 28 Monomer::modifCount(const QString &modif_name)
722 {
723 28 int count = 0;
724
725
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if(!mpa_modifList)
726 28 return 0;
727
728 for(int iter = 0; iter < mpa_modifList->size(); ++iter)
729 {
730 Modif *modif = mpa_modifList->at(iter);
731
732 if(modif_name == modif->name())
733 ++count;
734 }
735
736 return count;
737 }
738
739
740 /*!
741 \brief Returns true if this monomer is valid, false otherwise.
742
743 Validation of the monomer occurs if:
744
745 \list
746 \li Its name is not empty
747 \li Its code is not empty and its syntax is correct
748 \li Its formula validates
749 \li Its modifications (if any) validate
750 \endlist
751
752 \sa checkCodeSyntax()
753 */
754 bool
755 8252 Monomer::validate()
756 {
757 IsotopicDataCstSPtr isotopic_data_csp =
758
1/2
✓ Branch 2 taken 8252 times.
✗ Branch 3 not taken.
8252 mcsp_polChemDef->getIsotopicDataCstSPtr();
759
760
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8252 times.
8252 if(m_name.isEmpty())
761 return false;
762
763
3/4
✓ Branch 1 taken 8252 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 8248 times.
8252 if(!checkCodeSyntax())
764 4 return false;
765
766
3/4
✓ Branch 2 taken 8248 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 8244 times.
8248 if(!Formula::validate(isotopic_data_csp))
767 4 return false;
768
769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8244 times.
8244 if(mpa_modifList)
770 {
771 for(int iter = 0; iter < mpa_modifList->size(); ++iter)
772 {
773 if(!mpa_modifList->at(iter)->validate())
774 return false;
775 }
776 }
777
778 8244 return true;
779 8252 }
780
781 /*!
782 \brief Calculates this monomer's monoisotopic and avg masses.
783
784 The calculation is performed by computing the masses
785 of this monomer's formula.
786
787 Returns true if the calculations were successful, false otherwise.
788
789 \sa Formula::accountMasses()
790 */
791 bool
792 8952 Monomer::calculateMasses()
793 {
794 IsotopicDataCstSPtr isotopic_data_csp =
795
1/2
✓ Branch 2 taken 8952 times.
✗ Branch 3 not taken.
8952 mcsp_polChemDef->getIsotopicDataCstSPtr();
796
797 8952 m_mono = 0;
798 8952 m_avg = 0;
799
800 // qDebug() << "Accounting masses for monomer: " << m_name;
801
802
2/4
✓ Branch 2 taken 8952 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 8952 times.
8952 if(!Formula::accountMasses(isotopic_data_csp, &m_mono, &m_avg))
803 return false;
804
805 8952 return true;
806 8952 }
807
808 /*!
809 \brief Calculates this monomer's monoisotopic and avg masses.
810
811 The calculation is performed by computing the masses
812 of this monomer's formula.
813
814 If \a monomer_chemical_entities & MONOMER_CHEMENT_MODIF is true, then the
815 masses are updated to account for the mass of modifications.
816
817 Returns true if the calculations were successful, false otherwise.
818
819 \sa Formula::accountMasses()
820 */
821 bool
822 8932 Monomer::calculateMasses(int monomer_chemical_entities)
823 {
824
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8932 times.
8932 if(calculateMasses() != true)
825 return false;
826
827
2/2
✓ Branch 0 taken 692 times.
✓ Branch 1 taken 8240 times.
8932 if(monomer_chemical_entities & MONOMER_CHEMENT_MODIF)
828 {
829
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 676 times.
692 if(mpa_modifList)
830 {
831
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 16 times.
32 for(int iter = 0; iter < mpa_modifList->size(); ++iter)
832 {
833 16 Modif *modif = mpa_modifList->at(iter);
834
835 // qDebug() << "Before accounting masses for modification:" <<
836 // modif->name()
837 // << "mono:" << qSetRealNumberPrecision(6) << mono();
838
839 16 modif->accountMasses(&m_mono, &m_avg);
840
841 // qDebug() << "After accounting masses for modification:" <<
842 // modif->name()
843 // << "mono:" << qSetRealNumberPrecision(6) << mono();
844 }
845 }
846 }
847
848 8932 return true;
849 }
850
851 /*
852 \brief Calculates a Formula representing this monomer .
853
854 The calculated formula accounts for this monomer's formula and for its
855 modifications formulas if any and if \a (monomer_chemical_entities &
856 MONOMER_CHEMENT_MODIF) is true.
857
858 This monomer's formula must validate using Modif::validate.
859
860 Returns the Formula.
861
862 \sa Modif::accountFormula()
863 */
864 Formula
865 Monomer::calculateFormula(int monomer_chemical_entities) const
866 {
867 // We want to return the formula of this monomer that accounts for its
868 // modifications if so is requested.
869
870 IsotopicDataCstSPtr isotopic_data_csp =
871 mcsp_polChemDef->getIsotopicDataCstSPtr();
872
873 // qDebug() << "Calculating formula for monomer: " << m_name
874 //<< "with chemical entities:" << monomer_chemical_entities;
875
876 Formula formula(m_formula);
877
878 // qDebug() << "Basic formula:" << formula.toString();
879
880 // The Formula object above is only a text string. We need to convert that
881 // into the symbol/count pair by validating it with true true params.
882 // The formula is asked to validate with storage of the found symbol/count
883 // pairs and with resetting of the previous contents of the symbol/count map.
884
885 // We need to seed the symbol/count pairs because the following call
886 // (accountFormula()) will update the pairs' values.
887 if(!formula.validate(isotopic_data_csp, true, true))
888 {
889 qDebug() << "Formula:" << formula.toString() << "failed to validate.";
890 return Formula();
891 }
892
893 if(monomer_chemical_entities & MONOMER_CHEMENT_MODIF)
894 {
895 if(mpa_modifList)
896 {
897 for(int iter = 0; iter < mpa_modifList->size(); ++iter)
898 {
899 // qDebug() << "Before accounting modif:"
900 //<< mpa_modifList->at(iter)->name()
901 //<< "with formula:" << mpa_modifList->at(iter)->formula()
902 //<< "the global formula:" << formula.toString();
903
904 formula.accountFormula(mpa_modifList->at(iter)->formula(),
905 mcsp_polChemDef->getIsotopicDataCstSPtr());
906
907 // qDebug() << "After accounting modif:"
908 //<< mpa_modifList->at(iter)->name()
909 //<< "with formula:" << mpa_modifList->at(iter)->formula()
910 //<< "the new global formula:" << formula.toString();
911 }
912 }
913 }
914
915 // qDebug() << "Returning the formula as string:" << formula.toString();
916
917 return Formula(formula);
918 }
919
920 /*!
921 \brief Increases \a mono and \a avg by the corresponding member masses first
922 compounded by \a times.
923
924 Returns true.
925 */
926 bool
927 5568 Monomer::accountMasses(double *mono, double *avg, int times) const
928 {
929
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5568 times.
5568 Q_ASSERT(mono != nullptr);
930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5568 times.
5568 Q_ASSERT(avg != nullptr);
931
932 5568 *mono += m_mono * times;
933 5568 *avg += m_avg * times;
934
935 5568 return true;
936 }
937
938
939 /*!
940 \brief Accounts this monomer's masses in \a ponderable's mono and avg
941 masses.
942
943 This monomer's masses are stored in member data \c m_mono and \c m_avg. These
944 masses are multiplied by \a times before setting the values to \a
945 ponderable. \a ponderable cannot be nullptr.
946
947 Returns true.
948 */
949 bool
950 24 Monomer::accountMasses(Ponderable *ponderable, int times) const
951 {
952
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 Q_ASSERT(ponderable != nullptr);
953
954 24 ponderable->rmono() += m_mono * times;
955 24 ponderable->ravg() += m_avg * times;
956
957 24 return true;
958 }
959
960
961 /*!
962 \brief Parses the monomer XML \a element specifically for \a version.
963
964 Parses the monomer XML element passed as argument and for each
965 encountered data will set the data to this monomer (this is
966 called XML rendering).The parsing is delegated to a function that is specific
967 for for \a version of the polymer chemistry definition.
968
969 The XML element is found in the polymer chemistry definition and has the
970 following form:
971
972 \code
973 <monomers>
974 <mnm>
975 <name>Glycine</name>
976 <code>G</code>
977 <formula>C2H3N1O1</formula>
978 </mnm>
979 <mnm>
980 <name>Alanine</name>
981 <code>A</code>
982 <formula>C3H5N1O1</formula>
983 </mnm>
984 \endcode
985
986 After setting all the data, this monomer calculates it masses and
987 validates itself. If any of these steps fails, the error is reported
988 by returning false.
989
990 \sa validate()
991 */
992 bool
993 8232 Monomer::renderXmlMnmElement(const QDomElement &element,
994 [[maybe_unused]] int version)
995 {
996
1/2
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
8232 QDomElement child;
997
998 /* In a polymer chemistry definition, the xml node we are in is
999 * structured this way:
1000 *
1001 * <mnm>
1002 * <name>Glycine</name>
1003 * <code>G</code>
1004 * <formula>C2H3N1O1</formula>
1005 * </mnm>
1006 *
1007 * And the element parameter points to the
1008 *
1009 * <mnm> element tag:
1010 * ^
1011 * |
1012 * +----- here we are right now.
1013 *
1014 * Which means that element.tagName() == "mnm" and that we'll have
1015 * to go one step down to the first child of the current node in
1016 * order to get to the <name> element.
1017 *
1018 */
1019
1020
2/4
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 8232 times.
8232 if(element.tagName() != "mnm")
1021 return false;
1022
1023
3/6
✓ Branch 2 taken 8232 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8232 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8232 times.
✗ Branch 9 not taken.
8232 child = element.firstChildElement("name");
1024
1025
2/4
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8232 times.
8232 if(child.isNull())
1026 return false;
1027
1028
1/2
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
8232 m_name = child.text();
1029
1030
3/6
✓ Branch 2 taken 8232 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8232 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8232 times.
✗ Branch 9 not taken.
8232 child = child.nextSiblingElement("code");
1031
1032
2/4
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8232 times.
8232 if(child.isNull())
1033 return false;
1034
1035
1/2
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
8232 m_code = child.text();
1036
1037
3/6
✓ Branch 2 taken 8232 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8232 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8232 times.
✗ Branch 9 not taken.
8232 child = child.nextSiblingElement("formula");
1038
1039
2/4
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8232 times.
8232 if(child.isNull())
1040 return false;
1041
1042
2/4
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8232 times.
8232 if(!Formula::renderXmlFormulaElement(child))
1043 return false;
1044
1045
2/4
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8232 times.
8232 if(!this->calculateMasses(MONOMER_CHEMENT_NONE))
1046 {
1047 qDebug() << "Failed to calculate masses for monomer" << m_name;
1048
1049 return false;
1050 }
1051
1052
2/4
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8232 times.
8232 if(!validate())
1053 return false;
1054
1055 8232 return true;
1056 8232 }
1057
1058
1059 /*!
1060 \brief Formats this monomer's data as a string suitable to be used as an XML
1061 element in the polymer chemistry definition.
1062
1063 The typical monomer element that is generated in this function looks like
1064 this:
1065
1066 \code
1067 <monomers>
1068 <mnm>
1069 <name>Glycine</name>
1070 <code>G</code>
1071 <formula>C2H3N1O1</formula>
1072 </mnm>
1073 \endcode
1074
1075 The formatting of the XML element takes into account \a offset and \a
1076 indent by prepending the string with \a offset * \a indent character substring.
1077
1078 \a indent defaults to two spaces.
1079
1080 Returns a dynamically allocated string that needs to be freed after
1081 use.
1082 */
1083 QString *
1084 88 Monomer::formatXmlMnmElement(int offset, const QString &indent)
1085 {
1086 int newOffset;
1087 88 int iter = 0;
1088
1089
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 QString lead("");
1090
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 QString *string = new QString();
1091
1092 // Prepare the lead.
1093 88 newOffset = offset;
1094
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 88 times.
340 while(iter < newOffset)
1095 {
1096
1/2
✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
252 lead += indent;
1097 252 ++iter;
1098 }
1099
1100
3/6
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 88 times.
✗ Branch 8 not taken.
176 *string += QString("%1<mnm>\n").arg(lead);
1101
1102 // Prepare the lead.
1103 88 ++newOffset;
1104 88 lead.clear();
1105 88 iter = 0;
1106
2/2
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 88 times.
428 while(iter < newOffset)
1107 {
1108
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 lead += indent;
1109 340 ++iter;
1110 }
1111
1112 // Continue with indented elements.
1113
1114
4/8
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 88 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 88 times.
✗ Branch 11 not taken.
264 *string += QString("%1<name>%2</name>\n").arg(lead).arg(m_name);
1115
1116
4/8
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 88 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 88 times.
✗ Branch 11 not taken.
264 *string += QString("%1<code>%2</code>\n").arg(lead).arg(m_code);
1117
1118
4/8
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 88 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 88 times.
✗ Branch 11 not taken.
264 *string += QString("%1<formula>%2</formula>\n").arg(lead).arg(m_formula);
1119
1120 // Prepare the lead for the closing element.
1121 88 --newOffset;
1122 88 lead.clear();
1123 88 iter = 0;
1124
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 88 times.
340 while(iter < newOffset)
1125 {
1126
1/2
✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
252 lead += indent;
1127 252 ++iter;
1128 }
1129
1130
3/6
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 88 times.
✗ Branch 8 not taken.
176 *string += QString("%1</mnm>\n").arg(lead);
1131
1132 88 return string;
1133 88 }
1134
1135
1136 /*!
1137 \brief Parses into this monomer the XML monomer \a element passed as argument.
1138
1139 The XML element comes from a polymer sequence file, where the monomer is
1140 singled out (not in a sequence string) because it might be modified.
1141
1142 \a version indicates the format version of this XML \a element.
1143
1144 As soon as the monomer code is known, while parsing the \a element, the
1145 corresponding monomer is searched in the list of monomers in the member polymer
1146 chemistry definition (\c mcsp_polChemDef). Then, the found monomer is copied
1147 into \c this monomer so that both monomers are identical, effectively
1148 initializing this monomer to the monomer described by the \a element.
1149
1150 If the \a element contains one or more \c mdf modifications, these
1151 modifications are allocated as \l{Modif}'s and validated. If these
1152 modifications validate successfully, they are appended to this monomer's list
1153 of modifications.
1154
1155 Returns true if initializationt of his monomer with the contents of \a
1156 element succeeded, false otherwise.
1157
1158 \sa formatXmlMonomerElement(int offset, const QString &indent)
1159 */
1160 bool
1161 Monomer::renderXmlMonomerElement(const QDomElement &element,
1162 [[maybe_unused]] int version)
1163 {
1164 QDomElement child;
1165 QDomElement indentedChild;
1166
1167 if(element.tagName() != "monomer")
1168 return false;
1169
1170 child = element.firstChildElement("code");
1171
1172 if(child.isNull())
1173 return false;
1174
1175 QString code = child.text();
1176
1177 Monomer other(mcsp_polChemDef, "NOT_SET");
1178 const QList<Monomer *> &refList = mcsp_polChemDef->monomerList();
1179
1180 int index = -1;
1181 index = isCodeInList(code, refList, &other);
1182 if(index == -1)
1183 qFatal("Fatal error at %s@%d. Aborting.", __FILE__, __LINE__);
1184
1185 *this = other;
1186
1187 // Sanity check
1188 if(m_code != code)
1189 qFatal("Programming error. Both codes should be identical.");
1190
1191 // And now we have to manage the prop objects.
1192 child = child.nextSiblingElement();
1193
1194 while(!child.isNull())
1195 {
1196 if(child.tagName() != "mdf")
1197 return false;
1198
1199 // Allocate the modification that will be set to the monomer
1200 // element.
1201
1202 // Old version
1203 // Modif *modif = new Modif(mcsp_polChemDef, "NOT_SET", "NOT_SET");
1204 //
1205 // if(!modif->renderXmlMdfElement(child, version))
1206 // {
1207 // delete modif;
1208 // return false;
1209 // }
1210
1211 Modif *modif = new Modif(mcsp_polChemDef, child, version);
1212
1213 if(!modif->calculateMasses())
1214 {
1215 qDebug() << __FILE__ << __LINE__
1216 << "Failed to calculate masses for modification"
1217 << modif->name();
1218
1219 delete modif;
1220 return false;
1221 }
1222
1223 // The validation will take care of checking that the <targets>
1224 // element did have correct text inside.
1225
1226 if(!modif->validate())
1227 {
1228 delete modif;
1229 return false;
1230 }
1231
1232 // OK, at this point we can add the new modif to the list of
1233 // modifs.
1234 if(!mpa_modifList)
1235 mpa_modifList = new QList<Modif *>();
1236
1237 mpa_modifList->append(modif);
1238
1239 child = child.nextSiblingElement();
1240 }
1241
1242 return true;
1243 }
1244
1245
1246 /*!
1247 \brief Formats a string suitable to be used as an XML element in a
1248 polymer sequence file.
1249
1250 The typical monomer element that is generated in this function looks like
1251 this:
1252
1253 \code
1254 <monomer>
1255 <code>S</code>
1256 <prop>
1257 <name>MODIF</name>
1258 <data>Phosphorylation</data>
1259 </prop>
1260 <prop>
1261 <name>COMMENT</name>
1262 <data>Phosphorylation is only partial</data>
1263 </prop>
1264 </monomer>
1265 \endcode
1266
1267 The formatting of the XML element takes into account \a offset and \a
1268 indent by prepending the string with \a offset * \a indent character substring.
1269
1270 \a indent defaults to two spaces.
1271
1272 Returns a dynamically allocated string that needs to be freed after
1273 use.
1274 */
1275 QString *
1276 4 Monomer::formatXmlMonomerElement(int offset, const QString &indent) const
1277 {
1278 int newOffset;
1279 4 int iter = 0;
1280
1281
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QString lead("");
1282
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QString *string = new QString();
1283
1284 // Prepare the lead.
1285 4 newOffset = offset;
1286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 while(iter < newOffset)
1287 {
1288 lead += indent;
1289 ++iter;
1290 }
1291
1292
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
8 *string += QString("%1<monomer>\n").arg(lead);
1293
1294 // Prepare the lead.
1295 4 ++newOffset;
1296 4 lead.clear();
1297 4 iter = 0;
1298
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 while(iter < newOffset)
1299 {
1300
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 lead += indent;
1301 4 ++iter;
1302 }
1303
1304 // Continue with indented elements.
1305
1306
4/8
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
12 *string += QString("%1<code>%2</code>\n").arg(lead).arg(m_code);
1307
1308 // The monomer may have any number of modif objects, which we have
1309 // to document here.
1310
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 if(mpa_modifList && mpa_modifList->size())
1311 {
1312
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
8 for(iter = 0; iter < mpa_modifList->size(); ++iter)
1313 {
1314 4 Modif *modif = mpa_modifList->at(iter);
1315
1316
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 QString *modifString = modif->formatXmlMdfElement(newOffset);
1317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 Q_ASSERT(modifString);
1318
1319
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 *string += *modifString;
1320
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 delete modifString;
1321 }
1322 }
1323
1324 // Prepare the lead for the closing element.
1325 4 --newOffset;
1326 4 lead.clear();
1327 4 iter = 0;
1328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 while(iter < newOffset)
1329 {
1330 lead += indent;
1331 ++iter;
1332 }
1333
1334
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
8 *string += QString("%1</monomer>\n").arg(lead);
1335
1336 4 return string;
1337 4 }
1338
1339
1340 /*!
1341 \brief Outputs a string representing this monomer using qDebug().
1342 */
1343 void
1344 Monomer::debugPutStdErr() const
1345 {
1346 qDebug() << m_name << m_code << m_formula;
1347 }
1348
1349 } // namespace libXpertMass
1350
1351 } // namespace MsXpS
1352