GCC Code Coverage Report


./
File: src/XpertMass/PolChemDef.cpp
Date: 2024-08-24 11:26:06
Lines:
335/576
58.2%
Functions:
27/52
51.9%
Branches:
361/932
38.7%

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 /////////////////////// Qt includes
35 #include <QDebug>
36 #include <QFileInfo>
37 #include <QDir>
38
39
40 /////////////////////// Local includes
41 #include "PolChemDef.hpp"
42 #include "Monomer.hpp"
43 #include "Polymer.hpp"
44 #include "IsotopicDataLibraryHandler.hpp"
45 #include "IsotopicDataUserConfigHandler.hpp"
46
47
48 int polChemDefSPtrMetaTypeId =
49 qRegisterMetaType<MsXpS::libXpertMass::PolChemDefSPtr>(
50 "MsXpS::libXpertMass::PolChemDefSPtr");
51
52 int polChemDefCstSPtrMetaTypeId =
53 qRegisterMetaType<MsXpS::libXpertMass::PolChemDefCstSPtr>(
54 "MsXpS::libXpertMass::PolChemDefCstSPtr");
55
56
57 namespace MsXpS
58 {
59
60 namespace libXpertMass
61 {
62
63 /*!
64 \class MsXpS::libXpertMass::PolChemDef
65 \inmodule libXpertMass
66 \ingroup PolChemDef
67 \inheaderfile PolChemDef.hpp
68
69 \brief The PolChemDef class provides a complete set of chemical entities
70 fully qualifying a polymer chemistry definition, like Proteins, Saccharides or
71 Nucleic acids.
72
73 The PolChemDef class provides a full set of chemical entity definitions
74 (\l{Isotope}s, \l{Monomer}s, chemical \l{Modif}ications, \l{CrossLink}s),
75 chemical reaction models (in the liquid or gas phase, like \l Polymer cleavage:
76 \l CleaveSpec or \l Oligomer fragmentation: \l FragSpec)\dots
77 */
78
79 /*!
80 \variable MsXpS::libXpertMass::PolChemDef::m_name
81
82 \brief The name of the polymer chemistry definition, like \e{protein-1-letter}
83 or \e{nucac}, for example.
84
85 This name is typically identical to both the name of the directory where all
86 the data defining this \c PolChemDef is stored and the name of the XML file
87 that contains the definition itself.
88 */
89
90 /*!
91 \variable MsXpS::libXpertMass::PolChemDef::m_xmlDataFilePath
92
93 \brief The path to the XML data file that contains the description of this
94 polymer chemistry definition.
95 */
96
97
98 /*!
99 \variable MsXpS::libXpertMass::PolChemDef::m_isotopicDataFilePath
100
101 \brief The path to the file that contains this polymer chemistry definition's
102 isotopic data.
103 */
104
105 /*!
106 \variable MsXpS::libXpertMass::PolChemDef::m_leftCap
107
108 \brief The \l Formula that defines how of the left end of a polymer
109 sequence of this \l PolChemDef needs to be capped in order to finalize the
110 polymerization state of the \l Polymer sequence.
111
112 \sa PolChemDef::m_rightCap
113 */
114
115 /*!
116 \variable MsXpS::libXpertMass::PolChemDef::m_rightCap
117
118 \brief The \l Formula that defines how of the right end of a polymer
119 sequence of this \l PolChemDef needs to be capped in order to finalize the
120 polymerization state of the \l Polymer sequence.
121
122 \sa PolChemDef::m_leftCap
123 */
124
125 /*!
126 \variable MsXpS::libXpertMass::PolChemDef::m_codeLength
127
128 \brief The maximum length of a \l Monomer code in this defintion.
129
130 The valid syntax of a Monomer code is that the first character of the code is
131 uppercase and all the remaining ones are lowercase. The total number of
132 characters cannot exceed m_codeLength.
133 */
134
135 /*!
136 \variable MsXpS::libXpertMass::PolChemDef::m_delimitedCodes
137
138 \brief The set of \l Monomer codes separated by '@' characters, like
139 "@Ala@Tyr@Phe@".
140 */
141
142 /*!
143 \variable MsXpS::libXpertMass::PolChemDef::m_ionizeRule
144
145 \brief The \l{IonizeRule}{ionization rule} that governs the manner the \l
146 Polymer sequences of this polymer chemistry definition are ionized by default.
147 */
148
149 /*!
150 \variable MsXpS::libXpertMass::PolChemDef::msp_isotopicData
151
152 \brief The isotopic data defining the fundamentals of this \l PolChemDef
153 instance.
154 */
155
156 /*!
157 \variable MsXpS::libXpertMass::PolChemDef::m_monomerList
158
159 \brief The list of \l{Monomer}s defined to be part of this \l PolChemDef
160 instance.
161 */
162
163
164 /*!
165 \variable MsXpS::libXpertMass::PolChemDef::m_modifList
166
167 \brief The list of \l{Modif}s defined to be part of this \l PolChemDef
168 instance.
169 */
170
171 /*!
172 \variable MsXpS::libXpertMass::PolChemDef::m_crossLinkerList
173
174 The list of \l{CrossLinker}s defined to be part of this \l PolChemDef
175 instance.
176 */
177
178 /*!
179 \variable MsXpS::libXpertMass::PolChemDef::m_cleaveSpecList
180
181 \brief The list of \l{CleaveSpec}s defining the various ways to cleave
182 \l Polymer sequences of this \l PolChemDef instance.
183 */
184
185 /*!
186 \variable MsXpS::libXpertMass::PolChemDef::m_fragSpecList
187
188 \brief The list of \l{FragSpec}s defining the various ways to fragment \l
189 Oligomer sequences of this \l PolChemDef instance.
190 */
191
192 /*!
193 \variable MsXpS::libXpertMass::PolChemDef::m_monomerSpecList
194
195 \brief The list of \l{MonomerSpec}s defining how \l{Monomer}s are represented
196 in the graphical user interface.
197 */
198
199
200 /*!
201 \variable MsXpS::libXpertMass::PolChemDef::m_modifSpecList
202
203 \brief The list of \l{ModifSpec}s defining how \l{Modif}s are represented
204 in the graphical user interface.
205 */
206
207 /*!
208 \variable MsXpS::libXpertMass::PolChemDef::m_crossLinkerSpecList
209
210 \brief The list of \l{CrossLinkerSpec}s defining how \l{CrossLinker}s are
211 represented in the graphical user interface.
212 */
213
214 /*!
215 \variable MsXpS::libXpertMass::PolChemDef::mp_repositoryList
216
217 \brief The list of \l PolChemDef instances available in the repositories.
218 */
219
220
221 /*!
222 \variable MsXpS::libXpertMass::POL_CHEM_DEF_FILE_FORMAT_VERSION
223
224 \brief The latest version of the format of the file containing the
225 polymer chemistry definition.
226
227 Brought to 1 20230130 for massXpert2
228 */
229 const int POL_CHEM_DEF_FILE_FORMAT_VERSION = 1;
230
231 /*!
232 \brief Constructs a polymer chemistry definition.
233 */
234
3/6
✓ Branch 5 taken 401 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 401 times.
✗ Branch 11 not taken.
✓ Branch 15 taken 401 times.
✗ Branch 16 not taken.
401 PolChemDef::PolChemDef()
235 {
236 // qDebug() << "Constructing PolChemDef *:" << this;
237
238 // We have to set the m_codeLength member to 1. It would make no
239 // sense to have monomers described with codes of 0-character
240 // length.
241 401 m_codeLength = 1;
242
243 401 return;
244 }
245
246
247 /*!
248 \brief Constructs a polymer chemistry definition on the basis of \a
249 pol_chem_def_spec.
250
251 The \a pol_chem_def_spec polymer chemistry definition specification provides
252 the name of the polymer chemistry definition and of the file that contains
253 it.
254 */
255
3/6
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✓ Branch 15 taken 12 times.
✗ Branch 16 not taken.
12 PolChemDef::PolChemDef(const PolChemDefSpec &pol_chem_def_spec)
256 {
257
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 m_name = pol_chem_def_spec.name();
258
259 // qDebug() << "Constructing PolChemDef *:" << this << "with name:" <<
260 // m_name;
261
262
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 m_xmlDataFilePath = pol_chem_def_spec.getFilePath();
263
264 12 m_codeLength = 1;
265
266 12 return;
267 }
268
269 /*!
270 \brief Destroys the polymer chemistry definition
271 */
272 834 PolChemDef::~PolChemDef()
273 {
274 // qDebug() << "Entering ~PolChemDef *:" << this << "with name:" << m_name;
275
276 // We have to free all the allocated stuff in the QList members !
277
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
1668 while(!m_monomerList.isEmpty())
278 delete m_monomerList.takeFirst();
279
280
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
1668 while(!m_modifList.isEmpty())
281 delete m_modifList.takeFirst();
282
283
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
1668 while(!m_crossLinkerList.isEmpty())
284 delete m_crossLinkerList.takeFirst();
285
286
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
1668 while(!m_cleaveSpecList.isEmpty())
287 delete m_cleaveSpecList.takeFirst();
288
289
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
1668 while(!m_fragSpecList.isEmpty())
290 delete m_fragSpecList.takeFirst();
291
292
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
1668 while(!m_monomerSpecList.isEmpty())
293 delete m_monomerSpecList.takeFirst();
294
295
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
1668 while(!m_modifSpecList.isEmpty())
296 delete m_modifSpecList.takeFirst();
297
298 // qDebug()
299 // << "Leaving ~PolChemDef():" << this;
300 834 }
301
302
303 /*!
304 \brief Sets the \a name of this PolChemDef instance.
305 */
306 void
307 404 PolChemDef::setName(const QString &name)
308 {
309 404 m_name = name;
310 404 }
311
312
313 /*!
314 \brief Returns the name of this PolChemDef instance.
315 */
316 QString
317 16 PolChemDef::name() const
318 {
319 16 return m_name;
320 }
321
322
323 /*!
324 \brief Sets the \a file_path of this PolChemDef instance.
325 */
326 void
327 408 PolChemDef::setXmlDataFilePath(const QString &file_path)
328 {
329 408 m_xmlDataFilePath = file_path;
330 408 }
331
332
333 /*!
334 \brief Returns the file path of this PolChemDef instance.
335 */
336 QString
337 12 PolChemDef::getXmlDataFilePath() const
338 {
339 12 return m_xmlDataFilePath;
340 }
341
342
343 /*!
344 \brief Returns the absolute directory path of this PolChemDef instance.
345 */
346 QString
347 4 PolChemDef::getXmlDataDirPath() const
348 {
349 // qDebug() << "The xml data file path:" << m_xmlDataFilePath;
350
351
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QFileInfo fileInfo(m_xmlDataFilePath);
352
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QDir dir(fileInfo.dir());
353
354 // qDebug() << "Returning the pol chem def data dir path:" <<
355
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 dir.absolutePath();
356
357
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 return dir.absolutePath();
358 4 }
359
360 /*!
361 \brief Sets the path of the isotopic data file to \a file_path.
362 */
363 void
364 396 PolChemDef::setIsotopicDataFilePath(const QString &file_path)
365 {
366 396 m_isotopicDataFilePath = file_path;
367 396 }
368
369 /*!
370 \brief Returns the path of the isotopic data file.
371 */
372 QString
373 396 PolChemDef::getIsotopicDataFilePath() const
374 {
375 396 return m_isotopicDataFilePath;
376 }
377
378 /*!
379 \brief Returns the path of the isotopic data file.
380
381 The deduction is based on the fact that the file should have
382 "isotopic-data.dat" as its name.
383 */
384 QString
385 400 PolChemDef::deduceIsotopicDataFilePath() const
386 {
387 // From the xml data file path, deduce the file name of the isotopic data.
388
1/2
✓ Branch 1 taken 400 times.
✗ Branch 2 not taken.
400 QFileInfo file_info(m_xmlDataFilePath);
389
390
2/4
✓ Branch 1 taken 400 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 400 times.
400 if(!file_info.exists())
391 qFatal(
392 "Programming error. At this stage the location of the polymer chemistry "
393 "definition file should be known.");
394
395
1/2
✓ Branch 1 taken 400 times.
✗ Branch 2 not taken.
400 QDir dir(file_info.dir());
396
397 QString isotopic_data_file_path =
398
3/6
✓ Branch 2 taken 400 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 400 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 400 times.
✗ Branch 9 not taken.
400 dir.absolutePath() + QDir::separator() + "isotopic-data.dat";
399
400 400 return isotopic_data_file_path;
401 400 }
402
403
404 /*!
405 \brief Sets the left cap \a formula.
406 */
407 void
408 PolChemDef::setLeftCap(const Formula &formula)
409 {
410 m_leftCap = formula;
411 }
412
413 /*!
414 \brief Returns the left cap formula.
415 */
416 const Formula &
417 60 PolChemDef::leftCap() const
418 {
419 60 return m_leftCap;
420 }
421
422
423 /*!
424 \brief Sets the right cap \a formula.
425 */
426 void
427 PolChemDef::setRightCap(const Formula &formula)
428 {
429 m_rightCap = formula;
430 }
431
432
433 /*!
434 \brief Returns the right cap formula.
435 */
436 const Formula &
437 60 PolChemDef::rightCap() const
438 {
439 60 return m_rightCap;
440 }
441
442
443 /*!
444 \brief Sets the \a code_length.
445 */
446 void
447 PolChemDef::setCodeLength(int code_length)
448 {
449 m_codeLength = code_length;
450 }
451
452
453 /*!
454 \brief Returns the code length.
455 */
456 int
457 57720 PolChemDef::codeLength() const
458 {
459 57720 return m_codeLength;
460 }
461
462 /*!
463 \brief Constructs a string with the codes of all the \l{Monomer}s in this
464 PolChemDef instance.
465
466 The codes are delimited by the '@' character.
467
468 Returns true.
469 */
470 bool
471 PolChemDef::calculateDelimitedCodes()
472 {
473 // We have to produce a QString containing all the codes from the
474 // monomers known to this polymer chemistry definition.
475
476 m_delimitedCodes.clear();
477 m_delimitedCodes.append('@');
478
479 for(int iter = 0; iter < m_monomerList.size(); ++iter)
480 {
481 Monomer *monomer = m_monomerList.at(iter);
482 Q_ASSERT(monomer);
483
484 m_delimitedCodes.append(monomer->code());
485 m_delimitedCodes.append('@');
486 }
487
488 // Close the string with a delim char:
489 m_delimitedCodes.append('@');
490
491 return true;
492 }
493
494
495 /*!
496 \brief Returns a string with the codes of all the \l{Monomer}s in this
497 PolChemDef instance.
498
499 The codes are delimited by the '@' character.
500 */
501 const QString &
502 PolChemDef::delimitedCodes()
503 {
504 if(m_delimitedCodes.isEmpty())
505 calculateDelimitedCodes();
506
507 return m_delimitedCodes;
508 }
509
510
511 /*!
512 \brief Sets the ionization rule to \a ionize_rule.
513 */
514 void
515 PolChemDef::setIonizeRule(const IonizeRule &ionize_rule)
516 {
517 m_ionizeRule = ionize_rule;
518 }
519
520
521 /*!
522 \brief Returns a const reference to the ionization rule.
523 */
524 const IonizeRule &
525 4 PolChemDef::ionizeRule() const
526 {
527 4 return m_ionizeRule;
528 }
529
530 /*!
531 \brief Returns a pointer to the ionization rule.
532 */
533 IonizeRule *
534 PolChemDef::ionizeRulePtr()
535 {
536 return &m_ionizeRule;
537 }
538
539 /*!
540 \brief Sets the isotopic data to \a isotopic_data_sp.
541 */
542 void
543 PolChemDef::setIsotopicDataSPtr(IsotopicDataSPtr isotopic_data_sp)
544 {
545 msp_isotopicData = isotopic_data_sp;
546 }
547
548 /*!
549 \brief Returns the isotopic data as const shared pointer..
550 */
551 IsotopicDataCstSPtr
552 44968 PolChemDef::getIsotopicDataCstSPtr() const
553 {
554 44968 return msp_isotopicData;
555 }
556
557 /*!
558 \brief Returns the isotopic data as non-const shared pointer..
559 */
560 IsotopicDataSPtr
561 424 PolChemDef::getIsotopicDataSPtr()
562 {
563 424 return msp_isotopicData;
564 }
565
566
567 /*!
568 \brief Returns a const reference to the list of monomers.
569 */
570 const QList<Monomer *> &
571 19964 PolChemDef::monomerList() const
572 {
573 19964 return m_monomerList;
574 }
575
576 /*!
577 \brief Returns a pointer to the list of monomers.
578 */
579 QList<Monomer *> *
580 PolChemDef::monomerListPtr()
581 {
582 return &m_monomerList;
583 }
584
585 /*!
586 \brief Returns a const reference to the list of modifications.
587 */
588 const QList<Modif *> &
589 3216 PolChemDef::modifList() const
590 {
591 3216 return m_modifList;
592 }
593
594 /*!
595 \brief Returns a pointer to the list of modifications.
596 */
597 QList<Modif *> *
598 PolChemDef::modifListPtr()
599 {
600 return &m_modifList;
601 }
602
603 /*!
604 \brief Searches in the member list of modifications a modification by \a name.
605
606 If the modification object is found, and \a modification_p is non-nullptr, it
607 is copied in \a modification_p.
608
609 Returns true if the modification was found, false otherwise.
610 */
611 bool
612 12420 PolChemDef::referenceModifByName(const QString &name, Modif *modif_p) const
613 {
614
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12420 times.
12420 if(name.isEmpty())
615 return false;
616
617
2/2
✓ Branch 1 taken 160768 times.
✓ Branch 2 taken 10436 times.
171204 for(int iter = 0; iter < m_modifList.size(); ++iter)
618 {
619 160768 Modif *iter_modif = m_modifList.at(iter);
620
621
3/4
✓ Branch 1 taken 160768 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1984 times.
✓ Branch 6 taken 158784 times.
160768 if(iter_modif->name() == name)
622 {
623
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1960 times.
1984 if(modif_p)
624 {
625 24 *modif_p = *iter_modif;
626
627 24 return true;
628 }
629
630 1960 return true;
631 }
632 }
633
634 10436 return false;
635 }
636
637
638 /*!
639 \brief Searches in the member list of modifications a modification by \a
640 name.
641
642 If the modification object is found it is copied in \a modif.
643
644 Returns true if the modification was found, false otherwise.
645 */
646 bool
647 PolChemDef::referenceModifByName(const QString &name, Modif &modif) const
648 {
649 if(name.isEmpty())
650 return false;
651
652 for(int iter = 0; iter < m_modifList.size(); ++iter)
653 {
654 Modif *iter_modif = m_modifList.at(iter);
655
656 if(iter_modif->name() == name)
657 {
658 modif = *iter_modif;
659
660 return true;
661 }
662 }
663
664 return false;
665 }
666
667 /*!
668 \brief Returns a const reference to the list of cross-linkers.
669 */
670 const QList<CrossLinker *> &
671 356 PolChemDef::crossLinkerList() const
672 {
673 356 return m_crossLinkerList;
674 }
675
676 /*!
677 \brief Returns a pointer to the list of cross-linkers.
678 */
679 QList<CrossLinker *> *
680 PolChemDef::crossLinkerListPtr()
681 {
682 return &m_crossLinkerList;
683 }
684
685 /*!
686 \brief Returns a const reference to the list of cleavage specifications.
687 */
688 const QList<CleaveSpec *> &
689 348 PolChemDef::cleaveSpecList() const
690 {
691 348 return m_cleaveSpecList;
692 }
693
694 /*!
695 \brief Returns a pointer to the list of cleavage specifications.
696 */
697 QList<CleaveSpec *> *
698 PolChemDef::cleaveSpecListPtr()
699 {
700 return &m_cleaveSpecList;
701 }
702
703 /*!
704 \brief Returns a const reference to the list of fragmentation specifications.
705 */
706 const QList<FragSpec *> &
707 348 PolChemDef::fragSpecList() const
708 {
709 // qDebug() << "Size of the frag spec list:" << m_fragSpecList.size();
710 348 return m_fragSpecList;
711 }
712
713 /*!
714 \brief Returns a pointer to the list of fragmentation specifications.
715 */
716 QList<FragSpec *> *
717 PolChemDef::fragSpecListPtr()
718 {
719 return &m_fragSpecList;
720 }
721
722 /*!
723 \brief Searches in the member list of cross-linkers a cross-linker by \a name.
724
725 If the cross-linker object is found, and \a cross_linker_p is non-nullptr, it
726 is copied in \a cross_linker_p.
727
728 Returns true if the cross-linker was found, false otherwise.
729 */
730 bool
731 PolChemDef::referenceCrossLinkerByName(const QString &name,
732 CrossLinker *cross_linker_p) const
733 {
734 if(name.isEmpty())
735 return false;
736
737 for(int iter = 0; iter < m_crossLinkerList.size(); ++iter)
738 {
739 CrossLinker *localCrossLinker = m_crossLinkerList.at(iter);
740
741 if(localCrossLinker->name() == name)
742 {
743 if(cross_linker_p)
744 {
745 *cross_linker_p = *localCrossLinker;
746
747 return true;
748 }
749
750 return true;
751 }
752 }
753
754 return false;
755 }
756
757
758 /*!
759 \brief Returns a const reference to the list of monomer specifications.
760 */
761 QList<MonomerSpec *> &
762 PolChemDef::monomerSpecList() const
763 {
764 return m_monomerSpecList;
765 }
766
767 /*!
768 \brief Returns a pointer to the list of monomer specifications.
769 */
770 QList<MonomerSpec *> *
771 PolChemDef::monomerSpecListPtr()
772 {
773 return &m_monomerSpecList;
774 }
775
776 /*!
777 \brief Returns a const reference to the list of modification specifications.
778 */
779 QList<ModifSpec *> &
780 PolChemDef::modifSpecList() const
781 {
782 return m_modifSpecList;
783 }
784
785 /*!
786 \brief Returns a pointer to the list of modification specifications.
787 */
788 QList<ModifSpec *> *
789 PolChemDef::modifSpecListPtr()
790 {
791 return &m_modifSpecList;
792 }
793
794 /*!
795 \brief Returns a const reference to the list of cross-linker specifications.
796 */
797 QList<CrossLinkerSpec *> &
798 PolChemDef::crossLinkerSpecList() const
799 {
800 return m_crossLinkerSpecList;
801 }
802
803 /*!
804 \brief Returns a pointer to the list of cross-linker specifications.
805 */
806 QList<CrossLinkerSpec *> *
807 PolChemDef::crossLinkerSpecListPtr()
808 {
809 return &m_crossLinkerSpecList;
810 }
811
812 bool
813 PolChemDef::operator==(const PolChemDef &other) const
814 {
815 if(&other == this)
816 return true;
817
818 if(m_name != other.m_name)
819 return false;
820
821 if(m_xmlDataFilePath != other.m_xmlDataFilePath)
822 return false;
823
824 if(m_isotopicDataFilePath != other.m_isotopicDataFilePath)
825 return false;
826
827 if(m_leftCap != other.m_leftCap)
828 return false;
829
830 if(m_rightCap != other.m_rightCap)
831 return false;
832
833 if(m_codeLength != other.m_codeLength)
834 return false;
835
836 if(m_delimitedCodes != other.m_delimitedCodes)
837 return false;
838
839 if(m_ionizeRule != other.m_ionizeRule)
840 return false;
841
842 if(msp_isotopicData != nullptr && other.msp_isotopicData != nullptr)
843 {
844 if(*msp_isotopicData.get() == *other.msp_isotopicData.get())
845 return false;
846 }
847
848 if(m_monomerList.size() != other.m_monomerList.size())
849 return false;
850
851 for(int iter = 0; iter < m_monomerList.size(); ++iter)
852 {
853 if(*m_monomerList.at(iter) != *other.m_monomerList.at(iter))
854 return false;
855 }
856
857 if(m_modifList.size() != other.m_modifList.size())
858 return false;
859
860 for(int iter = 0; iter < m_modifList.size(); ++iter)
861 {
862 if(*m_modifList.at(iter) != *other.m_modifList.at(iter))
863 return false;
864 }
865
866 if(m_crossLinkerList.size() != other.m_crossLinkerList.size())
867 return false;
868
869 for(int iter = 0; iter < m_crossLinkerList.size(); ++iter)
870 {
871 if(*m_crossLinkerList.at(iter) != *other.m_crossLinkerList.at(iter))
872 return false;
873 }
874
875 if(m_cleaveSpecList.size() != other.m_cleaveSpecList.size())
876 return false;
877
878 for(int iter = 0; iter < m_cleaveSpecList.size(); ++iter)
879 {
880 if(*m_cleaveSpecList.at(iter) != *other.m_cleaveSpecList.at(iter))
881 return false;
882 }
883
884 if(m_fragSpecList.size() != other.m_fragSpecList.size())
885 return false;
886
887 for(int iter = 0; iter < m_fragSpecList.size(); ++iter)
888 {
889 if(*m_fragSpecList.at(iter) != *other.m_fragSpecList.at(iter))
890 return false;
891 }
892
893 return true;
894 }
895
896 /*!
897 \brief Returns true if \c this and \a other differ.
898
899 Returns the negated result of operator==().
900 */
901 bool
902 PolChemDef::operator!=(const PolChemDef &other) const
903 {
904 if(&other == this)
905 return false;
906
907 return !operator==(other);
908 }
909
910 /*!
911 \brief Parses the polymer chemistry definition file and updates \a
912 pol_chem_def_sp accordingly.
913
914 Upon parsing of the file and validation of the data, the \a
915 pol_chem_def_sp is updated, essentially initializing it with the data from
916 the file.
917
918 Note that the \a pol_chem_def_sp should have a working set of isotopic
919 data.
920
921 Returns true if the parsing was successful and false otherwise.
922 */
923 bool
924 392 PolChemDef::renderXmlPolChemDefFile(PolChemDefSPtr pol_chem_def_sp)
925 {
926
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 392 times.
✗ Branch 5 not taken.
392 Q_ASSERT(pol_chem_def_sp != nullptr && pol_chem_def_sp.get() != nullptr);
927
928 // qDebug() << "The PolChemDef *:" << pol_chem_def_sp.get()
929 //<< "and usage:" << pol_chem_def_sp.use_count();
930
931 ///////////////////// ATTENTION ///////////////////
932 // Before reading the polymer chemistry data file, we need to make sure
933 // we actually have read the isotopic data!
934
935 // qDebug() << "First check if we have isotopic data ready.";
936
937
2/6
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 392 times.
392 if(pol_chem_def_sp->getIsotopicDataSPtr() == nullptr)
938 {
939 // qDebug() << "No isotopic data found in the polymer chemistry "
940 // "definition, need to load the data.";
941
942 // First read the data!
943 std::size_t count = pol_chem_def_sp->loadIsotopicData(pol_chem_def_sp);
944
945 if(!count)
946 qFatal("Programming error. The isotopic data could not be loaded.");
947
948 // qDebug() << "At this point the isotopic data were loaded fine
949 // with"
950 //<< count << "isotopes loaded.";
951 }
952
953
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 392 times.
✗ Branch 5 not taken.
392 QDomDocument doc("polChemDefData");
954
1/2
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
392 QDomElement element;
955
1/2
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
392 QDomElement child;
956
1/2
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
392 QDomElement indentedChild;
957
958
1/2
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
392 QFile file(pol_chem_def_sp->m_xmlDataFilePath);
959
960 // qDebug() << "The polymer chemistry definition file:"
961 // << pol_chem_def_sp->m_xmlDataFilePath;
962
963 392 Monomer *monomer = 0;
964 392 Modif *modif = 0;
965 392 CrossLinker *crossLinker = 0;
966 392 CleaveSpec *cleaveSpec = 0;
967 392 FragSpec *fragSpec = 0;
968
969
970 // The general structure of the file we are reading is this:
971 //
972 // <polchemdefinition version="1">
973 // <polchemdefdata">
974 // <name>protein</name>
975 // <leftcap>+H</leftcap>
976 // <rightcap>+OH</rightcap>
977 // <codelen>1</codelen>
978 // <ionizerule>
979 // <formula>+H</formula>
980 // <charge>1</charge>
981 // <level>1</level>
982 // </ionizerule>
983 // <monomers>
984 // <mnm>
985 // <name>Glycine</name>
986 // <code>G</code>
987 // <formula>C2H3NO</formula>
988 // </mnm>
989 // </monomers>
990 // <modifs>
991 // <mdf>
992 // <name>Phosphorylation</name>
993 // <formula>-H+H2PO3</formula>
994 // </mdf>
995 // </modifs>
996 // <cleavespecs>
997 // <cls>
998 // <name>CyanogenBromide</name>
999 // <pattern>M/</pattern>
1000 // <clr>
1001 // <re-mnm-code>M</re-mnm-code>
1002 // <re-formula>-CH2S+O</re-formula>
1003 // </clr>
1004 // </cls>
1005 // </cleavespecs>
1006 // <fragspecs>
1007 // <fgs>
1008 // <name>a</name>
1009 // <end>LE</end>
1010 // <formula>-C1O1</formula>
1011 // <fgr>
1012 // <name>a-fgr-1</name>
1013 // <formula>+H200</formula>
1014 // <prev-mnm-code>E</prev-mnm-code>
1015 // <this-mnm-code>D</this-mnm-code>
1016 // <next-mnm-code>F</next-mnm-code>
1017 // <comment>comment here!</comment>
1018 // </fgr>
1019 // </fgs>
1020 // </fragspecs>
1021 // </polchemdefdata>
1022 // </polchemdefinition>
1023
1024
1025
2/4
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 392 times.
392 if(!file.open(QIODevice::ReadOnly))
1026 return false;
1027
1028
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(!doc.setContent(&file))
1029 {
1030 qDebug() << "Failed to set doc content.";
1031
1032 file.close();
1033 return false;
1034 }
1035
1036
1/2
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
392 file.close();
1037
1038 // qDebug() << "Closed the polymer chemistry definition file.";
1039
1040
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 392 times.
✗ Branch 5 not taken.
392 element = doc.documentElement();
1041
1042
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(element.tagName() != "polchemdefinition")
1043 {
1044 qDebug() << "Polymer chemistry definition file is erroneous\n";
1045 return false;
1046 }
1047
1048 ///////////////////////////////////////////////
1049 // Check the version of the document.
1050
1051 392 QString text;
1052
1053
3/6
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 392 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 392 times.
392 if(!element.hasAttribute("version"))
1054 text = "1";
1055 else
1056
2/4
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 392 times.
✗ Branch 6 not taken.
392 text = element.attribute("version");
1057
1058 // qDebug() << "The format of the definition:" << text;
1059
1060 392 bool ok = false;
1061
1062
1/2
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
392 int version = text.toInt(&ok, 10);
1063
1064
2/4
✓ Branch 0 taken 392 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 392 times.
392 if(version < 1 || !ok)
1065 {
1066 qDebug() << "Polymer chemistry definition file has bad "
1067 "version number:"
1068 << version;
1069
1070 return false;
1071 }
1072
1073 //////////////////////////////////////////////
1074 // <polymer chemistry data>
1075
1076
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = element.firstChildElement();
1077
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "polchemdefdata")
1078 {
1079 qDebug() << "Polymer chemistry definition file is erroneous\n";
1080 return false;
1081 }
1082
1083 // <name>
1084
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.firstChildElement();
1085
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "name")
1086 return false;
1087
1/2
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
392 pol_chem_def_sp->m_name = child.text();
1088
1089 // <leftcap>
1090
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.nextSiblingElement();
1091
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "leftcap")
1092 return false;
1093
2/4
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 392 times.
✗ Branch 6 not taken.
392 pol_chem_def_sp->m_leftCap.setFormula(child.text());
1094
1095 // <rightcap>
1096
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.nextSiblingElement();
1097
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "rightcap")
1098 return false;
1099
2/4
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 392 times.
✗ Branch 6 not taken.
392 pol_chem_def_sp->m_rightCap.setFormula(child.text());
1100
1101 // <codelen>
1102
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.nextSiblingElement();
1103
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "codelen")
1104 return false;
1105 392 ok = false;
1106
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 392 times.
✗ Branch 5 not taken.
392 pol_chem_def_sp->m_codeLength = child.text().toInt(&ok);
1107
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(pol_chem_def_sp->m_codeLength == 0 && !ok)
1108 return false;
1109
1110 // <ionizerule>
1111
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.nextSiblingElement();
1112
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "ionizerule")
1113 return false;
1114
2/4
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 392 times.
392 if(!pol_chem_def_sp->m_ionizeRule.renderXmlIonizeRuleElement(child))
1115 return false;
1116
1117 // We have to ascertain that the IonizeRule is valid.
1118 IsotopicDataCstSPtr isotopic_data_csp =
1119
1/2
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
392 pol_chem_def_sp->getIsotopicDataCstSPtr();
1120
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 392 times.
392 if(!pol_chem_def_sp->m_ionizeRule.IonizeRule::validate(isotopic_data_csp))
1121 return false;
1122
1123 // <monomers>
1124
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.nextSiblingElement();
1125
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "monomers")
1126 return false;
1127
1128
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 indentedChild = child.firstChildElement();
1129
3/4
✓ Branch 1 taken 8624 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8232 times.
✓ Branch 4 taken 392 times.
8624 while(!indentedChild.isNull())
1130 {
1131 // qDebug() << "Now rendering one of all the mnm elements.";
1132
1133
2/4
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 8232 times.
8232 if(indentedChild.tagName() != "mnm")
1134 return false;
1135
1136
3/8
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 8232 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 8232 times.
✗ Branch 11 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
8232 monomer = new Monomer(pol_chem_def_sp, "NOT_SET");
1137
1138
2/4
✓ Branch 1 taken 8232 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8232 times.
8232 if(!monomer->renderXmlMnmElement(indentedChild, version))
1139 {
1140 qDebug() << "Failed to render mnm element.";
1141
1142 delete monomer;
1143 return false;
1144 }
1145
1146
1/2
✓ Branch 2 taken 8232 times.
✗ Branch 3 not taken.
8232 pol_chem_def_sp->m_monomerList.append(monomer);
1147
1148
2/4
✓ Branch 3 taken 8232 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8232 times.
✗ Branch 7 not taken.
8232 indentedChild = indentedChild.nextSiblingElement();
1149 }
1150
1151 // qDebug() << "Size of MonomerList:" <<
1152 // pol_chem_def_sp->m_monomerList.size()
1153 //<< "pol chem def usage:" << pol_chem_def_sp.use_count();
1154
1155 // <modifs>
1156
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.nextSiblingElement();
1157
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "modifs")
1158 return false;
1159
1160
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 indentedChild = child.firstChildElement();
1161
3/4
✓ Branch 1 taken 10584 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10192 times.
✓ Branch 4 taken 392 times.
10584 while(!indentedChild.isNull())
1162 {
1163
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 10192 times.
10192 if(indentedChild.tagName() != "mdf")
1164 return false;
1165
1166
3/8
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 10192 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 10192 times.
✗ Branch 10 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
10192 modif = new Modif(pol_chem_def_sp, "NOT_SET");
1167
1168
2/4
✓ Branch 1 taken 10192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10192 times.
10192 if(!modif->renderXmlMdfElement(indentedChild, version))
1169 {
1170 delete modif;
1171 return false;
1172 }
1173
1174
1/2
✓ Branch 2 taken 10192 times.
✗ Branch 3 not taken.
10192 pol_chem_def_sp->m_modifList.append(modif);
1175
1176
2/4
✓ Branch 3 taken 10192 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 10192 times.
✗ Branch 7 not taken.
10192 indentedChild = indentedChild.nextSiblingElement();
1177 }
1178
1179 // qDebug() << "Size of ModifList:" <<
1180 // pol_chem_def_sp->m_modifList.size()
1181 //<< "pol chem def usage:" << pol_chem_def_sp.use_count();
1182
1183 // <crosslinkers>
1184
1185 // Note that crosslinkers have appeared since version 3.
1186
1187
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.nextSiblingElement();
1188
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "crosslinkers")
1189 return false;
1190
1191
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 indentedChild = child.firstChildElement();
1192
3/4
✓ Branch 1 taken 1176 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 784 times.
✓ Branch 4 taken 392 times.
1176 while(!indentedChild.isNull())
1193 {
1194
2/4
✓ Branch 1 taken 784 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 784 times.
784 if(indentedChild.tagName() != "clk")
1195 return false;
1196
1197 // We set the formula to nothing below because that formula might be
1198 // empty in the polymer chemistry definition.
1199
4/10
✓ Branch 1 taken 784 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 784 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 784 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 784 times.
✗ Branch 12 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
784 crossLinker = new CrossLinker(pol_chem_def_sp, "NOT_SET", "");
1200
1201
2/4
✓ Branch 1 taken 784 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 784 times.
784 if(!crossLinker->renderXmlClkElement(indentedChild, version))
1202 {
1203 delete crossLinker;
1204 return false;
1205 }
1206
1207 // qDebug() << "Rendered CrossLinker: " << crossLinker->name()
1208 //<< "with masses:" << crossLinker->mono() << "/"
1209 //<< crossLinker->avg();
1210
1211
1/2
✓ Branch 2 taken 784 times.
✗ Branch 3 not taken.
784 pol_chem_def_sp->m_crossLinkerList.append(crossLinker);
1212
1213
2/4
✓ Branch 3 taken 784 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 784 times.
✗ Branch 7 not taken.
784 indentedChild = indentedChild.nextSiblingElement();
1214 }
1215
1216 // qDebug() << "Size of CrossLinkerList:"
1217 //<< pol_chem_def_sp->m_crossLinkerList.size()
1218 //<< "pol chem def usage:" << pol_chem_def_sp.use_count();
1219
1220 // <cleavespecs>
1221
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.nextSiblingElement();
1222
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "cleavespecs")
1223 return false;
1224
1225
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 indentedChild = child.firstChildElement();
1226
3/4
✓ Branch 1 taken 3528 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3136 times.
✓ Branch 4 taken 392 times.
3528 while(!indentedChild.isNull())
1227 {
1228
2/4
✓ Branch 1 taken 3136 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3136 times.
3136 if(indentedChild.tagName() != "cls")
1229 return false;
1230
1231
3/8
✓ Branch 1 taken 3136 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3136 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 3136 times.
✗ Branch 10 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
3136 cleaveSpec = new CleaveSpec(pol_chem_def_sp, "NOT_SET");
1232
1233
2/4
✓ Branch 1 taken 3136 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3136 times.
3136 if(!cleaveSpec->renderXmlClsElement(indentedChild, version))
1234 {
1235 delete cleaveSpec;
1236 return false;
1237 }
1238
1239
1/2
✓ Branch 2 taken 3136 times.
✗ Branch 3 not taken.
3136 pol_chem_def_sp->m_cleaveSpecList.append(cleaveSpec);
1240
1241
2/4
✓ Branch 3 taken 3136 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3136 times.
✗ Branch 7 not taken.
3136 indentedChild = indentedChild.nextSiblingElement();
1242 }
1243
1244 // qDebug() << "Size of CleaveSpecList:"
1245 //<< pol_chem_def_sp->m_cleaveSpecList.size()
1246 //<< "pol chem def usage:" << pol_chem_def_sp.use_count();
1247
1248 // <fragspecs>
1249
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 child = child.nextSiblingElement();
1250
2/4
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 392 times.
392 if(child.tagName() != "fragspecs")
1251 return false;
1252
1253
2/4
✓ Branch 3 taken 392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 392 times.
✗ Branch 7 not taken.
392 indentedChild = child.firstChildElement();
1254
3/4
✓ Branch 1 taken 3136 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2744 times.
✓ Branch 4 taken 392 times.
3136 while(!indentedChild.isNull())
1255 {
1256
2/4
✓ Branch 1 taken 2744 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2744 times.
2744 if(indentedChild.tagName() != "fgs")
1257 return false;
1258
1259
3/8
✓ Branch 1 taken 2744 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 2744 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 2744 times.
✗ Branch 11 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
2744 fragSpec = new FragSpec(pol_chem_def_sp, "NOT_SET");
1260
1261
2/4
✓ Branch 1 taken 2744 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2744 times.
2744 if(!fragSpec->renderXmlFgsElement(indentedChild, version))
1262 {
1263 delete fragSpec;
1264 return false;
1265 }
1266
1267
1/2
✓ Branch 2 taken 2744 times.
✗ Branch 3 not taken.
2744 pol_chem_def_sp->m_fragSpecList.append(fragSpec);
1268
1269
2/4
✓ Branch 3 taken 2744 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2744 times.
✗ Branch 7 not taken.
2744 indentedChild = indentedChild.nextSiblingElement();
1270 }
1271
1272 // qDebug() << "Size of FragSpecList:" <<
1273 // pol_chem_def_sp->m_fragSpecList.size()
1274 // << "pol chem def usage:" << pol_chem_def_sp.use_count();
1275
1276 // qDebug() << "Returning true" << "pol chem def usage:" <<
1277 // pol_chem_def_sp.use_count();
1278
1279 392 return true;
1280 392 }
1281
1282 /*!
1283 \brief Loads the isotopic data stored in the file \a file_path.
1284
1285 The data loaded from file are parsed and validated. Upon parsing of the
1286 file, the data are stored in the \a pol_chem_def_sp instance's isotopic
1287 data member.
1288
1289 If \a file_path is empty, it is reconstructed using the directory of the
1290 polymer chemistry definition and the fact that the isotopic data file name
1291 is "isotopic-data.dat".
1292
1293 Returns the count of parsed isotopes.
1294 */
1295 std::size_t
1296 396 PolChemDef::loadIsotopicData(PolChemDefSPtr pol_chem_def_sp,
1297 const QString &file_path)
1298 {
1299 // There are three situations:
1300 //
1301 // 1. The file_path exists and the data are loaded from there.
1302 //
1303 // 2. A file named isotopic-data.dat is found in the polymer chemistry
1304 // definition directory and it is loaded.
1305 //
1306 // 3. No file named isotopic-data.dat is found in the polymer chemistry
1307 // defintion directory and then data are loaded from the IsoSpec tables.
1308
1309 // If the provided argument is not empty and actually describes an
1310 // existing file, then save the data there.
1311 396 QString local_file_path(file_path);
1312
1/2
✓ Branch 1 taken 396 times.
✗ Branch 2 not taken.
396 QFileInfo local_file_info(local_file_path);
1313
1314
2/8
✗ Branch 1 not taken.
✓ Branch 2 taken 396 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 396 times.
✗ Branch 9 not taken.
396 if(local_file_path.isEmpty() || !local_file_info.exists())
1315 {
1316 // qDebug() << "The provided file name" << file_path << "does not
1317 // exist.";
1318
1319 // Then try the member datum that provides the name of the file from
1320 // which to load the isotopic data.
1321
1/2
✓ Branch 2 taken 396 times.
✗ Branch 3 not taken.
396 local_file_path = pol_chem_def_sp->getIsotopicDataFilePath();
1322
1/2
✓ Branch 1 taken 396 times.
✗ Branch 2 not taken.
396 local_file_info.setFile(local_file_path);
1323
1324
2/8
✗ Branch 1 not taken.
✓ Branch 2 taken 396 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 396 times.
✗ Branch 9 not taken.
396 if(local_file_path.isEmpty() || !local_file_info.exists())
1325 {
1326 // qDebug() << "The member datum file name " << local_file_path
1327 //<< "does not exist.";
1328
1329 // Last resort: deduce the isotopic data file name from the
1330 // directory of the polymer chemistry definition.
1331
1332
1/2
✓ Branch 2 taken 396 times.
✗ Branch 3 not taken.
396 local_file_path = pol_chem_def_sp->deduceIsotopicDataFilePath();
1333
1334 // qDebug() << "Crafted the isotopic-data.dat file path:"
1335 //<< local_file_path;
1336
1337 // Finally for a later last check:
1338
1/2
✓ Branch 1 taken 396 times.
✗ Branch 2 not taken.
396 local_file_info.setFile(local_file_path);
1339 }
1340 }
1341
1342 // qDebug() << "Allocating brand new isotopic data instance.";
1343
1344 // At this point we can delete the pre-exsting isotopic data.
1345
1/2
✓ Branch 1 taken 396 times.
✗ Branch 2 not taken.
396 pol_chem_def_sp->msp_isotopicData = std::make_shared<IsotopicData>();
1346
1347 // Allocate a specific handler to the kind of isotopic data (library
1348 // tables or user file).
1349
1350 396 std::size_t count = 0;
1351
1352
4/8
✓ Branch 1 taken 396 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 396 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 396 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 396 times.
396 if(local_file_path.isEmpty() || !local_file_info.exists())
1353 {
1354 // qDebug() << "Loading the isotopic data from the library.";
1355 IsotopicDataLibraryHandler isotopic_data_handler(
1356 pol_chem_def_sp->msp_isotopicData);
1357
1358 std::size_t non_isotope_skipped_items = 0;
1359 count = isotopic_data_handler.loadData(non_isotope_skipped_items);
1360 }
1361 else
1362 {
1363 // qDebug() << "Loading the isotopic data from file:" <<
1364 // local_file_path;
1365
1366 IsotopicDataUserConfigHandler isotopic_data_handler(
1367
1/2
✓ Branch 4 taken 396 times.
✗ Branch 5 not taken.
396 pol_chem_def_sp->msp_isotopicData);
1368
1369
1/2
✓ Branch 1 taken 396 times.
✗ Branch 2 not taken.
396 count = isotopic_data_handler.loadData(local_file_path);
1370
1371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 396 times.
396 if(!count)
1372 {
1373 qDebug() << "Failed to load any isotopic data.";
1374 return false;
1375 }
1376
1377 // Now set the file path to the pol chem def.
1378
1379
1/2
✓ Branch 2 taken 396 times.
✗ Branch 3 not taken.
396 pol_chem_def_sp->setIsotopicDataFilePath(local_file_path);
1380
1/2
✓ Branch 1 taken 396 times.
✗ Branch 2 not taken.
396 }
1381
1382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 396 times.
396 if(!count)
1383 {
1384 qDebug() << "Failed to load any isotopic data.";
1385 return false;
1386 }
1387
1388 396 return count;
1389 396 }
1390
1391
1392 /*!
1393 \brief Returns a string with the XML DTD for a polymer chemistry
1394 definition file.
1395 */
1396 QString *
1397 4 PolChemDef::formatXmlDtd()
1398 {
1399 QString *string = new QString(
1400 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
1401 "<!-- DTD for polymer definitions, used by the\n"
1402 "'massXpert' mass spectrometry application.\n"
1403 "Copyright 2006,2007,2008 Filippo Rusconi\n"
1404 "Licensed under the GNU GPL -->\n"
1405 "<!DOCTYPE polchemdefinition [\n"
1406 "<!ELEMENT polchemdefinition (polchemdefdata)>\n"
1407 "<!ATTLIST polchemdefinition version NMTOKEN #REQUIRED>\n"
1408 "<!ELEMENT polchemdefdata "
1409 "(name,leftcap,rightcap,codelen,ionizerule,monomers,modifs,"
1410 "crosslinkers,"
1411 "cleavespecs,fragspecs)>\n"
1412 "<!ELEMENT ionizerule (formula,charge,level)>\n"
1413 "<!ELEMENT monomers (mnm*)>\n"
1414 "<!ELEMENT modifs (mdf*)>\n"
1415 "<!ELEMENT crosslinkers (clk*)>\n"
1416 "<!ELEMENT cleavespecs (cls*)>\n"
1417 "<!ELEMENT fragspecs (fgs*)>\n"
1418 "<!ELEMENT mnm (name,code,formula)>\n"
1419 "<!ELEMENT mdf (name,formula,targets,maxcount)>\n"
1420 "<!ELEMENT clk (name,formula,modifname*)>\n"
1421 "<!ELEMENT cls (name,pattern,clr*)>\n"
1422 "<!ELEMENT fgs (name,end,formula,sidechaincontrib,comment?,fgr*)>\n"
1423 "<!ELEMENT clr "
1424 "(name,(le-mnm-code,le-formula)?,(re-mnm-code,re-formula)?)>\n"
1425 "<!ELEMENT fgr "
1426 "(name,formula,prev-mnm-code?,curr-mnm-code?,next-mnm-code?,comment?)"
1427 ">\n"
1428 "<!ELEMENT leftcap (#PCDATA)>\n"
1429 "<!ELEMENT rightcap (#PCDATA)>\n"
1430 "<!ELEMENT codelen (#PCDATA)>\n"
1431 "<!ELEMENT charge (#PCDATA)>\n"
1432 "<!ELEMENT maxcount (#PCDATA)>\n"
1433 "<!ELEMENT level (#PCDATA)>\n"
1434 "<!ELEMENT name (#PCDATA)>\n"
1435 "<!ELEMENT modifname (#PCDATA)>\n"
1436 "<!ELEMENT code (#PCDATA)>\n"
1437 "<!ELEMENT formula (#PCDATA)>\n"
1438 "<!ELEMENT sidechaincontrib (#PCDATA)>\n"
1439 "<!ELEMENT targets (#PCDATA)>\n"
1440 "<!ELEMENT pattern (#PCDATA)>\n"
1441 "<!ELEMENT end (#PCDATA)>\n"
1442 "<!ELEMENT le-mnm-code (#PCDATA)>\n"
1443 "<!ELEMENT re-mnm-code (#PCDATA)>\n"
1444 "<!ELEMENT le-formula (#PCDATA)>\n"
1445 "<!ELEMENT re-formula (#PCDATA)>\n"
1446 "<!ELEMENT comment (#PCDATA)>\n"
1447 "<!ELEMENT prev-mnm-code (#PCDATA)>\n"
1448 "<!ELEMENT curr-mnm-code (#PCDATA)>\n"
1449 "<!ELEMENT next-mnm-code (#PCDATA)>\n"
1450
1/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 "]>\n");
1451
1452 4 return string;
1453 }
1454
1455
1456 /*!
1457 \brief Writes the polymer chemistry definition to file.
1458
1459 The file's name is from m_xmlDataFilePath.
1460
1461 Returns true if successful, false otherwise.
1462 */
1463 bool
1464 4 PolChemDef::writeXmlFile()
1465 {
1466 4 QString *string = 0;
1467
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QString indent(" ");
1468 4 QString lead;
1469
1470 4 int offset = 0;
1471 4 int iter = 0;
1472
1473 // We are asked to send an xml description of the polymer chemistry
1474 // definition.
1475
1476
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QFile file(m_xmlDataFilePath);
1477
1478
2/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4 if(!file.open(QIODevice::WriteOnly))
1479 {
1480 qDebug() << "Failed to open file" << m_xmlDataFilePath << "for writing.";
1481
1482 return false;
1483 }
1484
1485
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QTextStream stream(&file);
1486
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 stream.setEncoding(QStringConverter::Utf8);
1487
1488 // The DTD
1489
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 string = formatXmlDtd();
1490
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 stream << *string;
1491
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 delete string;
1492
1493
1494 // Open the <polchemdefinition> element.
1495
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 stream << QString("<polchemdefinition version=\"%1\">\n")
1496
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 .arg(POL_CHEM_DEF_FILE_FORMAT_VERSION);
1497
1498 // Prepare the lead.
1499 4 ++offset;
1500 4 lead.clear();
1501 4 iter = 0;
1502
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 while(iter < offset)
1503 {
1504
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 lead += indent;
1505 4 ++iter;
1506 }
1507
1508 // Open the <polchemdefdata> element.
1509
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 stream << QString("%1<polchemdefdata>\n").arg(lead);
1510
1511 // Prepare the lead.
1512 4 ++offset;
1513 4 lead.clear();
1514 4 iter = 0;
1515
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 while(iter < offset)
1516 {
1517
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 lead += indent;
1518 8 ++iter;
1519 }
1520
1521
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 stream << QString("%1<name>%2</name>\n").arg(lead).arg(m_name);
1522
1523 stream
1524
5/10
✓ 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.
✓ Branch 13 taken 4 times.
✗ Branch 14 not taken.
12 << QString("%1<leftcap>%2</leftcap>\n").arg(lead).arg(m_leftCap.toString());
1525
1526
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 stream << QString("%1<rightcap>%2</rightcap>\n")
1527
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 .arg(lead)
1528
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(m_rightCap.toString());
1529
1530
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 stream << QString("%1<codelen>%2</codelen>\n").arg(lead).arg(m_codeLength);
1531
1532 // Before writing the ionization rule, set the level to 1. This
1533 // member datum is set to 0 in the constructor.
1534
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 m_ionizeRule.setLevel(1);
1535
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 string = m_ionizeRule.formatXmlIonizeRuleElement(offset);
1536
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 stream << *string;
1537
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 delete string;
1538
1539
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 stream << QString("%1<monomers>\n").arg(lead);
1540
1541 // Prepare the lead.
1542 4 ++offset;
1543 4 lead.clear();
1544 4 iter = 0;
1545
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 while(iter < offset)
1546 {
1547
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 lead += indent;
1548 12 ++iter;
1549 }
1550
1551
2/2
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 4 times.
88 for(iter = 0; iter < m_monomerList.size(); ++iter)
1552 {
1553
2/4
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 84 times.
✗ Branch 6 not taken.
84 QString *newString = m_monomerList.at(iter)->formatXmlMnmElement(offset);
1554
1555
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 stream << *newString;
1556
1557
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 delete newString;
1558 }
1559
1560 // Prepare the lead.
1561 4 --offset;
1562 4 lead.clear();
1563 4 iter = 0;
1564
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 while(iter < offset)
1565 {
1566
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 lead += indent;
1567 8 ++iter;
1568 }
1569
1570
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 stream << QString("%1</monomers>\n").arg(lead);
1571
1572
1573
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 stream << QString("%1<modifs>\n").arg(lead);
1574
1575 // Prepare the lead.
1576 4 ++offset;
1577 4 lead.clear();
1578 4 iter = 0;
1579
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 while(iter < offset)
1580 {
1581
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 lead += indent;
1582 12 ++iter;
1583 }
1584
1585
2/2
✓ Branch 1 taken 104 times.
✓ Branch 2 taken 4 times.
108 for(iter = 0; iter < m_modifList.size(); ++iter)
1586 {
1587
2/4
✓ Branch 2 taken 104 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 104 times.
✗ Branch 6 not taken.
104 QString *newString = m_modifList.at(iter)->formatXmlMdfElement(offset);
1588
1589
1/2
✓ Branch 1 taken 104 times.
✗ Branch 2 not taken.
104 stream << *newString;
1590
1591
1/2
✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
104 delete newString;
1592 }
1593
1594 // Prepare the lead.
1595 4 --offset;
1596 4 lead.clear();
1597 4 iter = 0;
1598
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 while(iter < offset)
1599 {
1600
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 lead += indent;
1601 8 ++iter;
1602 }
1603
1604
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 stream << QString("%1</modifs>\n").arg(lead);
1605
1606
1607
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 stream << QString("%1<crosslinkers>\n").arg(lead);
1608
1609 // Prepare the lead.
1610 4 ++offset;
1611 4 lead.clear();
1612 4 iter = 0;
1613
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 while(iter < offset)
1614 {
1615
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 lead += indent;
1616 12 ++iter;
1617 }
1618
1619
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 4 times.
12 for(iter = 0; iter < m_crossLinkerList.size(); ++iter)
1620 {
1621 QString *newString =
1622
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 m_crossLinkerList.at(iter)->formatXmlClkElement(offset);
1623
1624
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 stream << *newString;
1625
1626
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 delete newString;
1627 }
1628
1629 // Prepare the lead.
1630 4 --offset;
1631 4 lead.clear();
1632 4 iter = 0;
1633
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 while(iter < offset)
1634 {
1635
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 lead += indent;
1636 8 ++iter;
1637 }
1638
1639
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 stream << QString("%1</crosslinkers>\n").arg(lead);
1640
1641
1642
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 stream << QString("%1<cleavespecs>\n").arg(lead);
1643
1644 // Prepare the lead.
1645 4 ++offset;
1646 4 lead.clear();
1647 4 iter = 0;
1648
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 while(iter < offset)
1649 {
1650
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 lead += indent;
1651 12 ++iter;
1652 }
1653
1654
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 4 times.
36 for(int iter = 0; iter < m_cleaveSpecList.size(); ++iter)
1655 {
1656 QString *newString =
1657
2/4
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
32 m_cleaveSpecList.at(iter)->formatXmlClsElement(offset);
1658
1659
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 stream << *newString;
1660
1661
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 delete newString;
1662 }
1663
1664 // Prepare the lead.
1665 4 --offset;
1666 4 lead.clear();
1667 4 iter = 0;
1668
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 while(iter < offset)
1669 {
1670
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 lead += indent;
1671 8 ++iter;
1672 }
1673
1674
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 stream << QString("%1</cleavespecs>\n").arg(lead);
1675
1676
1677
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 stream << QString("%1<fragspecs>\n").arg(lead);
1678
1679
1680 // Prepare the lead.
1681 4 ++offset;
1682 4 lead.clear();
1683 4 iter = 0;
1684
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 while(iter < offset)
1685 {
1686
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 lead += indent;
1687 12 ++iter;
1688 }
1689
1690
2/2
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 4 times.
32 for(int iter = 0; iter < m_fragSpecList.size(); ++iter)
1691 {
1692
2/4
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
28 QString *newString = m_fragSpecList.at(iter)->formatXmlFgsElement(offset);
1693
1694
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 stream << *newString;
1695
1696
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 delete newString;
1697 }
1698
1699 // Prepare the lead.
1700 4 --offset;
1701 4 lead.clear();
1702 4 iter = 0;
1703
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 while(iter < offset)
1704 {
1705
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 lead += indent;
1706 8 ++iter;
1707 }
1708
1709
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 stream << QString("%1</fragspecs>\n").arg(lead);
1710
1711 // Prepare the lead.
1712 4 --offset;
1713 4 lead.clear();
1714 4 iter = 0;
1715
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 while(iter < offset)
1716 {
1717
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 lead += indent;
1718 4 ++iter;
1719 }
1720
1721
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 stream << QString("%1</polchemdefdata>\n").arg(lead);
1722
1723 // Prepare the lead.
1724 4 --offset;
1725 4 lead.clear();
1726 4 iter = 0;
1727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 while(iter < offset)
1728 {
1729 lead += indent;
1730 ++iter;
1731 }
1732
1733
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 stream << QString("%1</polchemdefinition>\n").arg(lead);
1734
1735
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 file.close();
1736
1737 4 return true;
1738 4 }
1739
1740 /*!
1741 \brief Writes the isotopic data in the \a pol_chem_def_sp PolChemDef
1742 instance to file \a file_path.
1743
1744 Returns the count of isotopes written to file.
1745 */
1746 std::size_t
1747 PolChemDef::writeIsotopicData(PolChemDefSPtr pol_chem_def_sp,
1748 const QString &file_path)
1749 {
1750 // There are three situations:
1751 //
1752 // 1. The file_path is not empty and the data are saved there.
1753 //
1754 // 2. The file_path is empty and the data are stored in the member file
1755 // path name (if not empty).
1756 //
1757 // 3. The file path is crafted from the directory of the polymer
1758 // chemistry definition.
1759
1760
1761 // Whatever the situation, the isotopic data handler we need here is
1762 // this one:
1763 IsotopicDataUserConfigHandler isotopic_data_handler(
1764 pol_chem_def_sp->msp_isotopicData);
1765
1766 // We'll instantiate the proper isotopic data handler depending on the
1767 // situation.
1768
1769 if(!file_path.isEmpty())
1770 {
1771 // We have a file name, store in there.
1772 pol_chem_def_sp->setIsotopicDataFilePath(file_path);
1773 return isotopic_data_handler.writeData(file_path);
1774 }
1775
1776 // Check the member datum.
1777
1778 if(!pol_chem_def_sp->m_isotopicDataFilePath.isEmpty())
1779 {
1780 // We have a file name, store in there.
1781 return isotopic_data_handler.writeData(
1782 pol_chem_def_sp->m_isotopicDataFilePath);
1783 }
1784
1785 // Last resort: deduce the isotopic data file name from the directory
1786 // of the polymer chemistry definition.
1787
1788 QString local_file_path = pol_chem_def_sp->getXmlDataDirPath();
1789 QFileInfo local_file_info(local_file_path);
1790
1791 if(!local_file_info.exists())
1792 qFatal(
1793 "Programming error. At this stage the name of the polymer "
1794 "chemistry definition file should be known.");
1795
1796 QDir dir(local_file_info.dir());
1797
1798 local_file_path =
1799 dir.absolutePath() + QDir::separator() + "isotopic-data.dat";
1800
1801 pol_chem_def_sp->setIsotopicDataFilePath(local_file_path);
1802
1803 return isotopic_data_handler.writeData(local_file_path);
1804 }
1805
1806 /*!
1807 \brief Returns a string list with the mass difference between all the
1808 \l{Monomer}s in this PolChemDef instace.
1809
1810 If the difference is below the \a threshold, the difference is added to
1811 the string list, otherwise it is skipped. The masses that are compared
1812 between every two monomers is of \a mass_type.
1813 */
1814 QStringList *
1815 PolChemDef::differenceBetweenMonomers(double threshold, MassType mass_type)
1816 {
1817 // qDebug()
1818 // << "threshold" << threshold;
1819
1820 QStringList *list = new QStringList();
1821 ;
1822
1823 // We iterate in the list of monomers and compute a difference of
1824 // mass for each monomer with respect to all the other ones. If
1825 // the mass difference is less or equal to the threshold, then the
1826 // pair is returned.
1827
1828 for(int iter = 0; iter < m_monomerList.size(); ++iter)
1829 {
1830 Monomer *monomer1 = m_monomerList.at(iter);
1831
1832 monomer1->calculateMasses();
1833
1834 for(int jter = 0; jter < m_monomerList.size(); ++jter)
1835 {
1836 // We are not going to explain that the same monomer has the
1837 // same mass !
1838 if(iter == jter)
1839 continue;
1840
1841 Monomer *monomer2 = m_monomerList.at(jter);
1842
1843 monomer2->calculateMasses();
1844
1845 // At this point we have the masses for both monomers.
1846
1847 if(mass_type != MassType::MASS_MONO &&
1848 mass_type != MassType::MASS_AVG)
1849 {
1850 qDebug() << "Please set the mass type "
1851 "to either MassType::MASS_MONO or "
1852 "MassType::MASS_AVG";
1853
1854 return list;
1855 }
1856
1857 double diff = 0;
1858
1859 if(mass_type == MassType::MASS_MONO)
1860 {
1861 diff = monomer2->mass(MassType::MASS_MONO) -
1862 monomer1->mass(MassType::MASS_MONO);
1863 }
1864 else
1865 //(monoOrAvg == MassType::MASS_AVG)
1866 {
1867 diff = monomer2->mass(MassType::MASS_AVG) -
1868 monomer1->mass(MassType::MASS_AVG);
1869 }
1870
1871 // At this point, make sure that diff is within the
1872 // threshold. Note that to avoid duplicates, we remove all
1873 // values that are negative.
1874
1875 if(diff >= 0 && diff <= threshold)
1876 {
1877 QString line = QString("%1 - %2 = %3")
1878 .arg(monomer2->name())
1879 .arg(monomer1->name())
1880 .arg(diff);
1881
1882 list->append(line);
1883 }
1884 }
1885 // End of
1886 // for (int jter = 0; jter < m_monomerList.size(); ++jter)
1887 }
1888 // End of
1889 // for (int iter = 0; iter < m_monomerList.size(); ++iter)
1890
1891 // Only return a list if it contains at least one item.
1892
1893 if(!list->size())
1894 {
1895 delete list;
1896 list = 0;
1897 }
1898
1899 return list;
1900 }
1901
1902 } // namespace libXpertMass
1903
1904 } // namespace MsXpS
1905