/* 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>
#include <QSettings>


/////////////////////// Local includes
#include <massxpert/gui/MonomerModificationDlg.hpp>


namespace msXpSmassXpert
{

MonomerModificationDlg::MonomerModificationDlg(SequenceEditorWnd *editorWnd,
                                               /* no polymer **/
                                               /* no PolChemDef **/
                                               const QString &settingsFilePath)
  : AbstractSeqEdWndDependentDlg(editorWnd,
                                 0, /*polymer **/
                                 0, /*polChemDef **/
                                 settingsFilePath,
                                 "MonomerModificationDlg",
                                 "Monomer modification")
{

  if(!initialize())
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);
}


MonomerModificationDlg::~MonomerModificationDlg()
{
}


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

  populateAvailableModifList();
  populateMonomerList();
  populateModifAndModifiedMonomerLists();

  updateSelectionData();
  if(m_coordinateList.size() >= 1)
    m_ui.currentSelectionRadioButton->setChecked(true);

  connect(m_ui.updateCurrentSelectionDataPushButton,
          SIGNAL(clicked()),
          this,
          SLOT(updateSelectionData()));

  connect(m_ui.modifiedMonomerListWidget,
          SIGNAL(itemSelectionChanged()),
          this,
          SLOT(modifiedMonomerListWidgetItemSelectionChanged()));

  connect(m_ui.modifListWidget,
          SIGNAL(itemSelectionChanged()),
          this,
          SLOT(modifListWidgetItemSelectionChanged()));

  m_ui.displayAllModifsCheckBox->setChecked(true);
  connect(m_ui.displayAllModifsCheckBox,
          SIGNAL(stateChanged(int)),
          this,
          SLOT(displayAllModifsChanged(int)));

  connect(m_ui.modifyPushButton, SIGNAL(clicked()), this, SLOT(modify()));

  connect(m_ui.unmodifyPushButton, SIGNAL(clicked()), this, SLOT(unmodify()));

  connect(this, SIGNAL(rejected()), this, SLOT(close()));

  return true;
}


void
MonomerModificationDlg::readSettings()
{
  QSettings settings(m_configSettingsFilePath, QSettings::IniFormat);
  settings.beginGroup(m_wndTypeName);
  restoreGeometry(settings.value("geometry").toByteArray());
  m_ui.hSplitter->restoreState(settings.value("hSplitter").toByteArray());
  m_ui.vSplitter->restoreState(settings.value("vSplitter").toByteArray());
  settings.endGroup();
}


void
MonomerModificationDlg::writeSettings()
{

  QSettings settings(m_configSettingsFilePath, QSettings::IniFormat);
  settings.beginGroup(m_wndTypeName);
  settings.setValue("geometry", saveGeometry());
  settings.setValue("hSplitter", m_ui.hSplitter->saveState());
  settings.setValue("vSplitter", m_ui.vSplitter->saveState());
  settings.endGroup();
}


bool
MonomerModificationDlg::populateAvailableModifList()
{
  PolChemDef *polChemDef = mp_editorWnd->polChemDef();
  Q_ASSERT(polChemDef);

  for(int iter = 0; iter < polChemDef->modifList().size(); ++iter)
    {
      Modif *modif = polChemDef->modifList().at(iter);
      Q_ASSERT(modif);

      m_ui.availableModifListWidget->addItem(modif->name());
    }

  return true;
}


