/* massXpert - the true massist's program.
   --------------------------------------
   Copyright(C) 2006,2007 Filippo Rusconi

   http://www.massxpert.org/massXpert

   This file is part of the massXpert project.

   The massxpert project is the successor to the "GNU polyxmass"
   project that is an official GNU project package(see
   www.gnu.org). The massXpert project is not endorsed by the GNU
   project, although it is released ---in its entirety--- under the
   GNU General Public License. A huge part of the code in massXpert
   is actually a C++ rewrite of code in GNU polyxmass. As such
   massXpert was started at the Centre National de la Recherche
   Scientifique(FRANCE), that granted me the formal authorization to
   publish it under this Free Software License.

   This software is free software; you can redistribute it and/or
   modify it under the terms of the GNU  General Public
   License version 3, as published by the Free Software Foundation.
   

   This software is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this software; if not, write to the

   Free Software Foundation, Inc.,

   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/


/////////////////////// Qt includes
#include<QMessageBox>
#include<QFileDialog>

/////////////////////// Local includes
#include "mzCalculationDlg.hpp"
#include "application.hpp"
#include "polChemDef.hpp"
#include "spectrumCalculationDlg.hpp"


namespace massXpert
{

  MzCalculationDlg::MzCalculationDlg(QWidget *parent,
				     const PolChemDef *polChemDef,
				     const IonizeRule *ionizeRule,
				     double mono, double avg)
    : QDialog(parent), mp_polChemDef(polChemDef),
      m_atomList(mp_polChemDef->atomList())
  {
    Q_ASSERT(parent);
    Q_ASSERT(polChemDef);
    Q_ASSERT(ionizeRule);
  
    Application *application = static_cast<Application *>(qApp);
    QLocale locale = application->locale();

    m_ionizeRule = *ionizeRule;

    m_ui.setupUi(this);

    setupTreeView();

    if (mono != 0)
      m_ui.monoLineEdit->setText(locale.toString(mono, 'f', 
						 MXP_OLIGOMER_DEC_PLACES));

    if (avg != 0)
      m_ui.avgLineEdit->setText(locale.toString(avg, 'f', 
						MXP_OLIGOMER_DEC_PLACES));

    if(mono || avg)
      {
        // If we are setting masses directly from here, then that means
        // that the formula line edit must be disabled.
        m_ui.formulaCheckBox->setCheckState(Qt::Unchecked);
        m_ui.startFormulaLineEdit->setDisabled(true);
      }
    else
      {
        // No masses are being preseeded. So let the user the full
        // opportunity ot enter a formula.
        m_ui.formulaCheckBox->setCheckState(Qt::Checked);
        m_ui.startFormulaLineEdit->setDisabled(false);
      }
    
    m_ui.srcIonizeRuleChargeSpinBox->setRange(1, 1000000000);
    m_ui.srcIonizeRuleLevelSpinBox->setRange(0, 1000000000);
  
    m_ui.destIonizeRuleChargeSpinBox->setRange(1, 1000000000);
    m_ui.destIonizeRuleStartLevelSpinBox->setRange(0, 1000000000);
    m_ui.destIonizeRuleEndLevelSpinBox->setRange(0, 1000000000);


    m_ui.srcIonizeRuleFormulaLineEdit->setText(m_ionizeRule.formula());
    m_ui.srcIonizeRuleChargeSpinBox->setValue(m_ionizeRule.charge());
    m_ui.srcIonizeRuleLevelSpinBox->setValue(m_ionizeRule.level());
    
    m_ui.destIonizeRuleFormulaLineEdit->setText(m_ionizeRule.formula());
    m_ui.destIonizeRuleChargeSpinBox->setValue(m_ionizeRule.charge());
    m_ui.destIonizeRuleStartLevelSpinBox->setValue(m_ionizeRule.level());
    m_ui.destIonizeRuleEndLevelSpinBox->setValue(m_ionizeRule.level());


    // The results-exporting menus. ////////////////////////////////

    QStringList comboBoxItemList;

    comboBoxItemList 
      << tr("To Clipboard") 
      << tr("To File")
      << tr("Select File")
      << tr("Calculate spectrum");
  
    m_ui.exportResultsComboBox->addItems(comboBoxItemList);
  
    connect(m_ui.exportResultsComboBox,
	     SIGNAL(activated(int)),
	     this,
	     SLOT(exportResults(int)));

    mpa_resultsString = new QString();
  
    //////////////////////////////////// The results-exporting menus.
  

    QSettings settings 
     (static_cast<Application *>(qApp)->configSettingsFilePath(), 
       QSettings::IniFormat);
  
    settings.beginGroup("mz_calculation_dlg");

    restoreGeometry(settings.value("geometry").toByteArray());

    m_ui.ponderableSplitter->
      restoreState(settings.value("ponderableSplitter").toByteArray());
  
    settings.endGroup();

    connect(m_ui.calculatePushButton,
	     SIGNAL(clicked()),
	     this,
	     SLOT(calculate()));

    connect(m_ui.formulaCheckBox,
            SIGNAL(toggled(bool)),
            this,
            SLOT(formulaCheckBoxToggled(bool)));
  }


  MzCalculationDlg::~MzCalculationDlg()
  {
    delete mpa_resultsString;
  
    delete mpa_mzTreeViewModel;
  
    delete mpa_mzProxyModel;

    freeIonizableList();

    while(!m_oligomerList.isEmpty())
      delete m_oligomerList.takeFirst();
  }


  void 
  MzCalculationDlg::closeEvent(QCloseEvent *event)
  {
    if (event)
      printf("%s", "");
  
    QSettings settings 
     (static_cast<Application *>(qApp)->configSettingsFilePath(), 
       QSettings::IniFormat);
  
    settings.beginGroup("mz_calculation_dlg");

    settings.setValue("geometry", saveGeometry());
  
    settings.setValue("ponderableSplitter", 
		       m_ui.ponderableSplitter->saveState());

    settings.endGroup();
  }


  void
  MzCalculationDlg::setupTreeView()
  {
    // Model stuff all thought for sorting.
    mpa_mzTreeViewModel = 
      new MzCalculationTreeViewModel(&m_ionizableList, this);
  
    mpa_mzProxyModel = new MzCalculationTreeViewSortProxyModel(this);
    mpa_mzProxyModel->setSourceModel(mpa_mzTreeViewModel);
  
    m_ui.mzTreeView->setModel(mpa_mzProxyModel);
    m_ui.mzTreeView->setParentDlg(this);
    mpa_mzTreeViewModel->setTreeView(m_ui.mzTreeView);
  }


  void
  MzCalculationDlg::formulaCheckBoxToggled(bool checked)
  {
    // If checked, then the user is responsible for entering a valid
    // formula.

    if(checked)
      {
        m_ui.startFormulaLineEdit->setDisabled(true);
      }
    else
      {
        m_ui.startFormulaLineEdit->setDisabled(false);
      }
  }
  
 
  void
  MzCalculationDlg::calculate()
  {
    // The calculation can be accomplished in two different manners:
    //
    // 1. Starting from a formula, in which case it will be necessary
    // to know what is the ionization status of the analyte for which
    // the formula is entered. This status is found in the source
    // ionizeRule. Once this is done, the masses can be computed for
    // the formula and are programmatically set to the mono and avg
    // m/z line edit widgets.
    // 
    // 2. Starting from mono and avg m/z values immediately. Uncheck
    // the Formula check box in this case.
    
    // First get all the data for the source ionizable.

    // Because this function can be called multiple times from the
    // same dialog window, make sure that the formula is cleared.
    m_formula.clear();
    
    // The source ionizeRule. Start with this because we'll need right
    // away.
    IonizeRule srcIonizeRule;
    if(!getSrcIonizeRuleData(&srcIonizeRule))
      return;
    
    // Are we being given a formula to start with?
    
    bool fromFormula = false;
    
    if(m_ui.formulaCheckBox->checkState() == Qt::Checked)
      {
        QString text = m_ui.startFormulaLineEdit->text();
        
        if(text.isEmpty())
          {
            // Then the masses must be null.
            m_ui.monoLineEdit->setText("0.000");
            m_ui.avgLineEdit->setText("0.000");
            
            return;
          }
        
        Formula formula(text);

        // Do not bother storing all the atoms in the formula, this is
        // only a check (false param below).  m_atomList is a reference to
        // the atom list of the polymer chemistry definition currently
        // used in the caller calculator window.

        if (!formula.validate(m_atomList, false, true))
          {
            m_ui.monoLineEdit->setText("0.000");
            m_ui.avgLineEdit->setText("0.000");

            QMessageBox::warning 
              (this, 
               tr("massXpert - m/z Ratio Calculator"),
               tr("%1@%2\n"
                  "Failed to validate the formula.")
               .arg(__FILE__)
               .arg(__LINE__),
               QMessageBox::Ok);
            
            return;
          }
    
        // qDebug() << __FILE__ << __LINE__
        //          << "Formula:" << formula.formula() << "validated." ;

        // At this point we know we could actually validate the formula,
        // so do that work with the member formula:

        // We want to validate the formula and in the mean time construct
        // the list of all the AtomCount objects(first true), and since
        // the formula is reused we also ensure that that list is reset
        // (second true). m_atomList is a reference to the atom list of
        // the polymer chemistry definition currently used in the caller
        // calculator window.

        m_formula.setFormula(text);
        m_formula.validate(m_atomList, true, true);
    
        // Calculation of the m/z corresponding to the formula requires
        // dividing the mass obtained for the formula by the product
        // (level * unitary) of the ionizerule.

        int charge = srcIonizeRule.charge() * srcIonizeRule.level();
    
        double monoMass = 0;
        double avgMass = 0;
    
        // It is impossible that we have an error here, since the formula
        // was previously validated.
        if (!m_formula.accountMasses(m_atomList, &monoMass, &avgMass, 1))
          qFatal("Fatal error at %s@%d.Aborting.", __FILE__, __LINE__);

        if(charge)
          {
            monoMass /= charge;
            avgMass /= charge;
          }
    
        // Great, now show the data.

        Application *application = static_cast<Application *>(qApp);
    
        QString mz;
    
        mz = application->locale().
          toString(monoMass, 'f', MXP_OLIGOMER_DEC_PLACES);
        // qDebug() << __FILE__ << __LINE__
        //          << "monoMass:" << monoMass;
        
        m_ui.monoLineEdit->setText(mz);

        mz = application->locale().
          toString(avgMass, 'f', MXP_OLIGOMER_DEC_PLACES);
        // qDebug() << __FILE__ << __LINE__
        //          << "avgMass:" << avgMass;

        m_ui.avgLineEdit->setText(mz);

        fromFormula = true;
      }

    // Whatever the way we get the mon/avg mz values, make a
    // ponderable with them.
    Ponderable *ponderable = getSourcePonderable();
    if (!ponderable)
      return;
    
    // Create an Ionizable with empty masses but with proper
    // IonizeRule. Note that we check if the IonizeRule has a non-0
    // level, in which case we tell so to the caller with a true
    // boolean.
    Ionizable ionizable(mp_polChemDef, "NOT_SET", *ponderable,
                        srcIonizeRule,
			(srcIonizeRule.level() ? true : false));
    
    // At this point the ionizable is fully qualified.

    // No longer in use.
    delete ponderable;

    // Now, because we want to be able to compute elemental
    // compositions for each destination ionization level, we have to
    // kraft an elemental representation of what the molecule
    // is. This, only if the mz values above were calculated with a
    // provided formula.
    if(fromFormula)
      {
        // The text string in the startFormulaLineEdit widget
        // corresponds to the molecular entity already ionized with
        // srcIonizeRule (if level is non-zero). So, to go back to
        // non-ionized elemental composition, we have to remove from
        // the formula the equivalent atoms of the source ionizerule
        // multiplied by ionization level.

        // qDebug() << __FILE__ << __LINE__
        //          << "Formula before deionization:" << m_formula.text();
        
        m_formula.accountInList(srcIonizeRule.formula(),
                                m_atomList, 
                                -1 * srcIonizeRule.level());
        
        // qDebug() << __FILE__ << __LINE__
        //          << "Formula after deionization:" << m_formula.text();
      }
        
    // At this point, the source ionizable is filled with data. And we
    // know the data are correct because everything was validated.

    // The destination ionizeRule(note that the m_level member datum
    // is not set as it will be generated during the for loop later;
    // this does not impede validation of the IonizeRule).
    IonizeRule destIonizeRule;
    if (!getDestIonizeRuleData(&destIonizeRule))
      return;
    
    // Get the destination start/end ionization levels and make sure
    // they are in an increasing order.
    int startLevel = m_ui.destIonizeRuleStartLevelSpinBox->value();
    int endLevel = m_ui.destIonizeRuleEndLevelSpinBox->value();
    
    if (startLevel > endLevel)
      {
	int temp = endLevel;
	endLevel = startLevel;
	startLevel = temp;
      }

    // Empty the treeView model, so that we can put fresh data in
    // it. Same for the oligomer list!

    mpa_mzTreeViewModel->removeAll();

    while(!m_oligomerList.isEmpty())
      delete m_oligomerList.takeFirst();
        
    for (int level = startLevel ; level < endLevel + 1; ++level)
      {
	destIonizeRule.setLevel(level);

	// Reionize the ionizable.
	if(ionizable.ionize(destIonizeRule) == -1)
	  {
	    QMessageBox::warning 
	     (this, 
	       tr("massXpert - m/z Ratio Calculator"),
	       tr("%1@%2\n"
		   "Failed to perform reionization.")
	       .arg(__FILE__)
	       .arg(__LINE__),
	       QMessageBox::Ok);
	    
	    return;
          }
        
        Ionizable *newIonizable = new Ionizable(ionizable);
        
        mpa_mzTreeViewModel->addIonizable(newIonizable);
        
	// Kraft an oligomer, that we'll set apart in case the user
	// wants to compute a spectrum to simulate the charge envelope
	// peaks.

        Oligomer *oligomer = new Oligomer(ionizable,
                                          CalcOptions(),
                                          -1, -1);

        // qDebug() << __FILE__ << __LINE__
        //          << "oligomer->charge:" << oligomer->charge();

        // If we are working from a formula, then compute the new
        // formula for the present ionization status and create a
        // property with that new formula to append to the list of
        // properties in the oligomer. 

        if(fromFormula)
          {
            Formula newFormula(m_formula);
            
            newFormula.accountInList(destIonizeRule.formula(),
                                     m_atomList, destIonizeRule.level());
            
            // qDebug() << __FILE__ << __LINE__
            //          << "Formula after reionization (level)" 
            //          << level
            //          << newFormula.text();
            
            
            StringProp *prop = new StringProp("ELEMENTAL_COMPOSITION",
                                              newFormula.text());
        
            oligomer->appendProp(static_cast<Prop *>(prop));
          }
                
	m_oligomerList.append(oligomer);
      }
  }
  

  bool
  MzCalculationDlg::getSrcIonizeRuleData(IonizeRule *ionizeRule)
  {
    Q_ASSERT(ionizeRule);

    ionizeRule->setFormula(m_ui.srcIonizeRuleFormulaLineEdit->text());
    ionizeRule->setCharge(m_ui.srcIonizeRuleChargeSpinBox->value());
    ionizeRule->setLevel(m_ui.srcIonizeRuleLevelSpinBox->value());

    if (!ionizeRule->validate(mp_polChemDef->atomList()))
      {
	QMessageBox::warning 
	 (this, 
	   tr("massXpert - m/z Ratio Calculator"),
	   tr("%1@%2\n"
	       "Failed to validate initial ionization rule.")
	   .arg(__FILE__)
	   .arg(__LINE__),
	   QMessageBox::Ok);

	return false;
      }
  
    return true;
  }


  bool
  MzCalculationDlg::getDestIonizeRuleData(IonizeRule *ionizeRule)
  {
    Q_ASSERT(ionizeRule);
    
    ionizeRule->setFormula(m_ui.destIonizeRuleFormulaLineEdit->text());
    ionizeRule->setCharge(m_ui.destIonizeRuleChargeSpinBox->value());
    // The level is dealt with in another function, as it might
    // encompass more than one single value(see calculate()). Note
    // that if level is 0, this does not invalidate the ionizeRule.

    if (!ionizeRule->validate(mp_polChemDef->atomList()))
      {
	QMessageBox::warning 
	 (this, 
	   tr("massXpert - m/z Ratio Calculator"),
	   tr("%1@%2\n"
	       "Failed to validate target ionization rule.")
	   .arg(__FILE__)
	   .arg(__LINE__),
	   QMessageBox::Ok);

	return false;
      }
    
    return true;
  }


  Ponderable *
  MzCalculationDlg::getSourcePonderable()
  {
    Application *application = static_cast<Application *>(qApp);
    QLocale locale = application->locale();
    
    QString text;
    
    double mono = 0;
    double avg = 0;

    bool ok = false;
    
    // Mono mass
    text = m_ui.monoLineEdit->text();
    
    if (text.isEmpty())
      mono = 0;
    else
      {
	mono = locale.toDouble(text, &ok);

	if(!mono && !ok)
	  {
	    QMessageBox::warning 
	     (this, 
	       tr("massXpert - m/z Ratio Calculator"),
	       tr("%1@%2\n"
		   "Failed to read mono mass.")
	       .arg(__FILE__)
	       .arg(__LINE__),
	       QMessageBox::Ok);
	    
	    return 0;
	  }
      }

    // Avg mass
    text = m_ui.avgLineEdit->text();
    
    if (text.isEmpty())
      avg = 0;
    else
      {
	avg = locale.toDouble(text, &ok);

	if(!avg && !ok)
	  {
	    QMessageBox::warning 
	     (this, 
	       tr("massXpert - m/z Ratio Calculator"),
	       tr("%1@%2\n"
		   "Failed to read mono mass.")
	       .arg(__FILE__)
	       .arg(__LINE__),
	       QMessageBox::Ok);
	    
	    return 0;
	  }
      }

    // At this point we can allocate the Ponderable:
    return new Ponderable(mono, avg);
  }
  

  void 
  MzCalculationDlg::freeIonizableList()
  {
    while(!m_ionizableList.isEmpty())
      delete m_ionizableList.takeFirst();
  }


  // The results-exporting functions. ////////////////////////////////
  // The results-exporting functions. ////////////////////////////////
  // The results-exporting functions. ////////////////////////////////
  void
  MzCalculationDlg::exportResults(int index)
  {
    // Remember that we had set up the combobox with the following strings:
    // << tr("To &Clipboard") 
    // << tr("To &File")
    // << tr("&Select File");

    if (index == 0)
      {
	exportResultsClipboard();
      }
    else if (index == 1)
      {
	exportResultsFile();
      }
    else if (index == 2)
      {
	selectResultsFile();
      }
    else if (index == 3)
      {
	calculateSpectrum();
      }
    else 
      Q_ASSERT(0);
  
  }


  void
  MzCalculationDlg::prepareResultsTxtString()
  {
    Application *application = static_cast<Application *>(qApp);
    QLocale locale = application->locale();

    mpa_resultsString->clear();
  
    *mpa_resultsString += QObject::tr("# \n"
                                      "# ---------------------------\n"
                                      "# m/z Calculations: \n"
                                      "# ---------------------------\n");
    
    QString value;
  
    *mpa_resultsString += QObject::tr("\nSource conditions:\n"
				       "------------------\n");
  
    *mpa_resultsString += QObject::tr("Mono mass: %1")
      .arg(m_ui.monoLineEdit->text());
  
    *mpa_resultsString += QObject::tr(" - Avg mass: %1\n")
      .arg(m_ui.avgLineEdit->text());
    
    *mpa_resultsString += QObject::tr("Ionization formula: %1\n")
      .arg(m_ui.srcIonizeRuleFormulaLineEdit->text());
  
    *mpa_resultsString += QObject::tr("Ionization charge: %1 - ")
      .arg(m_ui.srcIonizeRuleChargeSpinBox->value());
  
    *mpa_resultsString += QObject::tr("Ionization level: %1\n")
      .arg(m_ui.srcIonizeRuleLevelSpinBox->value());
  
    *mpa_resultsString += QObject::tr("\nDestination conditions:\n"
				       "-----------------------\n");

    *mpa_resultsString += QObject::tr("Ionization formula: %1\n")
      .arg(m_ui.destIonizeRuleFormulaLineEdit->text());
  
    *mpa_resultsString += QObject::tr("Ionization charge: %1 - ")
      .arg(m_ui.destIonizeRuleChargeSpinBox->value());
  
    *mpa_resultsString += QObject::tr("Start level: %1 - ")
      .arg(m_ui.destIonizeRuleStartLevelSpinBox->value());

    *mpa_resultsString += QObject::tr("End level: %1\n\n\n")
      .arg(m_ui.destIonizeRuleEndLevelSpinBox->value());
  
    MzCalculationTreeViewModel *model = 
      static_cast<MzCalculationTreeViewModel *>(m_ui.mzTreeView->model());
    Q_ASSERT(model);
  
    int rowCount = model->rowCount();
    //   qDebug() << __FILE__ << __LINE__ << "rowCount" << rowCount;
    if (!rowCount)
      return;

    QString mzString;

    for (int iter = 0; iter < rowCount; ++iter)
      {
	QModelIndex currentIndex = model->index(iter,
						 MZ_CALC_LEVEL_COLUMN,
						 QModelIndex());
	Q_ASSERT(currentIndex.isValid());

	// We have to make sure we translate correctly from
	// locale-based textual representation of double numbers
	// to real double numbers.
	
	bool ok = false;
	
	QString valueString = 
	  model->data(currentIndex, Qt::DisplayRole).toString();
	
	double value = locale.toDouble(valueString, &ok);
	
	if (!value && !ok)
	  qFatal("Fatal error at %s@%d. Program aborted.",
		 __FILE__, __LINE__);
	
	mzString += QObject::tr("Level: %1 -- ")
	  .arg(locale.toString(value, 'f', MXP_PH_PKA_DEC_PLACES));
	
	currentIndex = model->index(iter,
				     MZ_CALC_MONO_COLUMN,
				     QModelIndex());
	Q_ASSERT(currentIndex.isValid());
      
	ok = false;
	
	valueString = 
	  model->data(currentIndex, Qt::DisplayRole).toString();
	
	value = locale.toDouble(valueString, &ok);
	
	if (!value && !ok)
	  qFatal("Fatal error at %s@%d. Program aborted.",
		 __FILE__, __LINE__);
	
	mzString += QObject::tr("Mono: %1 -- ")
	  .arg(locale.toString(value, 'f', MXP_OLIGOMER_DEC_PLACES));
      
	currentIndex = model->index(iter,
				     MZ_CALC_AVG_COLUMN,
				     QModelIndex());
	Q_ASSERT(currentIndex.isValid());

	ok = false;
	
	valueString = 
	  model->data(currentIndex, Qt::DisplayRole).toString();
	
	value = locale.toDouble(valueString, &ok);
	
	if (!value && !ok)
	  qFatal("Fatal error at %s@%d. Program aborted.",
		 __FILE__, __LINE__);
	
	mzString += QObject::tr("Avg: %1")
	  .arg(locale.toString(value, 'f', MXP_OLIGOMER_DEC_PLACES));

	mzString += ("\n");
      }

    *mpa_resultsString += mzString;
  }


  bool 
  MzCalculationDlg::exportResultsClipboard()
  {
    prepareResultsTxtString();
  
    QClipboard *clipboard = QApplication::clipboard();

    clipboard->setText(*mpa_resultsString, QClipboard::Clipboard);
  
    return true;
  }


  bool 
  MzCalculationDlg::exportResultsFile()
  {
    if (m_resultsFilePath.isEmpty())
      {
	if(!selectResultsFile())
	  return false;
      }
  
    QFile file(m_resultsFilePath);
  
    if (!file.open(QIODevice::WriteOnly | QIODevice::Append))
      {
	QMessageBox::information(this, 
				  tr("massXpert - Export Data"),
				  tr("Failed to open file in append mode."),
				  QMessageBox::Ok);
	return false;
      }
  
    QTextStream stream(&file);
    stream.setCodec("UTF-8");

    prepareResultsTxtString();
  
    stream << *mpa_resultsString;
  
    file.close();

    return true;
  }


  bool 
  MzCalculationDlg::selectResultsFile()
  {
    m_resultsFilePath = 
      QFileDialog::getSaveFileName(this, tr("Select File To Export Data To"),
				    QDir::homePath(),
				    tr("Data files(*.dat *.DAT)"));
  
    if (m_resultsFilePath.isEmpty())
      return false;

    return true;
  }


  bool
  MzCalculationDlg::calculateSpectrum()
  {
    SpectrumCalculationDlg *dlg = 
      new SpectrumCalculationDlg(this, 
                                 mp_polChemDef->atomList(),
                                 MXP_SPECTRUM_CALCULATION_MODE_SPECTRUM);
    
    // We now have to prepare the land for the calculations.

    dlg->setOligomerList(&m_oligomerList);
        
    // We really need that the dialog be set modal because we want to
    // be able to access all the atom and oligomer data freely and
    // durably.
    dlg->setModal(true);
    
    dlg->show();

    return true;
  }
 
  //////////////////////////////////// The results-exporting functions.
  //////////////////////////////////// The results-exporting functions.
  //////////////////////////////////// The results-exporting functions.

} // namespace massXpert
