Logo Search packages:      
Sourcecode: massxpert version File versions

mzLabInputOligomerTreeView.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 <QDebug>
#include <QHeaderView>
#include <QMouseEvent>


/////////////////////// Local includes
#include "mzLabInputOligomerTreeViewModel.hpp"
#include "mzLabInputOligomerTreeViewSortProxyModel.hpp"
#include "mzLabInputOligomerTreeView.hpp"
#include "mzLabInputOligomerTreeViewItem.hpp"
#include "cleaveOligomerTreeViewMimeData.hpp"
#include "fragmentOligomerTreeViewMimeData.hpp"
#include "massSearchOligomerTreeViewMimeData.hpp"
#include "oligomer.hpp"
#include "mzLabWnd.hpp"
#include "mzLabInputOligomerTreeViewDlg.hpp"
#include "application.hpp"


namespace massXpert
{

  MzLabInputOligomerTreeView::MzLabInputOligomerTreeView(QWidget *parent)
    : QTreeView(parent)
  {

    setAlternatingRowColors(true);
    setAllColumnsShowFocus(true);
    //    setSortingEnabled(true);
  
    QHeaderView *headerView = header();
  
    headerView->setClickable(true);
    headerView->setMovable(true);

    setAcceptDrops(true);
    setDropIndicatorShown(true);

    connect(this,
           SIGNAL(activated(const QModelIndex &)),
           this,
           SLOT(itemActivated(const QModelIndex &)));  
  }


  MzLabInputOligomerTreeView::~MzLabInputOligomerTreeView()
  {
  }


  MzLabInputOligomerTreeViewDlg *
  MzLabInputOligomerTreeView::getParentDlg()
  {
    return mp_parentDlg;
  }
  
  void 
  MzLabInputOligomerTreeView::setParentDlg(MzLabInputOligomerTreeViewDlg *dlg)
  {
    Q_ASSERT(dlg);
    mp_parentDlg = dlg;
  }

  
  MzLabWnd *
  MzLabInputOligomerTreeView::getMzLabWnd()
  {
    return mp_mzLabWnd;
  }
  

  void 
  MzLabInputOligomerTreeView::setMzLabWnd(MzLabWnd *wnd)
  {
    Q_ASSERT(wnd);
    
    mp_mzLabWnd = wnd;
  }
  


  void 
  MzLabInputOligomerTreeView::mousePressEvent(QMouseEvent *mouseEvent)
  {
    if (mouseEvent->buttons() & Qt::RightButton)
      {
      //contextMenu->popup(mouseEvent->globalPos());
      return;
      }
  
    QTreeView::mousePressEvent(mouseEvent);
  }

  
  void  
  MzLabInputOligomerTreeView::dragEnterEvent(QDragEnterEvent *event)
  {
    const CleaveOligomerTreeViewMimeData *treeViewData =
      qobject_cast<const CleaveOligomerTreeViewMimeData *>(event->mimeData());
    
    if (treeViewData)
      {
      event->acceptProposedAction();
      event->accept();
      return ;
      }
    else if (event->mimeData()->hasFormat("text/plain")) 
      {
      event->acceptProposedAction();
      event->accept();
      return ;
      }
    
    event->ignore();
    
    return;
  }
  
  
  void  
  MzLabInputOligomerTreeView::dragMoveEvent(QDragMoveEvent *event)
  {
    event->setDropAction(Qt::CopyAction);
    event->accept();
  }
  