bool
MonomerModificationDlg::populateModifAndModifiedMonomerLists()
{
  // We'll need a pointer to the polymer sequence.
  Polymer *polymer = mp_editorWnd->polymer();

  m_ui.modifiedMonomerListWidget->clear();
  m_ui.modifListWidget->clear();

  // For all the monomers in the polymer sequence, check which
  // modifications they bear. If any, add their name and monomer
  // pointer to the list.

  for(int iter = 0; iter < polymer->size(); ++iter)
    {
      const Monomer *monomer = polymer->at(iter);

      QList<Modif *> *list = monomer->modifList();

      if(!list || list->isEmpty())
        continue;

      // At this point we know the monomer is modified. Let's take the
      // opportunity to add this monomer to the list of modified
      // monomers.

      QString text = QString("%1/%2/%3")
                       .arg(monomer->code())
                       .arg(iter + 1)
                       .arg((quintptr)monomer);

      m_ui.modifiedMonomerListWidget->addItem(text);

      for(int jter = 0; jter < list->size(); ++jter)
        {
          Modif *modif = list->at(jter);

          QString text = QString("%1/%2/%3/%4/%5")
                           .arg(modif->name())
                           .arg(monomer->code())
                           .arg(iter + 1)
                           .arg((quintptr)modif)
                           .arg((quintptr)monomer);

          // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << "()"
          //<< "monomer ptr:" << monomer
          //<< "modif ptr:" << modif
          //<< text;

          m_ui.modifListWidget->addItem(text);
        }
    }

  return true;
}


bool
MonomerModificationDlg::populateModifiedMonomerList()
{
  // We'll need a pointer to the polymer sequence.
  Polymer *polymer = mp_editorWnd->polymer();

  m_ui.modifiedMonomerListWidget->clear();

  // For all the monomers in the polymer sequence, check if they are
  // modified. If so, add their code position and monomer pointer to
  // the list.

  for(int iter = 0; iter < polymer->size(); ++iter)
    {
      const Monomer *monomer = polymer->at(iter);

      QList<Modif *> *list = monomer->modifList();

      if(!list || list->isEmpty())
        continue;

      QString text = QString("%1/%2/%3")
                       .arg(monomer->code())
                       .arg(iter + 1)
                       .arg((quintptr)monomer);

      // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << "()"
      //<< "monomer ptr:" << monomer
      //<< text;

      m_ui.modifiedMonomerListWidget->addItem(text);
    }

  return true;
}


