/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2018 Filippo Rusconi
 *
 * http://www.msxpertsuite.org
 *
 * This file is part of the msXpertSuite project.
 *
 * The msXpertSuite project is the successor of the massXpert project. This
 * project now includes various independent modules:
 *
 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 program. If not, see <http://www.gnu.org/licenses/>.
 *
 * END software license
 */


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


/////////////////////// Local includes
#include <massxpert/gui/CleaveSpecDefDlg.hpp>
#include <massxpert/nongui/PolChemDef.hpp>
#include <massxpert/gui/PolChemDefWnd.hpp>


namespace msXpSmassXpert
{

CleaveSpecDefDlg::CleaveSpecDefDlg(PolChemDef *polChemDef,
                                   PolChemDefWnd *polChemDefWnd,
                                   const QString &settingsFilePath)
  : AbstractPolChemDefDependentDlg{
      polChemDef,
      polChemDefWnd,
      settingsFilePath,
      "CleaveSpecDefDlg",
      "massXpert: Cleavage specification definition"}
{
  mp_list = polChemDef->cleaveSpecListPtr();

  if(!initialize())
    qFatal(
      "Fatal error at %s@%d. Failed to initialize the %s window. Program "
      "aborted.",
      __FILE__,
      __LINE__,
      m_wndTypeName.toLatin1().data());
}


CleaveSpecDefDlg::~CleaveSpecDefDlg()
{
}


void
CleaveSpecDefDlg::closeEvent(QCloseEvent *event)
{
  // No real close, because we did not ask that
  // close==destruction. Thus we only hide the dialog remembering its
  // position and size.


  mp_polChemDefWnd->m_ui.cleavagePushButton->setChecked(false);

  writeSettings();
}


void
CleaveSpecDefDlg::readSettings()
{
  QSettings settings(m_settingsFilePath, QSettings::IniFormat);

  settings.beginGroup(m_wndTypeName);
  restoreGeometry(settings.value("geometry").toByteArray());
  m_ui.splitter->restoreState(settings.value("splitter").toByteArray());
  settings.endGroup();
}


void
CleaveSpecDefDlg::writeSettings()
{

  QSettings settings(m_settingsFilePath, QSettings::IniFormat);

  settings.beginGroup(m_wndTypeName);
  restoreGeometry(settings.value("geometry").toByteArray());
  settings.setValue("splitter", m_ui.splitter->saveState());
  settings.endGroup();
}


bool
CleaveSpecDefDlg::initialize()
{
  m_ui.setupUi(this);

  // Set all the cleaveSpecs to the list widget.

  for(int iter = 0; iter < mp_list->size(); ++iter)
    {
      CleaveSpec *cleaveSpec = mp_list->at(iter);

      m_ui.cleaveSpecListWidget->addItem(cleaveSpec->name());
    }

  readSettings();

  // Make the connections.

  connect(m_ui.addCleaveSpecPushButton,
          SIGNAL(clicked()),
          this,
          SLOT(addCleaveSpecPushButtonClicked()));

  connect(m_ui.removeCleaveSpecPushButton,
          SIGNAL(clicked()),
          this,
          SLOT(removeCleaveSpecPushButtonClicked()));

  connect(m_ui.moveUpCleaveSpecPushButton,
          SIGNAL(clicked()),
          this,
          SLOT(moveUpCleaveSpecPushButtonClicked()));

  connect(m_ui.moveDownCleaveSpecPushButton,
          SIGNAL(clicked()),
          this,
          SLOT(moveDownCleaveSpecPushButtonClicked()));

  connect(m_ui.addCleaveRulePushButton,
          SIGNAL(clicked()),
          this,
          SLOT(addCleaveRulePushButtonClicked()));

  connect(m_ui.removeCleaveRulePushButton,
          SIGNAL(clicked()),
          this,
          SLOT(removeCleaveRulePushButtonClicked()));

  connect(m_ui.moveUpCleaveRulePushButton,
          SIGNAL(clicked()),
          this,
          SLOT(moveUpCleaveRulePushButtonClicked()));

  connect(m_ui.moveDownCleaveRulePushButton,
          SIGNAL(clicked()),
          this,
          SLOT(moveDownCleaveRulePushButtonClicked()));

  connect(m_ui.applyCleaveSpecPushButton,
          SIGNAL(clicked()),
          this,
          SLOT(applyCleaveSpecPushButtonClicked()));

  connect(m_ui.applyCleaveRulePushButton,
          SIGNAL(clicked()),
          this,
          SLOT(applyCleaveRulePushButtonClicked()));

  connect(m_ui.validatePushButton,
          SIGNAL(clicked()),
          this,
          SLOT(validatePushButtonClicked()));

  connect(m_ui.cleaveSpecListWidget,
          SIGNAL(itemSelectionChanged()),
          this,
          SLOT(cleaveSpecListWidgetItemSelectionChanged()));

  connect(m_ui.cleaveRuleListWidget,
          SIGNAL(itemSelectionChanged()),
          this,
          SLOT(cleaveRuleListWidgetItemSelectionChanged()));

  return true;
}


void
CleaveSpecDefDlg::addCleaveSpecPushButtonClicked()
{
  // We are asked to add a new cleaveSpec. We'll add it right after the
  // current item.

  // Returns -1 if the list is empty.
  int index = m_ui.cleaveSpecListWidget->currentRow();

  CleaveSpec *newCleaveSpec =
    new CleaveSpec(mp_polChemDef, tr("Type Spec Name"), tr("Type Pattern"));

  mp_list->insert(index, newCleaveSpec);
  m_ui.cleaveSpecListWidget->insertItem(index, newCleaveSpec->name());

  setModified();

  // Needed so that the setCurrentRow() call below actually set the
  // current row!
  if(index <= 0)
    index = 0;

  m_ui.cleaveSpecListWidget->setCurrentRow(index);

  // Erase cleaveRule data that might be left over by precedent current
  // cleaveSpec.
  updateCleaveRuleDetails(0);

  // Set the focus to the lineEdit that holds the name of the cleaveSpec.
  m_ui.nameLineEdit->setFocus();
  m_ui.nameLineEdit->selectAll();
}


void
CleaveSpecDefDlg::removeCleaveSpecPushButtonClicked()
{
  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveSpecListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;

  // Get the index of the current cleaveSpec.
  int index = m_ui.cleaveSpecListWidget->currentRow();

  QListWidgetItem *item = m_ui.cleaveSpecListWidget->takeItem(index);
  delete item;

  CleaveSpec *cleaveSpec = mp_list->takeAt(index);
  Q_ASSERT(cleaveSpec);
  delete cleaveSpec;

  setModified();

  // If there are remaining items, we want to set the next item the
  // currentItem. If not, then, the currentItem should be the one
  // preceding the cleaveSpec that we removed.

  if(m_ui.cleaveSpecListWidget->count() >= index + 1)
    {
      m_ui.cleaveSpecListWidget->setCurrentRow(index);
      cleaveSpecListWidgetItemSelectionChanged();
    }

  // If there are no more items in the cleaveSpec list, remove all the items
  // from the cleaveRuleList.

  if(!m_ui.cleaveSpecListWidget->count())
    {
      m_ui.cleaveRuleListWidget->clear();
      clearAllDetails();
    }
}


void
CleaveSpecDefDlg::moveUpCleaveSpecPushButtonClicked()
{
  // Move the current row to one index less.

  // If no cleaveSpec is selected, just return.

  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveSpecListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;

  // Get the index of the cleaveSpec and the cleaveSpec itself.
  int index = m_ui.cleaveSpecListWidget->currentRow();

  // If the item is already at top of list, do nothing.
  if(!index)
    return;

  mp_list->move(index, index - 1);

  QListWidgetItem *item = m_ui.cleaveSpecListWidget->takeItem(index);

  m_ui.cleaveSpecListWidget->insertItem(index - 1, item);
  m_ui.cleaveSpecListWidget->setCurrentRow(index - 1);
  cleaveSpecListWidgetItemSelectionChanged();

  setModified();
}


void
CleaveSpecDefDlg::moveDownCleaveSpecPushButtonClicked()
{
  // Move the current row to one index less.

  // If no cleaveSpec is selected, just return.

  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveSpecListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;

  // Get the index of the cleaveSpec and the cleaveSpec itself.
  int index = m_ui.cleaveSpecListWidget->currentRow();

  // If the item is already at bottom of list, do nothing.
  if(index == m_ui.cleaveSpecListWidget->count() - 1)
    return;

  mp_list->move(index, index + 1);

  QListWidgetItem *item = m_ui.cleaveSpecListWidget->takeItem(index);
  m_ui.cleaveSpecListWidget->insertItem(index + 1, item);
  m_ui.cleaveSpecListWidget->setCurrentRow(index + 1);
  cleaveSpecListWidgetItemSelectionChanged();

  setModified();
}


void
CleaveSpecDefDlg::addCleaveRulePushButtonClicked()
{
  // We are asked to add a new cleaveRule. We'll add it right after the
  // current item. Note however, that one cleaveSpec has to be selected.

  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveSpecListWidget->selectedItems();

  if(selectedList.size() != 1)
    {
      QMessageBox::information(this,
                               tr("massXpert - Cleavage definition"),
                               tr("Please, select a cleavage first."),
                               QMessageBox::Ok);
      return;
    }

  // Get the index of the current cleaveSpec so that we know to which cleaveSpec
  // we'll add the cleaveRule.
  int index = m_ui.cleaveSpecListWidget->currentRow();

  // What's the actual cleaveSpec?
  CleaveSpec *cleaveSpec = mp_list->at(index);
  Q_ASSERT(cleaveSpec);

  // Allocate the new cleaveRule.
  CleaveRule *newCleaveRule =
    new CleaveRule(mp_polChemDef, tr("Type Rule Name"));

  // Get the row index of the current cleaveRule item. Returns -1 if the
  // list is empty.
  index = m_ui.cleaveRuleListWidget->currentRow();

  m_ui.cleaveRuleListWidget->insertItem(index, newCleaveRule->name());

  // Needed so that the setCurrentRow() call below actually set the
  // current row!
  if(index <= 0)
    index = 0;

  cleaveSpec->ruleList()->insert(index, newCleaveRule);

  m_ui.cleaveRuleListWidget->setCurrentRow(index);

  setModified();

  // Set the focus to the lineEdit that holds the mass of the cleaveRule.
  m_ui.cleaveRuleNameLineEdit->setFocus();
  m_ui.cleaveRuleNameLineEdit->selectAll();
}


void
CleaveSpecDefDlg::removeCleaveRulePushButtonClicked()
{
  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveRuleListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;


  // Get the index of the current cleaveSpec so that we know from
  // which cleaveSpec we'll remove the cleaveRule.
  int index = m_ui.cleaveSpecListWidget->currentRow();

  CleaveSpec *cleaveSpec = mp_list->at(index);
  Q_ASSERT(cleaveSpec);

  // Get the index of the current cleaveRule.
  index = m_ui.cleaveRuleListWidget->currentRow();

  // First remove the item from the listwidget because that will have
  // cleaveRuleListWidgetItemSelectionChanged() triggered and we have to
  // have the item in the cleaveRule list in the cleaveSpec! Otherwise a crash
  // occurs.
  QListWidgetItem *item = m_ui.cleaveRuleListWidget->takeItem(index);
  delete item;

  // Remove the cleaveRule from the cleaveSpec proper.

  QList<CleaveRule *> *cleaveRuleList = cleaveSpec->ruleList();

  CleaveRule *cleaveRule = cleaveRuleList->at(index);

  cleaveSpec->ruleList()->removeAt(index);
  delete cleaveRule;

  // If there are remaining items, we want to set the next item the
  // currentItem. If not, then, the currentItem should be the one
  // preceding the cleaveSpec that we removed.

  if(m_ui.cleaveRuleListWidget->count() >= index + 1)
    {
      m_ui.cleaveRuleListWidget->setCurrentRow(index);
      cleaveRuleListWidgetItemSelectionChanged();
    }

  // If there are no more items in the cleaveRule list, remove all the
  // details.

  if(!m_ui.cleaveRuleListWidget->count())
    {
      updateCleaveRuleDetails(0);
    }
  else
    {
    }

  setModified();
}


void
CleaveSpecDefDlg::moveUpCleaveRulePushButtonClicked()
{
  // Move the current row to one index less.

  // If no cleaveRule is selected, just return.

  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveRuleListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;

  // Get the cleaveSpec to which the cleaveRule belongs.
  int index              = m_ui.cleaveSpecListWidget->currentRow();
  CleaveSpec *cleaveSpec = mp_list->at(index);

  // Get the index of the current cleaveRule item.
  index = m_ui.cleaveRuleListWidget->currentRow();

  // If the item is already at top of list, do nothing.
  if(!index)
    return;

  // Get the cleaveRule itself from the cleaveSpec.
  CleaveRule *cleaveRule = cleaveSpec->ruleList()->at(index);

  cleaveSpec->ruleList()->removeAt(index);
  cleaveSpec->ruleList()->insert(index - 1, cleaveRule);

  QListWidgetItem *item = m_ui.cleaveRuleListWidget->takeItem(index);
  m_ui.cleaveRuleListWidget->insertItem(index - 1, item);
  m_ui.cleaveRuleListWidget->setCurrentRow(index - 1);
  cleaveRuleListWidgetItemSelectionChanged();

  setModified();
}


void
CleaveSpecDefDlg::moveDownCleaveRulePushButtonClicked()
{
  // Move the current row to one index less.

  // If no cleaveRule is selected, just return.

  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveRuleListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;

  // Get the cleaveSpec to which the cleaveRule belongs.
  int index              = m_ui.cleaveSpecListWidget->currentRow();
  CleaveSpec *cleaveSpec = mp_list->at(index);

  // Get the index of the current cleaveRule item.
  index = m_ui.cleaveRuleListWidget->currentRow();

  // If the item is already at top of list, do nothing.
  if(index == m_ui.cleaveRuleListWidget->count() - 1)
    return;

  // Get the cleaveRule itself from the cleaveSpec.
  CleaveRule *cleaveRule = cleaveSpec->ruleList()->at(index);

  cleaveSpec->ruleList()->removeAt(index);
  cleaveSpec->ruleList()->insert(index + 1, cleaveRule);

  QListWidgetItem *item = m_ui.cleaveRuleListWidget->takeItem(index);
  m_ui.cleaveRuleListWidget->insertItem(index + 1, item);
  m_ui.cleaveRuleListWidget->setCurrentRow(index + 1);
  cleaveRuleListWidgetItemSelectionChanged();

  setModified();
}


void
CleaveSpecDefDlg::applyCleaveSpecPushButtonClicked()
{
  // We are asked to apply the data for the cleaveSpec.

  // If no cleaveSpec is selected, just return.

  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveSpecListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;

  // Get the index of the current cleaveSpec item.
  int index = m_ui.cleaveSpecListWidget->currentRow();

  CleaveSpec *cleaveSpec = mp_list->at(index);

  // We do not want more than one cleaveSpec by the same name or the same
  // symbol.

  QString editName    = m_ui.nameLineEdit->text();
  QString editPattern = m_ui.patternLineEdit->text();

  // If a cleaveSpec is found in the list with the same name, and that
  // cleaveSpec is not the one that is current in the cleaveSpec list,
  // then we are making a double entry, which is not allowed.

  int nameRes = CleaveSpec::isNameInList(editName, *mp_list);
  if(nameRes != -1 && nameRes != index)
    {
      QMessageBox::warning(this,
                           tr("massXpert - Cleavage definition"),
                           tr("A cleavage with same name exists already."),
                           QMessageBox::Ok);
      return;
    }

  CleaveSpec newSpec(mp_polChemDef, "NOT_SET", editPattern);
  if(!newSpec.parse())
    {
      QMessageBox::warning(this,
                           tr("massXpert - Cleavage definition"),
                           tr("The cleavage failed to parse."),
                           QMessageBox::Ok);
      return;
    }

  cleaveSpec->setName(editName);
  cleaveSpec->setPattern(editPattern);

  // Update the list widget item.

  QListWidgetItem *item = m_ui.cleaveSpecListWidget->currentItem();
  item->setData(Qt::DisplayRole, cleaveSpec->name());

  setModified();
}


void
CleaveSpecDefDlg::applyCleaveRulePushButtonClicked()
{
  // We are asked to apply the data for the cleaveRule.

  // If no cleaveRule is selected, just return.

  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveRuleListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;

  // Get the cleaveSpec to which the cleaveRule belongs.
  int index              = m_ui.cleaveSpecListWidget->currentRow();
  CleaveSpec *cleaveSpec = mp_list->at(index);

  // Get the index of the current cleaveRule item.
  index = m_ui.cleaveRuleListWidget->currentRow();

  // Get the cleaveRule itself from the cleaveSpec.
  CleaveRule *cleaveRule = cleaveSpec->ruleList()->at(index);

  QString editName = m_ui.cleaveRuleNameLineEdit->text();

  QString leftCode    = m_ui.leftCodeLineEdit->text();
  QString leftFormula = m_ui.leftFormulaLineEdit->text();

  QString rightCode    = m_ui.rightCodeLineEdit->text();
  QString rightFormula = m_ui.rightFormulaLineEdit->text();

  // If a cleaveRule is found in the list with the same name, and that
  // cleaveRule is not the one that is current in the cleaveRule list,
  // then we are making a double entry, which is not allowed.

  int nameRes = CleaveRule::isNameInList(editName, *cleaveSpec->ruleList());
  if(nameRes != -1 && nameRes != index)
    {
      QMessageBox::warning(this,
                           tr("massXpert - Cleavage definition"),
                           tr("A cleavage rule with same name "
                              "exists already."),
                           QMessageBox::Ok);
      return;
    }

  if(!leftCode.isEmpty())
    {
      const QList<Monomer *> &monomerList = mp_polChemDef->monomerList();

      if(Monomer::isCodeInList(leftCode, monomerList) == -1)
        {
          QMessageBox::warning(this,
                               tr("massXpert - Cleavage definition"),
                               tr("The left code is not known."),
                               QMessageBox::Ok);
          return;
        }
    }

  {
    msXpSlibmass::Formula formula(leftFormula);

    if(!formula.validate(mp_polChemDef->atomList()))
      {
        QMessageBox::warning(this,
                             tr("massXpert - Monomer definition"),
                             tr("The formula failed to validate."),
                             QMessageBox::Ok);
        return;
      }
  }


  if(!rightCode.isEmpty())
    {
      const QList<Monomer *> &monomerList = mp_polChemDef->monomerList();

      if(Monomer::isCodeInList(rightCode, monomerList) == -1)
        {
          QMessageBox::warning(this,
                               tr("massXpert - Cleavage definition"),
                               tr("The right code is not known."),
                               QMessageBox::Ok);
          return;
        }
    }

  {
    msXpSlibmass::Formula formula(rightFormula);

    if(!formula.validate(mp_polChemDef->atomList()))
      {
        QMessageBox::warning(this,
                             tr("massXpert - Monomer definition"),
                             tr("The formula failed to validate."),
                             QMessageBox::Ok);
        return;
      }
  }

  cleaveRule->setName(editName);

  cleaveRule->setLeftCode(leftCode);
  cleaveRule->setLeftFormula(leftFormula);

  cleaveRule->setRightCode(rightCode);
  cleaveRule->setRightFormula(rightFormula);

  // Update the list widget item.

  QListWidgetItem *item = m_ui.cleaveRuleListWidget->currentItem();
  item->setData(Qt::DisplayRole, cleaveRule->name());

  setModified();
}


bool
CleaveSpecDefDlg::validatePushButtonClicked()
{
  QStringList errorList;

  // All we have to do is validate the cleaveSpec definition. For that we'll
  // go in the listwidget items one after the other and make sure that
  // everything is fine and that colinearity is perfect between the
  // cleaveSpec list and the listwidget.

  int itemCount = m_ui.cleaveSpecListWidget->count();

  if(itemCount != mp_list->size())
    {
      errorList << QString(
        tr("\nThe number of cleavages in the list widget \n"
           "and in the list of cleavages is not identical.\n"));

      QMessageBox::warning(this,
                           tr("massXpert - Cleavage definition"),
                           errorList.join("\n"),
                           QMessageBox::Ok);
      return false;
    }

  for(int iter = 0; iter < mp_list->size(); ++iter)
    {
      QListWidgetItem *item = m_ui.cleaveSpecListWidget->item(iter);

      CleaveSpec *cleaveSpec = mp_list->at(iter);

      if(item->text() != cleaveSpec->name())
        errorList << QString(tr("\nCleavage at index %1 has not the same\n"
                                "name as the list widget item at the\n"
                                "same index.\n")
                               .arg(iter));

      if(!cleaveSpec->validate())
        errorList << QString(
          tr("\nCleavage at index %1 failed to validate.\n").arg(iter));
    }

  if(errorList.size())
    {
      QMessageBox::warning(this,
                           tr("massXpert - Cleavage definition"),
                           errorList.join("\n"),
                           QMessageBox::Ok);
      return false;
    }
  else
    {
      QMessageBox::warning(this,
                           tr("massXpert - Cleavage definition"),
                           ("Validation: success\n"),
                           QMessageBox::Ok);
    }

  return true;
}


void
CleaveSpecDefDlg::cleaveSpecListWidgetItemSelectionChanged()
{
  // The cleaveSpec item has changed. Empty the cleaveRule list and update its
  // contents. Update the details for the cleaveSpec.

  // The list is a single-item-selection list.

  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveSpecListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;

  // Get the index of the current cleaveSpec.
  int index = m_ui.cleaveSpecListWidget->currentRow();

  CleaveSpec *cleaveSpec = mp_list->at(index);
  Q_ASSERT(cleaveSpec);

  // Set the data of the cleaveSpec to their respective widgets.
  updateCleaveSpecIdentityDetails(cleaveSpec);

  // The list of cleaveRules
  m_ui.cleaveRuleListWidget->clear();

  for(int iter = 0; iter < cleaveSpec->ruleList()->size(); ++iter)
    {
      CleaveRule *cleaveRule = cleaveSpec->ruleList()->at(iter);

      m_ui.cleaveRuleListWidget->addItem(cleaveRule->name());
    }

  if(!m_ui.cleaveRuleListWidget->count())
    updateCleaveRuleDetails(0);
  else
    {
      // And now select the first row in the cleaveRule list widget.
      m_ui.cleaveRuleListWidget->setCurrentRow(0);
    }
}


void
CleaveSpecDefDlg::cleaveRuleListWidgetItemSelectionChanged()
{
  // The cleaveRule item has changed. Update the details for the cleaveRule.

  // The list is a single-item-selection list.

  QList<QListWidgetItem *> selectedList =
    m_ui.cleaveRuleListWidget->selectedItems();

  if(selectedList.size() != 1)
    return;

  // Get the index of the current cleaveSpec.
  int index = m_ui.cleaveSpecListWidget->currentRow();

  // Find the cleaveRule object in the list of cleaveRules.
  CleaveSpec *cleaveSpec = mp_list->at(index);
  Q_ASSERT(cleaveSpec);

  // Get the index of the current cleaveRule.
  index = m_ui.cleaveRuleListWidget->currentRow();

  // Get the cleaveRule that is currently selected from the cleaveSpec's list
  // of cleaveRules.
  CleaveRule *cleaveRule = cleaveSpec->ruleList()->at(index);
  Q_ASSERT(cleaveRule);

  // Set the data of the cleaveRule to their respective widgets.
  updateCleaveRuleDetails(cleaveRule);
}


void
CleaveSpecDefDlg::updateCleaveSpecIdentityDetails(CleaveSpec *cleaveSpec)
{
  if(cleaveSpec)
    {
      m_ui.nameLineEdit->setText(cleaveSpec->name());
      m_ui.patternLineEdit->setText(cleaveSpec->pattern());
    }
  else
    {
      m_ui.nameLineEdit->setText("");
      m_ui.patternLineEdit->setText("");
    }
}


void
CleaveSpecDefDlg::updateCleaveRuleDetails(CleaveRule *cleaveRule)
{
  if(cleaveRule)
    {
      m_ui.cleaveRuleNameLineEdit->setText(cleaveRule->name());

      m_ui.leftCodeLineEdit->setText(cleaveRule->leftCode());
      m_ui.leftFormulaLineEdit->setText(cleaveRule->leftFormula().text());

      m_ui.rightCodeLineEdit->setText(cleaveRule->rightCode());
      m_ui.rightFormulaLineEdit->setText(cleaveRule->rightFormula().text());
    }
  else
    {
      m_ui.cleaveRuleNameLineEdit->setText("");

      m_ui.leftCodeLineEdit->setText("");
      m_ui.leftFormulaLineEdit->setText("");

      m_ui.rightCodeLineEdit->setText("");
      m_ui.rightFormulaLineEdit->setText("");
    }
}


void
CleaveSpecDefDlg::clearAllDetails()
{
  m_ui.nameLineEdit->setText("");
  m_ui.patternLineEdit->setText("");

  m_ui.cleaveRuleNameLineEdit->setText("");

  m_ui.leftCodeLineEdit->setText("");
  m_ui.leftFormulaLineEdit->setText("");

  m_ui.rightCodeLineEdit->setText("");
  m_ui.rightFormulaLineEdit->setText("");
}


// VALIDATION
bool
CleaveSpecDefDlg::validate()
{
  return validatePushButtonClicked();
}

} // namespace msXpSmassXpert