  void  
  MzLabInputOligomerTreeView::dropEvent(QDropEvent *event)
  {
    PolChemDef *polChemDef = mp_mzLabWnd->polChemDef();
    const QList<Atom*> &atomList = polChemDef->atomList();

    IonizeRule ionizeRule = mp_mzLabWnd->ionizeRule();
    int totalCharge = ionizeRule.charge() * ionizeRule.level();
        
    // Check if one drop already occurred and if it was with the same
    // mass type as now. Otherwise alert the user.

    MassType previousMassType = mp_parentDlg->previousMassType();
    MassType massType = mp_parentDlg->massType();

    bool isFragment = mp_parentDlg->isFragment();
    
    if (previousMassType != MXT_MASS_NONE && 
      previousMassType != massType)
      {
      int ret = 
        QMessageBox::question(this, tr("massXpert: mzLab"),
                         tr("You are switching mass types." 
                             "Ok to continue ?"),
                         QMessageBox::Yes | QMessageBox::No,
                         QMessageBox::No);
      
      if(ret == QMessageBox::No)
        {
          event->ignore();
          return;
        }
      }
    
    OligomerList *oligomerList = new OligomerList("NOT_SET");
    
    // We may have data from:

    // A cleavage(CleaveOligomerTreeViewMimeData).

    // A fragmentation(FragmentOligomerTreeViewMimeData).

    // A arbitrary text.

    // Try with data from a cleavage.

    const CleaveOligomerTreeViewMimeData *treeViewMimeData =
      qobject_cast<const CleaveOligomerTreeViewMimeData *> 
     (event->mimeData());
    
    if (treeViewMimeData)
      {
      const CleaveOligomerTreeView *treeView  = treeViewMimeData->treeView();
      
      // Perform the copying of the data... The list below will
      // receive a copy of each oligomer in the drag start treeView.
      
      int count =
        treeView->selectedOligomers(oligomerList, oligomerList->size());
      
      if(!count)
        {
          delete oligomerList;

          return;
        }
      else
        {
          // We absolutely have to change the mp_polChemDef of the
          // oligomer, as it points to the polymer chemistry
          // definition tied to the sequence editor window's
          // polymer, but we cannot make sure that polymer chemistry
          // definition will remain there. Thus we change that
          // polymer chemistry definition pointer to point to ours.
          for (int iter = 0; iter < oligomerList->size(); ++iter)
            {
            Oligomer *oligomer = oligomerList->at(iter);
            
            oligomer->setPolChemDef(polChemDef);
            }
        }
      }
    else 
      {

      // Try with data from a fragmentation.

      const FragmentOligomerTreeViewMimeData *treeViewMimeData =
        qobject_cast<const FragmentOligomerTreeViewMimeData *> 
       (event->mimeData());
      
      if(treeViewMimeData)
        {
          // The data are from a fragmentation simulated in
          // massXpert, thus we can set the data format to fragment:
          mp_parentDlg->setFragment(true);
          
          const FragmentOligomerTreeView *treeView  = 
            treeViewMimeData->treeView();
          
          // Perform the copying of the data... The list below will
          // receive a copy of each oligomer in the drag start treeView.
          
          int count =
            treeView->selectedOligomers(oligomerList, oligomerList->size());
          
          if (!count)
            {
            delete oligomerList;

            return;
            }
          else
            {
            // We absolutely have to change the mp_polChemDef of
            // the oligomer, as it points to the polymer chemistry
            // definition tied to the sequence editor window's
            // polymer, but we cannot make sure that polymer
            // chemistry definition will remain there. Thus we
            // change that polymer chemistry definition pointer to
            // point to ours.
            for(int iter = 0; iter < oligomerList->size(); ++iter)
              {
                FragmentOligomer *oligomer = 
                  static_cast<FragmentOligomer *>(oligomerList->at(iter));
                
                oligomer->setPolChemDef(polChemDef);
              
//              qDebug() << __FILE__ << __LINE__
//                     << "charge:" << oligomer->charge();
//              oligomer->ionizeRule().debugPutStdErr();
              }
            }
        }
      else 
        {

          // Try with data from a mass search.

          const MassSearchOligomerTreeViewMimeData *treeViewMimeData =
            qobject_cast<const MassSearchOligomerTreeViewMimeData *> 
           (event->mimeData());
      
          if (treeViewMimeData)
            {
            const MassSearchOligomerTreeView *treeView  = 
              treeViewMimeData->treeView();
          
            // Perform the copying of the data... The list below will
            // receive a copy of each oligomer in the drag start treeView.
          
            int count =
              treeView->selectedOligomers(oligomerList, 
                                     oligomerList->size());
          
            if(!count)
              {
                delete oligomerList;

                return;
              }
            else
              {
                // We absolutely have to change the mp_polChemDef
                // of the oligomer, as it points to the polymer
                // chemistry definition tied to the sequence
                // editor window's polymer, but we cannot make
                // sure that polymer chemistry definition will
                // remain there. Thus we change that polymer
                // chemistry definition pointer to point to ours.
                for (int iter = 0; iter < oligomerList->size(); ++iter)
                  {
                  Oligomer *oligomer = oligomerList->at(iter);
                
                  oligomer->setPolChemDef(polChemDef);
                  }
              }
            }
          else
            {
            // Try with data from arbitrary text. 

            // Note that if the fragments checkbox is checked,
            // then oligomers that are created here on the basis
            // of the data should be FragmentOligomer instances
            // specially, for their ionization rule, to take into
            // account the fact that a FragmentOligomer instance
            // of charge one has actually no ionizeRule formula,
            // as it was created ionized from the beginning.

            if(event->mimeData()->hasText())
              {
                Application *application = static_cast<Application *>(qApp);
                QLocale locale = application->locale();
            
                QString text = event->mimeData()->text();
            
                // The text that we get might have a single item
                // per line, in which case this is the mass 'm',
                // or two items per line separated with a blank,
                // then these are the mass 'm' and the charge 'z'.
            
                QStringList stringList = text.split("\n",
                                           QString::SkipEmptyParts,
                                           Qt::CaseSensitive);
      
                // qDebug() << stringList;

                // At this point we either have strings like
                // "195.12392 3"(charge is present) or
                // "195.12392"(charge is absent).

                // Remember that the data should be read using the
                // locale of the system.

                for (int iter = 0; iter < stringList.size(); ++iter)
                  {
                  QString text = stringList.at(iter);
          
                  QStringList stringList = text.split(QRegExp("\\s+"),
                                               QString::SkipEmptyParts); 
          
                  if(stringList.size() == 1)
                    {
                      // Only a mass, and no charge, apparently.
                      bool ok = false;
            
                      double mass = locale.toDouble(stringList.first(), &ok);
            
                      if (!mass && !ok)
                        {
                        QMessageBox::warning(this,
                                          tr("massXpert - Drag and drop"),
                                          tr("%1@%2\n"
                                            "Failed to convert %3 to double")
                                          .arg(__FILE__)
                                          .arg(__LINE__)
                                          .arg(stringList.first()));
                
                        event->ignore();
                      
                        delete oligomerList;
                      
                        return;
                        }
            
                      Oligomer *oligomer = 0;
                      
                      if(!isFragment)
                        {
                        // Note that if the ionizeRule has a total charge
                        //(charge() * level()), then we have to set this
                        // oligomer to charged state(totalCharge ? true : false).
                        oligomer = 
                          new Oligomer(polChemDef, "NOT_SET",
                                    Ponderable(mass, mass),
                                    ionizeRule,
                                    (totalCharge ? true : false),
                                    -1, -1);
                        }
                      else
                        {
                        // We are dealing with an oligomer
                        // obtained via fragmentation, its
                        // treatement is thus somewhat more
                        // subtle.
                        
                        if(totalCharge == 1)
                          {
                            // The fragment oligomer is
                            // charged only once, which means
                            // we are creating an oligomer
                            // with no ionization rule, as, by
                            // defintion a fragmentation
                            // oligomer is created charged one
                            // with no proactive ionization.

                            IonizeRule tempIonizeRule;
                            
                            oligomer = 
                              new Oligomer(polChemDef, "NOT_SET",
                                        Ponderable(mass, mass),
                                        tempIonizeRule,
                                        false, -1, -1);
                          }
                        else
                          {
                            // The oligomer is ionized more
                            // than once. The ionization rule
                            // that we'll use is ionizeRule.
                            
                            IonizeRule tempIonizeRule;

                            tempIonizeRule.setFormula(ionizeRule.formula());

                            int incrementCharge = totalCharge - 1;
                            int requiredLevel = incrementCharge / ionizeRule.charge();

                            tempIonizeRule.setCharge(ionizeRule.charge());
                            tempIonizeRule.setLevel(requiredLevel);

                            if (!tempIonizeRule.validate(atomList))
                              {
                              QMessageBox::warning(this,
                                                tr("massXpert - Drag and drop"),
                                                tr("%1@%2\n"
                                                  "Failed to validate the "
                                                  "ionization rule")
                                                .arg(__FILE__)
                                                .arg(__LINE__));
                              
                              event->ignore();
                              
                              delete oligomerList;
                              
                              return;
                              }
                            
                            // Create an oligomer that IS
                            // ionized.
                            oligomer = 
                              new Oligomer(polChemDef, "NOT_SET",
                                        Ponderable(mass, mass),
                                        tempIonizeRule,
                                        true, -1, -1);
                          }
                        }
                      

                      qDebug() << __FILE__ << __LINE__
                             << "charge:" << oligomer->charge();
                  
                      oligomer->ionizeRule().debugPutStdErr();
                  
                      oligomerList->append(oligomer);
                    }
                  else if (stringList.size() == 2)
                    {
                      // One mass and one charge, apparently.
                      bool ok = false;
            
                      double mass = locale.toDouble(stringList.first(), &ok);
            
                      if (!mass && !ok)
                        {
                        QMessageBox::warning(this,
                                          tr("massXpert - Drag and drop"),
                                          tr("%1@%2\n"
                                            "Failed to convert %3 to double")
                                          .arg(__FILE__)
                                          .arg(__LINE__)
                                          .arg(stringList.first()));
                
                        event->ignore();

                        delete oligomerList;
                
                        return;
                        }

                      // Work with the charge
                      int charge = locale.toInt(stringList.at(1), &ok);
            
                      if (!charge && !ok)
                        {
                        QMessageBox::warning(this,
                                          tr("massXpert - Drag and drop"),
                                          tr("%1@%2\n"
                                            "Failed to convert %3 to int")
                                          .arg(__FILE__)
                                          .arg(__LINE__)
                                          .arg(stringList.at(1)));
                
                        event->ignore();
               
                        delete oligomerList;
                
                        return;
                        }
            
                      if(!isFragment)
                        {
                        ionizeRule.setLevel(charge);

                        // Note that if the ionizeRule has a total charge
                        //(charge() * level()), then we have to set this
                        // oligomer to charged state(totalCharge ? true : false).
                        Oligomer *oligomer = 
                          new Oligomer(polChemDef, "NOT_SET",
                                    Ponderable(mass, mass),
                                    ionizeRule,
                                    (totalCharge ? true : false),
                                    -1, -1);

                        qDebug() << __FILE__ << __LINE__
                               << "charge:" << oligomer->charge();
                        
                        oligomer->ionizeRule().debugPutStdErr();

                        oligomerList->append(oligomer);
                        }
                      else // if (isFragment)
                        {
                        // We are dealing with an oligomer
                        // obtained via fragmentation, its
                        // treatement is thus somewhat more
                        // subtle.
                        
                        if(charge == 1)
                          {
                            // The fragment oligomer is
                            // charged only once, which means
                            // we are creating an oligomer
                            // with no ionization rule, as, by
                            // defintion a fragmentation
                            // oligomer is created charged one
                            // with no proactive ionization.

                            IonizeRule tempIonizeRule;
                            
                            FragmentOligomer *oligomer = 
                              new FragmentOligomer(polChemDef, "NOT_SET",
                                              Ponderable(mass, mass),
                                              tempIonizeRule,
                                              false, -1, -1);
                            
                            qDebug() << __FILE__ << __LINE__
                                   << "charge:" 
                                   << static_cast<FragmentOligomer *>(oligomer)->
                              charge();

                            oligomer->ionizeRule().debugPutStdErr();
                            
                            oligomerList->append(oligomer);
                          }
                        else if (charge > 1)
                          {
                            // The oligomer is ionized more
                            // than once. The ionization rule
                            // that we'll use is ionizeRule.
                            
                            IonizeRule tempIonizeRule;

                            tempIonizeRule.setFormula(ionizeRule.formula());

                            int incrementCharge = charge - 1;
                            int requiredLevel = incrementCharge / ionizeRule.charge();

                            tempIonizeRule.setCharge(ionizeRule.charge());
                            tempIonizeRule.setLevel(requiredLevel);

                            if (!tempIonizeRule.validate(atomList))
                              {
                              QMessageBox::warning(this,
                                                tr("massXpert - Drag and drop"),
                                                tr("%1@%2\n"
                                                  "Failed to validate the "
                                                  "ionization rule")
                                                .arg(__FILE__)
                                                .arg(__LINE__));
                              
                              event->ignore();
                              
                              delete oligomerList;
                              
                              return;
                              }
                            
                            // Create an oligomer that IS
                            // ionized.
                            FragmentOligomer *oligomer = 
                              new FragmentOligomer(polChemDef, "NOT_SET",
                                        Ponderable(mass, mass),
                                        tempIonizeRule,
                                        true, -1, -1);
                            
                            qDebug() << __FILE__ << __LINE__
                                   << "charge:" 
                                   << static_cast<FragmentOligomer *>(oligomer)->
                              charge();
                            
                            oligomer->ionizeRule().debugPutStdErr();
                            
                            oligomerList->append(oligomer);
                          }
                        else if (!charge)
                          {
                            QMessageBox::warning(this,
                                            tr("massXpert - Drag and drop"),
                                            tr("%1@%2\n"
                                                "Charge of a fragmentation oligomer "
                                                "cannot be 0")
                                            .arg(__FILE__)
                                            .arg(__LINE__));
                            
                            event->ignore();
                            
                            delete oligomerList;
                            
                            return;
                          }
                        }

                    }
                  else
                    {
                      QMessageBox::warning(this,
                                      tr("massXpert - Drag and drop"),
                                      tr("%1@%2\n"
                                          "Failed to read line %3")
                                      .arg(__FILE__)
                                      .arg(__LINE__)
                                      .arg(stringList.first()));
            
                      event->ignore();
            
                      delete oligomerList;
            
                      return;
                    }
                  }
              }
            // End of
            // if (event->mimeData()->hasText())
            }
          // End of test data from mass search.
        }
      // End of test data from fragmentation.
      }
    // End of test data from cleavage.

    // At this point we should have something in oligomerList.
    
    if (!oligomerList->size())
      {
      event->ignore();

      delete oligomerList;
      
      return;
      }
    
    MzLabInputOligomerTreeViewModel *treeViewModel = 
      static_cast<MzLabInputOligomerTreeViewModel *>(model());
      
    while(oligomerList->size())
      {
      // At this point we want to add the oligomers to the model
      // data. we simultaneously remove the oligomer from the
      // list as the ownership passes to the model.
      treeViewModel->addOligomer(oligomerList->takeFirst());
      }
      
    // We want the action to be a copy action and not a move
    // action because the data come from "static" data residing in
    // the treeView of the cleavage dialog window.
    event->setDropAction(Qt::CopyAction);
    event->accept();

    delete oligomerList;

    // Let the dialog know that we have set masses of type
    // massType. This way, we'll be able to check that later drops
    // are for the same mass type.
    mp_parentDlg->setPreviousMassType(massType);
    
    return;
  }
  