bool
MonomerModificationDlg::populateModifList(bool all)
{
  // We'll need a pointer to the polymer sequence.
  Polymer *polymer = mp_editorWnd->polymer();

  // First-off remove all the items.
  m_ui.modifListWidget->clear();

  if(all)
    {
      // For all the monomers in the polymer sequence, check which
      // modifications they bear. If any, add their name and monomer
      // pointer to the list.

      for(int iter = 0; iter < polymer->size(); ++iter)
        {
          const Monomer *monomer = polymer->at(iter);

          QList<Modif *> *modifList = monomer->modifList();

          if(!modifList || modifList->isEmpty())
            continue;

          for(int jter = 0; jter < modifList->size(); ++jter)
            {
              Modif *modif = modifList->at(jter);

              QString text = QString("%1/%2/%3/%4/%5")
                               .arg(modif->name())
                               .arg(monomer->code())
                               .arg(iter + 1)
                               .arg((quintptr)modif)
                               .arg((quintptr)monomer);

              // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << "()"
              //<< "monomer ptr:" << monomer
              //<< "modif ptr:" << modif
              //<< text;

              m_ui.modifListWidget->addItem(text);
            }
        }
    }
  else
    {
      // We are interested only in the modifs for the currently
      // selected cross-linked monomers(if any) in the
      // modifiedMonomerListWidget.

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

      if(!selectedList.size())
        return true;

      for(int iter = 0; iter < selectedList.size(); ++iter)
        {
          QListWidgetItem *item = selectedList.at(iter);

          // What's the text of the item ?
          QString text = item->text();

          // The string is in the form "code/pos/monomerPtr"

          QStringList stringList =
            text.split('/', QString::SkipEmptyParts, Qt::CaseSensitive);

          // The monomer position is the second string in the list.
          bool ok = false;
          int pos = stringList.at(1).toInt(&ok);

          if(!pos && !ok)
            return false;

          // What if the sequence changed and the monomer is no more
          // in a valid range? We want to avoid a crash. See below for
          // an even better sanity check.
          if(pos - 1 < 0 || pos > polymer->size())
            {
              QMessageBox::warning(this,
                                   tr("massXpert - Modify monomers"),
                                   tr("%1@%2\n"
                                      "The monomer index does not correspond "
                                      "to a valid polymer sequence range.\n"
                                      "Avoid modifying the sequence while "
                                      "working with modifications.")
                                     .arg(__FILE__)
                                     .arg(__LINE__),
                                   QMessageBox::Ok);

              populateModifAndModifiedMonomerLists();

              return false;
            }

          // The monomer(quintptr) pointer is the third string in the list.
          ok                        = false;
          quintptr pointerCastToInt = stringList.at(2).toLongLong(&ok, 10);
          Monomer *monomer = reinterpret_cast<Monomer *>(pointerCastToInt);

          // Sanity check, are we dealing with the same monomer now
          // compared to the one of which the item was displayed when
          // the window was opened ?
          if(monomer != polymer->at(pos - 1))
            {
              QMessageBox::warning(this,
                                   tr("massXpert - Modify monomers"),
                                   tr("%1@%2\n"
                                      "The monomer selected does not "
                                      "correspond to a valid sequence "
                                      "monomer.\n"
                                      "Avoid modifying the sequence while "
                                      "working with modifications.")
                                     .arg(__FILE__)
                                     .arg(__LINE__),
                                   QMessageBox::Ok);

              populateModifAndModifiedMonomerLists();

              return false;
            }

          // Iterate in the monomer's modifications and for each one
          // create a new item.

          QList<Modif *> *modifList = monomer->modifList();

          // It is not possible that the monomer has no modif,
          // otherwise how come would it be listed in the list of
          // modified monomers.

          Q_ASSERT(modifList && !modifList->isEmpty());

          for(int jter = 0; jter < modifList->size(); ++jter)
            {
              Modif *modif = modifList->at(jter);

              QString text = QString("%1/%2/%3/%4/%5")
                               .arg(modif->name())
                               .arg(monomer->code())
                               .arg(pos)
                               .arg((quintptr)modif)
                               .arg((quintptr)monomer);

              m_ui.modifListWidget->addItem(text);
            }
        }
      // End of
      // for (int iter = 0; iter < selectedList.size(); ++iter)
    }
  // End of else , that is we only display modifs for selected
  // monomers.

  return true;
}


bool
MonomerModificationDlg::populateMonomerList()
{
  PolChemDef *polChemDef = mp_editorWnd->polChemDef();
  Q_ASSERT(polChemDef);

  for(int iter = 0; iter < polChemDef->monomerList().size(); ++iter)
    {
      Monomer *monomer = polChemDef->monomerList().at(iter);
      Q_ASSERT(monomer);

      QString text = monomer->code() + '=' + monomer->name();

      m_ui.monomerListWidget->addItem(text);
    }

  return true;
}


void
MonomerModificationDlg::modifiedMonomerListWidgetItemSelectionChanged()
{
  // When an item is selected in the list of modified monomers, then
  // that means that the user does not want *all* the modifs to be
  // listed.

  m_ui.displayAllModifsCheckBox->setChecked(false);

  // Update the modif list data by listing only the modifs of the
  // currently selected monomer.

  populateModifList(false);
}


void
MonomerModificationDlg::modifListWidgetItemSelectionChanged()
{
  //   qDebug() << __FILE__ << __LINE__
  // 	    << "MonomerModificationDlg::"
  //     "modifListWidgetItemSelectionChanged()";
}


void
MonomerModificationDlg::displayAllModifsChanged(int checkState)
{
  // When checked, we should list all the modifs in the
  // modifListWidget, and not only the modifs for the currently
  // selected modified monomer.

  if(checkState == Qt::Checked)
    populateModifList(true);
  else
    populateModifList(false);
}


