1 /* massXpert - the true massist's program. 2 -------------------------------------- 3 Copyright(C) 2006,2007 Filippo Rusconi 4 5 http://www.massxpert.org/massXpert 6 7 This file is part of the massXpert project. 8 9 The massxpert project is the successor to the "GNU polyxmass" 10 project that is an official GNU project package(see 11 www.gnu.org). The massXpert project is not endorsed by the GNU 12 project, although it is released ---in its entirety--- under the 13 GNU General Public License. A huge part of the code in massXpert 14 is actually a C++ rewrite of code in GNU polyxmass. As such 15 massXpert was started at the Centre National de la Recherche 16 Scientifique(FRANCE), that granted me the formal authorization to 17 publish it under this Free Software License. 18 19 This software is free software; you can redistribute it and/or 20 modify it under the terms of the GNU General Public 21 License version 3, as published by the Free Software Foundation. 22 23 24 This software is distributed in the hope that it will be useful, 25 but WITHOUT ANY WARRANTY; without even the implied warranty of 26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 General Public License for more details. 28 29 You should have received a copy of the GNU General Public License 30 along with this software; if not, write to the 31 32 Free Software Foundation, Inc., 33 34 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 35 */ 36 37 38 /////////////////////// Qt includes 39 #include <QMessageBox> 40 41 42 /////////////////////// Local includes 43 #include "application.hpp" 44 #include "monomerModificationDlg.hpp" 45 46 47 namespace massXpert 48 { 49 MonomerModificationDlg(QWidget * parent)50 MonomerModificationDlg::MonomerModificationDlg(QWidget *parent) 51 : QDialog(parent) 52 { 53 Q_ASSERT(parent); 54 55 m_ui.setupUi(this); 56 57 mp_editorWnd = static_cast<SequenceEditorWnd *>(parent); 58 59 populateAvailableModifList(); 60 populateMonomerList(); 61 populateModifAndModifiedMonomerLists(); 62 63 updateSelectionData(); 64 if (m_coordinateList.size() >= 1) 65 m_ui.currentSelectionRadioButton->setChecked(true); 66 67 68 QSettings settings 69 (static_cast<Application *>(qApp)->configSettingsFilePath(), 70 QSettings::IniFormat); 71 72 settings.beginGroup("monomer_modification_dlg"); 73 74 restoreGeometry(settings.value("geometry").toByteArray()); 75 m_ui.hSplitter->restoreState(settings.value("hSplitter").toByteArray()); 76 m_ui.vSplitter->restoreState(settings.value("vSplitter").toByteArray()); 77 78 settings.endGroup(); 79 80 connect(m_ui.updateCurrentSelectionDataPushButton, 81 SIGNAL(clicked()), 82 this, 83 SLOT(updateSelectionData())); 84 85 connect(m_ui.modifiedMonomerListWidget, 86 SIGNAL(itemSelectionChanged()), 87 this, 88 SLOT(modifiedMonomerListWidgetItemSelectionChanged())); 89 90 connect(m_ui.modifListWidget, 91 SIGNAL(itemSelectionChanged()), 92 this, 93 SLOT(modifListWidgetItemSelectionChanged())); 94 95 m_ui.displayAllModifsCheckBox->setChecked(true); 96 connect(m_ui.displayAllModifsCheckBox, 97 SIGNAL(stateChanged(int)), 98 this, 99 SLOT(displayAllModifsChanged(int))); 100 101 connect(m_ui.modifyPushButton, 102 SIGNAL(clicked()), 103 this, 104 SLOT(modify())); 105 106 connect(m_ui.unmodifyPushButton, 107 SIGNAL(clicked()), 108 this, 109 SLOT(unmodify())); 110 111 connect(this, 112 SIGNAL(rejected()), 113 this, 114 SLOT(close())); 115 } 116 117 ~MonomerModificationDlg()118 MonomerModificationDlg::~MonomerModificationDlg() 119 { 120 } 121 122 123 void closeEvent(QCloseEvent * event)124 MonomerModificationDlg::closeEvent(QCloseEvent *event) 125 { 126 if (event) 127 printf("%s", ""); 128 129 QSettings settings 130 (static_cast<Application *>(qApp)->configSettingsFilePath(), 131 QSettings::IniFormat); 132 133 settings.beginGroup("monomer_modification_dlg"); 134 135 settings.setValue("geometry", saveGeometry()); 136 settings.setValue("hSplitter", m_ui.hSplitter->saveState()); 137 settings.setValue("vSplitter", m_ui.vSplitter->saveState()); 138 139 settings.endGroup(); 140 } 141 142 143 144 bool populateAvailableModifList()145 MonomerModificationDlg::populateAvailableModifList() 146 { 147 PolChemDef *polChemDef = mp_editorWnd->polChemDef(); 148 Q_ASSERT(polChemDef); 149 150 for (int iter = 0; iter < polChemDef->modifList().size(); ++iter) 151 { 152 Modif *modif = polChemDef->modifList().at(iter); 153 Q_ASSERT(modif); 154 155 m_ui.availableModifListWidget->addItem(modif->name()); 156 } 157 158 return true; 159 } 160 161 162 bool populateModifAndModifiedMonomerLists()163 MonomerModificationDlg::populateModifAndModifiedMonomerLists() 164 { 165 // We'll need a pointer to the polymer sequence. 166 Polymer *polymer = mp_editorWnd->polymer(); 167 168 m_ui.modifiedMonomerListWidget->clear(); 169 m_ui.modifListWidget->clear(); 170 171 // For all the monomers in the polymer sequence, check which 172 // modifications they bear. If any, add their name and monomer 173 // pointer to the list. 174 175 for (int iter = 0; iter < polymer->size(); ++iter) 176 { 177 const Monomer *monomer = polymer->at(iter); 178 179 QList<Modif *> *list = monomer->modifList(); 180 181 if(!list || list->isEmpty()) 182 continue; 183 184 // At this point we know the monomer is modified. Let's take the 185 // opportunity to add this monomer to the list of modified 186 // monomers. 187 188 QString text = QString("%1/%2/%3") 189 .arg(monomer->code()) 190 .arg(iter + 1) 191 .arg((quintptr) monomer); 192 193 m_ui.modifiedMonomerListWidget->addItem(text); 194 195 for(int jter = 0; jter < list->size(); ++jter) 196 { 197 Modif *modif = list->at(jter); 198 199 QString text = QString("%1/%2/%3/%4/%5") 200 .arg(modif->name()) 201 .arg(monomer->code()) 202 .arg(iter + 1) 203 .arg((quintptr) modif) 204 .arg((quintptr) monomer); 205 206 m_ui.modifListWidget->addItem(text); 207 } 208 } 209 210 return true; 211 } 212 213 214 bool populateModifiedMonomerList()215 MonomerModificationDlg::populateModifiedMonomerList() 216 { 217 // We'll need a pointer to the polymer sequence. 218 Polymer *polymer = mp_editorWnd->polymer(); 219 220 m_ui.modifiedMonomerListWidget->clear(); 221 222 // For all the monomers in the polymer sequence, check if they are 223 // modified. If so, add their code position and monomer pointer to 224 // the list. 225 226 for (int iter = 0; iter < polymer->size(); ++iter) 227 { 228 const Monomer *monomer = polymer->at(iter); 229 230 QList<Modif *> *list = monomer->modifList(); 231 232 if(!list || list->isEmpty()) 233 continue; 234 235 QString text = QString("%1/%2/%3") 236 .arg(monomer->code()) 237 .arg(iter + 1) 238 .arg((quintptr) monomer); 239 240 m_ui.modifiedMonomerListWidget->addItem(text); 241 } 242 243 return true; 244 } 245 246 247 bool populateModifList(bool all)248 MonomerModificationDlg::populateModifList(bool all) 249 { 250 // We'll need a pointer to the polymer sequence. 251 Polymer *polymer = mp_editorWnd->polymer(); 252 253 // First-off remove all the items. 254 m_ui.modifListWidget->clear(); 255 256 if (all) 257 { 258 // For all the monomers in the polymer sequence, check which 259 // modifications they bear. If any, add their name and monomer 260 // pointer to the list. 261 262 for(int iter = 0; iter < polymer->size(); ++iter) 263 { 264 const Monomer *monomer = polymer->at(iter); 265 266 QList<Modif *> *modifList = monomer->modifList(); 267 268 if (!modifList || modifList->isEmpty()) 269 continue; 270 271 for (int jter = 0; jter < modifList->size(); ++jter) 272 { 273 Modif *modif = modifList->at(jter); 274 275 QString text = QString("%1/%2/%3/%4/%5") 276 .arg(modif->name()) 277 .arg(monomer->code()) 278 .arg(iter + 1) 279 .arg((quintptr) modif) 280 .arg((quintptr) monomer); 281 282 m_ui.modifListWidget->addItem(text); 283 } 284 } 285 } 286 else 287 { 288 // We are interested only in the modifs for the currently 289 // selected cross-linked monomers(if any) in the 290 // modifiedMonomerListWidget. 291 292 QList<QListWidgetItem *> selectedList = 293 m_ui.modifiedMonomerListWidget->selectedItems(); 294 295 if(!selectedList.size()) 296 return true; 297 298 for(int iter = 0; iter < selectedList.size(); ++iter) 299 { 300 QListWidgetItem *item = selectedList.at(iter); 301 302 // What's the text of the item ? 303 QString text = item->text(); 304 305 // The string is in the form "code/pos/monomerPtr" 306 307 QStringList stringList = text.split('/', 308 QString::SkipEmptyParts, 309 Qt::CaseSensitive ); 310 311 // The monomer position is the second string in the list. 312 bool ok = false; 313 int pos = stringList.at(1).toInt(&ok); 314 315 if (!pos && !ok) 316 return false; 317 318 // What if the sequence changed and the monomer is no more 319 // in a valid range? We want to avoid a crash. See below for 320 // an even better sanity check. 321 if (pos - 1 < 0 || pos > polymer->size()) 322 { 323 QMessageBox::warning(this, 324 tr("massXpert - Modify monomers"), 325 tr("%1@%2\n" 326 "The monomer index does not correspond " 327 "to a valid polymer sequence range.\n" 328 "Avoid modifying the sequence while " 329 "working with modifications.") 330 .arg(__FILE__) 331 .arg(__LINE__), 332 QMessageBox::Ok); 333 334 populateModifAndModifiedMonomerLists(); 335 336 return false; 337 } 338 339 // The monomer(quintptr) pointer is the third string in the list. 340 ok = false; 341 quintptr pointerCastToInt = stringList.at(2).toInt(&ok); 342 Monomer *monomer = reinterpret_cast<Monomer *>(pointerCastToInt); 343 344 // Sanity check, are we dealing with the same monomer now 345 // compared to the one of which the item was displayed when 346 // the window was opened ? 347 if (monomer != polymer->at(pos - 1)) 348 { 349 QMessageBox::warning(this, 350 tr("massXpert - Modify monomers"), 351 tr("%1@%2\n" 352 "The monomer selected does not " 353 "correspond to a valid sequence " 354 "monomer.\n" 355 "Avoid modifying the sequence while " 356 "working with modifications.") 357 .arg(__FILE__) 358 .arg(__LINE__), 359 QMessageBox::Ok); 360 361 populateModifAndModifiedMonomerLists(); 362 363 return false; 364 } 365 366 // Iterate in the monomer's modifications and for each one 367 // create a new item. 368 369 QList<Modif *> *modifList = monomer->modifList(); 370 371 // It is not possible that the monomer has no modif, 372 // otherwise how come would it be listed in the list of 373 // modified monomers. 374 375 Q_ASSERT(modifList && !modifList->isEmpty()); 376 377 for (int jter = 0; jter < modifList->size(); ++jter) 378 { 379 Modif *modif = modifList->at(jter); 380 381 QString text = QString("%1/%2/%3/%4/%5") 382 .arg(modif->name()) 383 .arg(monomer->code()) 384 .arg(pos) 385 .arg((quintptr) modif) 386 .arg((quintptr) monomer); 387 388 m_ui.modifListWidget->addItem(text); 389 } 390 } 391 // End of 392 // for (int iter = 0; iter < selectedList.size(); ++iter) 393 } 394 // End of else , that is we only display modifs for selected 395 // monomers. 396 397 return true; 398 } 399 400 401 402 bool populateMonomerList()403 MonomerModificationDlg::populateMonomerList() 404 { 405 PolChemDef *polChemDef = mp_editorWnd->polChemDef(); 406 Q_ASSERT(polChemDef); 407 408 for (int iter = 0; iter < polChemDef->monomerList().size(); ++iter) 409 { 410 Monomer *monomer = polChemDef->monomerList().at(iter); 411 Q_ASSERT(monomer); 412 413 QString text = monomer->code() + '=' + monomer->name(); 414 415 m_ui.monomerListWidget->addItem(text); 416 } 417 418 return true; 419 } 420 421 422 void modifiedMonomerListWidgetItemSelectionChanged()423 MonomerModificationDlg::modifiedMonomerListWidgetItemSelectionChanged() 424 { 425 // When an item is selected in the list of modified monomers, then 426 // that means that the user does not want *all* the modifs to be 427 // listed. 428 429 m_ui.displayAllModifsCheckBox->setChecked(false); 430 431 // Update the modif list data by listing only the modifs of the 432 // currently selected monomer. 433 434 populateModifList(false); 435 } 436 437 438 void modifListWidgetItemSelectionChanged()439 MonomerModificationDlg::modifListWidgetItemSelectionChanged() 440 { 441 // qDebug() << __FILE__ << __LINE__ 442 // << "MonomerModificationDlg::" 443 // "modifListWidgetItemSelectionChanged()"; 444 } 445 446 displayAllModifsChanged(int checkState)447 void MonomerModificationDlg::displayAllModifsChanged(int checkState) 448 { 449 // When checked, we should list all the modifs in the 450 // modifListWidget, and not only the modifs for the currently 451 // selected modified monomer. 452 453 if (checkState == Qt::Checked) 454 populateModifList(true); 455 else 456 populateModifList(false); 457 } 458 459 460 bool updateSelectionData()461 MonomerModificationDlg::updateSelectionData() 462 { 463 // There might be more than one region selections. So get all 464 // these coordinates ! 465 466 bool res = mp_editorWnd->mpa_editorGraphicsView-> 467 selectionIndices(&m_coordinateList); 468 469 if (res) 470 { 471 // If there are more than one region selection or if there is 472 // one region selection but spanning more than one monomer, 473 // then set the target to be "current selected sequence". 474 475 if(m_coordinateList.size() > 1) 476 { 477 // Apparently there are multiple regions selected. 478 479 m_ui.currentSelectionLineEdit-> 480 setText(m_coordinateList.positionsAsText()); 481 } 482 else 483 { 484 Coordinates *coordinates = m_coordinateList.first(); 485 486 if (coordinates->start() == coordinates->end()) 487 { 488 489 // Construct a string with both the monomer code and 490 // its position in the sequence. 491 492 Polymer *polymer = mp_editorWnd->polymer(); 493 const Monomer *monomer = 494 polymer->monomerList().at(coordinates->start()); 495 496 QString text = tr("%1 at pos. %2") 497 .arg(monomer->code()) 498 .arg(coordinates->start() + 1); 499 500 m_ui.currentSelectionLineEdit->setText(text); 501 } 502 else 503 m_ui.currentSelectionLineEdit-> 504 setText(m_coordinateList.positionsAsText()); 505 } 506 } 507 508 // Return if there was a selection(multiple-region or not) or 509 // not. 510 return res; 511 } 512 513 514 515 int prepareIndicesList()516 MonomerModificationDlg::prepareIndicesList() 517 { 518 Polymer *polymer = mp_editorWnd->polymer(); 519 520 m_indicesList.clear(); 521 522 bool isSelectionPresent = updateSelectionData(); 523 524 if (m_ui.currentSelectionRadioButton->isChecked()) 525 { 526 // If there is no selection. 527 if(!isSelectionPresent) 528 return 0; 529 530 // Now, for each Coordinates in the CoordinateList, append the 531 // indices... 532 533 for(int iter = 0; iter < m_coordinateList.size(); ++iter) 534 { 535 Coordinates *coordinates = m_coordinateList.at(iter); 536 537 for (int iter = coordinates->start(); 538 iter < coordinates->end() + 1; ++iter) 539 m_indicesList.append(iter); 540 } 541 } 542 else if (m_ui.sameCodeRadioButton->isChecked()) 543 { 544 // Get the code of the currently selected monomer. 545 if(!isSelectionPresent) 546 return 0; 547 548 if(m_coordinateList.size() > 1) 549 return 0; 550 551 Coordinates *coordinates = m_coordinateList.at(0); 552 553 if(coordinates->start() != coordinates->end()) 554 return 0; 555 556 QString code = 557 polymer->monomerList().at(coordinates->start())->code(); 558 559 for(int iter = 0; iter < polymer->monomerList().size(); ++iter) 560 { 561 const Monomer *monomer = polymer->monomerList().at(iter); 562 Q_ASSERT(monomer); 563 564 if (monomer->code() == code) 565 m_indicesList.append(iter); 566 } 567 } 568 else if (m_ui.fromListRadioButton->isChecked()) 569 { 570 QList<QListWidgetItem *> selectedList = 571 m_ui.monomerListWidget->selectedItems(); 572 573 if(!selectedList.size()) 574 return 0; 575 576 for(int iter = 0; iter < selectedList.size(); ++iter) 577 { 578 QListWidgetItem *item = selectedList.at(iter); 579 580 QString text = item->text(); 581 582 int index = text.indexOf('='); 583 Q_ASSERT(index > 0); 584 585 QString code = text.left(index); 586 587 for (int jter = 0 ; jter < polymer->monomerList().size(); ++jter) 588 { 589 const Monomer *monomer = polymer->monomerList().at(jter); 590 Q_ASSERT(monomer); 591 592 if(monomer->code() == code) 593 m_indicesList.append(jter); 594 } 595 } 596 } 597 else if (m_ui.allRadioButton->isChecked()) 598 { 599 for(int iter = 0; iter < polymer->monomerList().size(); ++iter) 600 m_indicesList.append(iter); 601 } 602 else 603 { 604 QMessageBox::warning(this, 605 tr("massXpert - Modify monomers"), 606 tr("No target is selected."), 607 QMessageBox::Ok);; 608 return 0; 609 } 610 611 // qDebug() << "Indices:" << m_indicesList.size(); 612 613 return m_indicesList.size(); 614 } 615 616 617 bool parseModifDefinition(Modif * modif)618 MonomerModificationDlg::parseModifDefinition(Modif *modif) 619 { 620 Q_ASSERT(modif); 621 622 QString text = m_ui.modifNameLineEdit->text(); 623 624 modif->setName(text); 625 626 text = m_ui.modifFormulaLineEdit->text(); 627 628 modif->setFormula(text); 629 630 // Attention, we have to compute the masses of the modif ! 631 632 if (!modif->calculateMasses()) 633 return false; 634 635 text = m_ui.modifTargetsLineEdit->text(); 636 637 modif->setTargets(text); 638 639 if (!modif->validate()) 640 return false; 641 642 return true; 643 } 644 645 646 void modify()647 MonomerModificationDlg::modify() 648 { 649 QStringList errorList; 650 651 Polymer *polymer = mp_editorWnd->polymer(); 652 653 // There are two ways to perform a modification: either select one 654 // modification from the list of available modifications as defined 655 // in the polymer chemistry definition, or perform a quick and dirty 656 // modification definition in the dialog. 657 658 QString text; 659 660 Modif *modif = new Modif(polymer->polChemDef(), 661 "NOT_SET", 662 "NOT_SET"); 663 664 if (m_ui.defineModifGroupBox->isChecked()) 665 { 666 // The user wants to use a self-defined modification. 667 668 if(!parseModifDefinition(modif)) 669 { 670 QMessageBox::warning(this, 671 tr("massXpert - Modify monomers"), 672 tr("The defined modification failed " 673 "to parse."), 674 QMessageBox::Ok); 675 return; 676 } 677 678 // At this point the modification is correct. 679 } 680 else 681 { 682 // Get the modification currently selected. 683 QList<QListWidgetItem *> selectedList = 684 m_ui.availableModifListWidget->selectedItems(); 685 686 if(selectedList.size() != 1) 687 { 688 QMessageBox::warning(this, 689 tr("massXpert - Modify monomers"), 690 tr("No modification is selected " 691 "in the list."), 692 QMessageBox::Ok); 693 return; 694 } 695 696 text = selectedList.at(0)->text(); 697 Q_ASSERT(!text.isEmpty()); 698 699 // With the name of the modification get to the modif proper. 700 701 bool res = polymer->polChemDef()->modif(text, modif); 702 if(!res) 703 qFatal("Fatal error at %s@%d. Program aborted.", 704 __FILE__, __LINE__); 705 706 // At this point the modification is correct. Set a bool to true 707 // to know later that the modif was from the polChemDef. 708 } 709 710 // Is the modification work with allowed overriding of the target 711 // and the max count limitations? 712 bool override = m_ui.overrideLimitationsCheckBox->isChecked(); 713 714 // Construct a list of all the indices where the modification should 715 // apply. 716 if (!prepareIndicesList()) 717 return; 718 719 for (int iter = 0; iter < m_indicesList.size(); ++iter) 720 { 721 int index = m_indicesList.at(iter); 722 723 const Monomer *monomer = polymer->monomerList().at(index); 724 725 // Append the position and code of the currently iterated 726 // monomer. We will remove that string if the result is not 727 // bad. If the result below is bad, then the corresponding error 728 // will have been appended and we will not remove anything. 729 730 errorList.append(tr("Pos. %1: %2 --------------") 731 .arg(iter + 1) 732 .arg(monomer->code())); 733 734 // Upon modification, the monomer takes ownership of the modif, 735 // so we have to allocate one each time using the template 736 // prepared above. 737 738 Modif *newModif = new Modif(*modif); 739 740 int ret = const_cast<Monomer *>(monomer)->modify(newModif, 741 override, 742 errorList); 743 744 // The modification went ok, which means we can remove the last 745 // string that we prudentially added in case an error was to be 746 // output. If the modification failed(ret == false) we do not 747 // perform any modification for the monomer dealt-with. 748 749 if(!ret) 750 { 751 errorList.append("\n"); 752 } 753 else 754 { 755 errorList.removeLast(); 756 757 mp_editorWnd->setWindowModified(true); 758 759 // We have to make sure that the vignette knows for which 760 // chemical entity it is created. 761 762 ret = mp_editorWnd->mpa_editorGraphicsView-> 763 modifyVignetteAt(index, newModif); 764 765 Q_ASSERT(ret); 766 } 767 } 768 // End of 769 // for (int iter = 0; iter < m_indicesList.size(); ++iter) 770 771 m_ui.messagesTextEdit->append(tr("New operation: modify with %1\n") 772 .arg(modif->name()) + errorList.join("")); 773 774 // At this point we can delete the modif template. 775 delete modif; 776 777 populateModifAndModifiedMonomerLists(); 778 779 mp_editorWnd->updateWholeSequenceMasses(true); 780 mp_editorWnd->updateSelectedSequenceMasses(true); 781 782 // mp_editorWnd->mpa_editorGraphicsView->updateSequence(); 783 } 784 785 786 void unmodify()787 MonomerModificationDlg::unmodify() 788 { 789 // We only can unmodify in the following cases: 790 791 // If one or more modifications are selected in the 792 // m_ui.modifListWidget(which is a multiple selection list). 793 794 QList<QListWidgetItem *> selectedList = 795 m_ui.modifListWidget->selectedItems(); 796 797 if (!selectedList.size()) 798 return; 799 800 // For each item in the selection list, get the item, get to the 801 // monomer and perform the unmodification. 802 803 for (int iter = 0; iter < selectedList.size(); ++iter) 804 { 805 QListWidgetItem *item = selectedList.at(iter); 806 807 // Get the text which is of the form 808 809 // "Phosphorylation/S/12/136958312/136678312", 810 811 // which is the name of the modification, the code of the 812 // modified monomer and its position, the pointer to 813 // the modification and finally the pointer to 814 // the modified monomer". 815 816 QString text = item->text(); 817 818 QStringList stringList = text.split('/', 819 QString::SkipEmptyParts, 820 Qt::CaseSensitive ); 821 822 bool ok = false; 823 824 // The modif(quintptr) pointer is the third string in the list. 825 quintptr pointerCastToInt = stringList.at(3).toInt(&ok); 826 Modif *modif = reinterpret_cast<Modif *>(pointerCastToInt); 827 828 // The monomer(quintptr) pointer is the fourth string in the 829 // list. 830 ok = false; 831 pointerCastToInt = stringList.at(4).toInt(&ok); 832 Monomer *monomer = reinterpret_cast<Monomer *>(pointerCastToInt); 833 834 //Because the sequence might have changed since the moment 835 //this window was opened, we should make sure the monomer to 836 //unmodify is still there ! 837 838 int index = mp_editorWnd->polymer()->monomerIndex(monomer); 839 840 if(index == -1) 841 { 842 // Hmmm, the monomer is no more in the sequence, the 843 // sequence has been modified and the monomer has been 844 // erased. 845 846 QMessageBox::warning(this, 847 tr("massXpert - Modify monomers"), 848 tr("%1@%2\n" 849 "The monomer to unmodify does not exist " 850 "in the sequence anymore.\n" 851 "Avoid modifying the sequence while " 852 "working with modifications.") 853 .arg(__FILE__) 854 .arg(__LINE__), 855 QMessageBox::Ok); 856 857 populateModifAndModifiedMonomerLists(); 858 859 return; 860 } 861 862 863 // The monomer index at the time the monomer modification window 864 // was opened. Note that the index might change if the user 865 // edits the sequence after having opened *this window. Also, 866 // note that for the reader to use the value in the list item, 867 // it was set as a position, not an index, which means we have 868 // to remove one from the value. 869 // ok = false; 870 // int index = stringList.at(2).toInt(&ok) - 1; 871 872 873 // At this point we know which modification we have to remove 874 // and from which monomer. 875 876 int ret = monomer->unmodify(modif); 877 if(!ret) 878 qFatal("Fatal error at %s@%d. Program aborted.", 879 __FILE__, __LINE__); 880 881 mp_editorWnd->setWindowModified(true); 882 883 // At this point, we have to make sure we remove the 884 // modification vignette. 885 886 // Note that because a monomer might be modified more than once, 887 // and with the same modification, we ought to remove the proper 888 // vignette. 889 890 bool val = mp_editorWnd->mpa_editorGraphicsView-> 891 unmodifyVignetteAt(index, modif); 892 893 if(!val) 894 qFatal("Fatal error at %s@%d. Program aborted.", 895 __FILE__, __LINE__); 896 897 // mp_editorWnd->mpa_editorGraphicsView->updateSequence(); 898 } 899 900 populateModifAndModifiedMonomerLists(); 901 902 mp_editorWnd->updateWholeSequenceMasses(true); 903 mp_editorWnd->updateSelectedSequenceMasses(true); 904 } 905 906 } // namespace massXpert 907