1 /* massXpert - the true massist's program.
2    --------------------------------------
3    Copyright(C) 2006,2007 Filippo Rusconi
4 
5    http://www.massxpert.org/massXpert
6 
7    This file is part of the massXpert project.
8 
9    The massxpert project is the successor to the "GNU polyxmass"
10    project that is an official GNU project package(see
11    www.gnu.org). The massXpert project is not endorsed by the GNU
12    project, although it is released ---in its entirety--- under the
13    GNU General Public License. A huge part of the code in massXpert
14    is actually a C++ rewrite of code in GNU polyxmass. As such
15    massXpert was started at the Centre National de la Recherche
16    Scientifique(FRANCE), that granted me the formal authorization to
17    publish it under this Free Software License.
18 
19    This software is free software; you can redistribute it and/or
20    modify it under the terms of the GNU  General Public
21    License version 3, as published by the Free Software Foundation.
22 
23 
24    This software is distributed in the hope that it will be useful,
25    but WITHOUT ANY WARRANTY; without even the implied warranty of
26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27    General Public License for more details.
28 
29    You should have received a copy of the GNU General Public License
30    along with this software; if not, write to the
31 
32    Free Software Foundation, Inc.,
33 
34    51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
35 */
36 
37 
38 /////////////////////// Qt includes
39 #include<QMessageBox>
40 #include<QFileDialog>
41 
42 /////////////////////// Local includes
43 #include "massSearchDlg.hpp"
44 #include "application.hpp"
45 
46 
47 namespace massXpert
48 {
49 
MassSearchDlg(QWidget * parent,Polymer * polymer,const CalcOptions & calcOptions,IonizeRule * ionizeRule)50   MassSearchDlg::MassSearchDlg(QWidget *parent,
51                                Polymer *polymer,
52                                const CalcOptions &calcOptions,
53                                IonizeRule *ionizeRule)
54     : QDialog(parent),
55       mp_polymer(polymer),
56       m_calcOptions(calcOptions),
57       mp_ionizeRule(ionizeRule)
58   {
59     Q_ASSERT(parent);
60     Q_ASSERT(mp_polymer && mp_ionizeRule);
61 
62     m_ui.setupUi(this);
63 
64     mp_editorWnd = static_cast<SequenceEditorWnd *>(parent);
65 
66     m_ui.delimiterLineEdit->setText("$");
67 
68     // Set the current whole/selected sequence data in the
69     // m_calcOptions instance and in the corresponding widgets (true =
70     // read from sequence editor window).
71     updateSelectionData(true);
72 
73     m_monoTolerance = 0;
74     m_avgTolerance = 0;
75 
76     m_ionizeStart = 0;
77     m_ionizeEnd  = 0;
78 
79     m_currentMass = 0;
80     m_foundOligosCount = 0;
81 
82     m_abort = false;
83     m_sequenceEmbedded = false;
84 
85     populateToleranceTypeComboBoxes();
86 
87     setupTableViews();
88 
89     m_ui.ionizationStartSpinBox->setRange(-1000000000, 1000000000);
90     m_ui.ionizationStartSpinBox->setValue(1);
91 
92     m_ui.ionizationEndSpinBox->setRange(-1000000000, 1000000000);
93     m_ui.ionizationEndSpinBox->setValue(1);
94 
95     m_ui.massSearchProgressBar->setRange(0, 100);
96     m_ui.massSearchProgressBar->setValue(0);
97 
98     m_ui.avgToleranceComboBox->setToolTip(tr("AMU: atom mass unit \n"
99                                              "PCT: percent \n"
100                                              "PPM: part per million"));
101     m_ui.monoToleranceComboBox->setToolTip(tr("AMU: atom mass unit \n"
102                                               "PCT: percent \n"
103                                               "PPM: part per million"));
104 
105     m_ui.monoMassLineEdit->setText("1");
106     m_ui.avgMassLineEdit->setText("1");
107 
108 
109     // The tolerance when filtering mono/avg masses...
110     QStringList stringList;
111 
112     stringList << tr("AMU") << tr("PCT") << tr("PPM");
113 
114     m_ui.monoFilterToleranceComboBox->insertItems(0, stringList);
115 
116     m_ui.monoFilterToleranceComboBox->setToolTip(tr("AMU: atom mass unit \n"
117                                                     "PCT: percent \n"
118                                                     "PPM: part per million"));
119 
120     m_ui.avgFilterToleranceComboBox->insertItems(0, stringList);
121 
122     m_ui.avgFilterToleranceComboBox->setToolTip(tr("AMU: atom mass unit \n"
123                                                    "PCT: percent \n"
124                                                    "PPM: part per million"));
125 
126     m_ui.monoFilterToleranceLineEdit->setText("1");
127     m_ui.avgFilterToleranceLineEdit->setText("1");
128 
129     monoFilterAct = new QAction(tr("Toggle Mono Filtering"), this);
130     monoFilterAct->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_M, Qt::Key_F));
131     this->addAction(monoFilterAct);
132     connect(monoFilterAct,
133             SIGNAL(triggered()),
134             this,
135             SLOT(monoFilterOptionsToggled()));
136 
137     m_ui.monoFilteringOptionsGroupBox->addAction(monoFilterAct);
138 
139     avgFilterAct = new QAction(tr("Toggle Avg Filtering"), this);
140     avgFilterAct->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_A, Qt::Key_F));
141     this->addAction(avgFilterAct);
142     connect(avgFilterAct,
143             SIGNAL(triggered()),
144             this,
145             SLOT(avgFilterOptionsToggled()));
146 
147     m_ui.avgFilteringOptionsGroupBox->addAction(avgFilterAct);
148 
149     // When the dialog box is created it is created with the groupbox
150     // unchecked.
151     m_ui.monoFilteringOptionsFrame->setVisible(false);
152     m_ui.avgFilteringOptionsFrame->setVisible(false);
153 
154     // When the filtering group box will be opened, the focus will be on
155     // the first widget of the groupbox:
156     mp_monoFocusWidget = m_ui.monoFilterSearchedLineEdit;
157     mp_avgFocusWidget = m_ui.avgFilterSearchedLineEdit;
158 
159 
160 
161     // The results-exporting menus. ////////////////////////////////
162 
163     QStringList comboBoxItemList;
164 
165     comboBoxItemList
166       << tr("To Clipboard")
167       << tr("To File")
168       << tr("Select File");
169 
170     m_ui.exportResultsComboBox->addItems(comboBoxItemList);
171 
172     connect(m_ui.exportResultsComboBox,
173             SIGNAL(activated(int)),
174             this,
175             SLOT(exportResults(int)));
176 
177     mpa_resultsString = new QString();
178 
179     //////////////////////////////////// The results-exporting menus.
180 
181 
182     QSettings settings
183       (static_cast<Application *>(qApp)->configSettingsFilePath(),
184        QSettings::IniFormat);
185 
186     settings.beginGroup("mass_search_dlg");
187 
188     restoreGeometry(settings.value("geometry").toByteArray());
189 
190     m_ui.oligomersSplitter->
191       restoreState(settings.value("oligomersSplitter").toByteArray());
192 
193     m_ui.oligoDetailsSplitter->
194       restoreState(settings.value("oligoDetailsSplitter").toByteArray());
195 
196     m_ui.tableViewsSplitter->
197       restoreState(settings.value("tableViewsSplitter").toByteArray());
198 
199     settings.endGroup();
200 
201 
202     connect(m_ui.searchPushButton,
203             SIGNAL(clicked()),
204             this,
205             SLOT(search()));
206 
207     connect(m_ui.abortPushButton,
208             SIGNAL(clicked()),
209             this,
210             SLOT(abort()));
211 
212     connect(m_ui.updateCurrentSelectionDataPushButton,
213             SIGNAL(clicked()),
214             this,
215             SLOT(updateWholeSelectedSequenceData()));
216 
217 
218     // MONO set of filtering widgets
219     connect(m_ui.monoFilterSearchedLineEdit,
220             SIGNAL(returnPressed()),
221             this,
222             SLOT(monoFilterSearched()));
223 
224     connect(m_ui.monoFilterErrorLineEdit,
225             SIGNAL(returnPressed()),
226             this,
227             SLOT(monoFilterError()));
228 
229     connect(m_ui.monoFilterMonoMassLineEdit,
230             SIGNAL(returnPressed()),
231             this,
232             SLOT(monoFilterMonoMass()));
233 
234     connect(m_ui.monoFilterAvgMassLineEdit,
235             SIGNAL(returnPressed()),
236             this,
237             SLOT(monoFilterAvgMass()));
238 
239     connect(m_ui.monoFilteringOptionsGroupBox,
240             SIGNAL(clicked(bool)),
241             this,
242             SLOT(monoFilterOptions(bool)));
243 
244     // AVG set of filtering widgets
245     connect(m_ui.avgFilterSearchedLineEdit,
246             SIGNAL(returnPressed()),
247             this,
248             SLOT(avgFilterSearched()));
249 
250     connect(m_ui.avgFilterErrorLineEdit,
251             SIGNAL(returnPressed()),
252             this,
253             SLOT(avgFilterError()));
254 
255     connect(m_ui.avgFilterMonoMassLineEdit,
256             SIGNAL(returnPressed()),
257             this,
258             SLOT(avgFilterMonoMass()));
259 
260     connect(m_ui.avgFilterAvgMassLineEdit,
261             SIGNAL(returnPressed()),
262             this,
263             SLOT(avgFilterAvgMass()));
264 
265     connect(m_ui.avgFilteringOptionsGroupBox,
266             SIGNAL(clicked(bool)),
267             this,
268             SLOT(avgFilterOptions(bool)));
269   }
270 
271 
~MassSearchDlg()272   MassSearchDlg::~MassSearchDlg()
273   {
274     delete mpa_resultsString;
275 
276     delete mpa_monoOligomerTableViewModel;
277 
278     delete mpa_monoProxyModel;
279 
280     delete mpa_avgOligomerTableViewModel;
281 
282     delete mpa_avgProxyModel;
283 
284     freeAllOligomerLists();
285   }
286 
287 
288   void
closeEvent(QCloseEvent * event)289   MassSearchDlg::closeEvent(QCloseEvent *event)
290   {
291     if (event)
292       printf("%s", "");
293 
294     QSettings settings
295       (static_cast<Application *>(qApp)->configSettingsFilePath(),
296        QSettings::IniFormat);
297 
298     settings.beginGroup("mass_search_dlg");
299 
300     settings.setValue("geometry", saveGeometry());
301 
302     settings.setValue("oligomersSplitter",
303                       m_ui.oligomersSplitter->saveState());
304 
305     settings.setValue("oligoDetailsSplitter",
306                       m_ui.oligoDetailsSplitter->saveState());
307 
308     settings.setValue("tableViewsSplitter",
309                       m_ui.tableViewsSplitter->saveState());
310 
311     settings.endGroup();
312   }
313 
314 
315   SequenceEditorWnd *
editorWnd()316   MassSearchDlg::editorWnd()
317   {
318     return mp_editorWnd;
319   }
320 
321 
322   bool
populateToleranceTypeComboBoxes()323   MassSearchDlg::populateToleranceTypeComboBoxes()
324   {
325     QStringList stringList;
326 
327     stringList << tr("AMU") << tr("PCT") << tr("PPM");
328 
329     m_ui.monoToleranceComboBox->insertItems(0, stringList);
330     m_ui.avgToleranceComboBox->insertItems(0, stringList);
331 
332     return true;
333   }
334 
335   void
updateWholeSelectedSequenceData()336   MassSearchDlg::updateWholeSelectedSequenceData()
337   {
338     updateSelectionData(true);
339   }
340 
341 
342   bool
updateSelectionData(bool fromSequenceEditor)343   MassSearchDlg::updateSelectionData(bool fromSequenceEditor)
344   {
345     // There are two situations:
346 
347     // 1. This function is called from the constructor to setup data
348     // in the whole/selected sequence groupBox widget. It gets the
349     // info directly from the sequence editor window
350     // (fromSequenceEditor = true). By default the param is true,
351     // because this is expected for when this slot is called upon
352     // clicking on the Update button.
353 
354     // 2. This function is called only to set the whole/selected
355     // sequence data in the calculation options instance. The data are
356     // read directly from the widgets and the sequence editor window
357     // is not probed.
358 
359     if (!fromSequenceEditor)
360       {
361         // Only update that whole/selected sequence data in the
362         // m_calcOptions from the widgettry and not from the
363         // sequence. Because the user cannot modify the selection text
364         // in the line edit widget, all we need to know is: whole or
365         // selected sequence.
366 
367         if (m_ui.wholeSequenceRadioButton->isChecked())
368           {
369             // Set the "selection" to be the whole sequence.
370 
371             Coordinates coordinates(0, mp_polymer->size() - 1);
372             m_calcOptions.setCoordinateList(coordinates);
373 
374             m_ui.wholeSequenceRadioButton->setChecked(true);
375 
376             return true;
377           }
378         // Else, we do not need to do anything. The selection is
379         // updated by clicking onto the Update button.
380 
381         return true;
382       }
383 
384     // At this point, we are asked to update the whole/selected
385     // sequence data directly from the sequence editor window. So get
386     // all these coordinates !
387 
388     CoordinateList coordList;
389 
390     bool res = mp_editorWnd->mpa_editorGraphicsView->
391       selectionIndices(&coordList);
392 
393     if (res)
394       {
395         // If there are more than one region selection or if there is
396         // one region selection but spanning more than one monomer,
397         // then set the target to be "current selected sequence".
398 
399         if(coordList.size() > 1)
400           {
401             // Apparently there are multiple regions selected.
402 
403             m_ui.currentSelectionLineEdit->
404               setText(coordList.positionsAsText());
405 
406             m_calcOptions.setCoordinateList(coordList);
407           }
408         else
409           {
410             Coordinates *coordinates = coordList.first();
411 
412             if (coordinates->start() == coordinates->end())
413               {
414                 // Construct a string with both the monomer code and
415                 // its position in the sequence.
416 
417                 Polymer *polymer = mp_editorWnd->polymer();
418                 const Monomer *monomer =
419                   polymer->monomerList().at(coordinates->start());
420 
421                 QString text = tr("%1 at pos. %2")
422                   .arg(monomer->code())
423                   .arg(coordinates->start() + 1);
424 
425                 m_ui.currentSelectionLineEdit->setText(text);
426               }
427             else
428               {
429                 m_ui.currentSelectionLineEdit->
430                   setText(coordList.positionsAsText());
431               }
432 
433             m_calcOptions.setCoordinateList(*coordinates);
434           }
435 
436         m_ui.currentSelectionRadioButton->setChecked(true);
437       }
438     else
439       {
440         // There is no selection, set the "selection" to be the
441         // whole sequence.
442 
443         Coordinates coordinates(0, mp_polymer->size() - 1);
444         m_calcOptions.setCoordinateList(coordinates);
445 
446         m_ui.wholeSequenceRadioButton->setChecked(true);
447       }
448 
449     // Return if there was a selection(multiple-region or not) or
450     // not.
451     return res;
452   }
453 
454 
455   bool
checkTolerance(int type)456   MassSearchDlg::checkTolerance(int type)
457   {
458     double nominal = 0;
459     bool ok = false;
460 
461     QString text;
462 
463     if (type & MXT_MASS_MONO)
464       {
465         text = m_ui.monoMassLineEdit->text();
466       }
467     else if (type & MXT_MASS_AVG)
468       {
469         text = m_ui.avgMassLineEdit->text();
470       }
471     else
472       Q_ASSERT(0);
473 
474     if (text.isEmpty())
475       return false;
476 
477     nominal = text.toDouble(&ok);
478 
479     if (!nominal && !ok)
480       return false;
481 
482     return true;
483   }
484 
485   bool
calculateTolerance(double value,int type)486   MassSearchDlg::calculateTolerance(double value, int type)
487   {
488     int index = 0;
489     double nominal = 0;
490 
491     bool ok = false;
492 
493     QString text;
494 
495 
496     if (type & MXT_MASS_MONO)
497       {
498         index = m_ui.monoToleranceComboBox->currentIndex();
499         text = m_ui.monoMassLineEdit->text();
500       }
501     else if (type & MXT_MASS_AVG)
502       {
503         index = m_ui.avgToleranceComboBox->currentIndex();
504         text = m_ui.avgMassLineEdit->text();
505       }
506     else
507       Q_ASSERT(0);
508 
509 
510     nominal = text.toDouble(&ok);
511 
512     if (!nominal && !ok)
513       return false;
514 
515     if (index == 0)
516       {
517         // MXT_MASS_TOLERANCE_AMU
518 
519         type & MXT_MASS_MONO ?
520           m_monoTolerance = nominal :
521           m_avgTolerance = nominal;
522 
523         return true;
524       }
525     else if (index == 1)
526       {
527         // MXT_MASS_TOLERANCE_PCT
528 
529         type & MXT_MASS_MONO ?
530           m_monoTolerance = nominal *(value / 100) :
531           m_avgTolerance = nominal *(value / 100);
532 
533         return true;
534       }
535     else if (index == 2)
536       {
537         // MXT_MASS_TOLERANCE_PPM
538 
539         type & MXT_MASS_MONO ?
540           m_monoTolerance = nominal *(value / 1000000) :
541           m_avgTolerance = nominal *(value / 1000000);
542 
543         return true;
544       }
545     else
546       Q_ASSERT(0);
547 
548     return false;
549   }
550 
551 
552   bool
parseMassText(int type)553   MassSearchDlg::parseMassText(int type)
554   {
555     Application *application = static_cast<Application *>(qApp);
556     QLocale locale = application->locale();
557 
558     Q_ASSERT(type & MXT_MASS_MONO || type & MXT_MASS_AVG);
559 
560     QString text;
561 
562     if (type & MXT_MASS_MONO)
563       text = m_ui.monoMassTextEdit->toPlainText();
564     else if (type & MXT_MASS_AVG)
565       text = m_ui.avgMassTextEdit->toPlainText();
566     else
567       Q_ASSERT(0);
568 
569     QStringList splitList = text.split(QRegExp("\\s+"),
570                                        QString::SkipEmptyParts);
571 
572     for (int iter = 0; iter < splitList.size(); ++iter)
573       {
574         bool ok = false;
575 
576         double value = locale.toDouble(splitList.at(iter), &ok);
577 
578         if(!value && !ok)
579           {
580             qDebug() << "Error in mass list";
581 
582             return false;
583           }
584 
585         if(type & MXT_MASS_MONO)
586           m_monoMassesList.append(value);
587         else
588           m_avgMassesList.append(value);
589       }
590 
591     return true;
592   }
593 
594 
595   bool
searchMass(double value,const Coordinates & coordinates,int type)596   MassSearchDlg::searchMass(double value,
597                             const Coordinates &coordinates,
598                             int type)
599   {
600     //    CalcOptions localCalcOptions(*mp_calcOptions);
601     IonizeRule localIonizeRule(*mp_ionizeRule);
602 
603     int count = 0;
604     int cycle = 0;
605 
606     Q_ASSERT(type & MXT_MASS_MONO || type & MXT_MASS_AVG);
607 
608     int startIndex = coordinates.start();
609     int endIndex = coordinates.end();
610 
611     double maxValue = type & MXT_MASS_MONO ?
612       value + m_monoTolerance :
613       value + m_avgTolerance;
614 
615     double minValue = type & MXT_MASS_MONO ?
616       value - m_monoTolerance :
617       value - m_avgTolerance;
618 
619     if (minValue < 0)
620       minValue = 0;
621 
622     m_currentMass = value;
623     updateProgressDetails(type);
624 
625     for (int iter = startIndex; iter < endIndex + 1; ++iter)
626       {
627         if(m_abort)
628           return true;
629 
630         for(int jter = 0; jter < endIndex + 1 - iter; ++jter)
631           {
632             // Note that the ionization starts from a low value and goes
633             // to a higher value, that means that while this loop runs
634             // for a given oligomer, the m/z ratio goes diminishing.
635 
636             for (int kter = m_ionizeStart; kter < m_ionizeEnd + 1;
637                  ++kter, ++cycle)
638               {
639                 ++m_testedOligosCount;
640 
641                 if(cycle == 200)
642                   {
643                     cycle = 0;
644                     updateProgressDetails(type);
645                   }
646 
647                 localIonizeRule.setLevel(kter);
648 
649                 Oligomer oligomerTest(mp_polymer,
650                                       "NOT_SET" /*name*/,
651                                       QString("") /*description*/,
652                                       Ponderable(),
653                                       localIonizeRule, CalcOptions(),false,
654                                       iter, iter + jter);
655 
656                 oligomerTest.calculateMasses(&m_calcOptions);
657 
658                 double mz = type & MXT_MASS_MONO ?
659                   oligomerTest.mono() :
660                   oligomerTest.avg();
661 
662                 if(mz < minValue)
663                   // Oligomer's m/z already too small. Break
664                   // immediately as this cannot get any better by
665                   // continuing to increase the ionization level.
666                   break;
667 
668                 if(mz > maxValue)
669                   // Oligomer's m/z is still too big. Continue
670                   // incrementing the ionization level, so that its
671                   // m/z will decrease...
672                   continue;
673 
674 
675                 // At this point the oligomer has correct masses.
676 
677                 Oligomer *oligomerNew = new Oligomer(oligomerTest);
678 
679                 ++count;
680 
681                 int totalCharge = localIonizeRule.charge() *
682                   localIonizeRule.level();
683 
684                 QString name = QString("%1-z%2#%3")
685                   .arg(value)
686                   .arg(totalCharge)
687                   .arg(count);
688 
689                 oligomerNew->setName(name);
690 
691                 // Set the searched mz in a prop.
692 
693                 DoubleProp *prop = new DoubleProp("SEARCHED_MZ",
694                                                   value);
695 
696                 oligomerNew->appendProp(prop);
697 
698                 // Set the error mz in a prop.
699 
700                 double error = mz - value ;
701 
702                 prop = new DoubleProp("ERROR_MZ", error);
703 
704                 oligomerNew->appendProp(prop);
705 
706                 type & MXT_MASS_MONO ?
707                   mpa_monoOligomerTableViewModel->addOligomer(oligomerNew) :
708                   mpa_avgOligomerTableViewModel->addOligomer(oligomerNew);
709 
710                 ++m_foundOligosCount;
711 
712                 updateProgressDetails(type, false, oligomerNew);
713               }
714             // End of
715             // for (int kter = m_ionizeStart; kter < m_ionizeEnd + 1; ++kter)
716           }
717         // End of
718         // for (int jter = 0; jter < endIndex + 1 - iter; ++jter)
719       }
720     // End of
721     // for (int iter = startIndex; iter < endIndex + 1; ++iter)
722 
723     return true;
724   }
725 
726 
727   bool
searchMasses(int type)728   MassSearchDlg::searchMasses(int type)
729   {
730     if (!mp_polymer->size())
731       return false;
732 
733     const CoordinateList &coordinateList = m_calcOptions.coordinateList();
734 
735     if (type & MXT_MASS_MONO)
736       {
737         for(int iter = 0; iter < m_monoMassesList.size(); ++iter)
738           {
739             double value = m_monoMassesList.at(iter);
740 
741             if (!calculateTolerance(value, MXT_MASS_MONO))
742               return false;
743 
744             for (int iter = 0; iter < coordinateList.size(); ++iter)
745               {
746                 if(!searchMass(value, *(coordinateList.at(iter)),
747                                MXT_MASS_MONO))
748                   return false;
749 
750                 m_ui.massSearchProgressBar->setValue(++m_progressValue);
751 
752                 if(m_abort)
753                   return true;
754               }
755           }
756       }
757     else if (type & MXT_MASS_AVG)
758       {
759         for(int iter = 0; iter < m_avgMassesList.size(); ++iter)
760           {
761             double value = m_avgMassesList.at(iter);
762 
763             if (!calculateTolerance(value, MXT_MASS_AVG))
764               return false;
765 
766             for (int iter = 0; iter < coordinateList.size(); ++iter)
767               {
768                 if(!searchMass(value, *(coordinateList.at(iter)),
769                                MXT_MASS_AVG))
770                   return false;
771 
772                 m_ui.massSearchProgressBar->setValue(++m_progressValue);
773 
774                 if(m_abort)
775                   return true;
776               }
777           }
778       }
779     else
780       Q_ASSERT(0);
781 
782     return true;
783   }
784 
785 
786   void
search()787   MassSearchDlg::search()
788   {
789     // Update the options from the parent window.
790     m_calcOptions = mp_editorWnd->calcOptions();
791 
792     // Set the current whole/selected sequence data in the
793     // m_calcOptions instance (false = no read from sequence editor
794     // window).
795     updateSelectionData(false);
796 
797     updateIonizationData();
798 
799     // Empty the treeviews and the lists of oligomers.
800     mpa_monoOligomerTableViewModel->removeOligomers(0, -1);
801     mpa_avgOligomerTableViewModel->removeOligomers(0, -1);
802 
803     emptyAllMassLists();
804 
805     m_abort = false;
806 
807     if (!parseMassText(MXT_MASS_MONO))
808       {
809         QMessageBox::warning
810           (this,
811            tr("massXpert - Polymer Mass Search"),
812            tr("%1@%2\n"
813               "Failed to parse the masses to search for MONO.")
814            .arg(__FILE__)
815            .arg(__LINE__),
816            QMessageBox::Ok);
817 
818         return;
819       }
820 
821     if (!parseMassText(MXT_MASS_AVG))
822       {
823         QMessageBox::warning
824           (this,
825            tr("massXpert - Polymer Mass Search"),
826            tr("%1@%2\n"
827               "Failed to parse the masses to search for AVG.")
828            .arg(__FILE__)
829            .arg(__LINE__),
830            QMessageBox::Ok);
831 
832         return;
833       }
834 
835     if (m_monoMassesList.size())
836       {
837         if(!checkTolerance(MXT_MASS_MONO))
838           {
839             QMessageBox::information(this, tr("massxpert - Mass Search"),
840                                      tr("Enter a valid MONO tolerance value"),
841                                      QMessageBox::Ok);
842             return;
843           }
844       }
845 
846     if (m_avgMassesList.size())
847       {
848         if(!checkTolerance(MXT_MASS_AVG))
849           {
850             QMessageBox::information(this, tr("massxpert - Mass Search"),
851                                      tr("Enter a valid AVG tolerance value"),
852                                      QMessageBox::Ok);
853             return;
854           }
855       }
856 
857     setCursor(Qt::WaitCursor);
858 
859     m_testedOligosCount = 0;
860     m_foundOligosCount = 0;
861 
862     int massNumber = m_monoMassesList.size() + m_avgMassesList.size();
863     m_progressValue = 0;
864     m_ui.massSearchProgressBar->setRange(0, massNumber);
865 
866     updateProgressDetails(MXT_MASS_MONO, true);
867     updateProgressDetails(MXT_MASS_AVG, true);
868 
869     Application *application = static_cast<Application *>(qApp);
870 
871     if (!searchMasses(MXT_MASS_MONO))
872       {
873         QMessageBox::warning
874           (this,
875            tr("massXpert - Polymer Mass Search"),
876            tr("%1@%2\n"
877               "Failed to search for the MONO masses.")
878            .arg(__FILE__)
879            .arg(__LINE__),
880            QMessageBox::Ok);
881 
882         setCursor(Qt::ArrowCursor);
883         updateMassSearchDetails(m_calcOptions);
884         application->beep();
885 
886         return;
887       }
888 
889     if (!searchMasses(MXT_MASS_AVG))
890       {
891         QMessageBox::warning
892           (this,
893            tr("massXpert - Polymer Mass Search"),
894            tr("%1@%2\n"
895               "Failed to search for the AVG masses.")
896            .arg(__FILE__)
897            .arg(__LINE__),
898            QMessageBox::Ok);
899 
900         setCursor(Qt::ArrowCursor);
901         updateMassSearchDetails(m_calcOptions);
902         application->beep();
903 
904         return;
905       }
906 
907     setCursor(Qt::ArrowCursor);
908 
909     updateMassSearchDetails(m_calcOptions);
910 
911     application->beep();
912   }
913 
914 
915   void
setupTableViews()916   MassSearchDlg::setupTableViews()
917   {
918     // Model stuff all thought for sorting.
919     mpa_monoOligomerTableViewModel =
920       new MassSearchOligomerTableViewModel(&m_monoOligomerList, this);
921 
922     mpa_avgOligomerTableViewModel =
923       new MassSearchOligomerTableViewModel(&m_avgOligomerList, this);
924 
925     mpa_monoProxyModel = new MassSearchOligomerTableViewSortProxyModel(this);
926     mpa_monoProxyModel->setSourceModel(mpa_monoOligomerTableViewModel);
927     mpa_monoProxyModel->setFilterKeyColumn(-1);
928 
929     mpa_avgProxyModel = new MassSearchOligomerTableViewSortProxyModel(this);
930     mpa_avgProxyModel->setSourceModel(mpa_avgOligomerTableViewModel);
931     mpa_avgProxyModel->setFilterKeyColumn(-1);
932 
933     m_ui.monoOligomerTableView->setModel(mpa_monoProxyModel);
934     m_ui.monoOligomerTableView->setParentDlg(this);
935     m_ui.monoOligomerTableView->setOligomerList(&m_monoOligomerList);
936     mpa_monoOligomerTableViewModel->setTableView(m_ui.monoOligomerTableView);
937 
938     m_ui.avgOligomerTableView->setModel(mpa_avgProxyModel);
939     m_ui.avgOligomerTableView->setParentDlg(this);
940     m_ui.avgOligomerTableView->setOligomerList(&m_avgOligomerList);
941     mpa_avgOligomerTableViewModel->setTableView(m_ui.avgOligomerTableView);
942   }
943 
944 
945   void
updateIonizationData()946   MassSearchDlg::updateIonizationData()
947   {
948     m_ionizeStart = m_ui.ionizationStartSpinBox->value();
949     m_ionizeEnd = m_ui.ionizationEndSpinBox->value();
950 
951     if (m_ionizeStart > m_ionizeEnd)
952       {
953         int temp = m_ionizeStart;
954         m_ionizeStart = m_ionizeEnd;
955         m_ionizeEnd = temp;
956       }
957   }
958 
959 
960   void
updateProgressDetails(int type,bool reset,Oligomer * oligomer)961   MassSearchDlg::updateProgressDetails(int type, bool reset,
962                                        Oligomer *oligomer)
963   {
964     Application *application = static_cast<Application *>(qApp);
965     QLocale locale = application->locale();
966 
967     if (reset)
968       {
969         m_ui.lastOligoNameLineEdit->setText("");
970         m_ui.lastOligoCoordinatesLineEdit->setText("");
971         m_ui.lastOligoMonoMassLineEdit->setText("");
972         m_ui.lastOligoAvgMassLineEdit->setText("");
973 
974         m_ui.currentMassLineEdit->setText("");
975 
976         m_ui.lastOligoMassTypeLineEdit->setText("");
977 
978         m_ui.testedCountLabel->setText(QString().setNum(0));
979         m_ui.foundCountLabel->setText(QString().setNum(0));
980 
981         m_ui.massSearchProgressBar->setValue(0);
982 
983         application->processEvents();
984 
985         return;
986       }
987 
988     if (oligomer)
989       {
990         m_ui.lastOligoNameLineEdit->setText(oligomer->name());
991         QString coordinates(tr("[ %1 - %2 ]")
992                             .arg(oligomer->startIndex() + 1)
993                             .arg(oligomer->endIndex() + 1));
994 
995         m_ui.lastOligoCoordinatesLineEdit->setText(coordinates);
996 
997         QString mass = oligomer->mono(locale);
998         m_ui.lastOligoMonoMassLineEdit->setText(mass);
999 
1000         mass = oligomer->avg(locale);
1001         m_ui.lastOligoAvgMassLineEdit->setText(mass);
1002       }
1003 
1004     m_ui.currentMassLineEdit->setText(QString().setNum(m_currentMass,
1005                                                        'g', 10));
1006 
1007     type & MXT_MASS_MONO ?
1008       m_ui.lastOligoMassTypeLineEdit->setText(tr("MONO")) :
1009       m_ui.lastOligoMassTypeLineEdit->setText(tr("AVG"));
1010 
1011     m_ui.testedCountLabel->setText(QString().setNum(m_testedOligosCount));
1012     m_ui.foundCountLabel->setText(QString().setNum(m_foundOligosCount));
1013 
1014     m_ui.massSearchProgressBar->setValue(m_progressValue);
1015 
1016     application->processEvents();
1017   }
1018 
1019 
1020   void
updateMassSearchDetails(const CalcOptions & calcOptions)1021   MassSearchDlg::updateMassSearchDetails(const CalcOptions &calcOptions)
1022   {
1023     if (calcOptions.monomerEntities() & MXT_MONOMER_CHEMENT_MODIF)
1024       m_ui.modificationsCheckBox->setCheckState(Qt::Checked);
1025     else
1026       m_ui.modificationsCheckBox->setCheckState(Qt::Unchecked);
1027 
1028     if (calcOptions.polymerEntities() & MXT_POLYMER_CHEMENT_LEFT_END_MODIF)
1029       m_ui.leftModifCheckBox->setCheckState(Qt::Checked);
1030     else
1031       m_ui.leftModifCheckBox->setCheckState(Qt::Unchecked);
1032 
1033     if (calcOptions.polymerEntities() & MXT_POLYMER_CHEMENT_RIGHT_END_MODIF)
1034       m_ui.rightModifCheckBox->setCheckState(Qt::Checked);
1035     else
1036       m_ui.rightModifCheckBox->setCheckState(Qt::Unchecked);
1037   }
1038 
1039 
1040   void
updateOligomerSequence(QString * text)1041   MassSearchDlg::updateOligomerSequence(QString *text)
1042   {
1043     Q_ASSERT(text);
1044 
1045     m_ui.oligomerSequenceTextEdit->clear();
1046     m_ui.oligomerSequenceTextEdit->append(*text);
1047   }
1048 
1049 
1050   void
freeAllOligomerLists()1051   MassSearchDlg::freeAllOligomerLists()
1052   {
1053     while(!m_monoOligomerList.isEmpty())
1054       delete m_monoOligomerList.takeFirst();
1055 
1056     while(!m_avgOligomerList.isEmpty())
1057       delete m_avgOligomerList.takeFirst();
1058   }
1059 
1060 
1061   void
emptyAllMassLists()1062   MassSearchDlg::emptyAllMassLists()
1063   {
1064     while(!m_monoMassesList.isEmpty())
1065       m_monoMassesList.removeFirst();
1066 
1067     while(!m_avgMassesList.isEmpty())
1068       m_avgMassesList.removeFirst();
1069   }
1070 
1071 
1072   void
abort()1073   MassSearchDlg::abort()
1074   {
1075     m_abort = true;
1076   }
1077 
1078 
1079 
1080   bool
calculateFilterTolerance(double mass,int massType)1081   MassSearchDlg::calculateFilterTolerance(double mass, int massType)
1082   {
1083     // Get the tolerance that is in its lineEdit.
1084     QString text;
1085 
1086     if (massType == MXT_MASS_MONO)
1087       text = m_ui.monoFilterToleranceLineEdit->text();
1088     else if (massType == MXT_MASS_AVG)
1089       text = m_ui.avgFilterToleranceLineEdit->text();
1090     else
1091       Q_ASSERT(0);
1092 
1093     double tolerance = 0;
1094     bool ok = false;
1095 
1096     if (!text.isEmpty())
1097       {
1098         // Convert the string to a double.
1099         Application *application = static_cast<Application *>(qApp);
1100         QLocale locale = application->locale();
1101 
1102         ok = false;
1103         tolerance = locale.toDouble(text, &ok);
1104 
1105         if(!tolerance && !ok)
1106           return false;
1107       }
1108     else
1109       {
1110         m_filterTolerance = 0;
1111       }
1112 
1113     // What's the item currently selected in the comboBox?
1114     int index = 0;
1115 
1116     if (massType == MXT_MASS_MONO)
1117       index = m_ui.monoFilterToleranceComboBox->currentIndex();
1118     else if (massType == MXT_MASS_AVG)
1119       index = m_ui.avgFilterToleranceComboBox->currentIndex();
1120     else
1121       Q_ASSERT(0);
1122 
1123     if (index == 0)
1124       {
1125         // MXT_MASS_TOLERANCE_AMU
1126         m_filterTolerance = tolerance;
1127       }
1128     else if (index == 1)
1129       {
1130         // MXT_MASS_TOLERANCE_PCT
1131         m_filterTolerance =(tolerance / 100) * mass;
1132       }
1133     else if (index == 2)
1134       {
1135         // MXT_MASS_TOLERANCE_PPM
1136         m_filterTolerance =(tolerance / 1000000) * mass;
1137       }
1138     else
1139       Q_ASSERT(0);
1140 
1141     return true;
1142   }
1143 
1144 
1145   void
monoFilterOptions(bool checked)1146   MassSearchDlg::monoFilterOptions(bool checked)
1147   {
1148     if (!checked)
1149       {
1150         mpa_monoProxyModel->setFilterKeyColumn(-1);
1151 
1152         mpa_monoProxyModel->applyNewFilter();
1153 
1154         m_ui.monoFilteringOptionsFrame->setVisible(false);
1155       }
1156     else
1157       {
1158         m_ui.monoFilteringOptionsFrame->setVisible(true);
1159 
1160         // In this case, set focus to the last focused widget in the
1161         // groupbox or the first widget in the groubox if this is the
1162         // first time the filtering is used.
1163         mp_monoFocusWidget->setFocus();
1164       }
1165   }
1166 
1167 
1168   void
monoFilterOptionsToggled()1169   MassSearchDlg::monoFilterOptionsToggled()
1170   {
1171     bool isChecked = m_ui.monoFilteringOptionsGroupBox->isChecked();
1172 
1173     m_ui.monoFilteringOptionsGroupBox->setChecked(!isChecked);
1174     monoFilterOptions(!isChecked);
1175   }
1176 
1177 
1178   void
avgFilterOptions(bool checked)1179   MassSearchDlg::avgFilterOptions(bool checked)
1180   {
1181     if (!checked)
1182       {
1183         mpa_avgProxyModel->setFilterKeyColumn(-1);
1184 
1185         mpa_avgProxyModel->applyNewFilter();
1186 
1187         m_ui.avgFilteringOptionsFrame->setVisible(false);
1188       }
1189     else
1190       {
1191         m_ui.avgFilteringOptionsFrame->setVisible(true);
1192 
1193         // In this case, set focus to the last focused widget in the
1194         // groupbox or the first widget in the groubox if this is the
1195         // first time the filtering is used.
1196         mp_avgFocusWidget->setFocus();
1197       }
1198   }
1199 
1200 
1201   void
avgFilterOptionsToggled()1202   MassSearchDlg::avgFilterOptionsToggled()
1203   {
1204     bool isChecked = m_ui.avgFilteringOptionsGroupBox->isChecked();
1205 
1206     m_ui.avgFilteringOptionsGroupBox->setChecked(!isChecked);
1207     avgFilterOptions(!isChecked);
1208   }
1209 
1210 
1211   void
monoFilterSearched()1212   MassSearchDlg::monoFilterSearched()
1213   {
1214     // First off, we have to get the mass that is in the lineEdit.
1215 
1216     QString text = m_ui.monoFilterSearchedLineEdit->text();
1217 
1218     if (text.isEmpty())
1219       return;
1220 
1221     // Convert the string to a double.
1222     Application *application = static_cast<Application *>(qApp);
1223     QLocale locale = application->locale();
1224 
1225     bool ok = false;
1226     double mass = locale.toDouble(text, &ok);
1227 
1228     if (!mass && !ok)
1229       return;
1230 
1231     mpa_monoProxyModel->setSearchedFilter(mass);
1232 
1233     mpa_monoProxyModel->setFilterKeyColumn(0);
1234     mpa_monoProxyModel->applyNewFilter();
1235 
1236     mp_monoFocusWidget = m_ui.monoFilterSearchedLineEdit;
1237   }
1238 
1239 
1240   void
avgFilterSearched()1241   MassSearchDlg::avgFilterSearched()
1242   {
1243     // First off, we have to get the mass that is in the lineEdit.
1244 
1245     QString text = m_ui.avgFilterSearchedLineEdit->text();
1246 
1247     if (text.isEmpty())
1248       return;
1249 
1250     // Convert the string to a double.
1251     Application *application = static_cast<Application *>(qApp);
1252     QLocale locale = application->locale();
1253 
1254     bool ok = false;
1255     double mass = locale.toDouble(text, &ok);
1256 
1257     if (!mass && !ok)
1258       return;
1259 
1260     mpa_avgProxyModel->setSearchedFilter(mass);
1261 
1262     mpa_avgProxyModel->setFilterKeyColumn(0);
1263     mpa_avgProxyModel->applyNewFilter();
1264 
1265     mp_avgFocusWidget = m_ui.avgFilterSearchedLineEdit;
1266   }
1267 
1268 
1269   void
monoFilterError()1270   MassSearchDlg::monoFilterError()
1271   {
1272     // First off, we have to get the mass error that is in the lineEdit.
1273 
1274     QString text = m_ui.monoFilterErrorLineEdit->text();
1275 
1276     if (text.isEmpty())
1277       return;
1278 
1279     // Convert the string to a double.
1280     Application *application = static_cast<Application *>(qApp);
1281     QLocale locale = application->locale();
1282 
1283     bool ok = false;
1284     double mass = locale.toDouble(text, &ok);
1285 
1286     if (!mass && !ok)
1287       return;
1288 
1289     // At this point, depending on the item that is currently selected
1290     // in the comboBox, we'll have to actually compute the tolerance.
1291 
1292     if (!calculateFilterTolerance(mass, MXT_MASS_MONO))
1293       return ;
1294 
1295     mpa_monoProxyModel->setErrorFilter(mass);
1296     mpa_monoProxyModel->setTolerance(m_filterTolerance);
1297 
1298     mpa_monoProxyModel->setFilterKeyColumn(3);
1299     mpa_monoProxyModel->applyNewFilter();
1300 
1301     mp_monoFocusWidget = m_ui.monoFilterErrorLineEdit;
1302   }
1303 
1304 
1305   void
avgFilterError()1306   MassSearchDlg::avgFilterError()
1307   {
1308     // First off, we have to get the mass error that is in the lineEdit.
1309 
1310     QString text = m_ui.avgFilterErrorLineEdit->text();
1311 
1312     if (text.isEmpty())
1313       return;
1314 
1315     // Convert the string to a double.
1316     Application *application = static_cast<Application *>(qApp);
1317     QLocale locale = application->locale();
1318 
1319     bool ok = false;
1320     double mass = locale.toDouble(text, &ok);
1321 
1322     if (!mass && !ok)
1323       return;
1324 
1325     // At this point, depending on the item that is currently selected
1326     // in the comboBox, we'll have to actually compute the tolerance.
1327 
1328     if (!calculateFilterTolerance(mass, MXT_MASS_AVG))
1329       return ;
1330 
1331     mpa_avgProxyModel->setErrorFilter(mass);
1332     mpa_avgProxyModel->setTolerance(m_filterTolerance);
1333 
1334     mpa_avgProxyModel->setFilterKeyColumn(3);
1335     mpa_avgProxyModel->applyNewFilter();
1336 
1337     mp_avgFocusWidget = m_ui.avgFilterErrorLineEdit;
1338   }
1339 
1340 
1341   void
monoFilterMonoMass()1342   MassSearchDlg::monoFilterMonoMass()
1343   {
1344     // First off, we have to get the mass that is in the lineEdit.
1345 
1346     QString text = m_ui.monoFilterMonoMassLineEdit->text();
1347 
1348     if (text.isEmpty())
1349       return;
1350 
1351     // Convert the string to a double.
1352     Application *application = static_cast<Application *>(qApp);
1353     QLocale locale = application->locale();
1354 
1355     bool ok = false;
1356     double mass = locale.toDouble(text, &ok);
1357 
1358     if (!mass && !ok)
1359       return;
1360 
1361     // At this point, depending on the item that is currently selected
1362     // in the comboBox, we'll have to actually compute the tolerance.
1363 
1364     if (!calculateFilterTolerance(mass, MXT_MASS_MONO))
1365       return ;
1366 
1367     mpa_monoProxyModel->setMonoFilter(mass);
1368     mpa_monoProxyModel->setTolerance(m_filterTolerance);
1369 
1370     mpa_monoProxyModel->setFilterKeyColumn(4);
1371     mpa_monoProxyModel->applyNewFilter();
1372 
1373     mp_monoFocusWidget = m_ui.monoFilterMonoMassLineEdit;
1374   }
1375 
1376 
1377   void
avgFilterMonoMass()1378   MassSearchDlg::avgFilterMonoMass()
1379   {
1380     // First off, we have to get the mass that is in the lineEdit.
1381 
1382     QString text = m_ui.avgFilterMonoMassLineEdit->text();
1383 
1384     if (text.isEmpty())
1385       return;
1386 
1387     // Convert the string to a double.
1388     Application *application = static_cast<Application *>(qApp);
1389     QLocale locale = application->locale();
1390 
1391     bool ok = false;
1392     double mass = locale.toDouble(text, &ok);
1393 
1394     if (!mass && !ok)
1395       return;
1396 
1397     // At this point, depending on the item that is currently selected
1398     // in the comboBox, we'll have to actually compute the tolerance.
1399 
1400     if (!calculateFilterTolerance(mass, MXT_MASS_AVG))
1401       return ;
1402 
1403     mpa_avgProxyModel->setMonoFilter(mass);
1404     mpa_avgProxyModel->setTolerance(m_filterTolerance);
1405 
1406     mpa_avgProxyModel->setFilterKeyColumn(4);
1407     mpa_avgProxyModel->applyNewFilter();
1408 
1409     mp_avgFocusWidget = m_ui.avgFilterMonoMassLineEdit;
1410   }
1411 
1412 
1413   void
monoFilterAvgMass()1414   MassSearchDlg::monoFilterAvgMass()
1415   {
1416     // First off, we have to get the mass that is in the lineEdit.
1417 
1418     QString text = m_ui.monoFilterAvgMassLineEdit->text();
1419 
1420     if (text.isEmpty())
1421       return;
1422 
1423     // Convert the string to a double.
1424     Application *application = static_cast<Application *>(qApp);
1425     QLocale locale = application->locale();
1426 
1427     bool ok = false;
1428     double mass = locale.toDouble(text, &ok);
1429 
1430     if (!mass && !ok)
1431       return;
1432 
1433     // At this point, depending on the item that is currently selected
1434     // in the comboBox, we'll have to actually compute the tolerance.
1435 
1436     if (!calculateFilterTolerance(mass, MXT_MASS_MONO))
1437       return ;
1438 
1439     mpa_monoProxyModel->setAvgFilter(mass);
1440     mpa_monoProxyModel->setTolerance(m_filterTolerance);
1441 
1442     mpa_monoProxyModel->setFilterKeyColumn(5);
1443     mpa_monoProxyModel->applyNewFilter();
1444 
1445     mp_monoFocusWidget = m_ui.monoFilterAvgMassLineEdit;
1446   }
1447 
1448 
1449   void
avgFilterAvgMass()1450   MassSearchDlg::avgFilterAvgMass()
1451   {
1452     // First off, we have to get the mass that is in the lineEdit.
1453 
1454     QString text = m_ui.avgFilterAvgMassLineEdit->text();
1455 
1456     if (text.isEmpty())
1457       return;
1458 
1459     // Convert the string to a double.
1460     Application *application = static_cast<Application *>(qApp);
1461     QLocale locale = application->locale();
1462 
1463     bool ok = false;
1464     double mass = locale.toDouble(text, &ok);
1465 
1466     if (!mass && !ok)
1467       return;
1468 
1469     // At this point, depending on the item that is currently selected
1470     // in the comboBox, we'll have to actually compute the tolerance.
1471 
1472     if (!calculateFilterTolerance(mass, MXT_MASS_AVG))
1473       return ;
1474 
1475     mpa_avgProxyModel->setAvgFilter(mass);
1476     mpa_avgProxyModel->setTolerance(m_filterTolerance);
1477 
1478     mpa_avgProxyModel->setFilterKeyColumn(5);
1479     mpa_avgProxyModel->applyNewFilter();
1480 
1481     mp_avgFocusWidget = m_ui.avgFilterAvgMassLineEdit;
1482   }
1483 
1484 
1485 
1486   // The results-exporting functions. ////////////////////////////////
1487   // The results-exporting functions. ////////////////////////////////
1488   // The results-exporting functions. ////////////////////////////////
1489   void
exportResults(int index)1490   MassSearchDlg::exportResults(int index)
1491   {
1492     // Remember that we had set up the combobox with the following strings:
1493     // << tr("To &Clipboard")
1494     // << tr("To &File")
1495     // << tr("&Select File");
1496 
1497     if (index == 0)
1498       {
1499         exportResultsClipboard();
1500       }
1501     else if (index == 1)
1502       {
1503         exportResultsFile();
1504       }
1505     else if (index == 2)
1506       {
1507         selectResultsFile();
1508       }
1509     else
1510       Q_ASSERT(0);
1511 
1512   }
1513 
1514 
1515   void
prepareResultsTxtString()1516   MassSearchDlg::prepareResultsTxtString()
1517   {
1518     // Set the delimiter to the char/string that is in the
1519     // corresponding text line edit widget.
1520 
1521     QString delimiter = m_ui.delimiterLineEdit->text();
1522     // If delimiter is empty, the function that will prepare the
1523     // string will put the default character, that is '$'.
1524 
1525     mpa_resultsString->clear();
1526 
1527     // We only put the header info if the user does not want to have
1528     // the data formatted for XpertMiner, which only can get the data
1529     // in the format :
1530     //
1531     // mass <delim> charge <delim> name <delim> coords
1532     //
1533     // Note that name and coords are optional.
1534     bool forXpertMiner = false;
1535     MassType massType = MXT_MASS_NONE;
1536 
1537     forXpertMiner = m_ui.forXpertMinerCheckBox->isChecked();
1538 
1539     if (!forXpertMiner)
1540       {
1541         *mpa_resultsString += QObject::tr("# \n"
1542                                           "# ---------------------------\n"
1543                                           "# Mass Search: \n"
1544                                           "# ---------------------------\n");
1545       }
1546     else
1547       {
1548         // Then, we should ask whether the masses to be exported are
1549         // the mono or avg masses.
1550 
1551         if(m_ui.monoRadioButton->isChecked())
1552           massType = MXT_MASS_MONO;
1553         else
1554           massType = MXT_MASS_AVG;
1555       }
1556 
1557 
1558     // Should the oligomers have their sequence displayed?
1559     bool withSequence = m_ui.withSequenceCheckBox->isChecked();
1560 
1561     QString masses;
1562 
1563     // We only show the list of masses if we are exporting not for
1564     // XpertMiner.
1565 
1566     if(!forXpertMiner)
1567       {
1568         // Get the mono masses searched:
1569         masses = m_ui.monoMassTextEdit->toPlainText();
1570         if (!masses.isEmpty())
1571           {
1572             *mpa_resultsString += QObject::tr("\nSearched mono masses:\n"
1573                                               "%1\n")
1574               .arg(masses);
1575           }
1576       }
1577 
1578     QString *text = 0;
1579 
1580     // We export mono data only in two situations: when the data is
1581     // for XpertMiner and the user has selected the Mono radio button
1582     // or when the data is not for XpertMiner.
1583 
1584     if((!forXpertMiner) ||
1585        (forXpertMiner && m_ui.monoRadioButton->isChecked()))
1586       {
1587         // The mono treeview:
1588 
1589         text = m_ui.monoOligomerTableView->
1590           selectedOligomersAsPlainText(delimiter,
1591                                        withSequence,
1592                                        forXpertMiner,
1593                                        massType);
1594 
1595         *mpa_resultsString += *text;
1596 
1597         delete text;
1598       }
1599 
1600     if(!forXpertMiner)
1601       {
1602         // Get the avg masses searched:
1603         masses = m_ui.avgMassTextEdit->toPlainText();
1604         if (!masses.isEmpty())
1605           {
1606             *mpa_resultsString += QObject::tr("\nSearched average masses:\n"
1607                                               "%1\n")
1608               .arg(masses);
1609           }
1610       }
1611 
1612 
1613     // We export mono data only in two situations: when the data is
1614     // for XpertMiner and the user has selected the Mono radio button
1615     // or when the data is not for XpertMiner.
1616 
1617     if((!forXpertMiner) ||
1618        (forXpertMiner && m_ui.avgRadioButton->isChecked()))
1619       {
1620         // The avg treeview:
1621 
1622         text = m_ui.avgOligomerTableView->
1623           selectedOligomersAsPlainText(delimiter,
1624                                        withSequence,
1625                                        forXpertMiner,
1626                                        massType);
1627 
1628         *mpa_resultsString += *text;
1629 
1630         delete text;
1631       }
1632 
1633   }
1634 
1635 
1636   bool
exportResultsClipboard()1637   MassSearchDlg::exportResultsClipboard()
1638   {
1639     prepareResultsTxtString();
1640 
1641     QClipboard *clipboard = QApplication::clipboard();
1642 
1643     clipboard->setText(*mpa_resultsString, QClipboard::Clipboard);
1644 
1645     return true;
1646   }
1647 
1648 
1649   bool
exportResultsFile()1650   MassSearchDlg::exportResultsFile()
1651   {
1652     if (m_resultsFilePath.isEmpty())
1653       {
1654         if(!selectResultsFile())
1655           return false;
1656       }
1657 
1658     QFile file(m_resultsFilePath);
1659 
1660     if (!file.open(QIODevice::WriteOnly | QIODevice::Append))
1661       {
1662         QMessageBox::information(0,
1663                                  tr("massXpert - Export Data"),
1664                                  tr("Failed to open file in append mode."),
1665                                  QMessageBox::Ok);
1666         return false;
1667       }
1668 
1669     QTextStream stream(&file);
1670     stream.setCodec("UTF-8");
1671 
1672     prepareResultsTxtString();
1673 
1674     stream << *mpa_resultsString;
1675 
1676     file.close();
1677 
1678     return true;
1679   }
1680 
1681 
1682   bool
selectResultsFile()1683   MassSearchDlg::selectResultsFile()
1684   {
1685     m_resultsFilePath =
1686       QFileDialog::getSaveFileName(this, tr("Select File To Export Data To"),
1687                                    QDir::homePath(),
1688                                    tr("Data files(*.dat *.DAT)"));
1689 
1690     if (m_resultsFilePath.isEmpty())
1691       return false;
1692 
1693     return true;
1694   }
1695   //////////////////////////////////// The results-exporting functions.
1696   //////////////////////////////////// The results-exporting functions.
1697   //////////////////////////////////// The results-exporting functions.
1698 
1699 } // namespace massXpert
1700