bool
MonomerModificationDlg::updateSelectionData()
{
  // There might be more than one region selections. So get all
  // these coordinates !

  bool res =
    mp_editorWnd->mpa_editorGraphicsView->selectionIndices(&m_coordinateList);

  if(res)
    {
      // If there are more than one region selection or if there is
      // one region selection but spanning more than one monomer,
      // then set the target to be "current selected sequence".

      if(m_coordinateList.size() > 1)
        {
          // Apparently there are multiple regions selected.

          m_ui.currentSelectionLineEdit->setText(
            m_coordinateList.positionsAsText());
        }
      else
        {
          Coordinates *coordinates = m_coordinateList.first();

          if(coordinates->start() == coordinates->end())
            {

              // Construct a string with both the monomer code and
              // its position in the sequence.

              Polymer *polymer = mp_editorWnd->polymer();
              const Monomer *monomer =
                polymer->monomerList().at(coordinates->start());

              QString text = tr("%1 at pos. %2")
                               .arg(monomer->code())
                               .arg(coordinates->start() + 1);

              m_ui.currentSelectionLineEdit->setText(text);
            }
          else
            m_ui.currentSelectionLineEdit->setText(
              m_coordinateList.positionsAsText());
        }
    }

  // Return if there was a selection(multiple-region or not) or
  // not.
  return res;
}


int
MonomerModificationDlg::prepareIndicesList()
{
  Polymer *polymer = mp_editorWnd->polymer();

  m_indicesList.clear();

  bool isSelectionPresent = updateSelectionData();

  if(m_ui.currentSelectionRadioButton->isChecked())
    {
      // If there is no selection.
      if(!isSelectionPresent)
        return 0;

      // Now, for each Coordinates in the CoordinateList, append the
      // indices...

      for(int iter = 0; iter < m_coordinateList.size(); ++iter)
        {
          Coordinates *coordinates = m_coordinateList.at(iter);

          for(int iter = coordinates->start(); iter < coordinates->end() + 1;
              ++iter)
            m_indicesList.append(iter);
        }
    }
  else if(m_ui.sameCodeRadioButton->isChecked())
    {
      // Get the code of the currently selected monomer.
      if(!isSelectionPresent)
        return 0;

      if(m_coordinateList.size() > 1)
        return 0;

      Coordinates *coordinates = m_coordinateList.at(0);

      if(coordinates->start() != coordinates->end())
        return 0;

      QString code = polymer->monomerList().at(coordinates->start())->code();

      for(int iter = 0; iter < polymer->monomerList().size(); ++iter)
        {
          const Monomer *monomer = polymer->monomerList().at(iter);
          Q_ASSERT(monomer);

          if(monomer->code() == code)
            m_indicesList.append(iter);
        }
    }
  else if(m_ui.fromListRadioButton->isChecked())
    {
      QList<QListWidgetItem *> selectedList =
        m_ui.monomerListWidget->selectedItems();

      if(!selectedList.size())
        return 0;

      for(int iter = 0; iter < selectedList.size(); ++iter)
        {
          QListWidgetItem *item = selectedList.at(iter);

          QString text = item->text();

          int index = text.indexOf('=');
          Q_ASSERT(index > 0);

          QString code = text.left(index);

          for(int jter = 0; jter < polymer->monomerList().size(); ++jter)
            {
              const Monomer *monomer = polymer->monomerList().at(jter);
              Q_ASSERT(monomer);

              if(monomer->code() == code)
                m_indicesList.append(jter);
            }
        }
    }
  else if(m_ui.allRadioButton->isChecked())
    {
      for(int iter = 0; iter < polymer->monomerList().size(); ++iter)
        m_indicesList.append(iter);
    }
  else
    {
      QMessageBox::warning(this,
                           tr("massXpert - Modify monomers"),
                           tr("No target is selected."),
                           QMessageBox::Ok);
      return 0;
    }

  //   qDebug() << "Indices:" << m_indicesList.size();

  return m_indicesList.size();
}


