Logo Search packages:      
Sourcecode: massxpert version File versions

sequenceEditorWnd.cpp

/* 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 <QtGui>
#include <QtXml>
#include <QtGlobal>


/////////////////////// Local includes
#include "globals.hpp"
#include "application.hpp"
#include "sequenceEditorWnd.hpp"
#include "sequenceEditorGraphicsView.hpp"
#include "monomerModificationDlg.hpp"
#include "polymerModificationDlg.hpp"
#include "monomerCrossLinkDlg.hpp"
#include "cleavageDlg.hpp"
#include "fragmentationDlg.hpp"
#include "massSearchDlg.hpp"
#include "sequencePurificationDlg.hpp"
#include "mzCalculationDlg.hpp"
#include "compositionsDlg.hpp"
#include "pkaPhPi.hpp"
#include "pkaPhPiDataParser.hpp"
#include "pkaPhPiDlg.hpp"
#include "crossLink.hpp"
#include "crossLinkerSpec.hpp"
#include "decimalPlacesOptionsDlg.hpp"


namespace massXpert
{

  SequenceEditorWnd::SequenceEditorWnd()
  {
    mpa_polymer = 0;
  
    m_forciblyClose = false;
    m_noDelistWnd = false;
    m_postInitialized = false;
  
    if (!preInitialize())
      {
      QMessageBox::warning(0, 
                        tr("massXpert - Polymer Sequence Editor"),
                        tr("Failed to pre-initialize the polymer "
                          "sequence editor window."),
                        QMessageBox::Ok);
      }
  
    readSettings();
  
    show();
  }


  SequenceEditorWnd::~SequenceEditorWnd()
  {
    delete mpa_resultsString;

    while(!m_propList.isEmpty())
      delete m_propList.takeFirst();

    delete mpa_editorGraphicsScene;
    mpa_editorGraphicsScene = 0;
    
    delete mpa_editorGraphicsView;
    mpa_editorGraphicsView = 0;
    
    delete mpa_polymer;
  }


  void 
  SequenceEditorWnd::writeSettings()
  {
    QSettings settings 
     (static_cast<Application *>(qApp)->configSettingsFilePath(), 
       QSettings::IniFormat);
  
    settings.beginGroup("sequence_editor_wnd");
    settings.setValue("geometry", saveGeometry());
    settings.setValue("vignetteSize", 
                   mpa_editorGraphicsView->requestedVignetteSize());

    settings.setValue("hSplitterSize", m_ui.hSplitter->saveState());
    settings.setValue("vSplitterSize", m_ui.vSplitter->saveState());

    settings.endGroup();
  }


  void 
  SequenceEditorWnd::readSettings() 
  {
    QSettings settings 
     (static_cast<Application *>(qApp)->configSettingsFilePath(), 
       QSettings::IniFormat);

    settings.beginGroup("sequence_editor_wnd");

    restoreGeometry(settings.value("geometry").toByteArray());
    int vignetteSize = settings.value("vignetteSize", 32).toInt();
    mpa_editorGraphicsView->requestVignetteSize(vignetteSize);
    m_ui.vignetteSizeSpinBox->setValue(vignetteSize);

    m_ui.vSplitter->
      restoreState(settings.value("vSplitterSize").toByteArray());
    m_ui.hSplitter->
      restoreState(settings.value("hSplitterSize").toByteArray());

    settings.endGroup();
  }


  void
  SequenceEditorWnd::closeEvent(QCloseEvent *event)
  {
    Application *application = static_cast<Application *>(qApp);

    // We are asked to close the window even if it has unsaved data.
    if (m_forciblyClose)
      {
      m_forciblyClose = false;
      
      // We have to delist the window.
      if(!m_noDelistWnd)
        {
          m_noDelistWnd = false;
          int index = application->sequenceEditorWndList()->indexOf(this);
        
          application->sequenceEditorWndList()->takeAt(index);
        }
      
      writeSettings();
      
      event->accept();
      
      return;
      }

    if (maybeSave())
      {
      // We are asked not to remove this window from the list of all
      // the polymer chemistry definition windows. This occurs when
      // all the windows are closed in a raw in the application
      // object.

      if(m_noDelistWnd)
        {
          m_noDelistWnd = false;
        
          writeSettings();

          event->accept();
        
          return;
        }
      
      // We must remove this window from the application's list of
      // such windows:

      int index = application->sequenceEditorWndList()->indexOf(this);
      
      application->sequenceEditorWndList()->takeAt(index);
  
      writeSettings();
      
      event->accept();
      }
    else 
      {
      event->ignore();
      }
  }


  void
  SequenceEditorWnd::focusInEvent(QFocusEvent *event)
  {
    if (!event)
      printf("%s", "");

    Application *application = static_cast<Application *>(qApp);
    application->setLastFocusedWnd(this);
  }


  void
  SequenceEditorWnd::focusOutEvent(QFocusEvent *event)
  {
    if (!event)
      printf("%s", "");
  
    Application *application = static_cast<Application *>(qApp);
    application->setLastFocusedWnd(0);
  }



  // The results-exporting functions. ////////////////////////////////
  // The results-exporting functions. ////////////////////////////////
  // The results-exporting functions. ////////////////////////////////

  void
  SequenceEditorWnd::prepareResultsTxtString()
  {
    mpa_resultsString->clear();
  
    // First whole sequence
    bool entities =(m_calcOptions.monomerEntities() &
                 MXT_MONOMER_CHEMENT_MODIF);
  
    QString *sequence = 
      mpa_polymer->monomerText(-1, -1, entities);
  
    *mpa_resultsString += QObject::tr("\n---------------------------\n"
                               "Sequence Data: %1\n"
                               "---------------------------\n"
                               "Name: %1\n"
                               "Code : %2\n"
                               "File path: %3\n"
                               "Sequence: %4\n")
      .arg(mpa_polymer->name())
      .arg(mpa_polymer->code())
      .arg(mpa_polymer->filePath())
      .arg(*sequence);
  
    delete sequence;
  
    *mpa_resultsString += QObject::tr("\nIonization rule:\n");
  
    *mpa_resultsString += QObject::tr("Formula: %1 - ")
      .arg(m_ionizeRule.formula());
  
    *mpa_resultsString += QObject::tr("Charge: %1 - ")
      .arg(m_ionizeRule.charge());
  
    *mpa_resultsString += QObject::tr("Level: %1\n")
      .arg(m_ionizeRule.level());
  
    *mpa_resultsString += QObject::tr("\nCalculation options:\n");

    if (entities)
      *mpa_resultsString += QObject::tr("Account monomer modifs: yes\n");
    else
      *mpa_resultsString += QObject::tr("Account monomer modifs: no\n");
      
    entities =(m_calcOptions.monomerEntities() &
            MXT_MONOMER_CHEMENT_CROSS_LINK);

    if (entities)
      *mpa_resultsString += QObject::tr("Account cross-links: yes\n");
    else
      *mpa_resultsString += QObject::tr("Account cross-links: no\n");
  

    // Left end and right end modifs
    entities =(m_calcOptions.polymerEntities() &
            MXT_POLYMER_CHEMENT_LEFT_END_MODIF ||
            m_calcOptions.polymerEntities() &
            MXT_POLYMER_CHEMENT_RIGHT_END_MODIF);
      
    if (!entities)
      {
      *mpa_resultsString += QObject::tr("Account ends' modifs: no\n");
      }
    else
      {
      *mpa_resultsString += QObject::tr("Account ends' modifs: yes - ");
        
      // Left end modif
      entities =(m_calcOptions.polymerEntities() &
                MXT_POLYMER_CHEMENT_LEFT_END_MODIF);
      if(entities)
        {
          *mpa_resultsString += QObject::tr("Left end modif: %1 - ")
            .arg(mpa_polymer->leftEndModif().name());
        }
        
      // Right end modif
      entities =(m_calcOptions.polymerEntities() &
                MXT_POLYMER_CHEMENT_RIGHT_END_MODIF);
      if(entities)
        {
          *mpa_resultsString += QObject::tr("Right end modif: %1")
            .arg(mpa_polymer->leftEndModif().name());
        }
      }
      
    // The options about multi-region selections and multi-selection
    // regions.
    if (m_ui.multiRegionSelectionCheckBox->checkState())
      {
      *mpa_resultsString += 
        QObject::tr("\nMulti-region selection enabled: yes\n");

      if(m_ui.regionSelectionOligomerRadioButton->isChecked())
        {
          *mpa_resultsString += 
            QObject::tr("Multi-region selections are " 
                     "treated as oligomers\n");
        }
      else if (m_ui.regionSelectionResChainRadioButton->isChecked())
        {
          *mpa_resultsString += 
            QObject::tr("Multi-region selections are treated as "
                     "residual chains\n");
        }
        
      if(m_ui.multiSelectionRegionCheckBox->checkState())
        {
          *mpa_resultsString += 
            QObject::tr("Multi-selection region enabled: yes\n");
        }
      else
        {
          *mpa_resultsString += 
            QObject::tr("Multi-selection region enabled: no\n");
        }
      }
    else
      {
      *mpa_resultsString += 
        QObject::tr("\nMulti-region selection enabled: no\n");
      }
    

    // If there are cross-links, list all of these.

    if (mpa_polymer->crossLinkList().size())
      {
      *mpa_resultsString += QObject::tr("\n\nCross-links:\n");
      
      for(int iter = 0; iter < mpa_polymer->crossLinkList().size(); ++iter)
        {
          CrossLink *crossLink = mpa_polymer->crossLinkList().at(iter);
        
          QString *text = crossLink->prepareResultsTxtString();
        
          Q_ASSERT(text);
        
          *mpa_resultsString += *text;
        
          delete text;
        }
      }

    // Finally give the masses for the whole sequence:
  
    QString value;
  
    *mpa_resultsString += QObject::tr("\n\nWhole sequence mono mass: %1\n")
      .arg(m_ui.monoWholeMassLineEdit->text());

    *mpa_resultsString += QObject::tr("Whole sequence avg mass: %1\n\n")
      .arg(m_ui.avgWholeMassLineEdit->text());
  

    // And now the selected sequence region(s).

    entities =(m_calcOptions.monomerEntities() &
            MXT_MONOMER_CHEMENT_MODIF);
    
    sequence = mpa_polymer->monomerText(m_calcOptions.coordinateList(),
                               entities, true);
    
    *mpa_resultsString += *sequence;
    
    delete sequence;

    entities =(m_calcOptions.monomerEntities() &
            MXT_MONOMER_CHEMENT_CROSS_LINK);

    if (entities)
      {
      // We should inform that no, one, more cross-links might be left out:
      *mpa_resultsString += QObject::tr("%1\n\n")
        .arg(m_ui.incompleteCrossLinkWarningLabel->text());
      }
    
    *mpa_resultsString += QObject::tr("Selected sequence mono mass: %1\n")
      .arg(m_ui.monoSelectionMassLineEdit->text());
  
    *mpa_resultsString += QObject::tr("Selected sequence avg mass: %1\n")
      .arg(m_ui.avgSelectionMassLineEdit->text());
  }


  void 
  SequenceEditorWnd::exportClipboard()
  {
    prepareResultsTxtString();
  
    QClipboard *clipboard = QApplication::clipboard();
  
    clipboard->setText(*mpa_resultsString, QClipboard::Clipboard);  
  }


  void 
  SequenceEditorWnd::exportFile()
  {
    if (m_resultsFilePath.isEmpty())
      {
      if(!exportSelectFile())
        return;
      }
  
    QFile file(m_resultsFilePath);
  
    if (!file.open(QIODevice::WriteOnly | QIODevice::Append))
      {
      QMessageBox::information(0, 
                          tr("massXpert - Export Data"),
                          tr("Failed to open file in append mode."),
                          QMessageBox::Ok);
      return;
      }
  
    QTextStream stream(&file);
    stream.setCodec("UTF-8");

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


  bool
  SequenceEditorWnd::exportSelectFile()
  {
    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;
  
  }
  // The results-exporting functions. ////////////////////////////////
  // The results-exporting functions. ////////////////////////////////
  // The results-exporting functions. ////////////////////////////////




  void
  SequenceEditorWnd::createActions()
  {
    // File/Close
    closeAct = new QAction(tr("&Close"), this);
    closeAct->setShortcut(tr("Ctrl+W"));
    closeAct->setStatusTip(tr("Closes the sequence"));
    connect(closeAct, SIGNAL(triggered()), this, SLOT(close()));
  
    // File/Save
    saveAct = new QAction(tr("&Save"), this);
    saveAct->setShortcut(tr("Ctrl+S"));
    saveAct->setStatusTip(tr("Saves the sequence"));
    connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));
  
    // File/SaveAs
    saveAsAct = new QAction(tr("Save&As"), this);
    saveAsAct->setShortcut(tr("Ctrl+Alt+S"));
    saveAsAct->setStatusTip(tr("Saves the sequence in another file"));
    connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
  
    // File/ImportRaw
    importRawAct = new QAction(tr("&Import Raw"), this);
    importRawAct->setShortcut(tr("Ctrl+I"));
    importRawAct->setStatusTip(tr("Imports a raw text file"));
    connect(importRawAct, SIGNAL(triggered()), this, SLOT(importRaw()));
  
    // File/ExportClipboard
    exportClipboardAct = new QAction(tr("Export to &Clipboard"), this);
    exportClipboardAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_E,Qt::Key_C));
    exportClipboardAct->setStatusTip(tr("Export as text to the clipboard"));
    connect(exportClipboardAct, SIGNAL(triggered()), 
           this, SLOT(exportClipboard()));
  
    // File/ExportFile
    exportFileAct = new QAction(tr("Export to &File"), this);
    exportFileAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_E,Qt::Key_F));
    exportFileAct->setStatusTip(tr("Export as text to file"));
    connect(exportFileAct, SIGNAL(triggered()), 
           this, SLOT(exportFile()));
  
    // File/ExportSelectFile
    exportSelectFileAct = new QAction(tr("&Select Export File"), this);
    exportSelectFileAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_E,Qt::Key_S));
    exportSelectFileAct->setStatusTip(tr("Select file to export as text to"));
    connect(exportSelectFileAct, SIGNAL(triggered()), 
           this, SLOT(exportSelectFile()));
  

    // Edit/Copy
    clipboardCopyAct = new QAction(tr("&Copy"), this);
    clipboardCopyAct->setShortcut(tr("Ctrl+C"));
    clipboardCopyAct->setStatusTip(tr("Copy the selected "
                              "region of the sequence"));
    connect(clipboardCopyAct, SIGNAL(triggered()), 
           this, SLOT(clipboardCopy()));

    // Edit/Cut
    clipboardCutAct = new QAction(tr("C&ut"), this);
    clipboardCutAct->setShortcut(tr("Ctrl+X"));
    clipboardCutAct->setStatusTip(tr("Cut the selected "
                               "region of the sequence"));
    connect(clipboardCutAct, SIGNAL(triggered()), 
           this, SLOT(clipboardCut()));

    // Edit/Paste
    clipboardPasteAct = new QAction(tr("&Paste"), this);
    clipboardPasteAct->setShortcut(tr("Ctrl+V"));
    clipboardPasteAct->setStatusTip(tr("Copy the selected "
                               "region of the sequence"));
    connect(clipboardPasteAct, SIGNAL(triggered()), 
           this, SLOT(clipboardPaste()));

    // Edit/Find Sequence
    findSequenceAct = new QAction(tr("&Find Sequence"), this);
    findSequenceAct->setShortcut(tr("Ctrl+F"));
    findSequenceAct->setStatusTip(tr("Find a sequence "
                               "in the polymer sequence"));
    connect(findSequenceAct, SIGNAL(triggered()), 
           this, SLOT(findSequence()));
  

    // Chemistry/ModifyMonomer
    modifMonomerAct = new QAction(tr("Modify &Monomer(s)"), this);
    modifMonomerAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_M,Qt::Key_M));
    modifMonomerAct->setStatusTip(tr("Modifies monomer(s)"));
    connect(modifMonomerAct, SIGNAL(triggered()), this, 
           SLOT(modifMonomer()));
  
    // Chemistry/ModifyPolymer
    modifPolymerAct = new QAction(tr("Modify &Polymer"), this);
    modifPolymerAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_M,Qt::Key_P));
    modifPolymerAct->setStatusTip(tr("Modifies the polymer"));
    connect(modifPolymerAct, SIGNAL(triggered()), this, 
           SLOT(modifPolymer()));

    // Also connect that SLOT to the two buttons for left and right end
    // modif.
  
    connect(m_ui.leftEndModifPushButton,
           SIGNAL(clicked()),
           this, 
           SLOT(modifLeftEnd()));

    connect(m_ui.rightEndModifPushButton, 
           SIGNAL(clicked()),
           this, 
           SLOT(modifRightEnd()));

    // Chemistry/CrossLinkMonomer
    crossLinkMonomersAct = new QAction(tr("Cross-&link Monomers"), this);
    crossLinkMonomersAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_L,Qt::Key_M));
    crossLinkMonomersAct->setStatusTip(tr("Cross-link monomers"));
    connect(crossLinkMonomersAct, SIGNAL(triggered()), this, 
           SLOT(crossLinkMonomers()));

    // Chemistry/Cleave
    cleaveAct = new QAction(tr("&Cleave"), this);
    cleaveAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_K));
    cleaveAct->setStatusTip(tr("Cleaves the polymer"));
    connect(cleaveAct, SIGNAL(triggered()), this, 
           SLOT(cleave()));
  
    // Chemistry/Fragment
    fragmentAct = new QAction(tr("Fra&gment"), this);
    fragmentAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_G));
    fragmentAct->setStatusTip(tr("Fragments the polymer"));
    connect(fragmentAct, SIGNAL(triggered()), this, 
           SLOT(fragment()));
  
    // Chemistry/MassSearch
    massSearchAct = new QAction(tr("&Mass Search"), this);
    massSearchAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_M,Qt::Key_S));
    massSearchAct->setStatusTip(tr("Search oligomers based on mass"));
    connect(massSearchAct, SIGNAL(triggered()), this, 
           SLOT(massSearch()));
  
    // Chemistry/mzCalculation
    mzCalculationAct = new QAction(tr("Compute m/z &Ratios"), this);
    mzCalculationAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_M,Qt::Key_Z));
    mzCalculationAct->setStatusTip(tr("Compute ion charge families"));
    connect(mzCalculationAct, SIGNAL(triggered()), this, 
           SLOT(mzCalculation()));
  
    // Chemistry/compositions
    compositionsAct = new QAction(tr("Determine Compositions"), this);
    compositionsAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_D,Qt::Key_C));
    compositionsAct->setStatusTip(tr("Determine Compositions"));
    connect(compositionsAct, SIGNAL(triggered()), this, 
           SLOT(compositions()));
  
    // Chemistry/isoelectricPoint
    pkaPhPiAct = new QAction(tr("pKa pH pI"), this);
    pkaPhPiAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_P));
    pkaPhPiAct->setStatusTip(tr("pKa pH pI"));
    connect(pkaPhPiAct, SIGNAL(triggered()), this, 
           SLOT(pkaPhPi()));

    // Options/decimalPlaces
    decimalPlacesOptionsAct = new QAction(tr("Decimal places"), this);
    decimalPlacesOptionsAct->setShortcut 
     (QKeySequence(Qt::CTRL+Qt::Key_D));
    decimalPlacesOptionsAct->setStatusTip(tr("Decimal places"));
    connect(decimalPlacesOptionsAct, SIGNAL(triggered()), this, 
           SLOT(decimalPlacesOptions()));
  }


  void
  SequenceEditorWnd::createMenus()
  {
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(closeAct);
    fileMenu->addSeparator();
    fileMenu->addAction(saveAct);
    fileMenu->addAction(saveAsAct);
    fileMenu->addSeparator();
    fileMenu->addAction(importRawAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exportClipboardAct);
    fileMenu->addAction(exportFileAct);
    fileMenu->addAction(exportSelectFileAct);  
  
    editMenu = menuBar()->addMenu(tr("&Edit"));
    editMenu->addAction(clipboardCopyAct);
    editMenu->addAction(clipboardCutAct);
    editMenu->addAction(clipboardPasteAct);
    editMenu->addSeparator();
    editMenu->addAction(findSequenceAct);

    chemistryMenu = menuBar()->addMenu(tr("&Chemistry"));
    chemistryMenu->addAction(modifMonomerAct);
    chemistryMenu->addAction(modifPolymerAct);
    chemistryMenu->addAction(crossLinkMonomersAct);
    chemistryMenu->addAction(cleaveAct);
    chemistryMenu->addAction(fragmentAct);
    chemistryMenu->addAction(massSearchAct);
    chemistryMenu->addAction(mzCalculationAct);
    chemistryMenu->addAction(compositionsAct);
    chemistryMenu->addAction(pkaPhPiAct);

    optionsMenu = menuBar()->addMenu(tr("&Options"));
    optionsMenu->addAction(decimalPlacesOptionsAct);
  }


  // Before the creation of the polymer chemistry definition/polymer
  // relationship.
  bool
  SequenceEditorWnd::preInitialize()
  {
    m_ui.setupUi(this);

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

    QPixmap pixmap(":/images/massxpert-icon-32.png");
    QIcon icon(pixmap);
    setWindowIcon(icon);

    createActions();
    createMenus();

    setAttribute(Qt::WA_DeleteOnClose);
    statusBar()->setSizeGripEnabled(true);

    setFocusPolicy(Qt::StrongFocus);

    m_ui.ionizationChargeSpinBox->setRange(1, 1000000000);
    m_ui.ionizationLevelSpinBox->setRange(0, 1000000000);

    // By default, selected regions behave as oligomers, the way one
    // expects the system to behave when selecting oligomers that are
    // cross-linked, for example.
    m_ui.regionSelectionOligomerRadioButton->click();
    
    m_ui.incompleteCrossLinkWarningLabel->setText 
     (tr("Not accounting for cross-links"));
  
    mpa_editorGraphicsView = new SequenceEditorGraphicsView(this);
    mpa_editorGraphicsView->setParent(this);
    //    mpa_editorGraphicsView->setAlignment(Qt::AlignLeft);

    QVBoxLayout *layout = new QVBoxLayout(m_ui.graphicsViewFrame);
 
    layout->addWidget(static_cast<QWidget *>(mpa_editorGraphicsView));

    mp_progressBar = new QProgressBar;
    statusBar()->addPermanentWidget(mp_progressBar);

    // We want to be able to start a drag with the mass values...
    m_ui.monoWholeMassLineEdit->setDragEnabled(true);
    m_ui.avgWholeMassLineEdit->setDragEnabled(true);

    m_ui.regionSelectionOligomerRadioButton->setChecked(true);
    m_calcOptions.setSelectionType(SELECTION_TYPE_OLIGOMERS);

    m_ui.multiRegionSelectionCheckBox->setChecked(true);
    m_ui.multiSelectionRegionCheckBox->setChecked(false);
    
    setWindowModified(false);
  
    return true;
  }


  bool
  SequenceEditorWnd::postInitialize()
  {
    Q_ASSERT(mpa_polymer);
  
    connect(mpa_polymer,
           SIGNAL(crossLinksPartiallyEncompassedSignal(int)),
           this,
           SLOT(crossLinksPartiallyEncompassedSlot(int)));
  
    mpa_editorGraphicsScene = new QGraphicsScene(this);
    mpa_editorGraphicsView->setPolymer(mpa_polymer);
    mpa_editorGraphicsView->setScene(mpa_editorGraphicsScene);
  
    MonomerCodeEvaluator *evaluator = 
      new MonomerCodeEvaluator(mpa_polymer, this, 
                        m_ui.codeLineEdit,
                        m_ui.codeErrorLineEdit);
    mpa_editorGraphicsView->setMonomerCodeEvaluator(evaluator);
  
    m_ui.sequenceNameLineEdit->setText(mpa_polymer->name());
    updateWindowTitle();

    updatePolymerEndsModifs();
  
    statusBar()->showMessage(tr("Ready."));

    if (!populateMonomerCodeList())
      {
      QMessageBox::warning(0, 
                        tr("massXpert - Polymer Sequence Editor"),
                        tr("%1@%2\n"
                          "Failed to populate the monomer code list.")
                        .arg(__FILE__)
                        .arg(__LINE__),
                        QMessageBox::Ok);
      
      return false;
      }
  
    populateCalculationOptions();
  
    m_ui.vignetteListWidget->setSelectionMode 
     (QAbstractItemView::SingleSelection);


    ////// Connection of the SIGNALS and SLOTS //////
    connect(m_ui.vignetteSizeSpinBox,
           SIGNAL(editingFinished()),
           this,
           SLOT(vignetteSizeChanged()));

    connect(m_ui.sequenceNameLineEdit,
           SIGNAL(textChanged(const QString &)),
           this,
           SLOT(nameLineEditChanged(const QString &)));

    connect(m_ui.leftCapCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(calculationOptionsChanged()));

    connect(m_ui.rightCapCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(calculationOptionsChanged()));

    connect(m_ui.leftModifCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(leftModifOptionsChanged()));
    
    connect(m_ui.forceLeftModifCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(forceLeftModifOptionsChanged()));

    connect(m_ui.rightModifCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(rightModifOptionsChanged()));

    connect(m_ui.forceRightModifCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(forceRightModifOptionsChanged()));

    connect(m_ui.multiRegionSelectionCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(multiRegionSelectionOptionChanged(int)));

    connect(m_ui.multiSelectionRegionCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(multiSelectionRegionOptionChanged(int)));

    connect(m_ui.regionSelectionOligomerRadioButton,
           SIGNAL(toggled(bool)),
           this,
           SLOT(regionSelectionOligomerOptionChanged(bool)));

     connect(m_ui.regionSelectionResChainRadioButton,
           SIGNAL(toggled(bool)),
           this,
           SLOT(regionSelectionResChainOptionChanged(bool)));

    connect(m_ui.monomerModifCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(monomerModifOptionChanged(int)));

    connect(m_ui.monomerCrossLinkCheckBox,
           SIGNAL(stateChanged(int)),
           this,
           SLOT(monomerCrossLinkOptionChanged(int)));

    connect(m_ui.ionizationFormulaLineEdit,
           SIGNAL(editingFinished()),
           this,
           SLOT(calculationOptionsChanged()));

    connect(m_ui.ionizationChargeSpinBox,
           SIGNAL(valueChanged(int)),
           this,
           SLOT(calculationOptionsChanged()));

    connect(m_ui.ionizationLevelSpinBox,
           SIGNAL(valueChanged(int)),
           this,
           SLOT(calculationOptionsChanged()));

    ////// Connection of the SIGNALS and SLOTS //////
  
    m_postInitialized = true;
  
    return true;
  }


  QProgressBar *
  SequenceEditorWnd::progressBar()
  {
    return mp_progressBar;
  }

  bool 
  SequenceEditorWnd::openSequence(QString &filePath)
  {
    // We get the filePath of the sequence file.

    if (filePath.isEmpty() || !QFile::exists(filePath))
      {
      QMessageBox::warning(0, 
                        tr("massXpert - Polymer Sequence Editor"),
                        tr("%1@%2\n"
                          "Filepath is empty, or file does not exist.")
                        .arg(__FILE__)
                        .arg(__LINE__),
                        QMessageBox::Ok);
      
      return false;
      }
      
    QString name =
      Polymer::xmlPolymerFileGetPolChemDefName(filePath);
    
    if (name.isEmpty())
      {
      QMessageBox::warning 
       (0, 
         tr("massXpert - Polymer Sequence Editor"),
         tr("%1@%2\n"
             "Failed to get the polymer chemistry definition name.")
         .arg(__FILE__)
         .arg(__LINE__),
         QMessageBox::Ok);
      
      return false;
      }
  
    mp_polChemDef = preparePolChemDef(name);
  
    if (!mp_polChemDef)
      {
      QMessageBox::warning 
       (0, 
         tr("massXpert - Polymer Sequence Editor"),
         tr("%1@%2\n"
             "Failed to prepare the polymer chemistry definition.")
         .arg(__FILE__)
         .arg(__LINE__),
         QMessageBox::Ok);
            
      return false;
      }

    Application *application = static_cast<Application *>(qApp);
  
    mpa_polymer = new Polymer(mp_polChemDef, "NOT_SET", "NOT_SET",
                         application->userSpec()->userName());
    
    if (!readFile(filePath))
      {
      QMessageBox::warning 
       (0, 
         tr("massXpert - Polymer Sequence Editor"),
         tr("%1@%2\n"
             "Failed to load the polymer file.")
         .arg(__FILE__)
         .arg(__LINE__),
         QMessageBox::Ok);
      
      return false;
      }
  
    if (!postInitialize())
      return false;
    
    if (mpa_editorGraphicsView->drawSequence() == -1)
      {
      QMessageBox::warning 
       (0, 
         tr("massXpert - Polymer Sequence Editor"),
         tr("%1@%2\n"
             "Failed to draw the polymer sequence.")
         .arg(__FILE__)
         .arg(__LINE__),
         QMessageBox::Ok);
      
      return false;
      }
  
    focusInEvent(0);
  
    updateWholeSequenceMasses();
    updateSelectedSequenceMasses();

    return true;
  }


  bool 
  SequenceEditorWnd::newSequence(QString &filePath)
  {
    Application *application = static_cast<Application *>(qApp);


    // We get the filePath of the polymer chemistry definition file.
  
    PolChemDefSpec *polChemDefSpec = 
      application->polChemDefSpecFilePath(filePath);
  
    if (!polChemDefSpec)
      {
      QMessageBox::warning 
       (0, 
         tr("massXpert - Polymer Sequence Editor"),
         tr("%1@%2\n"
             "Failed to find the corresponding polymer chemistry "
             "filename.")
         .arg(__FILE__)
         .arg(__LINE__),
         QMessageBox::Ok);

      return false;
      }

    mp_polChemDef = preparePolChemDef(polChemDefSpec->name());
  
    if (!mp_polChemDef)
      {
      QMessageBox::warning 
       (0, 
         tr("massXpert - Polymer Sequence Editor"),
         tr("%1@%2\n"
             "Failed to prepare the polymer chemistry definition.")
         .arg(__FILE__)
         .arg(__LINE__),
         QMessageBox::Ok);
      
      return false;
      }

    mpa_polymer = new Polymer(mp_polChemDef, "NOT_SET", "NOT_SET",
                         application->userSpec()->userName());
  
    if (!postInitialize())
      return false;
    
    if (mpa_editorGraphicsView->drawSequence() == -1)
      {
      QMessageBox::warning 
       (0, 
         tr("massXpert - Polymer Sequence Editor"),
         tr("%1@%2\n"
             "Failed to draw the polymer sequence.")
         .arg(__FILE__)
         .arg(__LINE__),
         QMessageBox::Ok);
      
      return false;
      }
  
    focusInEvent(0);

    return true;
  }


  bool
  SequenceEditorWnd::readFile(const QString &filePath)
  {
    return mpa_polymer->renderXmlPolymerFile(filePath);
  }


  PolChemDef *
  SequenceEditorWnd::preparePolChemDef(const QString &name)
  {
    Application *application = static_cast<Application *>(qApp);
  
    // Is a polymer definition already available, or shall we have to
    // load one first ?
    PolChemDef *polChemDef = application->polChemDefName(name);
    //    qDebug() << __FILE__ << __LINE__ << "polChemDef:" << polChemDef;

    if (!polChemDef)
      {
      // No polymer chemistry definition by that name is currently
      // loaded in memory. We'll have to load one.
      
      PolChemDefSpec *polChemDefSpec = 
        application->polChemDefSpecName(name);
      
      if(!polChemDefSpec)
        {
          // No polymer chemistry definition by that name is
          // registered to the system. We cannot go further.

          QMessageBox::warning 
           (0, 
             tr("massXpert - Polymer Sequence Editor"),
             tr("%1@%2\n"
               "Failed to get the polymer chemistry "
               "definition specification: %3.")
             .arg(__FILE__)
             .arg(__LINE__)
             .arg(name),
             QMessageBox::Ok);
        
          return 0;
        }
      
      // polChemDefSpec should provide data to create a new polymer
      // chemistry definition object.

      polChemDef = new PolChemDef(*polChemDefSpec);
      
      if(!polChemDef->renderXmlPolChemDefFile())
        {
          delete polChemDef;

          QMessageBox::warning 
           (0, 
             tr("massXpert - Polymer Sequence Editor"),
             tr("%1@%2\n"
               "Failed to render the polymer chemistry"
               " definition xml file.")
             .arg(__FILE__)
             .arg(__LINE__),
             QMessageBox::Ok);
        
          return 0;
        }
      
      // We still have to initialize the m_monomerSpecList and
      // m_modifSpecList lists...
      QString dictionary = polChemDef->dirPath() + QDir::separator() + 
        "monomer_dictionary";
      
      if(!MonomerSpec::parseFile(dictionary, 
                             polChemDef->monomerSpecList()))
        {
          delete polChemDef;
        
          QMessageBox::warning 
           (0, 
             tr("massXpert - Polymer Sequence Editor"),
             tr("%1@%2\n"
               "Failed to parse the monomer dictionary file.")
             .arg(__FILE__)
             .arg(__LINE__),
             QMessageBox::Ok);
        
          return 0;
        }
       
      dictionary = polChemDef->dirPath() + QDir::separator() +
        "modification_dictionary";
      
      if(!ModifSpec::parseFile(dictionary, 
                           polChemDef->modifSpecList()))
        {
          delete polChemDef;
        
          QMessageBox::warning 
           (0, 
             tr("massXpert - Polymer Sequence Editor"),
             tr("%1@%2\n"
               "Failed to parse the modification dictionary file.")
             .arg(__FILE__)
             .arg(__LINE__),
             QMessageBox::Ok);

          return 0;
        }

      dictionary = polChemDef->dirPath() + QDir::separator() +
        "cross_linker_dictionary";
      
      if(!CrossLinkerSpec::parseFile(dictionary, 
                               polChemDef->crossLinkerSpecList()))
        {
          delete polChemDef;
        
          QMessageBox::warning 
           (0, 
             tr("massXpert - Polymer Sequence Editor"),
             tr("%1@%2\n"
               "Failed to parse the cross-linker dictionary file.")
             .arg(__FILE__)
             .arg(__LINE__),
             QMessageBox::Ok);
        
          return 0;
        }
      
      // Finally we can add this PolChemDef to the application list
      // of such objects. 
      application->polChemDefList()->append(polChemDef);

      // Note also that we have to tell the definition where to
      // auto-remove itself as soon as the reference count comes down
      // to 0.
      polChemDef->setRepositoryList(application->polChemDefList());

      // Finally increment the reference count of the polymer
      // chemistry definition.
      polChemDef->incrementRefCount();
      }
    else
      polChemDef->incrementRefCount();

    return polChemDef;
  }



  void
  SequenceEditorWnd::populateCalculationOptions()
  {
    const PolChemDef *polChemDef = mpa_polymer->polChemDef();
 
    if (!polChemDef)
      return;
  
    m_ionizeRule = polChemDef->ionizeRule();

    m_ui.ionizationFormulaLineEdit->setText(m_ionizeRule.formula());
    m_ui.ionizationChargeSpinBox->setValue(m_ionizeRule.charge());
    m_ui.ionizationLevelSpinBox->setValue(m_ionizeRule.level());
  
    // Update the masses|m/z ratios label.
    if (!m_ionizeRule.level())
      {
      m_ui.massesOrMzGroupBox->setTitle(tr("Masses"));
      }
    else
      {
      m_ui.massesOrMzGroupBox->setTitle(tr("m/z ratios"));
      }
      

    // qDebug() << MXT_CAP_NONE << MXT_CAP_LEFT 
    // << MXT_CAP_RIGHT << MXT_CAP_BOTH;

    m_ui.leftCapCheckBox->setChecked(m_calcOptions.capping() & MXT_CAP_LEFT);
    m_ui.rightCapCheckBox->setChecked(m_calcOptions.capping() & MXT_CAP_RIGHT);
  
    m_ui.monomerModifCheckBox->setChecked(m_calcOptions.monomerEntities() &
                                 MXT_MONOMER_CHEMENT_MODIF); 

    m_ui.leftModifCheckBox->setChecked(m_calcOptions.polymerEntities() & 
                              MXT_POLYMER_CHEMENT_LEFT_END_MODIF);
    m_ui.rightModifCheckBox->setChecked(m_calcOptions.polymerEntities() & 
                               MXT_POLYMER_CHEMENT_RIGHT_END_MODIF);
  }



  void
  SequenceEditorWnd::calculationOptionsChanged()
  {
    //   qDebug() << " calculationOptionsChanged";
  
    // CAPPING
    int value = 0;

    if (m_ui.leftCapCheckBox->checkState() == Qt::Checked)
      value |= MXT_CAP_LEFT;

    if (m_ui.rightCapCheckBox->checkState() == Qt::Checked)
      value |= MXT_CAP_RIGHT;
  
    m_calcOptions.setCapping(value);

    //   qDebug() << "capping: " << m_calcOptions.capping();


    //   qDebug() << "polymer entities: " << m_calcOptions.polymerEntities();
  
    // IONIZATION RULE

    const PolChemDef *polChemDef = mpa_polymer->polChemDef();

    QString text = m_ui.ionizationFormulaLineEdit->text();
  
    if (!text.isEmpty())
      {
      Formula formula(text);
      
      const QList<Atom *> &refList = polChemDef->atomList();
      
      if(!formula.validate(refList))
        {
          QMessageBox::warning(0,
                          tr("massXpert - Polymer Sequence Editor"),
                          tr("Ionization rule formula is not valid."),
                          QMessageBox::Ok);
        
          m_ui.ionizationFormulaLineEdit->setFocus();
        
          return;
        }
      
      m_ionizeRule.setFormula(text);
      //       qDebug() << "ionization formula: " << m_ionizeRule.formula();

      }
  
    m_ionizeRule.setCharge(m_ui.ionizationChargeSpinBox->value());
    //   qDebug() << "ionization charge: " << m_ionizeRule.charge();

    m_ionizeRule.setLevel(m_ui.ionizationLevelSpinBox->value());
    //   qDebug() << "ionization level: " << m_ionizeRule.level();

    // Update the masses|m/z ratios label.
    if (!m_ionizeRule.level())
      {
      m_ui.massesOrMzGroupBox->setTitle(tr("Masses"));
      }
    else
      {
      m_ui.massesOrMzGroupBox->setTitle(tr("m/z ratios"));
      }
  
    updateWholeSequenceMasses();
    updateSelectedSequenceMasses();
  }


  void 
  SequenceEditorWnd::leftModifOptionsChanged()
  {
    // POLYMER MODIFICATION
    int flags = m_calcOptions.polymerEntities();

    if (m_ui.leftModifCheckBox->checkState() == Qt::Checked)
      {
      flags |= MXT_POLYMER_CHEMENT_LEFT_END_MODIF;
      }
    else
      {
      flags &= ~MXT_POLYMER_CHEMENT_LEFT_END_MODIF;
      
      if(m_ui.forceLeftModifCheckBox->checkState() == Qt::Checked)
        {
          m_ui.forceLeftModifCheckBox->toggle();
          flags &= ~MXT_POLYMER_CHEMENT_FORCE_LEFT_END_MODIF;
        }
      }

    m_calcOptions.setPolymerEntities(flags);

    updateWholeSequenceMasses();
    updateSelectedSequenceMasses(false);    
  }
  

  void 
  SequenceEditorWnd::forceLeftModifOptionsChanged()
  {
    // POLYMER MODIFICATION
    int flags = m_calcOptions.polymerEntities();

    if (m_ui.forceLeftModifCheckBox->checkState() == Qt::Checked)
      {
      if(m_ui.leftModifCheckBox->checkState() != Qt::Checked)
        {
          m_ui.leftModifCheckBox->toggle();
          flags |= MXT_POLYMER_CHEMENT_LEFT_END_MODIF;
        }
      
      flags |= MXT_POLYMER_CHEMENT_FORCE_LEFT_END_MODIF;
      }
    else
      {
      flags &= ~MXT_POLYMER_CHEMENT_FORCE_LEFT_END_MODIF;
      }

    m_calcOptions.setPolymerEntities(flags);
    
    updateWholeSequenceMasses();
    updateSelectedSequenceMasses(false);    
  }
  

  void 
  SequenceEditorWnd::rightModifOptionsChanged()
  {
    // POLYMER MODIFICATION
    int flags = m_calcOptions.polymerEntities();

    if (m_ui.rightModifCheckBox->checkState() == Qt::Checked)
      {
      flags |= MXT_POLYMER_CHEMENT_RIGHT_END_MODIF;
      }
    else
      {
      flags &= ~MXT_POLYMER_CHEMENT_RIGHT_END_MODIF;
      
      if(m_ui.forceRightModifCheckBox->checkState() == Qt::Checked)
        {
          m_ui.forceRightModifCheckBox->toggle();
          flags &= ~MXT_POLYMER_CHEMENT_FORCE_RIGHT_END_MODIF;
        }
      }

    m_calcOptions.setPolymerEntities(flags);

    updateWholeSequenceMasses();
    updateSelectedSequenceMasses(false);    
  }
  

  void 
  SequenceEditorWnd::forceRightModifOptionsChanged()
  {
    // POLYMER MODIFICATION
    int flags = m_calcOptions.polymerEntities();

    if (m_ui.forceRightModifCheckBox->checkState() == Qt::Checked)
      {
      if(m_ui.rightModifCheckBox->checkState() != Qt::Checked)
        {
          m_ui.rightModifCheckBox->toggle();
          flags |= MXT_POLYMER_CHEMENT_RIGHT_END_MODIF;
        }
      
      flags |= MXT_POLYMER_CHEMENT_FORCE_RIGHT_END_MODIF;
      }
    else
      {
      flags &= ~MXT_POLYMER_CHEMENT_FORCE_RIGHT_END_MODIF;
      }

    m_calcOptions.setPolymerEntities(flags);
    
    updateWholeSequenceMasses();
    updateSelectedSequenceMasses(false);    
  }
  

  void 
  SequenceEditorWnd::multiRegionSelectionOptionChanged(int checkState)
  {
    if (checkState == Qt::Unchecked)
      {
//    qDebug() << __FILE__ << __LINE__
//            << "multiRegionSelectionOptionChanged: unchecked";

      // No multi-region selection... We remove all selections but
      // the last one.
      mpa_editorGraphicsView->resetSelectionButLastRegion();
      mpa_editorGraphicsView->setOngoingMouseMultiSelection(false);
      
      // Note that if no multi region selections are allowed,
      // multi-selection regions should be disallowed also. But we
      // do not want to uncheck the checkbox, we just inactivate it.

      m_ui.multiSelectionRegionCheckBox->setEnabled(false);
      }
    else
      {
      // Note that if multi region selections are allowed,
      // multi-selection regions should be possible also.

      m_ui.multiSelectionRegionCheckBox->setEnabled(true);
      }
    
    updateSelectedSequenceMasses(false);
  }

  
  bool
  SequenceEditorWnd::isMultiRegionSelection()
  {
    return m_ui.multiRegionSelectionCheckBox->isChecked();
  }
  

  void 
  SequenceEditorWnd::multiSelectionRegionOptionChanged(int checkState)
  {
    if (checkState == Qt::Unchecked)
      {
//    qDebug() << __FILE__ << __LINE__
//            << "multiSelectionRegionOptionChanged: unchecked";

      // No multi-selection regions... We remove all selections but
      // the first one.
      mpa_editorGraphicsView->resetMultiSelectionRegionsButFirstSelection();
      mpa_editorGraphicsView->setOngoingMouseMultiSelection(false);
      }

    updateSelectedSequenceMasses(false);
  }
  

  bool
  SequenceEditorWnd::isMultiSelectionRegion()
  {
    return m_ui.multiSelectionRegionCheckBox->isChecked();
  }
  

  void 
  SequenceEditorWnd::regionSelectionOligomerOptionChanged(bool checked)
  {
    if (checked)
      {
//    qDebug() << __FILE__ << __LINE__
//            << "regionSelectionOligomerOptionChanged checked";

      m_calcOptions.setSelectionType(SELECTION_TYPE_OLIGOMERS);
      }
    else
      m_calcOptions.setSelectionType(SELECTION_TYPE_RESIDUAL_CHAINS);

    updateSelectedSequenceMasses(false);
  }
  

  void 
  SequenceEditorWnd::regionSelectionResChainOptionChanged(bool checked)
  {
    if (checked)
      {
//    qDebug() << __FILE__ << __LINE__
//            << "regionSelectionResChainOptionChanged checked";

      m_calcOptions.setSelectionType(SELECTION_TYPE_RESIDUAL_CHAINS);
      }
    else
      m_calcOptions.setSelectionType(SELECTION_TYPE_OLIGOMERS);

    updateSelectedSequenceMasses(false);
  }
  

  void 
  SequenceEditorWnd::monomerModifOptionChanged(int checkState)
  {
    int flags = m_calcOptions.monomerEntities();

    if (checkState == Qt::Checked)
      flags |= MXT_MONOMER_CHEMENT_MODIF;
    else
      flags &= ~MXT_MONOMER_CHEMENT_MODIF;
  
    //   if (flags & MXT_MONOMER_CHEMENT_MODIF)
    //     qDebug() << __FILE__ << __LINE__ 
    //            << "monomerEntities set for MXT_MONOMER_CHEMENT_MODIF";
    //   else
    //     qDebug() << __FILE__ << __LINE__ 
    //            << "monomerEntities NOT set for MXT_MONOMER_CHEMENT_MODIF";

    m_calcOptions.setMonomerEntities(flags);
  
    updateWholeSequenceMasses(true);
    updateSelectedSequenceMasses(true);
  }



  void 
  SequenceEditorWnd::monomerCrossLinkOptionChanged(int checkState)
  {
    int flags = m_calcOptions.monomerEntities();

    if (checkState == Qt::Checked)
      flags |= MXT_MONOMER_CHEMENT_CROSS_LINK;
    else
      {
      flags &= ~MXT_MONOMER_CHEMENT_CROSS_LINK;
      
      m_ui.incompleteCrossLinkWarningLabel->setText 
       (tr("Not accounting for cross-links"));
      }
  
    //   if (flags & MXT_MONOMER_CHEMENT_CROSS_LINK)
    //     qDebug() << __FILE__ << __LINE__ 
    //            << "monomerEntities set for MXT_MONOMER_CHEMENT_CROSS_LINK";
    //   else
    //     qDebug() << __FILE__ << __LINE__ 
    //            << "monomerEntities NOT set for MXT_MONOMER_CHEMENT_CROSS_LINK";
  
    m_calcOptions.setMonomerEntities(flags);


    // When cross-links are to be accounted for, the multi-selection
    // region feature has to be inactivated.

    m_ui.multiSelectionRegionCheckBox->setChecked(false);
      
    updateWholeSequenceMasses(true);
    updateSelectedSequenceMasses(true);
  }



  bool 
  SequenceEditorWnd::populateMonomerCodeList(bool reset)
  {
    QListWidgetItem *item = 0;
  
    const PolChemDef *polChemDef = mpa_polymer->polChemDef();
 
    if (!polChemDef)
      return true;
    
    if (reset)
      {
      while( m_ui.vignetteListWidget->count())
        {
          item = m_ui.vignetteListWidget->takeItem(0);
//        qDebug() << __FILE__ << __LINE__
//                << item->text().toAscii();
        
          delete item;
        }
      }
  
    for (int iter = 0; iter < polChemDef->monomerList().size(); ++iter)
      {
      Monomer *monomer = polChemDef->monomerList().at(iter);

      QString text = monomer->code() + "=" + monomer->name();
      m_ui.vignetteListWidget->addItem(text);
      }

    // It would be interesting to know which item is double-clicked.

    connect(m_ui.vignetteListWidget,
           SIGNAL(itemDoubleClicked(QListWidgetItem *)),
           this,
           SLOT(vignetteListWidgetItemDoubleClicked(QListWidgetItem *)));
      
    return true;
  }


  const PolChemDef *
  SequenceEditorWnd::polChemDef() const
  {
    return mpa_polymer->polChemDef();
  }
  
  
  PolChemDef *
  SequenceEditorWnd::polChemDef()
  {
    return mp_polChemDef;
  }
  

  Polymer*
  SequenceEditorWnd::polymer()
  {
    return mpa_polymer;
  }


  QList<Prop *> *
  SequenceEditorWnd::propList()
  {
    return &m_propList;
  }


  const CalcOptions &
  SequenceEditorWnd::calcOptions() const
  {
    return m_calcOptions;
  }
  

  const IonizeRule &
  SequenceEditorWnd::ionizeRule() const
  {
    return m_ionizeRule;
  }
  

  void 
  SequenceEditorWnd::clearCompletionsListSelection()
  {
    m_ui.vignetteListWidget->clearSelection();
  }


  void 
  SequenceEditorWnd::completionsListSelectAt(int index)
  {
    if (index == -1)
      {
      m_ui.vignetteListWidget->selectAll();
      return;
      }
  
    QListWidgetItem *item = m_ui.vignetteListWidget->item(index);
    item->setSelected(true);
  }


  void 
  SequenceEditorWnd::setWindowModified(bool isModified)
  {
    emit polymerSequenceModifiedSignal();
    
    QWidget::setWindowModified(isModified);
  }
    

  void
  SequenceEditorWnd::updateWindowTitle()
  {
    if (mpa_polymer->filePath().isEmpty())
      setWindowTitle(tr("%1 %2[*]")
                  .arg(tr("massXpert - Polymer Sequence Editor:"))
                  .arg(tr("Untitled")));
    else
      {
      QFileInfo fileInfo(mpa_polymer->filePath());
      
      setWindowTitle(tr("%1 %2[*]")
                  .arg(tr("massXpert - Polymer Sequence Editor:"))
                  .arg(fileInfo.fileName()));
      }
  }


  void 
  SequenceEditorWnd::getsFocus()
  {
    focusInEvent(0);
  }


  void
  SequenceEditorWnd::updateMonomerPosition(int value)
  {
    QString str;

    if (value > 0)
      str.setNum(value);
    else
      str = tr("N/A");
  
    m_ui.monomerPositionLineEdit->setText(str);
  }


  void
  SequenceEditorWnd::updateWholeSequenceMasses(bool deep)
  {
//     qDebug() << __FILE__ << __LINE__
//          << "updateWholeSequenceMasses";

    m_calcOptions.setCoordinateList(Coordinates(0, mpa_polymer->size()));
    m_calcOptions.setDeepCalculation(deep);
    
    mpa_polymer->deionize();
    mpa_polymer->calculateMasses(m_calcOptions);
    mpa_polymer->ionize(m_ionizeRule);  
  
    Application *application = static_cast<Application *>(qApp);

    m_ui.monoWholeMassLineEdit->
      setText(mpa_polymer->mono(application->locale(), 
                          MXP_POLYMER_DEC_PLACES));
    m_ui.avgWholeMassLineEdit->
      setText(mpa_polymer->avg(application->locale(),
                         MXP_POLYMER_DEC_PLACES));
  }


  void
  SequenceEditorWnd::updateSelectedSequenceMasses(bool deep)
  {
//     qDebug() << __FILE__ << __LINE__
//          << "updateSelectedSequenceMasses";
    
    // If there is a factual selection(that is the selection is marked
    // by the selection mark, then the indexes are according to this schema:

    // [ATGC] -> start: 0 end: 3

    // while if the selection is fake, that is no actual selection is
    // performed, then , if cursor is located at ATGC|, then the indexes
    // are according to this schemaa:

    // ATGC| -> start: 0 end: 4

    // Because the calculations in the polymer are based on a for loop,
    // we need to adjust the values prior to setting them in the
    // calculation options vehicle. Note that the values set in start
    // and end are already "sorted", so that start <= end.

    CoordinateList coordinateList;
    
    // Should always return at least one item, that is the
    // pseudo-selection(start of sequence up to cursor index).
    bool realSelections = 
      mpa_editorGraphicsView->selectionIndices(&coordinateList);

    if (realSelections)
      {
      // We have increment all end indices for the items in the
      // coordinateList by one unit. See above for the explanation.
      for(int iter = 0; iter < coordinateList.size(); ++iter)
        {
          // No, we do not need to do this anymore.
          // coordinateList.at(iter)->incrementEnd();
        }
      }
    
    m_calcOptions.setCoordinateList(coordinateList);
    
    m_calcOptions.setDeepCalculation(deep);

    mpa_polymer->deionize();
    mpa_polymer->calculateMasses(m_calcOptions);
    mpa_polymer->ionize(m_ionizeRule);
  
    Application *application = static_cast<Application *>(qApp);

    m_ui.monoSelectionMassLineEdit->
      setText(mpa_polymer->mono(application->locale(),
                          MXP_OLIGOMER_DEC_PLACES));
    m_ui.avgSelectionMassLineEdit->
      setText(mpa_polymer->avg(application->locale(),
                         MXP_OLIGOMER_DEC_PLACES));  
  }


  bool 
  SequenceEditorWnd::maybeSave()
  {
    // Returns true if we can continue(either saved ok or discard). If
    // save failed or cancel we return false to indicate to the caller
    // that something is wrong.

    if (isWindowModified())
      {
      QMessageBox::StandardButton ret;
      ret = QMessageBox::warning 
       (this, tr("massXpert - Polymer Sequence Editor"),
         tr("The document %1 has been modified.\n"
             "Do you want to save your changes?")
         .arg(mpa_polymer->filePath()),
         QMessageBox::Save | QMessageBox::Discard 
         | QMessageBox::Cancel);
      
      if(ret == QMessageBox::Save)
        {
          // We want to save the file. If the file has no existing
          // file associate the save as function will be called
          // automatically.
          return save();
        }
      else if (ret == QMessageBox::Discard)
        return true;
      else if (ret == QMessageBox::Cancel)
        return false;
      }
  
    return true;
  }



  ////////////////////////////// SLOTS ///////////////////////////////
  bool
  SequenceEditorWnd::save()
  {
    // We must save to an xml file. It might be that the polymer
    // sequence is totally new, in which case the filePath() call will
    // return something invalid as a QFile object. In that case we ask
    // the saveAs() to do the job.

    if (!QFile::exists(mpa_polymer->filePath()))  
      return saveAs();
  
    if (!mpa_polymer->writeXmlFile())
      {
      statusBar()->showMessage(tr("File save failed."));
      return false;
      }
  
    statusBar()->showMessage(tr("File save succeeded."));
    setWindowModified(false);
    //  updateWindowTitle();
  
    return true;
  }


  bool
  SequenceEditorWnd::saveAs()
  {

    // We must save the new contents of the polymer sequence to an xml
    // file that is not the file from which this sequence might have
    // been saved.

    QString filePath = 
      QFileDialog::getSaveFileName(this, tr("Save Polymer Sequence File"),
                            QDir::homePath(),
                            tr("XML files(*.mxp *.mXp *.MXP)"));
  
    if (filePath.isEmpty())
      {
      statusBar()->showMessage(tr("Filepath is empty."));
      return false;
      }
  
    mpa_polymer->setFilePath(filePath);
  
    if (!mpa_polymer->writeXmlFile())
      {
      statusBar()->showMessage(tr("File save failed."));
      return false;
      }
  
    statusBar()->showMessage(tr("File save succeeded."));
    setWindowModified(false);
    updateWindowTitle();
  
    return true;
  }


  void
  SequenceEditorWnd::importRaw()
  {
    // Open a text file and make a QMxtSequence out of it. If errors,
    // then show the purification dialog.

    Sequence sequence;

    QString filePath;
    QString name;
  

    filePath = 
      QFileDialog::getOpenFileName(this, tr("Import Raw Text File"),
                            QDir::homePath(),
                            tr("Any file type(*)"));
      
    if (!QFile::exists(filePath))
      return;

    // Read the sequence.

    QFile file(filePath);
  
    if (!file.open(QFile::ReadOnly))
      return;

    QTextStream stream(&file);

    while(!stream.atEnd())
      {
      QString line = stream.readLine(1000);
      sequence.appendMonomerText(line);
      }
  
    // And now make sure the sequence is correct.

    QList<int> errorList ;
  
    if (sequence.makeMonomerList(mpa_polymer->polChemDef(),
                          true, &errorList) == -1)
      {
      SequencePurificationDlg *dlg = 
        new SequencePurificationDlg(this, &sequence, &errorList);
      
      dlg->show();
      
      return;
      }

    // At this point we can paste...
    int size = sequence.monomerList().size();
    int ret = mpa_editorGraphicsView->insertSequenceAtPoint(sequence);
  
    if ( ret != size)
      {
      QMessageBox::critical(0, 
                         tr("massXpert - Polymer Sequence Editor"),
                         tr("Failed to import the sequence."),
                         QMessageBox::Ok);
      }
  }



  void
  SequenceEditorWnd::clipboardCopy(QClipboard::Mode mode)
  {
    CoordinateList coordList;
    
    if (mpa_editorGraphicsView->selectionIndices(&coordList))
      {
      // There is a real selection, which is what we want, but if
      // there are more than one region selections than inform the
      // user.
      int selectionCount = coordList.size();
      
      if(selectionCount > 1)
        {
          QMessageBox::warning(this, 
                          tr("massXpert - Polymer Sequence Editor"),
                          tr("The sequence exported to the clipboard "
                              "will comprise %1 region selections.")
                          .arg(selectionCount),
                          QMessageBox::Ok);
        }

      QString *text = new QString;
      
      for(int iter = 0; iter < selectionCount; ++iter)
        {
          Coordinates *coordinates = coordList.at(iter);
          
          QString *sequence = 
            mpa_polymer->monomerText(coordinates->start(), 
                              coordinates->end(), false);
          
          *text += *sequence;
          
          delete sequence;
        }

      QClipboard *clipboard = QApplication::clipboard();
      clipboard->setText(*text, mode);
      
      delete text;
      }
  }
  
  
  void
  SequenceEditorWnd::clipboardCut(QClipboard::Mode mode)
  {
    CoordinateList coordList;
    
    if (mpa_editorGraphicsView->selectionIndices(&coordList))
      {
      // There is a real selection, which is what we want, but if
      // there are more than one region selections than we cannot
      // perform the action.
      int selectionCount = coordList.size();
      
      if(selectionCount > 1)
        {
          QMessageBox::information(this, 
                              tr("massXpert - Polymer Sequence Editor"),
                              tr("Cut operations are not supported "
                                "in multi-region selection mode."),
                              QMessageBox::Ok);
          
          return;
        }
      
      Coordinates *coordinates = coordList.last();

      QString *text = 
        mpa_polymer->monomerText(coordinates->start(), 
                            coordinates->end(), false);
      Q_ASSERT(text);
  
      QClipboard *clipboard = QApplication::clipboard();
      clipboard->setText(*text, mode);
  
      delete text;

      mpa_editorGraphicsView->removeSelectedOligomer();
      }
  }


  void
  SequenceEditorWnd::clipboardPaste(QClipboard::Mode mode)
  {
    CoordinateList coordList;
    
    if (mpa_editorGraphicsView->selectionIndices(&coordList))
      {
      // There is a real selection, which is what we want, but if
      // there are more than one region selections than we cannot
      // perform the action.
      int selectionCount = coordList.size();
      
      if(selectionCount > 1)
        {
          QMessageBox::information(this, 
                              tr("massXpert - Polymer Sequence Editor"),
                              tr("Paste operations are not supported "
                                "in multi-region selection mode."),
                              QMessageBox::Ok);
          
          return;
        }

      // There is one region selected, we have to first remove it
      // and then we insert the pasted sequence, which equals to a
      // sequence replacement.

      mpa_editorGraphicsView->removeSelectedOligomer();
      }
    
    QClipboard *clipboard = QApplication::clipboard();
    QString text;
  
    if (mode == QClipboard::Selection)
      text = clipboard->text(QClipboard::Selection);
    else
      text = clipboard->text(QClipboard::Clipboard);

    if (text.isEmpty())
      return;
    
    Sequence sequence(text);

    QList<int> errorList ;
  
    if (sequence.makeMonomerList(mpa_polymer->polChemDef(),
                          true, &errorList) == -1)
      {
      SequencePurificationDlg *dlg = 
        new SequencePurificationDlg(this, &sequence, &errorList);
      
      dlg->show();
      
      return;
      }

    // At this point we can paste...
    int size = sequence.monomerList().size();
    int ret = mpa_editorGraphicsView->insertSequenceAtPoint(sequence);
  
    if (ret != size)
      {
      QMessageBox::critical(0, 
                         tr("massXpert - Polymer Sequence Editor"),
                         tr("Failed to paste the sequence."),
                         QMessageBox::Ok);
      }
  }

  
  void
  SequenceEditorWnd::clipboardClear(QClipboard::Mode mode)
  {
    QClipboard *clipboard = QApplication::clipboard();

    clipboard->clear(mode);
  }


  void
  SequenceEditorWnd::findSequence()
  {
    SequenceEditorFindDlg *dlg = 
      new SequenceEditorFindDlg(this, mpa_polymer);
  
    dlg->show();
  
    return;
  }


  void 
  SequenceEditorWnd::vignetteSizeChanged()
  {
    int size = m_ui.vignetteSizeSpinBox->value();

    if (!m_postInitialized)
      return;
  
    mpa_editorGraphicsView->requestVignetteSize(size);
  }


  void 
  SequenceEditorWnd::nameLineEditChanged(const QString & text)
  {
    mpa_polymer->setName(text);
    setWindowModified(true);
    updateWindowTitle();
  }


  void
  SequenceEditorWnd::modifMonomer()
  {
    MonomerModificationDlg *dlg = new MonomerModificationDlg(this);
  
    dlg->show();
  }


  void
  SequenceEditorWnd::modifPolymer()
  {
    
    PolymerModificationDlg *dlg = new PolymerModificationDlg(this);
  
    dlg->show();
  }


  void
  SequenceEditorWnd::modifLeftEnd()
  {
    
    PolymerModificationDlg *dlg = 
      new PolymerModificationDlg(this, MXT_END_LEFT);
    
    dlg->show();
  }
  
  
  void
  SequenceEditorWnd::modifRightEnd()
  {
    
    PolymerModificationDlg *dlg = 
      new PolymerModificationDlg(this, MXT_END_RIGHT);
    
    dlg->show();
  }



  void
  SequenceEditorWnd::crossLinkMonomers()
  {
    MonomerCrossLinkDlg *dlg = new MonomerCrossLinkDlg(this);
  
    dlg->show();

    // Make the connection of the signal/slot pair, so that when a
    // crossLink changes in the polymer sequence, the
    // MonomerCrossLinkDlg will be triggered to redisplay the data.

    QObject::connect(mpa_polymer,
                  SIGNAL(crossLinkChangedSignal(Polymer *)),
                  dlg,
                  SLOT(crossLinkChangedSlot(Polymer *)));

    QObject::connect(this,
                  SIGNAL(polymerSequenceModifiedSignal()),
                  dlg,
                  SLOT(polymerSequenceModifiedSlot()));
  }
  

  void
  SequenceEditorWnd::cleave()
  {
    CleavageDlg *dlg = new CleavageDlg(this, 
                              mpa_polymer,
                              mpa_polymer->polChemDef(),
                              &m_calcOptions,
                              &m_ionizeRule);
    dlg->show();
  }


  void
  SequenceEditorWnd::fragment()
  {
    // At the moment we can only perform fragmentation on single
    // region selections.
    
    CoordinateList coordList;
    
    bool res = mpa_editorGraphicsView->selectionIndices(&coordList);
    
    if (!res)
      {
      QMessageBox::information(this, tr("massxpert"),
                          tr("No oligomer is selected. "
                              "Select an oligomer first"),
                          QMessageBox::Ok);
      return;
      }
    
    if (coordList.size() > 1)
      {
      QMessageBox::information(this, tr("massxpert"),
                          tr("Fragmentation simulations are not "
                              "supported\nin multi-region selection "
                              "mode."),
                          QMessageBox::Ok);
      return;
      }
    
    // No need to do this here, because the dialog window will have
    // its own calcOptions copy and will make this work anyway upon
    // initialization.
    
    //    m_calcOptions.setCoordinateList(coordList);
    
    FragmentationDlg *dlg = 
      new FragmentationDlg(this, 
                      mpa_polymer,
                      mpa_polymer->polChemDef(),
                      m_calcOptions,
                      m_ionizeRule);
  
    dlg->show();
  }


  void
  SequenceEditorWnd::massSearch()
  {
    MassSearchDlg *dlg = new MassSearchDlg(this, 
                                  mpa_polymer,
                                  m_calcOptions,
                                  &m_ionizeRule);
  
    dlg->show();
  }


  void
  SequenceEditorWnd::mzCalculation()
  {
    MzCalculationDlg *dlg = 
      new MzCalculationDlg(this, 
                      mpa_polymer->polChemDef(),
                      &m_ionizeRule);
  
    dlg->show();
  }


  void
  SequenceEditorWnd::compositions()
  {
    CompositionsDlg *dlg = 
      new CompositionsDlg(this, 
                     mpa_polymer,
                     &m_calcOptions,
                     &m_ionizeRule);
    
    dlg->show();
  }


  void
  SequenceEditorWnd::pkaPhPi()
  {
    // Make sure we can read the data file.

    // Where is the data file?
    QString filePath = mpa_polymer->polChemDef()->dirPath() +
      QDir::separator() + QString("pka_ph_pi.xml");

    //   qDebug() << __FILE__ << __LINE__
    //          << "pkaPhPi file is" << filePath;

    // Allocate the lists in which to store the different monomers and
    // modifs allocated upon parsing of the xml file.

    QList<Monomer *> *monomerList = new(QList<Monomer *>);
    QList<Modif *> *modifList = new(QList<Modif *>);
  
    // Create the parser using the above filePath.
    PkaPhPiDataParser parser(mpa_polymer->polChemDef(),
                        filePath);
  
    // Ask that the rendering be performed.
    if (!parser.renderXmlFile(monomerList, modifList))
      {
      delete monomerList;
      delete modifList;
      
      QMessageBox::warning(this, 
                        tr("massXpert - pKa pH pI"),
                        tr("%1@%2\n"
                          "Failed to render xml file(%3).")
                        .arg(__FILE__)
                        .arg(__LINE__)
                        .arg(filePath),
                        QMessageBox::Ok);
      return;
      }
      
    // Allocate a new PkaPhPi instance that we'll pass to the
    // dialog. Ownership of that object is taken by the dialog, which
    // will free it.
    PkaPhPi *pkaPhPi = new PkaPhPi(*mpa_polymer,
                            m_calcOptions,
                            monomerList,
                            modifList);
  
    PkaPhPiDlg *dlg = new PkaPhPiDlg(this, 
                              pkaPhPi,
                              *mpa_polymer,
                              m_calcOptions);
  
    dlg->show();
  }


  void
  SequenceEditorWnd::decimalPlacesOptions()
  {
    DecimalPlacesOptionsDlg *dlg = new DecimalPlacesOptionsDlg(this);
    
    dlg->show();
  }
  

  void 
  SequenceEditorWnd::crossLinksPartiallyEncompassedSlot(int count)
  {
    m_ui.incompleteCrossLinkWarningLabel->setText 
     (tr("Incomplete cross-links: %1").
       arg(count));
  }


  void
  SequenceEditorWnd::keyPressEvent(QKeyEvent *event)
  {
    event->accept(); 
  }


  void
  SequenceEditorWnd::updatePolymerEndsModifs()
  {
  
    QString text;
  
    text = mpa_polymer->leftEndModif().name();
  
    if (!text.isEmpty())
      {
      m_ui.leftEndModifPushButton->setText(text);
      }
    else
      {
      m_ui.leftEndModifPushButton->setText(tr("NOT_SET"));
      }
  
    text = mpa_polymer->rightEndModif().name();
  
    if (!text.isEmpty())
      {
      m_ui.rightEndModifPushButton->setText(text);
      }
    else
      {
      m_ui.rightEndModifPushButton->setText(tr("NOT_SET"));
      }
  }
  
  void 
  SequenceEditorWnd::vignetteListWidgetItemDoubleClicked(QListWidgetItem *item)
  {
    QString text = item->text();
        
    // The line of text has the following format:

    // Xcode=Name
    
    // Thus, we want to get the string prior to the '='

    QStringList elements = text.split("=");
    
    QString code = elements.first();
    
    // Now that we know the code, we can insert it at the right
    // place. First create a sequence with that code.

    Sequence sequence(code);
    QList<int> errorList;
        
    sequence.makeMonomerList(mp_polChemDef, false, &errorList);
    
    mpa_editorGraphicsView->insertSequenceAtPoint(sequence);
  }
  
} // namespace massXpert

Generated by  Doxygen 1.6.0   Back to index