GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/ChemicalGroup.cpp
Date: 2025-11-20 01:41:33
Lines:
185/242
76.4%
Functions:
21/29
72.4%
Branches:
146/344
42.4%

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 "MsXpS/libXpertMassCore/ChemicalGroup.hpp"
36
37
38 namespace MsXpS
39 {
40
41 namespace libXpertMassCore
42 {
43
44
45 /*!
46 \class MsXpS::libXpertMassCore::ChemicalGroup
47 \inmodule libXpertMassCore
48 \ingroup PolChemDefBuildingdBlocks
49 \inheaderfile ChemicalGroup.hpp
50
51 \brief The ChemicalGroup class provides a model for specifying the
52 acido-basic behaviour of a chemical group of either a \l Monomer object or of a
53 \l Modif object.
54
55 If the ChemicalGroup does not prove sufficient to characterize precisely the
56 acido-basic properties of an entity, \l ChemicalGroupRule instances can be
57 added to that effect.
58
59 In an pkaphpidata definition file, the following xml structure
60 is encountered:
61
62 \code
63 <pkaphpidata>
64 <monomers>
65 <monomer>
66 <code>A</code>
67 <mnmchemgroup>
68 <name>N-term NH2</name>
69 <pka>9.6</pka>
70 <acidcharged>TRUE</acidcharged>
71 <polrule>left_trapped</polrule>
72 <chemgrouprule>
73 <entity>LE_PLM_MODIF</entity>
74 <name>Acetylation</name>
75 <outcome>LOST</outcome>
76 </chemgrouprule>
77 </mnmchemgroup>
78 <mnmchemgroup>
79 <name>C-term COOH</name>
80 <pka>2.35</pka>
81 <acidcharged>FALSE</acidcharged>
82 <polrule>right_trapped</polrule>
83 </mnmchemgroup>
84 </monomer>
85 <monomer>
86 <code>C</code>
87 <mnmchemgroup>
88 <name>N-term NH2</name>
89 <pka>9.6</pka>
90 <acidcharged>TRUE</acidcharged>
91 <polrule>left_trapped</polrule>
92 <chemgrouprule>
93 <entity>LE_PLM_MODIF</entity>
94 <name>Acetylation</name>
95 <outcome>LOST</outcome>
96 </chemgrouprule>
97 </mnmchemgroup>
98 <mnmchemgroup>
99 <name>C-term COOH</name>
100 <pka>2.35</pka>
101 <acidcharged>FALSE</acidcharged>
102 <polrule>right_trapped</polrule>
103 </mnmchemgroup>
104 <mnmchemgroup>
105 <name>Lateral SH2</name>
106 <pka>8.3</pka>
107 <acidcharged>FALSE</acidcharged>
108 <polrule>never_trapped</polrule>
109 </mnmchemgroup>
110 </monomer>
111 .....
112 <modifs>
113 <modif>
114 <name>Phosphorylation</name>
115 <mdfchemgroup>
116 <name>none_set</name>
117 <pka>1.2</pka>
118 <acidcharged>FALSE</acidcharged>
119 </mdfchemgroup>
120 <mdfchemgroup>
121 <name>none_set</name>
122 <pka>6.5</pka>
123 <acidcharged>FALSE</acidcharged>
124 </mdfchemgroup>
125 </modif>
126 </modifs>
127 </pkaphpidata>
128 \endcode
129
130 \sa ChemicalGroupRule,
131 */
132
133 /*!
134 \variable MsXpS::libXpertMassCore::ChemicalGroup::m_name
135
136 \brief The name of the ChemicalGroup instance.
137 */
138
139 /*!
140 \variable MsXpS::libXpertMassCore::ChemicalGroup::m_pka
141
142 \brief The pKa of the ChemicalGroup instance.
143 */
144
145 /*!
146 \variable MsXpS::libXpertMassCore::ChemicalGroup::m_acidCharged
147
148 \brief Tells if the group is charged when in acid conditions (that is, the pH
149 is less than the pKa).
150 */
151
152 /*!
153 \variable MsXpS::libXpertMassCore::ChemicalGroup::m_polymerizationRule
154
155 \brief The way this ChemicalGroup behaves upon polymerization of the chemical
156 entity into a \l Polymer.
157 */
158
159 /*!
160 \variable MsXpS::libXpertMassCore::ChemicalGroup::m_rules
161
162 \brief The container of \l ChemicalGroupRule instances.
163 */
164
165 /*!
166 \brief Constructs a ChemicalGroup instance.
167
168 \a name The name of this ChemicalGroup.
169 \a pka The pKa value of this ChemicalGroup.
170 \a is_acid_charged Tells if the ChemicalGroup bears a charge when in acidic
171 conditions.
172 \a polymerization_rule Specifies the polymerization rule.
173
174 Upon construction the object is validated and m_isValid is set to the result of
175 that validation.
176 */
177 7 ChemicalGroup::ChemicalGroup(const QString &name,
178 float pka,
179 bool is_acid_charged,
180 7 Enums::ChemicalGroupTrapped polymerization_rule)
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 : m_name(name),
182 7 m_pka(pka),
183 7 m_acidCharged(is_acid_charged),
184
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 m_polymerizationRule(polymerization_rule)
185 {
186 7 if(m_pka <= 0 && m_pka >= 14)
187 qFatalStream() << "Programming error. pKa cannot be <=0 or >= 14.";
188
189 7 ErrorList error_list;
190
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 m_isValid = validate(&error_list);
191
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if(!m_isValid)
192
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
14 qCritical()
193
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 << "The ChemicalGroup right constructed did not validate successfully.";
194 7 }
195
196 /*!
197 \brief Construct a ChemicalGroup instance as a copy of \a other.
198
199 There is no checking of the validity of \a other.
200 */
201 1 ChemicalGroup::ChemicalGroup(const ChemicalGroup &other)
202
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 : m_name(other.m_name),
203 1 m_pka(other.m_pka),
204 1 m_acidCharged(other.m_acidCharged),
205 1 m_polymerizationRule(other.m_polymerizationRule),
206 1 m_isValid(other.m_isValid)
207 {
208 // We want a new allocation, not a shared pointer copy.
209
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for(const ChemicalGroupRuleSPtr &chemical_group_rule_sp : other.m_rules)
210 4 m_rules.emplace_back(
211
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 std::make_shared<ChemicalGroupRule>(*chemical_group_rule_sp.get()));
212 1 }
213
214 /*!
215 \brief Destructs this ChemicalGroup instance.
216 */
217 8 ChemicalGroup::~ChemicalGroup()
218 {
219 8 }
220
221 /*!
222 \brief Assigns \a other to this ChemicalGroup instance.
223
224 \note The ChemicalGroupRule instances in \a other are deep-duplicated.
225
226 Returns a reference to this ChemicalGroup instance.
227 */
228 ChemicalGroup &
229 1 ChemicalGroup::operator=(const ChemicalGroup &other)
230 {
231
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(&other == this)
232 return *this;
233
234 1 m_name = other.m_name;
235 1 m_pka = other.m_pka;
236 1 m_acidCharged = other.m_acidCharged;
237 1 m_polymerizationRule = other.m_polymerizationRule;
238
239 // We want a new allocation, not a shared pointer copy.
240
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for(const ChemicalGroupRuleSPtr &chemical_group_rule_sp : other.m_rules)
241 4 m_rules.emplace_back(
242
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 std::make_shared<ChemicalGroupRule>(*chemical_group_rule_sp.get()));
243
244 1 ErrorList error_list;
245
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
246
247 1 return *this;
248 1 }
249
250 /*!
251 \brief Sets the \a name.
252 */
253 void
254 3 ChemicalGroup::setName(QString name)
255 {
256 3 m_name = name;
257
258 3 ErrorList error_list;
259
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_isValid = validate(&error_list);
260
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(!m_isValid)
262 {
263 qCritical()
264 << "After setting name, the object did not validate successfully.";
265 }
266 3 }
267
268 /*!
269 \brief Returns the name.
270 */
271 QString
272 3 ChemicalGroup::getName() const
273 {
274
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 return m_name;
275 }
276
277 /*!
278 \brief Sets the pKa to \a pka.
279 */
280 void
281 3 ChemicalGroup::setPka(float pka)
282 {
283 3 m_pka = pka;
284
285 3 ErrorList error_list;
286
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_isValid = validate(&error_list);
287
288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(!m_isValid)
289 {
290 qCritical()
291 << "After setting pKa, the object did not validate successfully.";
292 }
293 3 }
294
295 /*!
296 \brief Returns the pKa.
297 */
298 float
299 3 ChemicalGroup::getPka() const
300 {
301 3 return m_pka;
302 }
303
304 /*!
305 \brief Sets the charge condition in acidic conditions to \a acid_charged.
306
307 If true, the group bears a charge when the pH is less than the pKa.
308 */
309 void
310 3 ChemicalGroup::setAcidCharged(bool acid_charged)
311 {
312 3 m_acidCharged = acid_charged;
313
314 3 ErrorList error_list;
315
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_isValid = validate(&error_list);
316
317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(!m_isValid)
318 {
319 qCritical() << "After setting acid charged bool, the object did not "
320 "validate successfully.";
321 }
322 3 }
323
324 /*!
325 \brief Returns the charge condition in acidic conditions.
326
327 If true, the group bears a charge when the pH is less than the pKa.
328 */
329 bool
330 3 ChemicalGroup::isAcidCharged() const
331 {
332 3 return m_acidCharged;
333 }
334
335 /*!
336 \brief Sets the polymerization rule to \a pol_rule.
337
338 The polymerization rule determines if the chemical group is trapped upon
339 formation of a Monomer-to-Monomer bond.
340 */
341 void
342 3 ChemicalGroup::setPolRule(Enums::ChemicalGroupTrapped pol_rule)
343 {
344 3 m_polymerizationRule = pol_rule;
345
346 3 ErrorList error_list;
347
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_isValid = validate(&error_list);
348
349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(!m_isValid)
350 {
351 qCritical() << "After setting Enums::ChemicalGroupTrapped, the object did not "
352 "validate successfully.";
353 }
354 3 }
355
356 /*!
357 \brief Returns the polymerization rule.
358 */
359 Enums::ChemicalGroupTrapped
360 2 ChemicalGroup::getPolRule() const
361 {
362 2 return m_polymerizationRule;
363 }
364
365 /*!
366 \brief Returns a const reference to the container of ChemicalGroupRule
367 instances.
368 */
369 const std::vector<ChemicalGroupRuleSPtr> &
370 5 ChemicalGroup::getRulesCstRef() const
371 {
372 5 return m_rules;
373 }
374
375
376 /*!
377 \brief Returns a reference to the container of ChemicalGroupRule instances.
378 */
379 std::vector<ChemicalGroupRuleSPtr> &
380 10 ChemicalGroup::getRulesRef()
381 {
382 10 return m_rules;
383 }
384
385 /*!
386 \brief Searches by \a entity for a ChemicalGroupRule instance.
387
388 Returns the \a index of the ChemicalGroupRule instance in the member list of
389 ChemicalGroupRule instances or -1 if not found.
390 */
391 ChemicalGroupRuleSPtr
392 8 ChemicalGroup::findRuleByEntity(const QString &entity, std::size_t &index) const
393 {
394
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if(index >= m_rules.size())
395 1 return nullptr;
396
397
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if(entity.isEmpty())
398 return nullptr;
399
400 7 std::vector<ChemicalGroupRuleSPtr>::const_iterator the_begin_iterator_cst =
401 7 m_rules.cbegin();
402 7 std::vector<ChemicalGroupRuleSPtr>::const_iterator the_iterator_cst =
403 7 m_rules.cbegin() + index;
404 7 std::vector<ChemicalGroupRuleSPtr>::const_iterator the_end_iterator_cst =
405 7 m_rules.cend();
406
407
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 while(the_iterator_cst != the_end_iterator_cst)
408 {
409
2/2
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2 times.
8 if((*the_iterator_cst)->getEntity() == entity)
410 {
411 6 index = std::distance(the_begin_iterator_cst, the_iterator_cst);
412 6 return *the_iterator_cst;
413 }
414
415 2 ++the_iterator_cst;
416 }
417
418 1 return nullptr;
419 }
420
421 /*!
422 \brief Searches by \a name for a ChemicalGroupRule instance.
423
424 Returns the \a index of the ChemicalGroupRule instance in the member list of
425 ChemicalGroupRule instances or -1 if not found.
426 */
427 ChemicalGroupRuleSPtr
428 6 ChemicalGroup::findRuleByName(const QString &name, std::size_t &index) const
429 {
430
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if(index >= m_rules.size())
431 1 return nullptr;
432
433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if(name.isEmpty())
434 return nullptr;
435
436
437 5 std::vector<ChemicalGroupRuleSPtr>::const_iterator the_begin_iterator_cst =
438 5 m_rules.cbegin();
439 5 std::vector<ChemicalGroupRuleSPtr>::const_iterator the_iterator_cst =
440 5 m_rules.cbegin() + index;
441 5 std::vector<ChemicalGroupRuleSPtr>::const_iterator the_end_iterator_cst =
442 5 m_rules.cend();
443
444
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 while(the_iterator_cst != the_end_iterator_cst)
445 {
446
2/2
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
8 if((*the_iterator_cst)->getName() == name)
447 {
448 4 index = std::distance(the_begin_iterator_cst, the_iterator_cst);
449 4 return *the_iterator_cst;
450 }
451
452 4 ++the_iterator_cst;
453 }
454
455 1 return nullptr;
456 }
457
458
459 /*!
460 \brief Searches by \a entity and \a name for a ChemicalGroupRule instance.
461
462 Returns the \a index of the ChemicalGroupRule instance in the member list of
463 ChemicalGroupRule instances or -1 if not found.
464 */
465 ChemicalGroupRuleSPtr
466 4 ChemicalGroup::findRuleByEntityAndName(const QString &entity,
467 const QString &name,
468 std::size_t &index) const
469 {
470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(index >= m_rules.size())
471 return nullptr;
472
473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(name.isEmpty())
474 return nullptr;
475
476 4 std::vector<ChemicalGroupRuleSPtr>::const_iterator the_begin_iterator_cst =
477 4 m_rules.cbegin();
478 4 std::vector<ChemicalGroupRuleSPtr>::const_iterator the_iterator_cst =
479 4 m_rules.cbegin() + index;
480 4 std::vector<ChemicalGroupRuleSPtr>::const_iterator the_end_iterator_cst =
481 4 m_rules.cend();
482
483
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 while(the_iterator_cst != the_end_iterator_cst)
484 {
485
5/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 2 times.
16 if((*the_iterator_cst)->getName() == name &&
486
1/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
6 (*the_iterator_cst)->getEntity() == entity)
487 {
488 4 index = std::distance(the_begin_iterator_cst, the_iterator_cst);
489 4 return *the_iterator_cst;
490 }
491
492 2 ++the_iterator_cst;
493 }
494
495 return nullptr;
496 }
497
498 /*!
499 \brief Validates this instance, setting eventual error messages in \a
500 error_list_p.
501
502 \note \a error_list_p is not cleared.
503
504 If the validation is successful, m_isValid is set to true, otherwise it is set
505 to false. That result is returned.
506 */
507 bool
508 22 ChemicalGroup::validate(ErrorList *error_list_p) const
509 {
510
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 15 times.
22 qsizetype error_count = error_list_p->size();
511
512
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 15 times.
22 if(m_name.isEmpty())
513 {
514
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 qCritical() << "The ChemicalGroup cannot validate with an empty name.";
515 14 error_list_p->push_back(
516 "The ChemicalGroup cannot validate with an empty name");
517 }
518
519 22 if(m_pka <= 0 && m_pka >= 14)
520 {
521 qCritical()
522 << "The ChemicalGroup cannot validate with an invalid pKa value.";
523 error_list_p->push_back(
524 "The ChemicalGroup cannot validate with an invalid pKa value.");
525 }
526
527 22 m_isValid = error_list_p->size() > error_count ? false : true;
528
529 22 return m_isValid;
530 }
531
532
533 /*!
534 \brief Returns the validity status of this instance.
535 */
536 bool
537 5 ChemicalGroup::isValid() const
538 {
539 5 return m_isValid;
540 }
541
542 /*!
543 \brief Parses the ChemicalGroup XML \a element \e{related to a \l Monomer}.
544
545 Upon parsing of the \a element (tag \code{<mnmchemgroup>}), its data
546 are validated and set to this ChemicalGroup instance, thus essentially
547 initializing it.
548
549 In an pkaphpidata definition file, the following xml structure
550 is encountered:
551
552 \code
553 <pkaphpidata>
554 <monomers>
555 <monomer>
556 <code>A</code>
557 <mnmchemgroup>
558 <name>N-term NH2</name>
559 <pka>9.6</pka>
560 <acidcharged>TRUE</acidcharged>
561 <polrule>left_trapped</polrule>
562 <chemgrouprule>
563 <entity>LE_PLM_MODIF</entity>
564 <name>Acetylation</name>
565 <outcome>LOST</outcome>
566 </chemgrouprule>
567 </mnmchemgroup>
568 <mnmchemgroup>
569 <name>C-term COOH</name>
570 <pka>2.35</pka>
571 <acidcharged>FALSE</acidcharged>
572 <polrule>right_trapped</polrule>
573 </mnmchemgroup>
574 </monomer>
575 <monomer>
576 <code>C</code>
577 <mnmchemgroup>
578 <name>N-term NH2</name>
579 <pka>9.6</pka>
580 <acidcharged>TRUE</acidcharged>
581 <polrule>left_trapped</polrule>
582 <chemgrouprule>
583 <entity>LE_PLM_MODIF</entity>
584 <name>Acetylation</name>
585 <outcome>LOST</outcome>
586 </chemgrouprule>
587 </mnmchemgroup>
588 <mnmchemgroup>
589 <name>C-term COOH</name>
590 <pka>2.35</pka>
591 <acidcharged>FALSE</acidcharged>
592 <polrule>right_trapped</polrule>
593 </mnmchemgroup>
594 <mnmchemgroup>
595 <name>Lateral SH2</name>
596 <pka>8.3</pka>
597 <acidcharged>FALSE</acidcharged>
598 <polrule>never_trapped</polrule>
599 </mnmchemgroup>
600 </monomer>
601 \endcode
602
603 Upon parsing of the \a element, all the data are validated and set to this
604 ChemicalGroup instance, thus essentially initializing it. If there are
605 \l{ChemicalGroupRule}s associated to the ChemicalGroup element, these are
606 rendered also.
607
608 Returns true if parsing and validation were successful, false otherwise.
609 */
610 bool
611 1 ChemicalGroup::renderXmlMnmElement(const QDomElement &element)
612 {
613 // The element the parameter points to is:
614 //
615 // <mnmchemgroup>
616 //
617 // Which means that element.tagName() == "mnmchemgroup" and that we'll
618 // have to go one step down to the first child of the current node
619 // in order to get to the \code<name>\endcode element.
620
621
622 1 QDomElement child;
623
624
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(element.tagName() != "mnmchemgroup")
625 return false;
626
627
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 child = element.firstChildElement("name");
628
629
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if(child.isNull())
630 return false;
631
632
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_name = child.text();
633
634
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
635
636
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
2 if(child.isNull() || child.tagName() != "pka")
637 return false;
638
639 1 bool ok = false;
640
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 m_pka = child.text().toFloat(&ok);
641
642
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if(!m_pka && !ok)
643 return false;
644
645
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if(m_pka <= 0 || m_pka >= 14)
646 return false;
647
648
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
649
650
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
2 if(child.isNull() || child.tagName() != "acidcharged")
651 return false;
652
653
5/12
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
2 if(child.text() != "FALSE" && child.text() != "TRUE")
654 return false;
655
656
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
3 m_acidCharged = (child.text() == "FALSE" ? false : true);
657
658 // And now the polrule element. There should be one, here, in fact,
659 // because we are dealing with a monomer, and not a modification.
660
661
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
662
663
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
2 if(child.isNull() || child.tagName() != "polrule")
664 return false;
665
666
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.text() == "never_trapped")
667 m_polymerizationRule = Enums::ChemicalGroupTrapped::NEVER;
668
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 else if(child.text() == "left_trapped")
669 1 m_polymerizationRule = Enums::ChemicalGroupTrapped::LEFT;
670 else if(child.text() == "right_trapped")
671 m_polymerizationRule = Enums::ChemicalGroupTrapped::RIGHT;
672 else
673 return false;
674
675 // And finally the chemical group rules... There might be zero, one
676 // or more.
677
678
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 QDomElement childChemGroupRule = child.nextSiblingElement("chemgrouprule");
679
680
3/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
2 while(!childChemGroupRule.isNull())
681 {
682
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 ChemicalGroupRuleSPtr chemical_group_rule_sp =
683 std::make_shared<ChemicalGroupRule>();
684
685
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if(!chemical_group_rule_sp->renderXmlElement(childChemGroupRule))
686 {
687 chemical_group_rule_sp.reset();
688 return false;
689 }
690
691
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_rules.push_back(chemical_group_rule_sp);
692
693
3/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
2 childChemGroupRule = childChemGroupRule.nextSiblingElement();
694 1 }
695
696 1 ErrorList error_list;
697
698
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
699
700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!m_isValid)
701 qCritical() << "Failed to validate successfully, with errors:" << Utils::joinErrorList(error_list);
702
703 1 return m_isValid;
704 3 }
705
706
707 /*!
708 \brief Parses the ChemicalGroup XML \a element \e{related to a \l Modif}.
709
710 Upon parsing of the \a element (tag <mnmchemgroup>), its data are validated and
711 set to this ChemicalGroup instance, thus essentially initializing it.
712
713 In an pkaphpidata definition file, the following xml structure
714 is encountered:
715
716 \code
717 <pkaphpidata>
718 <monomers>
719 <monomer>
720 <code>A</code>
721 <mnmchemgroup>
722 <name>N-term NH2</name>
723 <pka>9.6</pka>
724 <acidcharged>TRUE</acidcharged>
725 <polrule>left_trapped</polrule>
726 <chemgrouprule>
727 <entity>LE_PLM_MODIF</entity>
728 <name>Acetylation</name>
729 <outcome>LOST</outcome>
730 </chemgrouprule>
731 </mnmchemgroup>
732 <mnmchemgroup>
733 <name>C-term COOH</name>
734 <pka>2.35</pka>
735 <acidcharged>FALSE</acidcharged>
736 <polrule>right_trapped</polrule>
737 </mnmchemgroup>
738 </monomer>
739 .......
740 </monomers>
741 <modifs>
742 <modif>
743 <name>Phosphorylation</name>
744 <mdfchemgroup>
745 <name>none_set</name>
746 <pka>1.2</pka>
747 <acidcharged>FALSE</acidcharged>
748 </mdfchemgroup>
749 <mdfchemgroup>
750 <name>none_set</name>
751 <pka>6.5</pka>
752 <acidcharged>FALSE</acidcharged>
753 </mdfchemgroup>
754 </modif>
755 </modifs>
756 </pkaphpidata>
757 \endcode
758
759 Upon parsing of the \a element, all the data are validated and set to this
760 ChemicalGroup instance, thus essentially initializing it. If there are
761 \l{ChemicalGroupRule}s associated to the ChemicalGroup element, these are
762 rendered also.
763
764 Returns true if parsing and validation were successful, false otherwise.
765 */
766 bool
767 1 ChemicalGroup::renderXmlMdfElement(const QDomElement &element)
768 {
769 1 QDomElement child;
770
771
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(element.tagName() != "mdfchemgroup")
772 return false;
773
774
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 child = element.firstChildElement("name");
775
776
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if(child.isNull())
777 return false;
778
779
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_name = child.text();
780
781
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
782
783
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
2 if(child.isNull() || child.tagName() != "pka")
784 return false;
785
786 1 bool ok = false;
787
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 m_pka = child.text().toFloat(&ok);
788
789
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if(!m_pka && !ok)
790 return false;
791
792
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if(m_pka <= 0 || m_pka >= 14)
793 return false;
794
795
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
796
797
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
2 if(child.isNull() || child.tagName() != "acidcharged")
798 return false;
799
800
3/12
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
1 if(child.text() != "FALSE" && child.text() != "TRUE")
801 return false;
802
803
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
2 m_acidCharged = (child.text() == "FALSE" ? false : true);
804
805 1 ErrorList error_list;
806
807
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_isValid = validate(&error_list);
808
809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!m_isValid)
810 qCritical() << "Failed to validate successfully, with errors:" << Utils::joinErrorList(error_list);
811
812 1 return m_isValid;
813 2 }
814
815
816 //////////////////////// ChemicalGroupProp ////////////////////////
817 //////////////////////// ChemicalGroupProp ////////////////////////
818
819
820 /*!
821 \class MsXpS::libXpertMassCore::ChemicalGroupProp
822 \inmodule libXpertMassCore
823 \ingroup ThePropSystem
824
825 \brief The ChemicalGroupProp class provides a Prop instance of which the member
826 data points to a dynamically allocated \l ChemicalGroup instance.
827 */
828
829 /*!
830 \brief Constructs a ChemicalGroupProp instance using \a data and \a name.
831
832 The \a data pointer is set to the \l mpa_data member.
833 */
834 ChemicalGroupProp::ChemicalGroupProp(const QString &name, ChemicalGroup *data)
835 {
836 if(!name.isEmpty())
837 m_name = name;
838 else
839 m_name = QString();
840
841 mpa_data = static_cast<void *>(data);
842 }
843
844
845 /*!
846 \brief Constructs a ChemicalGroupProp instance as a copy of \a other.
847
848 The data in \a other are duplicated and set to this ChemicalGroupProp instance.
849 */
850 ChemicalGroupProp::ChemicalGroupProp(const ChemicalGroupProp &other)
851 : Prop(other)
852 {
853 if(other.mpa_data != nullptr)
854 {
855 ChemicalGroup *chemicalGroup =
856 static_cast<ChemicalGroup *>(other.mpa_data);
857
858 mpa_data = static_cast<void *>(new ChemicalGroup(*chemicalGroup));
859 }
860 else
861 mpa_data = nullptr;
862 }
863
864 /*!
865 \brief Destructs this ChemicalGroupProp instance.
866
867 The deletion of the data are delegated to \l deleteData().
868 */
869 ChemicalGroupProp::~ChemicalGroupProp()
870 {
871 deleteData();
872 }
873
874 /*!
875 \brief Deletes the member data.
876 */
877 void
878 ChemicalGroupProp::deleteData()
879 {
880 if(mpa_data != nullptr)
881 {
882 delete static_cast<ChemicalGroup *>(mpa_data);
883 mpa_data = nullptr;
884 }
885 }
886
887 /*!
888 \brief Assigns \a other to this ChemicalGroupProp instance.
889
890 The member data are first deleted and then set to a copy of those in \a other.
891 */
892 ChemicalGroupProp &
893 ChemicalGroupProp::operator=(const ChemicalGroupProp &other)
894 {
895 if(&other == this)
896 return *this;
897
898 Prop::operator=(other);
899
900 if(mpa_data != nullptr)
901 deleteData();
902
903 if(other.mpa_data != nullptr)
904 {
905 ChemicalGroup *chemicalGroup =
906 static_cast<ChemicalGroup *>(other.mpa_data);
907
908 mpa_data = static_cast<void *>(new ChemicalGroup(*chemicalGroup));
909 }
910 else
911 mpa_data = nullptr;
912
913 return *this;
914 }
915
916
917 /*!
918 \brief Duplicates this ChemicalGroupProp instance and returns its pointer.
919 */
920 ChemicalGroupProp *
921 ChemicalGroupProp::cloneOut() const
922 {
923 ChemicalGroupProp *new_p = new ChemicalGroupProp(*this);
924
925 return new_p;
926 }
927
928 bool
929 ChemicalGroupProp::renderXmlElement([[maybe_unused]] const QDomElement &element,
930 [[maybe_unused]] int version)
931 {
932 return false;
933 }
934
935 QString
936 ChemicalGroupProp::formatXmlElement([[maybe_unused]] int offset,
937 [[maybe_unused]] const QString &indent)
938 {
939 return QString();
940 }
941
942 } // namespace libXpertMassCore
943
944 } // namespace MsXpS
945