bool
MonomerModificationDlg::parseModifDefinition(Modif *modif)
{
  Q_ASSERT(modif);

  QString text = m_ui.modifNameLineEdit->text();

  modif->setName(text);

  text = m_ui.modifFormulaLineEdit->text();

  modif->setFormula(text);

  // Attention, we have to compute the masses of the modif !

  if(!modif->calculateMasses())
    return false;

  text = m_ui.modifTargetsLineEdit->text();

  modif->setTargets(text);

  if(!modif->validate())
    return false;

  return true;
}


void
MonomerModificationDlg::modify()
{
  QStringList errorList;

  Polymer *polymer = mp_editorWnd->polymer();

  // There are two ways to perform a modification: either select one
  // modification from the list of available modifications as defined
  // in the polymer chemistry definition, or perform a quick and dirty
  // modification definition in the dialog.

  QString text;

  Modif *modif = new Modif(polymer->polChemDef(), "NOT_SET", "NOT_SET");

  if(m_ui.defineModifGroupBox->isChecked())
    {
      // The user wants to use a self-defined modification.

      if(!parseModifDefinition(modif))
        {
          QMessageBox::warning(this,
                               tr("massXpert - Modify monomers"),
                               tr("The defined modification failed "
                                  "to parse."),
                               QMessageBox::Ok);
          return;
        }

      // At this point the modification is correct.
    }
  else
    {
      // Get the modification currently selected.
      QList<QListWidgetItem *> selectedList =
        m_ui.availableModifListWidget->selectedItems();

      if(selectedList.size() != 1)
        {
          QMessageBox::warning(this,
                               tr("massXpert - Modify monomers"),
                               tr("No modification is selected "
                                  "in the list."),
                               QMessageBox::Ok);
          return;
        }

      text = selectedList.at(0)->text();
      Q_ASSERT(!text.isEmpty());

      // With the name of the modification get to the modif proper.

      bool res = polymer->polChemDef()->modif(text, modif);
      if(!res)
        qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

      // At this point the modification is correct. Set a bool to true
      // to know later that the modif was from the polChemDef.
    }

  // Is the modification work with allowed overriding of the target
  // and the max count limitations?
  bool override = m_ui.overrideLimitationsCheckBox->isChecked();

  // Construct a list of all the indices where the modification should
  // apply.
  if(!prepareIndicesList())
    return;

  for(int iter = 0; iter < m_indicesList.size(); ++iter)
    {
      int index = m_indicesList.at(iter);

      const Monomer *monomer = polymer->monomerList().at(index);

      // Append the position and code of the currently iterated
      // monomer. We will remove that string if the result is not
      // bad. If the result below is bad, then the corresponding error
      // will have been appended and we will not remove anything.

      errorList.append(
        tr("Pos. %1: %2 --------------").arg(iter + 1).arg(monomer->code()));

      // Upon modification, the monomer takes ownership of the modif,
      // so we have to allocate one each time using the template
      // prepared above.

      Modif *newModif = new Modif(*modif);

      int ret =
        const_cast<Monomer *>(monomer)->modify(newModif, override, errorList);

      // The modification went ok, which means we can remove the last
      // string that we prudentially added in case an error was to be
      // output. If the modification failed(ret == false) we do not
      // perform any modification for the monomer dealt-with.

      // qDebug() << __FILE__ << __LINE__
      // << "Modifying cast monomer ptr: " << pointerCastToInt
      // << "with Monomer* ptr: " << monomer;

      if(!ret)
        {
          errorList.append("\n");
        }
      else
        {
          errorList.removeLast();

          mp_editorWnd->setWindowModified(true);

          // We have to make sure that the vignette knows for which
          // chemical entity it is created.

          ret = mp_editorWnd->mpa_editorGraphicsView->modifyVignetteAt(
            index, newModif);

          Q_ASSERT(ret);
        }
    }
  // End of
  // for (int iter = 0; iter < m_indicesList.size(); ++iter)

  m_ui.messagesTextEdit->append(
    tr("New operation: modify with %1\n").arg(modif->name()) +
    errorList.join(""));

  // At this point we can delete the modif template.
  delete modif;

  populateModifAndModifiedMonomerLists();

  mp_editorWnd->updateWholeSequenceMasses(true);
  mp_editorWnd->updateSelectedSequenceMasses(true);

  //  mp_editorWnd->mpa_editorGraphicsView->updateSequence();
}


