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

   http://www.filomace.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>


/////////////////////// Local includes
#include "application.hpp"
#include "cleaveSpecDefDlg.hpp"
#include "polChemDef.hpp"
#include "polChemDefWnd.hpp"


namespace massXpert
{

  CleaveSpecDefDlg::CleaveSpecDefDlg(PolChemDef *polChemDef, 
				      PolChemDefWnd *polChemDefWnd)
  {
    Q_ASSERT(polChemDef);
    mp_polChemDef = polChemDef;
    mp_list = polChemDef->cleaveSpecListPtr();
  
    Q_ASSERT(polChemDefWnd);
    mp_polChemDefWnd = polChemDefWnd;
  
    if (!initialize())
      {
	qDebug() << "Failed to initialize the cleavage definition window";
      }
  }


  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);

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

    settings.setValue("geometry", saveGeometry());

    settings.setValue("splitter", m_ui.splitter->saveState());

    settings.endGroup();
  }

  

  CleaveSpecDefDlg::~CleaveSpecDefDlg()
  {
  }

  
  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());
      }

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

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

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


    // 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;
	  }
      }
  
    {
      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;
	  }
      }
  
    {
      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("");
  }


  void 
  CleaveSpecDefDlg::setModified()
  {
    mp_polChemDefWnd->setWindowModified(true); 
  }


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

} // namespace massXpert