  void 
  MzLabInputOligomerTreeView::itemActivated(const QModelIndex &index)
  {
    if (!index.isValid())
      return;

    MzLabInputOligomerTreeViewModel *model();
  
    MzLabInputOligomerTreeViewItem *childItem = 
      static_cast<MzLabInputOligomerTreeViewItem *> 
     (index.internalPointer());
    
    Oligomer *oligomer = childItem->oligomer();

//     qDebug() << __FILE__ << __LINE__
//         << oligomer->name();
    
    // From the oligomer, check that its mp_polymer member is still
    // non-0.

    const Polymer *polymer = oligomer->polymer();
    
    if (!polymer)
      {
//    qDebug() << __FILE__ << __LINE__;
      
      return;
      }
    
    // Get the sequence editor window pointer out of the oligomer, if
    // it has one in the form of a NoDeletePointerProp.

    Prop *prop = const_cast<Oligomer *>(oligomer)->prop("SEQUENCE_EDITOR_WND");
    
    if (!prop)
      {
//    qDebug() << __FILE__ << __LINE__;
      
      return;
      }
    
    SequenceEditorWnd *editorWnd = 
      static_cast<SequenceEditorWnd *>(prop->data());

    if (!editorWnd)
      return;
    
    CoordinateList *coordinateList = 
      static_cast<CoordinateList *>(const_cast<Oligomer *>(oligomer));
    
    // Remove the previous selection, so that we can start fresh.
    editorWnd->mpa_editorGraphicsView->resetSelection();
  
    for (int iter = 0; iter < coordinateList->size(); ++iter)
      {
      Coordinates *coordinates = coordinateList->at(iter);
      
      int start = coordinates->start();
      int end = coordinates->end();
      
      if(start >= polymer->size() ||
          end >= polymer->size())
        {
          QMessageBox::warning(this,
                          tr("massXpert - Cleavage"),
                          tr("%1@%2\n"
                              "The monomer indices do not correspond "
                              "to a valid polymer sequence range.\n"
                              "Avoid modifying the sequence while "
                              "working with oligomers.")
                          .arg(__FILE__)
                          .arg(__LINE__),
                          QMessageBox::Ok);
          
          return;
        }
      
      editorWnd->mpa_editorGraphicsView->setSelection(*coordinates, 
                                           true, false);
      }
    
    editorWnd->updateSelectedSequenceMasses();  
  }

} // namespace massXpert

Generated by  Doxygen 1.6.0   Back to index