void
MonomerModificationDlg::unmodify()
{
  // We only can unmodify in the following cases:

  // If one or more modifications are selected in the
  // m_ui.modifListWidget(which is a multiple selection list).

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

  if(!selectedList.size())
    return;

  // For each item in the selection list, get the item, get to the
  // monomer and perform the unmodification.

  for(int iter = 0; iter < selectedList.size(); ++iter)
    {
      QListWidgetItem *item = selectedList.at(iter);

      // Get the text which is of the form

      // "Phosphorylation/S/12/136958312/136678312",

      // which is the name of the modification, the code of the
      // modified monomer and its position, the pointer to
      // the modification and finally the pointer to
      // the modified monomer".

      QString text = item->text();

      QStringList stringList =
        text.split('/', QString::SkipEmptyParts, Qt::CaseSensitive);

      bool ok = false;

      // The modif(quintptr) pointer is the third string in the list.
      quintptr pointerCastToInt = stringList.at(3).toLongLong(&ok, 10);
      Modif *modif              = reinterpret_cast<Modif *>(pointerCastToInt);

      // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << "()"
      //<< "modif ptr str:" << stringList.at(3)
      //<< "modif ptr:" << modif;

      // The monomer(quintptr) pointer is the fourth string in the
      // list.
      ok               = false;
      pointerCastToInt = stringList.at(4).toLongLong(&ok, 10);
      Monomer *monomer = reinterpret_cast<Monomer *>(pointerCastToInt);

      // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << "()"
      //<< "monomer ptr str:" << stringList.at(4)
      //<< "monomer ptr:" << monomer;

      // qDebug() << __FILE__ << __LINE__
      // << "Demodifying cast monomer ptr: " << pointerCastToInt
      // << "with Monomer* ptr: " << monomer;

      // Because the sequence might have changed since the moment
      // this window was opened, we should make sure the monomer to
      // unmodify is still there !

      int index = mp_editorWnd->polymer()->monomerIndex(monomer);

      if(index == -1)
        {
          // Hmmm, the monomer is no more in the sequence, the
          // sequence has been modified and the monomer has been
          // erased.

          QMessageBox::warning(this,
                               tr("massXpert - Modify monomers"),
                               tr("%1@%2\n"
                                  "The monomer to unmodify does not exist "
                                  "in the sequence anymore.\n"
                                  "Avoid modifying the sequence while "
                                  "working with modifications.")
                                 .arg(__FILE__)
                                 .arg(__LINE__),
                               QMessageBox::Ok);

          populateModifAndModifiedMonomerLists();

          return;
        }


      // The monomer index at the time the monomer modification window
      // was opened. Note that the index might change if the user
      // edits the sequence after having opened *this window. Also,
      // note that for the reader to use the value in the list item,
      // it was set as a position, not an index, which means we have
      // to remove one from the value.
      //	ok = false;
      //	int index = stringList.at(2).toInt(&ok) - 1;


      // At this point we know which modification we have to remove
      // and from which monomer.

      int ret = monomer->unmodify(modif);
      if(!ret)
        qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

      mp_editorWnd->setWindowModified(true);

      // At this point, we have to make sure we remove the
      // modification vignette.

      // Note that because a monomer might be modified more than once,
      // and with the same modification, we ought to remove the proper
      // vignette.

      bool val =
        mp_editorWnd->mpa_editorGraphicsView->unmodifyVignetteAt(index, modif);

      if(!val)
        qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

      //      mp_editorWnd->mpa_editorGraphicsView->updateSequence();
    }

  populateModifAndModifiedMonomerLists();

  mp_editorWnd->updateWholeSequenceMasses(true);
  mp_editorWnd->updateSelectedSequenceMasses(true);
}

} // namespace msXpSmassXpert
