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<QtGui> 40 #include<QtXml> 41 #include<QtGlobal> 42 #include<QMessageBox> 43 #include<QFileDialog> 44 45 /////////////////////// Local includes 46 #include "globals.hpp" 47 #include "application.hpp" 48 #include "sequenceEditorWnd.hpp" 49 #include "sequenceEditorGraphicsView.hpp" 50 #include "monomerModificationDlg.hpp" 51 #include "polymerModificationDlg.hpp" 52 #include "monomerCrossLinkDlg.hpp" 53 #include "cleavageDlg.hpp" 54 #include "fragmentationDlg.hpp" 55 #include "massSearchDlg.hpp" 56 #include "sequencePurificationDlg.hpp" 57 #include "sequenceImportDlg.hpp" 58 #include "mzCalculationDlg.hpp" 59 #include "compositionsDlg.hpp" 60 #include "pkaPhPi.hpp" 61 #include "pkaPhPiDataParser.hpp" 62 #include "pkaPhPiDlg.hpp" 63 #include "crossLink.hpp" 64 #include "crossLinkerSpec.hpp" 65 #include "decimalPlacesOptionsDlg.hpp" 66 #include "monomerDictionary.hpp" 67 68 69 namespace massXpert 70 { 71 SequenceEditorWnd()72 SequenceEditorWnd::SequenceEditorWnd() 73 { 74 mpa_polymer = 0; 75 76 m_forciblyClose = false; 77 m_noDelistWnd = false; 78 m_postInitialized = false; 79 80 if (!preInitialize()) 81 { 82 QMessageBox::warning(this, 83 tr("massXpert - Polymer Sequence Editor"), 84 tr("Failed to pre-initialize the polymer " 85 "sequence editor window."), 86 QMessageBox::Ok); 87 } 88 89 readSettings(); 90 91 show(); 92 } 93 94 ~SequenceEditorWnd()95 SequenceEditorWnd::~SequenceEditorWnd() 96 { 97 delete mpa_resultsString; 98 99 while(!m_propList.isEmpty()) 100 delete m_propList.takeFirst(); 101 102 delete mpa_editorGraphicsScene; 103 mpa_editorGraphicsScene = 0; 104 105 delete mpa_editorGraphicsView; 106 mpa_editorGraphicsView = 0; 107 108 delete mpa_polymer; 109 } 110 111 112 void writeSettings()113 SequenceEditorWnd::writeSettings() 114 { 115 QSettings settings 116 (static_cast<Application *>(qApp)->configSettingsFilePath(), 117 QSettings::IniFormat); 118 119 settings.beginGroup("sequence_editor_wnd"); 120 settings.setValue("geometry", saveGeometry()); 121 settings.setValue("vignetteSize", 122 mpa_editorGraphicsView->requestedVignetteSize()); 123 124 settings.setValue("hSplitterSize", m_ui.hSplitter->saveState()); 125 settings.setValue("vSplitterSize", m_ui.vSplitter->saveState()); 126 127 settings.setValue("calcEngineMonomersToolBox", 128 m_ui.calcEngineMonomersToolBox->currentIndex()); 129 130 settings.endGroup(); 131 } 132 133 134 void readSettings()135 SequenceEditorWnd::readSettings() 136 { 137 QSettings settings 138 (static_cast<Application *>(qApp)->configSettingsFilePath(), 139 QSettings::IniFormat); 140 141 settings.beginGroup("sequence_editor_wnd"); 142 143 restoreGeometry(settings.value("geometry").toByteArray()); 144 int vignetteSize = settings.value("vignetteSize", 32).toInt(); 145 mpa_editorGraphicsView->requestVignetteSize(vignetteSize); 146 m_ui.vignetteSizeSpinBox->setValue(vignetteSize); 147 148 m_ui.vSplitter-> 149 restoreState(settings.value("vSplitterSize").toByteArray()); 150 m_ui.hSplitter-> 151 restoreState(settings.value("hSplitterSize").toByteArray()); 152 153 m_ui.calcEngineMonomersToolBox-> 154 setCurrentIndex(settings.value("calcEngineMonomersToolBox").toInt()); 155 156 settings.endGroup(); 157 } 158 159 160 void closeEvent(QCloseEvent * event)161 SequenceEditorWnd::closeEvent(QCloseEvent *event) 162 { 163 Application *application = static_cast<Application *>(qApp); 164 165 // We are asked to close the window even if it has unsaved data. 166 if (m_forciblyClose) 167 { 168 m_forciblyClose = false; 169 170 // We have to delist the window. 171 if(!m_noDelistWnd) 172 { 173 m_noDelistWnd = false; 174 int index = application->sequenceEditorWndList()->indexOf(this); 175 176 application->sequenceEditorWndList()->takeAt(index); 177 } 178 179 writeSettings(); 180 181 event->accept(); 182 183 return; 184 } 185 186 if (maybeSave()) 187 { 188 // We are asked not to remove this window from the list of all 189 // the polymer chemistry definition windows. This occurs when 190 // all the windows are closed in a raw in the application 191 // object. 192 193 if(m_noDelistWnd) 194 { 195 m_noDelistWnd = false; 196 197 writeSettings(); 198 199 event->accept(); 200 201 return; 202 } 203 204 // We must remove this window from the application's list of 205 // such windows: 206 207 int index = application->sequenceEditorWndList()->indexOf(this); 208 209 application->sequenceEditorWndList()->takeAt(index); 210 211 writeSettings(); 212 213 event->accept(); 214 } 215 else 216 { 217 event->ignore(); 218 } 219 } 220 221 222 void focusInEvent(QFocusEvent * event)223 SequenceEditorWnd::focusInEvent(QFocusEvent *event) 224 { 225 if (!event) 226 printf("%s", ""); 227 228 Application *application = static_cast<Application *>(qApp); 229 application->setLastFocusedWnd(this); 230 } 231 232 233 void focusOutEvent(QFocusEvent * event)234 SequenceEditorWnd::focusOutEvent(QFocusEvent *event) 235 { 236 if (!event) 237 printf("%s", ""); 238 239 Application *application = static_cast<Application *>(qApp); 240 application->setLastFocusedWnd(0); 241 } 242 243 244 245 // The results-exporting functions. //////////////////////////////// 246 // The results-exporting functions. //////////////////////////////// 247 // The results-exporting functions. //////////////////////////////// 248 249 void prepareResultsTxtString()250 SequenceEditorWnd::prepareResultsTxtString() 251 { 252 mpa_resultsString->clear(); 253 254 // First whole sequence 255 bool entities =(m_calcOptions.monomerEntities() & 256 MXT_MONOMER_CHEMENT_MODIF); 257 258 QString *sequence = 259 mpa_polymer->monomerText(-1, -1, entities); 260 261 *mpa_resultsString += QObject::tr("\n---------------------------\n" 262 "Sequence Data: %1\n" 263 "---------------------------\n" 264 "Name: %1\n" 265 "Code : %2\n" 266 "File path: %3\n" 267 "Sequence: %4\n") 268 .arg(mpa_polymer->name()) 269 .arg(mpa_polymer->code()) 270 .arg(mpa_polymer->filePath()) 271 .arg(*sequence); 272 273 delete sequence; 274 275 *mpa_resultsString += QObject::tr("\nIonization rule:\n"); 276 277 *mpa_resultsString += QObject::tr("Formula: %1 - ") 278 .arg(m_ionizeRule.formula()); 279 280 *mpa_resultsString += QObject::tr("Charge: %1 - ") 281 .arg(m_ionizeRule.charge()); 282 283 *mpa_resultsString += QObject::tr("Level: %1\n") 284 .arg(m_ionizeRule.level()); 285 286 *mpa_resultsString += QObject::tr("\nCalculation options:\n"); 287 288 if (entities) 289 *mpa_resultsString += QObject::tr("Account monomer modifs: yes\n"); 290 else 291 *mpa_resultsString += QObject::tr("Account monomer modifs: no\n"); 292 293 entities =(m_calcOptions.monomerEntities() & 294 MXT_MONOMER_CHEMENT_CROSS_LINK); 295 296 if (entities) 297 *mpa_resultsString += QObject::tr("Account cross-links: yes\n"); 298 else 299 *mpa_resultsString += QObject::tr("Account cross-links: no\n"); 300 301 302 // Left end and right end modifs 303 entities =(m_calcOptions.polymerEntities() & 304 MXT_POLYMER_CHEMENT_LEFT_END_MODIF || 305 m_calcOptions.polymerEntities() & 306 MXT_POLYMER_CHEMENT_RIGHT_END_MODIF); 307 308 if (!entities) 309 { 310 *mpa_resultsString += QObject::tr("Account ends' modifs: no\n"); 311 } 312 else 313 { 314 *mpa_resultsString += QObject::tr("Account ends' modifs: yes - "); 315 316 // Left end modif 317 entities =(m_calcOptions.polymerEntities() & 318 MXT_POLYMER_CHEMENT_LEFT_END_MODIF); 319 if(entities) 320 { 321 *mpa_resultsString += QObject::tr("Left end modif: %1 - ") 322 .arg(mpa_polymer->leftEndModif().name()); 323 } 324 325 // Right end modif 326 entities =(m_calcOptions.polymerEntities() & 327 MXT_POLYMER_CHEMENT_RIGHT_END_MODIF); 328 if(entities) 329 { 330 *mpa_resultsString += QObject::tr("Right end modif: %1") 331 .arg(mpa_polymer->leftEndModif().name()); 332 } 333 } 334 335 // The options about multi-region selections and multi-selection 336 // regions. 337 if (m_ui.multiRegionSelectionCheckBox->checkState()) 338 { 339 *mpa_resultsString += 340 QObject::tr("\nMulti-region selection enabled: yes\n"); 341 342 if(m_ui.regionSelectionOligomerRadioButton->isChecked()) 343 { 344 *mpa_resultsString += 345 QObject::tr("Multi-region selections are " 346 "treated as oligomers\n"); 347 } 348 else if (m_ui.regionSelectionResChainRadioButton->isChecked()) 349 { 350 *mpa_resultsString += 351 QObject::tr("Multi-region selections are treated as " 352 "residual chains\n"); 353 } 354 355 if(m_ui.multiSelectionRegionCheckBox->checkState()) 356 { 357 *mpa_resultsString += 358 QObject::tr("Multi-selection region enabled: yes\n"); 359 } 360 else 361 { 362 *mpa_resultsString += 363 QObject::tr("Multi-selection region enabled: no\n"); 364 } 365 } 366 else 367 { 368 *mpa_resultsString += 369 QObject::tr("\nMulti-region selection enabled: no\n"); 370 } 371 372 // If there are cross-links, list all of these. 373 374 if (mpa_polymer->crossLinkList().size()) 375 { 376 *mpa_resultsString += QObject::tr("\n\nCross-links:\n"); 377 378 for(int iter = 0; iter < mpa_polymer->crossLinkList().size(); ++iter) 379 { 380 CrossLink *crossLink = mpa_polymer->crossLinkList().at(iter); 381 382 QString *text = crossLink->prepareResultsTxtString(); 383 384 Q_ASSERT(text); 385 386 *mpa_resultsString += *text; 387 388 delete text; 389 } 390 } 391 392 // Finally give the masses for the whole sequence: 393 394 QString value; 395 396 *mpa_resultsString += QObject::tr("\n\nWhole sequence mono mass: %1\n") 397 .arg(m_ui.monoWholeMassLineEdit->text()); 398 399 *mpa_resultsString += QObject::tr("Whole sequence avg mass: %1\n\n") 400 .arg(m_ui.avgWholeMassLineEdit->text()); 401 402 403 // And now the selected sequence region(s). 404 405 entities =(m_calcOptions.monomerEntities() & 406 MXT_MONOMER_CHEMENT_MODIF); 407 408 sequence = mpa_polymer->monomerText(m_calcOptions.coordinateList(), 409 entities, true); 410 411 *mpa_resultsString += *sequence; 412 413 delete sequence; 414 415 entities =(m_calcOptions.monomerEntities() & 416 MXT_MONOMER_CHEMENT_CROSS_LINK); 417 418 if (entities) 419 { 420 // We should inform that no, one, more cross-links might be left out: 421 *mpa_resultsString += QObject::tr("%1\n\n") 422 .arg(m_ui.incompleteCrossLinkWarningLabel->text()); 423 } 424 425 *mpa_resultsString += QObject::tr("Selected sequence mono mass: %1\n") 426 .arg(m_ui.monoSelectionMassLineEdit->text()); 427 428 *mpa_resultsString += QObject::tr("Selected sequence avg mass: %1\n") 429 .arg(m_ui.avgSelectionMassLineEdit->text()); 430 } 431 432 433 void exportClipboard()434 SequenceEditorWnd::exportClipboard() 435 { 436 prepareResultsTxtString(); 437 438 QClipboard *clipboard = QApplication::clipboard(); 439 440 clipboard->setText(*mpa_resultsString, QClipboard::Clipboard); 441 } 442 443 444 void exportFile()445 SequenceEditorWnd::exportFile() 446 { 447 if (m_resultsFilePath.isEmpty()) 448 { 449 if(!exportSelectFile()) 450 return; 451 } 452 453 QFile file(m_resultsFilePath); 454 455 if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) 456 { 457 QMessageBox::information(this, 458 tr("massXpert - Export Data"), 459 tr("Failed to open file in append mode."), 460 QMessageBox::Ok); 461 return; 462 } 463 464 QTextStream stream(&file); 465 stream.setCodec("UTF-8"); 466 467 prepareResultsTxtString(); 468 469 stream << *mpa_resultsString; 470 471 file.close(); 472 } 473 474 475 bool exportSelectFile()476 SequenceEditorWnd::exportSelectFile() 477 { 478 m_resultsFilePath = 479 QFileDialog::getSaveFileName(this, tr("Select File To Export Data To"), 480 QDir::homePath(), 481 tr("Data files(*.dat *.DAT)")); 482 483 if (m_resultsFilePath.isEmpty()) 484 return false; 485 486 return true; 487 488 } 489 // The results-exporting functions. //////////////////////////////// 490 // The results-exporting functions. //////////////////////////////// 491 // The results-exporting functions. //////////////////////////////// 492 493 494 495 496 void createActions()497 SequenceEditorWnd::createActions() 498 { 499 // File/Close 500 closeAct = new QAction(tr("&Close"), this); 501 closeAct->setShortcut(tr("Ctrl+W")); 502 closeAct->setStatusTip(tr("Closes the sequence")); 503 connect(closeAct, SIGNAL(triggered()), this, SLOT(close())); 504 505 // File/Save 506 saveAct = new QAction(tr("&Save"), this); 507 saveAct->setShortcut(tr("Ctrl+S")); 508 saveAct->setStatusTip(tr("Saves the sequence")); 509 connect(saveAct, SIGNAL(triggered()), this, SLOT(save())); 510 511 // File/SaveAs 512 saveAsAct = new QAction(tr("Save&as"), this); 513 saveAsAct->setShortcut(tr("Ctrl+Alt+S")); 514 saveAsAct->setStatusTip(tr("Saves the sequence in another file")); 515 connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs())); 516 517 518 519 // File/ImportRaw 520 importRawAct = new QAction(tr("&Import raw"), this); 521 importRawAct->setShortcut(tr("Ctrl+I")); 522 importRawAct->setStatusTip(tr("Imports a raw text file")); 523 connect(importRawAct, SIGNAL(triggered()), this, SLOT(importRaw())); 524 525 // File/ImportPdb 526 importPdbProtAct = new QAction(tr("&Import PDB"), this); 527 importPdbProtAct->setShortcut(tr("Ctrl+I")); 528 importPdbProtAct->setStatusTip(tr("Imports a PDB file")); 529 connect(importPdbProtAct, SIGNAL(triggered()), this, SLOT(importPdbProt())); 530 531 532 533 // File/ExportClipboard 534 exportClipboardAct = new QAction(tr("Export to &clipboard"), this); 535 exportClipboardAct->setShortcut 536 (QKeySequence(Qt::CTRL+Qt::Key_E,Qt::Key_C)); 537 exportClipboardAct->setStatusTip(tr("Export as text to the clipboard")); 538 connect(exportClipboardAct, SIGNAL(triggered()), 539 this, SLOT(exportClipboard())); 540 541 // File/ExportFile 542 exportFileAct = new QAction(tr("Export to &file"), this); 543 exportFileAct->setShortcut 544 (QKeySequence(Qt::CTRL+Qt::Key_E,Qt::Key_F)); 545 exportFileAct->setStatusTip(tr("Export as text to file")); 546 connect(exportFileAct, SIGNAL(triggered()), 547 this, SLOT(exportFile())); 548 549 // File/ExportSelectFile 550 exportSelectFileAct = new QAction(tr("&Select export file"), this); 551 exportSelectFileAct->setShortcut 552 (QKeySequence(Qt::CTRL+Qt::Key_E,Qt::Key_S)); 553 exportSelectFileAct->setStatusTip(tr("Select file to export as text to")); 554 connect(exportSelectFileAct, SIGNAL(triggered()), 555 this, SLOT(exportSelectFile())); 556 557 558 // Edit/Copy to Clipboard 559 clipboardCopyAct = new QAction(tr("&Copy"), this); 560 clipboardCopyAct->setShortcut(tr("Ctrl+C")); 561 clipboardCopyAct->setStatusTip(tr("Copy the selected " 562 "region of the sequence")); 563 connect(clipboardCopyAct, SIGNAL(triggered()), 564 this, SLOT(clipboardCopy())); 565 566 // Edit/Cut 567 clipboardCutAct = new QAction(tr("C&ut"), this); 568 clipboardCutAct->setShortcut(tr("Ctrl+X")); 569 clipboardCutAct->setStatusTip(tr("Cut the selected " 570 "region of the sequence")); 571 connect(clipboardCutAct, SIGNAL(triggered()), 572 this, SLOT(clipboardCut())); 573 574 // Edit/Paste 575 clipboardPasteAct = new QAction(tr("&Paste"), this); 576 clipboardPasteAct->setShortcut(tr("Ctrl+V")); 577 clipboardPasteAct->setStatusTip(tr("Copy the selected " 578 "region of the sequence")); 579 connect(clipboardPasteAct, SIGNAL(triggered()), 580 this, SLOT(clipboardPaste())); 581 582 // Edit/Find Sequence 583 findSequenceAct = new QAction(tr("&Find sequence"), this); 584 findSequenceAct->setShortcut(tr("Ctrl+F")); 585 findSequenceAct->setStatusTip(tr("Find a sequence " 586 "in the polymer sequence")); 587 connect(findSequenceAct, SIGNAL(triggered()), 588 this, SLOT(findSequence())); 589 590 591 // Chemistry/ModifyMonomer 592 modifMonomerAct = new QAction(tr("Modify &monomer(s)"), this); 593 modifMonomerAct->setShortcut 594 (QKeySequence(Qt::CTRL+Qt::Key_M,Qt::Key_M)); 595 modifMonomerAct->setStatusTip(tr("Modifies monomer(s)")); 596 connect(modifMonomerAct, SIGNAL(triggered()), this, 597 SLOT(modifMonomer())); 598 599 // Chemistry/ModifyPolymer 600 modifPolymerAct = new QAction(tr("Modify &polymer"), this); 601 modifPolymerAct->setShortcut 602 (QKeySequence(Qt::CTRL+Qt::Key_M,Qt::Key_P)); 603 modifPolymerAct->setStatusTip(tr("Modifies the polymer")); 604 connect(modifPolymerAct, SIGNAL(triggered()), this, 605 SLOT(modifPolymer())); 606 607 // Also connect that SLOT to the two buttons for left and right end 608 // modif. 609 610 connect(m_ui.leftEndModifPushButton, 611 SIGNAL(clicked()), 612 this, 613 SLOT(modifLeftEnd())); 614 615 connect(m_ui.rightEndModifPushButton, 616 SIGNAL(clicked()), 617 this, 618 SLOT(modifRightEnd())); 619 620 // Chemistry/CrossLinkMonomer 621 crossLinkMonomersAct = new QAction(tr("Cross-&link monomers"), this); 622 crossLinkMonomersAct->setShortcut 623 (QKeySequence(Qt::CTRL+Qt::Key_L,Qt::Key_M)); 624 crossLinkMonomersAct->setStatusTip(tr("Cross-link monomers")); 625 connect(crossLinkMonomersAct, SIGNAL(triggered()), this, 626 SLOT(crossLinkMonomers())); 627 628 // Chemistry/Cleave 629 cleaveAct = new QAction(tr("&Cleave"), this); 630 cleaveAct->setShortcut 631 (QKeySequence(Qt::CTRL+Qt::Key_K)); 632 cleaveAct->setStatusTip(tr("Cleaves the polymer")); 633 connect(cleaveAct, SIGNAL(triggered()), this, 634 SLOT(cleave())); 635 636 // Chemistry/Fragment 637 fragmentAct = new QAction(tr("Fra&gment"), this); 638 fragmentAct->setShortcut 639 (QKeySequence(Qt::CTRL+Qt::Key_G)); 640 fragmentAct->setStatusTip(tr("Fragments the polymer")); 641 connect(fragmentAct, SIGNAL(triggered()), this, 642 SLOT(fragment())); 643 644 // Chemistry/MassSearch 645 massSearchAct = new QAction(tr("Search &masses"), this); 646 massSearchAct->setShortcut 647 (QKeySequence(Qt::CTRL+Qt::Key_M,Qt::Key_S)); 648 massSearchAct->setStatusTip(tr("Search oligomers based on mass")); 649 connect(massSearchAct, SIGNAL(triggered()), this, 650 SLOT(massSearch())); 651 652 // Chemistry/mzCalculation 653 mzCalculationAct = new QAction(tr("Compute m/z &ratios"), this); 654 mzCalculationAct->setShortcut 655 (QKeySequence(Qt::CTRL+Qt::Key_M,Qt::Key_Z)); 656 mzCalculationAct->setStatusTip(tr("Compute ion charge families")); 657 connect(mzCalculationAct, SIGNAL(triggered()), this, 658 SLOT(mzCalculation())); 659 660 // Chemistry/compositions 661 compositionsAct = new QAction(tr("Determine compositions"), this); 662 compositionsAct->setShortcut 663 (QKeySequence(Qt::CTRL+Qt::Key_D,Qt::Key_C)); 664 compositionsAct->setStatusTip(tr("Determine compositions")); 665 connect(compositionsAct, SIGNAL(triggered()), this, 666 SLOT(compositions())); 667 668 // Chemistry/isoelectricPoint 669 pkaPhPiAct = new QAction(tr("pKa pH pI"), this); 670 pkaPhPiAct->setShortcut 671 (QKeySequence(Qt::CTRL+Qt::Key_P)); 672 pkaPhPiAct->setStatusTip(tr("pKa pH pI")); 673 connect(pkaPhPiAct, SIGNAL(triggered()), this, 674 SLOT(pkaPhPi())); 675 676 // Options/decimalPlaces 677 decimalPlacesOptionsAct = new QAction(tr("Decimal places"), this); 678 decimalPlacesOptionsAct->setShortcut 679 (QKeySequence(Qt::CTRL+Qt::Key_D)); 680 decimalPlacesOptionsAct->setStatusTip(tr("Decimal places")); 681 connect(decimalPlacesOptionsAct, SIGNAL(triggered()), this, 682 SLOT(decimalPlacesOptions())); 683 684 // Calculator (preseed with whole sequence masses) 685 newCalculatorWholeSequenceMassesAct = 686 new QAction(tr("New calculator (whole seq. masses)"), this); 687 688 newCalculatorWholeSequenceMassesAct->setStatusTip 689 (tr("Start new calculator preseeded with whole sequence masses")); 690 691 connect(newCalculatorWholeSequenceMassesAct, 692 SIGNAL(triggered()), 693 this, 694 SLOT(newCalculatorWholeSequenceMasses())); 695 696 // Calculator (preseed with selected sequence masses) 697 newCalculatorSelectedSequenceMassesAct = 698 new QAction(tr("New calculator (selected seq. masses)"), this); 699 700 newCalculatorSelectedSequenceMassesAct->setStatusTip 701 (tr("Start new calculator preseeded with selected sequence masses")); 702 703 connect(newCalculatorSelectedSequenceMassesAct, 704 SIGNAL(triggered()), 705 this, 706 SLOT(newCalculatorSelectedSequenceMasses())); 707 } 708 709 710 void createMenus()711 SequenceEditorWnd::createMenus() 712 { 713 fileMenu = menuBar()->addMenu(tr("&File")); 714 fileMenu->addAction(closeAct); 715 fileMenu->addSeparator(); 716 fileMenu->addAction(saveAct); 717 fileMenu->addAction(saveAsAct); 718 fileMenu->addSeparator(); 719 720 // Sequence importers menu 721 fileImportMenu = fileMenu->addMenu(tr("&Import")); 722 fileImportMenu->addAction(importRawAct); 723 fileImportMenu->addAction(importPdbProtAct); 724 725 fileMenu->addSeparator(); 726 fileMenu->addAction(exportClipboardAct); 727 fileMenu->addAction(exportFileAct); 728 fileMenu->addAction(exportSelectFileAct); 729 730 editMenu = menuBar()->addMenu(tr("&Edit")); 731 editMenu->addAction(clipboardCopyAct); 732 733 editMenu->addAction(clipboardCutAct); 734 editMenu->addAction(clipboardPasteAct); 735 editMenu->addSeparator(); 736 editMenu->addAction(findSequenceAct); 737 738 chemistryMenu = menuBar()->addMenu(tr("&Chemistry")); 739 chemistryMenu->addAction(modifMonomerAct); 740 chemistryMenu->addAction(modifPolymerAct); 741 chemistryMenu->addAction(crossLinkMonomersAct); 742 chemistryMenu->addAction(cleaveAct); 743 chemistryMenu->addAction(fragmentAct); 744 chemistryMenu->addAction(massSearchAct); 745 chemistryMenu->addAction(mzCalculationAct); 746 chemistryMenu->addAction(compositionsAct); 747 chemistryMenu->addAction(pkaPhPiAct); 748 749 optionsMenu = menuBar()->addMenu(tr("&Options")); 750 optionsMenu->addAction(decimalPlacesOptionsAct); 751 752 calculatorMenu = menuBar()->addMenu(tr("&Calculator")); 753 calculatorMenu->addAction(newCalculatorWholeSequenceMassesAct); 754 calculatorMenu->addAction(newCalculatorSelectedSequenceMassesAct); 755 } 756 757 758 // Before the creation of the polymer chemistry definition/polymer 759 // relationship. 760 bool preInitialize()761 SequenceEditorWnd::preInitialize() 762 { 763 m_ui.setupUi(this); 764 765 // The results-exporting menus. //////////////////////////////// 766 mpa_resultsString = new QString(); 767 //////////////////////////////////// The results-exporting menus. 768 769 QPixmap pixmap(":/images/massxpert-icon-32.png"); 770 QIcon icon(pixmap); 771 setWindowIcon(icon); 772 773 createActions(); 774 createMenus(); 775 776 setAttribute(Qt::WA_DeleteOnClose); 777 statusBar()->setSizeGripEnabled(true); 778 779 setFocusPolicy(Qt::StrongFocus); 780 781 m_ui.ionizationChargeSpinBox->setRange(1, 1000000000); 782 m_ui.ionizationLevelSpinBox->setRange(0, 1000000000); 783 784 // By default, selected regions behave as oligomers, the way one 785 // expects the system to behave when selecting oligomers that are 786 // cross-linked, for example. 787 m_ui.regionSelectionOligomerRadioButton->click(); 788 789 m_ui.incompleteCrossLinkWarningLabel->setText 790 (tr("Not accounting for cross-links")); 791 792 mpa_editorGraphicsView = new SequenceEditorGraphicsView(this); 793 mpa_editorGraphicsView->setParent(this); 794 // mpa_editorGraphicsView->setAlignment(Qt::AlignLeft); 795 796 QVBoxLayout *layout = new QVBoxLayout(m_ui.graphicsViewFrame); 797 798 layout->addWidget(static_cast<QWidget *>(mpa_editorGraphicsView)); 799 800 mp_progressBar = new QProgressBar; 801 statusBar()->addPermanentWidget(mp_progressBar); 802 803 // We want to be able to start a drag with the mass values... 804 m_ui.monoWholeMassLineEdit->setDragEnabled(true); 805 m_ui.avgWholeMassLineEdit->setDragEnabled(true); 806 807 m_ui.regionSelectionOligomerRadioButton->setChecked(true); 808 m_calcOptions.setSelectionType(SELECTION_TYPE_OLIGOMERS); 809 810 m_ui.multiRegionSelectionCheckBox->setChecked(true); 811 m_ui.multiSelectionRegionCheckBox->setChecked(false); 812 813 // Set the pointer to this window as text in the corresponding 814 // line edit widget. 815 816 QString text = QString("%1").arg((quintptr) this); 817 m_ui.thisWndLineEdit->setText(text); 818 819 setWindowModified(false); 820 821 return true; 822 } 823 824 825 bool postInitialize()826 SequenceEditorWnd::postInitialize() 827 { 828 Q_ASSERT(mpa_polymer); 829 830 connect(mpa_polymer, 831 SIGNAL(crossLinksPartiallyEncompassedSignal(int)), 832 this, 833 SLOT(crossLinksPartiallyEncompassedSlot(int))); 834 835 mpa_editorGraphicsScene = new QGraphicsScene(this); 836 mpa_editorGraphicsView->setPolymer(mpa_polymer); 837 mpa_editorGraphicsView->setScene(mpa_editorGraphicsScene); 838 839 MonomerCodeEvaluator *evaluator = 840 new MonomerCodeEvaluator(mpa_polymer, this, 841 m_ui.codeLineEdit, 842 m_ui.codeErrorLineEdit); 843 mpa_editorGraphicsView->setMonomerCodeEvaluator(evaluator); 844 845 m_ui.sequenceNameLineEdit->setText(mpa_polymer->name()); 846 updateWindowTitle(); 847 848 updatePolymerEndsModifs(); 849 850 statusBar()->showMessage(tr("Ready.")); 851 852 if (!populateMonomerCodeList()) 853 { 854 QMessageBox::warning(this, 855 tr("massXpert - Polymer Sequence Editor"), 856 tr("%1@%2\n" 857 "Failed to populate the monomer code list.") 858 .arg(__FILE__) 859 .arg(__LINE__), 860 QMessageBox::Ok); 861 862 return false; 863 } 864 865 populateCalculationOptions(); 866 867 m_ui.vignetteListWidget->setSelectionMode 868 (QAbstractItemView::MultiSelection); 869 870 871 ////// Connection of the SIGNALS and SLOTS ////// 872 connect(m_ui.vignetteSizeSpinBox, 873 SIGNAL(editingFinished()), 874 this, 875 SLOT(vignetteSizeChanged())); 876 877 connect(m_ui.sequenceNameLineEdit, 878 SIGNAL(textChanged(const QString &)), 879 this, 880 SLOT(nameLineEditChanged(const QString &))); 881 882 connect(m_ui.leftCapCheckBox, 883 SIGNAL(stateChanged(int)), 884 this, 885 SLOT(calculationOptionsChanged())); 886 887 connect(m_ui.rightCapCheckBox, 888 SIGNAL(stateChanged(int)), 889 this, 890 SLOT(calculationOptionsChanged())); 891 892 connect(m_ui.leftModifCheckBox, 893 SIGNAL(stateChanged(int)), 894 this, 895 SLOT(leftModifOptionsChanged())); 896 897 connect(m_ui.forceLeftModifCheckBox, 898 SIGNAL(stateChanged(int)), 899 this, 900 SLOT(forceLeftModifOptionsChanged())); 901 902 connect(m_ui.rightModifCheckBox, 903 SIGNAL(stateChanged(int)), 904 this, 905 SLOT(rightModifOptionsChanged())); 906 907 connect(m_ui.forceRightModifCheckBox, 908 SIGNAL(stateChanged(int)), 909 this, 910 SLOT(forceRightModifOptionsChanged())); 911 912 connect(m_ui.multiRegionSelectionCheckBox, 913 SIGNAL(stateChanged(int)), 914 this, 915 SLOT(multiRegionSelectionOptionChanged(int))); 916 917 connect(m_ui.multiSelectionRegionCheckBox, 918 SIGNAL(stateChanged(int)), 919 this, 920 SLOT(multiSelectionRegionOptionChanged(int))); 921 922 connect(m_ui.regionSelectionOligomerRadioButton, 923 SIGNAL(toggled(bool)), 924 this, 925 SLOT(regionSelectionOligomerOptionChanged(bool))); 926 927 connect(m_ui.regionSelectionResChainRadioButton, 928 SIGNAL(toggled(bool)), 929 this, 930 SLOT(regionSelectionResChainOptionChanged(bool))); 931 932 connect(m_ui.monomerModifCheckBox, 933 SIGNAL(stateChanged(int)), 934 this, 935 SLOT(monomerModifOptionChanged(int))); 936 937 connect(m_ui.monomerCrossLinkCheckBox, 938 SIGNAL(stateChanged(int)), 939 this, 940 SLOT(monomerCrossLinkOptionChanged(int))); 941 942 connect(m_ui.ionizationFormulaLineEdit, 943 SIGNAL(editingFinished()), 944 this, 945 SLOT(calculationOptionsChanged())); 946 947 connect(m_ui.ionizationChargeSpinBox, 948 SIGNAL(valueChanged(int)), 949 this, 950 SLOT(calculationOptionsChanged())); 951 952 connect(m_ui.ionizationLevelSpinBox, 953 SIGNAL(valueChanged(int)), 954 this, 955 SLOT(calculationOptionsChanged())); 956 957 connect(m_ui.selectionLineEdit, 958 SIGNAL(textEdited(const QString &)), 959 this, 960 SLOT(coordinatesManuallyEdited(const QString &))); 961 962 963 964 ////// Connection of the SIGNALS and SLOTS ////// 965 966 m_postInitialized = true; 967 968 return true; 969 } 970 971 972 QProgressBar * progressBar()973 SequenceEditorWnd::progressBar() 974 { 975 return mp_progressBar; 976 } 977 978 bool openSequence(QString & filePath)979 SequenceEditorWnd::openSequence(QString &filePath) 980 { 981 // We get the filePath of the sequence file. 982 983 if (filePath.isEmpty() || !QFile::exists(filePath)) 984 { 985 QMessageBox::warning(this, 986 tr("massXpert - Polymer Sequence Editor"), 987 tr("%1@%2\n" 988 "Filepath is empty, or file does not exist.") 989 .arg(__FILE__) 990 .arg(__LINE__), 991 QMessageBox::Ok); 992 993 return false; 994 } 995 996 QString name = 997 Polymer::xmlPolymerFileGetPolChemDefName(filePath); 998 999 if (name.isEmpty()) 1000 { 1001 QMessageBox::warning 1002 (this, 1003 tr("massXpert - Polymer Sequence Editor"), 1004 tr("%1@%2\n" 1005 "Failed to get the polymer chemistry definition name.") 1006 .arg(__FILE__) 1007 .arg(__LINE__), 1008 QMessageBox::Ok); 1009 1010 return false; 1011 } 1012 1013 mp_polChemDef = preparePolChemDef(name); 1014 1015 if (!mp_polChemDef) 1016 { 1017 QMessageBox::warning 1018 (this, 1019 tr("massXpert - Polymer Sequence Editor"), 1020 tr("%1@%2\n" 1021 "Failed to prepare the polymer chemistry definition.") 1022 .arg(__FILE__) 1023 .arg(__LINE__), 1024 QMessageBox::Ok); 1025 1026 return false; 1027 } 1028 1029 Application *application = static_cast<Application *>(qApp); 1030 1031 mpa_polymer = new Polymer(mp_polChemDef, "NOT_SET", "NOT_SET", 1032 application->userSpec()->userName()); 1033 1034 if (!readFile(filePath)) 1035 { 1036 QMessageBox::warning 1037 (this, 1038 tr("massXpert - Polymer Sequence Editor"), 1039 tr("%1@%2\n" 1040 "Failed to load the polymer file.") 1041 .arg(__FILE__) 1042 .arg(__LINE__), 1043 QMessageBox::Ok); 1044 1045 return false; 1046 } 1047 1048 if (!postInitialize()) 1049 return false; 1050 1051 if (mpa_editorGraphicsView->drawSequence() == -1) 1052 { 1053 QMessageBox::warning 1054 (this, 1055 tr("massXpert - Polymer Sequence Editor"), 1056 tr("%1@%2\n" 1057 "Failed to draw the polymer sequence.") 1058 .arg(__FILE__) 1059 .arg(__LINE__), 1060 QMessageBox::Ok); 1061 1062 return false; 1063 } 1064 1065 focusInEvent(0); 1066 1067 updateWholeSequenceMasses(); 1068 updateSelectedSequenceMasses(); 1069 1070 return true; 1071 } 1072 1073 1074 bool newSequence(QString & filePath)1075 SequenceEditorWnd::newSequence(QString &filePath) 1076 { 1077 Application *application = static_cast<Application *>(qApp); 1078 1079 1080 // We get the filePath of the polymer chemistry definition file. 1081 1082 PolChemDefSpec *polChemDefSpec = 1083 application->polChemDefSpecFilePath(filePath); 1084 1085 if (!polChemDefSpec) 1086 { 1087 QMessageBox::warning 1088 (this, 1089 tr("massXpert - Polymer Sequence Editor"), 1090 tr("%1@%2\n" 1091 "Failed to find the corresponding polymer chemistry " 1092 "filename.") 1093 .arg(__FILE__) 1094 .arg(__LINE__), 1095 QMessageBox::Ok); 1096 1097 return false; 1098 } 1099 1100 mp_polChemDef = preparePolChemDef(polChemDefSpec->name()); 1101 1102 if (!mp_polChemDef) 1103 { 1104 QMessageBox::warning 1105 (this, 1106 tr("massXpert - Polymer Sequence Editor"), 1107 tr("%1@%2\n" 1108 "Failed to prepare the polymer chemistry definition.") 1109 .arg(__FILE__) 1110 .arg(__LINE__), 1111 QMessageBox::Ok); 1112 1113 return false; 1114 } 1115 1116 mpa_polymer = new Polymer(mp_polChemDef, "NOT_SET", "NOT_SET", 1117 application->userSpec()->userName()); 1118 1119 if (!postInitialize()) 1120 return false; 1121 1122 if (mpa_editorGraphicsView->drawSequence() == -1) 1123 { 1124 QMessageBox::warning 1125 (this, 1126 tr("massXpert - Polymer Sequence Editor"), 1127 tr("%1@%2\n" 1128 "Failed to draw the polymer sequence.") 1129 .arg(__FILE__) 1130 .arg(__LINE__), 1131 QMessageBox::Ok); 1132 1133 return false; 1134 } 1135 1136 focusInEvent(0); 1137 1138 return true; 1139 } 1140 1141 1142 bool readFile(const QString & filePath)1143 SequenceEditorWnd::readFile(const QString &filePath) 1144 { 1145 return mpa_polymer->renderXmlPolymerFile(filePath); 1146 } 1147 1148 1149 PolChemDef * preparePolChemDef(const QString & name)1150 SequenceEditorWnd::preparePolChemDef(const QString &name) 1151 { 1152 Application *application = static_cast<Application *>(qApp); 1153 1154 // Is a polymer definition already available, or shall we have to 1155 // load one first ? 1156 PolChemDef *polChemDef = application->polChemDefName(name); 1157 // qDebug() << __FILE__ << __LINE__ << "polChemDef:" << polChemDef; 1158 1159 if (!polChemDef) 1160 { 1161 // No polymer chemistry definition by that name is currently 1162 // loaded in memory. We'll have to load one. 1163 1164 PolChemDefSpec *polChemDefSpec = 1165 application->polChemDefSpecName(name); 1166 1167 if(!polChemDefSpec) 1168 { 1169 // No polymer chemistry definition by that name is 1170 // registered to the system. We cannot go further. 1171 1172 QMessageBox::warning 1173 (this, 1174 tr("massXpert - Polymer Sequence Editor"), 1175 tr("%1@%2\n" 1176 "Failed to get the polymer chemistry " 1177 "definition specification: %3.") 1178 .arg(__FILE__) 1179 .arg(__LINE__) 1180 .arg(name), 1181 QMessageBox::Ok); 1182 1183 return 0; 1184 } 1185 1186 // polChemDefSpec should provide data to create a new polymer 1187 // chemistry definition object. 1188 1189 polChemDef = new PolChemDef(*polChemDefSpec); 1190 1191 if(!polChemDef->renderXmlPolChemDefFile()) 1192 { 1193 delete polChemDef; 1194 1195 QMessageBox::warning 1196 (this, 1197 tr("massXpert - Polymer Sequence Editor"), 1198 tr("%1@%2\n" 1199 "Failed to render the polymer chemistry" 1200 " definition xml file.") 1201 .arg(__FILE__) 1202 .arg(__LINE__), 1203 QMessageBox::Ok); 1204 1205 return 0; 1206 } 1207 1208 // We still have to initialize the m_monomerSpecList and 1209 // m_modifSpecList lists... 1210 QString dictionary = polChemDef->dirPath() + QDir::separator() + 1211 "monomer_dictionary"; 1212 1213 if(!MonomerSpec::parseFile(dictionary, 1214 polChemDef->monomerSpecList())) 1215 { 1216 delete polChemDef; 1217 1218 QMessageBox::warning 1219 (this, 1220 tr("massXpert - Polymer Sequence Editor"), 1221 tr("%1@%2\n" 1222 "Failed to parse the monomer dictionary file.") 1223 .arg(__FILE__) 1224 .arg(__LINE__), 1225 QMessageBox::Ok); 1226 1227 return 0; 1228 } 1229 1230 dictionary = polChemDef->dirPath() + QDir::separator() + 1231 "modification_dictionary"; 1232 1233 if(!ModifSpec::parseFile(dictionary, 1234 polChemDef->modifSpecList())) 1235 { 1236 delete polChemDef; 1237 1238 QMessageBox::warning 1239 (this, 1240 tr("massXpert - Polymer Sequence Editor"), 1241 tr("%1@%2\n" 1242 "Failed to parse the modification dictionary file.") 1243 .arg(__FILE__) 1244 .arg(__LINE__), 1245 QMessageBox::Ok); 1246 1247 return 0; 1248 } 1249 1250 dictionary = polChemDef->dirPath() + QDir::separator() + 1251 "cross_linker_dictionary"; 1252 1253 if(!CrossLinkerSpec::parseFile(dictionary, 1254 polChemDef->crossLinkerSpecList())) 1255 { 1256 delete polChemDef; 1257 1258 QMessageBox::warning 1259 (this, 1260 tr("massXpert - Polymer Sequence Editor"), 1261 tr("%1@%2\n" 1262 "Failed to parse the cross-linker dictionary file.") 1263 .arg(__FILE__) 1264 .arg(__LINE__), 1265 QMessageBox::Ok); 1266 1267 return 0; 1268 } 1269 1270 // Finally we can add this PolChemDef to the application list 1271 // of such objects. 1272 application->polChemDefList()->append(polChemDef); 1273 1274 // Note also that we have to tell the definition where to 1275 // auto-remove itself as soon as the reference count comes down 1276 // to 0. 1277 polChemDef->setRepositoryList(application->polChemDefList()); 1278 1279 // Finally increment the reference count of the polymer 1280 // chemistry definition. 1281 polChemDef->incrementRefCount(); 1282 } 1283 else 1284 polChemDef->incrementRefCount(); 1285 1286 return polChemDef; 1287 } 1288 1289 1290 1291 void populateCalculationOptions()1292 SequenceEditorWnd::populateCalculationOptions() 1293 { 1294 const PolChemDef *polChemDef = mpa_polymer->polChemDef(); 1295 1296 if (!polChemDef) 1297 return; 1298 1299 m_ionizeRule = polChemDef->ionizeRule(); 1300 1301 m_ui.ionizationFormulaLineEdit->setText(m_ionizeRule.formula()); 1302 m_ui.ionizationChargeSpinBox->setValue(m_ionizeRule.charge()); 1303 m_ui.ionizationLevelSpinBox->setValue(m_ionizeRule.level()); 1304 1305 // Update the masses|m/z ratios label. 1306 if (!m_ionizeRule.level()) 1307 { 1308 m_ui.massesOrMzGroupBox->setTitle(tr("Masses")); 1309 } 1310 else 1311 { 1312 m_ui.massesOrMzGroupBox->setTitle(tr("m/z ratios")); 1313 } 1314 1315 1316 // qDebug() << MXT_CAP_NONE << MXT_CAP_LEFT 1317 // << MXT_CAP_RIGHT << MXT_CAP_BOTH; 1318 1319 m_ui.leftCapCheckBox->setChecked(m_calcOptions.capping() & MXT_CAP_LEFT); 1320 m_ui.rightCapCheckBox->setChecked(m_calcOptions.capping() & MXT_CAP_RIGHT); 1321 1322 m_ui.monomerModifCheckBox->setChecked(m_calcOptions.monomerEntities() & 1323 MXT_MONOMER_CHEMENT_MODIF); 1324 1325 m_ui.leftModifCheckBox->setChecked(m_calcOptions.polymerEntities() & 1326 MXT_POLYMER_CHEMENT_LEFT_END_MODIF); 1327 m_ui.rightModifCheckBox->setChecked(m_calcOptions.polymerEntities() & 1328 MXT_POLYMER_CHEMENT_RIGHT_END_MODIF); 1329 } 1330 1331 1332 1333 void calculationOptionsChanged()1334 SequenceEditorWnd::calculationOptionsChanged() 1335 { 1336 // qDebug() << " calculationOptionsChanged"; 1337 1338 // CAPPING 1339 int value = 0; 1340 1341 if (m_ui.leftCapCheckBox->checkState() == Qt::Checked) 1342 value |= MXT_CAP_LEFT; 1343 1344 if (m_ui.rightCapCheckBox->checkState() == Qt::Checked) 1345 value |= MXT_CAP_RIGHT; 1346 1347 m_calcOptions.setCapping(value); 1348 1349 // qDebug() << "capping: " << m_calcOptions.capping(); 1350 1351 1352 // qDebug() << "polymer entities: " << m_calcOptions.polymerEntities(); 1353 1354 // IONIZATION RULE 1355 1356 QString text = m_ui.ionizationFormulaLineEdit->text(); 1357 1358 if (!text.isEmpty()) 1359 { 1360 const PolChemDef *polChemDef = mpa_polymer->polChemDef(); 1361 const QList<Atom *> &refList = polChemDef->atomList(); 1362 1363 Formula formula(text); 1364 1365 if(!formula.validate(refList)) 1366 { 1367 QMessageBox::warning(this, 1368 tr("massXpert - Polymer Sequence Editor"), 1369 tr("Ionization rule formula is not valid."), 1370 QMessageBox::Ok); 1371 1372 m_ui.ionizationFormulaLineEdit->setFocus(); 1373 1374 return; 1375 } 1376 1377 m_ionizeRule.setFormula(text); 1378 // qDebug() << "ionization formula: " << m_ionizeRule.formula(); 1379 1380 } 1381 1382 m_ionizeRule.setCharge(m_ui.ionizationChargeSpinBox->value()); 1383 // qDebug() << "ionization charge: " << m_ionizeRule.charge(); 1384 1385 m_ionizeRule.setLevel(m_ui.ionizationLevelSpinBox->value()); 1386 // qDebug() << "ionization level: " << m_ionizeRule.level(); 1387 1388 // Update the masses|m/z ratios label. 1389 if (!m_ionizeRule.level()) 1390 { 1391 m_ui.massesOrMzGroupBox->setTitle(tr("Masses")); 1392 } 1393 else 1394 { 1395 m_ui.massesOrMzGroupBox->setTitle(tr("m/z ratios")); 1396 } 1397 1398 updateWholeSequenceMasses(); 1399 updateSelectedSequenceMasses(); 1400 } 1401 1402 1403 // returns -1 in case of error, otherwise returns the number of 1404 // coordinates effectively present in the coordinateList 1405 int coordinatesManuallyEdited(const QString & text)1406 SequenceEditorWnd::coordinatesManuallyEdited(const QString &text) 1407 { 1408 // The user is editing new selection coordinates, so make the 1409 // corresponding selection in the sequence editor window. 1410 1411 QString oldCoordText = m_ui.selectionLineEdit->text(); 1412 QString newCoordText = text; 1413 1414 CoordinateList oldCoordList; 1415 mpa_editorGraphicsView->selectionIndices(&oldCoordList); 1416 1417 CoordinateList newCoordList; 1418 int res = newCoordList.setCoordinates(newCoordText); 1419 if (res == -1) 1420 { 1421 m_ui.selectionLineEdit->setText(oldCoordText); 1422 return -1; 1423 } 1424 1425 // Make sure the coordinates can fit the current selection model. 1426 1427 bool isMultiRegion = m_ui.multiRegionSelectionCheckBox->checkState(); 1428 bool isMultiSelection = m_ui.multiSelectionRegionCheckBox->checkState(); 1429 1430 if(newCoordList.size() > 1 && !isMultiRegion) 1431 { 1432 m_ui.selectionLineEdit->setText(oldCoordText); 1433 return -1; 1434 } 1435 1436 if(newCoordList.overlap() && !isMultiSelection) 1437 { 1438 m_ui.selectionLineEdit->setText(oldCoordText); 1439 return -1; 1440 } 1441 1442 // At this point, we should be able to change the coordinates of 1443 // the selection according to the user's wishes. 1444 1445 mpa_editorGraphicsView->resetSelection(); 1446 mpa_editorGraphicsView->setSelection(newCoordList, 1447 isMultiRegion, 1448 isMultiSelection); 1449 1450 return newCoordList.size(); 1451 } 1452 1453 1454 void leftModifOptionsChanged()1455 SequenceEditorWnd::leftModifOptionsChanged() 1456 { 1457 // POLYMER MODIFICATION 1458 int flags = m_calcOptions.polymerEntities(); 1459 1460 if (m_ui.leftModifCheckBox->checkState() == Qt::Checked) 1461 { 1462 flags |= MXT_POLYMER_CHEMENT_LEFT_END_MODIF; 1463 } 1464 else 1465 { 1466 flags &= ~MXT_POLYMER_CHEMENT_LEFT_END_MODIF; 1467 1468 if(m_ui.forceLeftModifCheckBox->checkState() == Qt::Checked) 1469 { 1470 m_ui.forceLeftModifCheckBox->toggle(); 1471 flags &= ~MXT_POLYMER_CHEMENT_FORCE_LEFT_END_MODIF; 1472 } 1473 } 1474 1475 m_calcOptions.setPolymerEntities(flags); 1476 1477 updateWholeSequenceMasses(); 1478 updateSelectedSequenceMasses(false); 1479 } 1480 1481 1482 void forceLeftModifOptionsChanged()1483 SequenceEditorWnd::forceLeftModifOptionsChanged() 1484 { 1485 // POLYMER MODIFICATION 1486 int flags = m_calcOptions.polymerEntities(); 1487 1488 if (m_ui.forceLeftModifCheckBox->checkState() == Qt::Checked) 1489 { 1490 if(m_ui.leftModifCheckBox->checkState() != Qt::Checked) 1491 { 1492 m_ui.leftModifCheckBox->toggle(); 1493 flags |= MXT_POLYMER_CHEMENT_LEFT_END_MODIF; 1494 } 1495 1496 flags |= MXT_POLYMER_CHEMENT_FORCE_LEFT_END_MODIF; 1497 } 1498 else 1499 { 1500 flags &= ~MXT_POLYMER_CHEMENT_FORCE_LEFT_END_MODIF; 1501 } 1502 1503 m_calcOptions.setPolymerEntities(flags); 1504 1505 updateWholeSequenceMasses(); 1506 updateSelectedSequenceMasses(false); 1507 } 1508 1509 1510 void rightModifOptionsChanged()1511 SequenceEditorWnd::rightModifOptionsChanged() 1512 { 1513 // POLYMER MODIFICATION 1514 int flags = m_calcOptions.polymerEntities(); 1515 1516 if (m_ui.rightModifCheckBox->checkState() == Qt::Checked) 1517 { 1518 flags |= MXT_POLYMER_CHEMENT_RIGHT_END_MODIF; 1519 } 1520 else 1521 { 1522 flags &= ~MXT_POLYMER_CHEMENT_RIGHT_END_MODIF; 1523 1524 if(m_ui.forceRightModifCheckBox->checkState() == Qt::Checked) 1525 { 1526 m_ui.forceRightModifCheckBox->toggle(); 1527 flags &= ~MXT_POLYMER_CHEMENT_FORCE_RIGHT_END_MODIF; 1528 } 1529 } 1530 1531 m_calcOptions.setPolymerEntities(flags); 1532 1533 updateWholeSequenceMasses(); 1534 updateSelectedSequenceMasses(false); 1535 } 1536 1537 1538 void forceRightModifOptionsChanged()1539 SequenceEditorWnd::forceRightModifOptionsChanged() 1540 { 1541 // POLYMER MODIFICATION 1542 int flags = m_calcOptions.polymerEntities(); 1543 1544 if (m_ui.forceRightModifCheckBox->checkState() == Qt::Checked) 1545 { 1546 if(m_ui.rightModifCheckBox->checkState() != Qt::Checked) 1547 { 1548 m_ui.rightModifCheckBox->toggle(); 1549 flags |= MXT_POLYMER_CHEMENT_RIGHT_END_MODIF; 1550 } 1551 1552 flags |= MXT_POLYMER_CHEMENT_FORCE_RIGHT_END_MODIF; 1553 } 1554 else 1555 { 1556 flags &= ~MXT_POLYMER_CHEMENT_FORCE_RIGHT_END_MODIF; 1557 } 1558 1559 m_calcOptions.setPolymerEntities(flags); 1560 1561 updateWholeSequenceMasses(); 1562 updateSelectedSequenceMasses(false); 1563 } 1564 1565 1566 void multiRegionSelectionOptionChanged(int checkState)1567 SequenceEditorWnd::multiRegionSelectionOptionChanged(int checkState) 1568 { 1569 if (checkState == Qt::Unchecked) 1570 { 1571 // qDebug() << __FILE__ << __LINE__ 1572 // << "multiRegionSelectionOptionChanged: unchecked"; 1573 1574 // No multi-region selection... We remove all selections but 1575 // the last one. 1576 mpa_editorGraphicsView->resetSelectionButLastRegion(); 1577 mpa_editorGraphicsView->setOngoingMouseMultiSelection(false); 1578 1579 // Note that if no multi region selections are allowed, 1580 // multi-selection regions should be disallowed also. But we 1581 // do not want to uncheck the checkbox, we just inactivate it. 1582 1583 m_ui.multiSelectionRegionCheckBox->setEnabled(false); 1584 } 1585 else 1586 { 1587 // Note that if multi region selections are allowed, 1588 // multi-selection regions should be possible also. 1589 1590 m_ui.multiSelectionRegionCheckBox->setEnabled(true); 1591 } 1592 1593 updateSelectedSequenceMasses(false); 1594 } 1595 1596 1597 bool isMultiRegionSelection()1598 SequenceEditorWnd::isMultiRegionSelection() 1599 { 1600 return m_ui.multiRegionSelectionCheckBox->isChecked(); 1601 } 1602 1603 1604 void multiSelectionRegionOptionChanged(int checkState)1605 SequenceEditorWnd::multiSelectionRegionOptionChanged(int checkState) 1606 { 1607 if (checkState == Qt::Unchecked) 1608 { 1609 // qDebug() << __FILE__ << __LINE__ 1610 // << "multiSelectionRegionOptionChanged: unchecked"; 1611 1612 // No multi-selection regions... We remove all selections but 1613 // the first one. 1614 mpa_editorGraphicsView->resetMultiSelectionRegionsButFirstSelection(); 1615 mpa_editorGraphicsView->setOngoingMouseMultiSelection(false); 1616 } 1617 1618 updateSelectedSequenceMasses(false); 1619 } 1620 1621 1622 bool isMultiSelectionRegion()1623 SequenceEditorWnd::isMultiSelectionRegion() 1624 { 1625 return m_ui.multiSelectionRegionCheckBox->isChecked(); 1626 } 1627 1628 1629 void regionSelectionOligomerOptionChanged(bool checked)1630 SequenceEditorWnd::regionSelectionOligomerOptionChanged(bool checked) 1631 { 1632 if (checked) 1633 { 1634 // qDebug() << __FILE__ << __LINE__ 1635 // << "regionSelectionOligomerOptionChanged checked"; 1636 1637 m_calcOptions.setSelectionType(SELECTION_TYPE_OLIGOMERS); 1638 } 1639 else 1640 m_calcOptions.setSelectionType(SELECTION_TYPE_RESIDUAL_CHAINS); 1641 1642 updateSelectedSequenceMasses(false); 1643 } 1644 1645 1646 void regionSelectionResChainOptionChanged(bool checked)1647 SequenceEditorWnd::regionSelectionResChainOptionChanged(bool checked) 1648 { 1649 if (checked) 1650 { 1651 // qDebug() << __FILE__ << __LINE__ 1652 // << "regionSelectionResChainOptionChanged checked"; 1653 1654 m_calcOptions.setSelectionType(SELECTION_TYPE_RESIDUAL_CHAINS); 1655 } 1656 else 1657 m_calcOptions.setSelectionType(SELECTION_TYPE_OLIGOMERS); 1658 1659 updateSelectedSequenceMasses(false); 1660 } 1661 1662 1663 void monomerModifOptionChanged(int checkState)1664 SequenceEditorWnd::monomerModifOptionChanged(int checkState) 1665 { 1666 int flags = m_calcOptions.monomerEntities(); 1667 1668 if (checkState == Qt::Checked) 1669 flags |= MXT_MONOMER_CHEMENT_MODIF; 1670 else 1671 flags &= ~MXT_MONOMER_CHEMENT_MODIF; 1672 1673 // if (flags & MXT_MONOMER_CHEMENT_MODIF) 1674 // qDebug() << __FILE__ << __LINE__ 1675 // << "monomerEntities set for MXT_MONOMER_CHEMENT_MODIF"; 1676 // else 1677 // qDebug() << __FILE__ << __LINE__ 1678 // << "monomerEntities NOT set for MXT_MONOMER_CHEMENT_MODIF"; 1679 1680 m_calcOptions.setMonomerEntities(flags); 1681 1682 updateWholeSequenceMasses(true); 1683 updateSelectedSequenceMasses(true); 1684 } 1685 1686 1687 1688 void monomerCrossLinkOptionChanged(int checkState)1689 SequenceEditorWnd::monomerCrossLinkOptionChanged(int checkState) 1690 { 1691 int flags = m_calcOptions.monomerEntities(); 1692 1693 if (checkState == Qt::Checked) 1694 flags |= MXT_MONOMER_CHEMENT_CROSS_LINK; 1695 else 1696 { 1697 flags &= ~MXT_MONOMER_CHEMENT_CROSS_LINK; 1698 1699 m_ui.incompleteCrossLinkWarningLabel->setText 1700 (tr("Not accounting for cross-links")); 1701 } 1702 1703 // if (flags & MXT_MONOMER_CHEMENT_CROSS_LINK) 1704 // qDebug() << __FILE__ << __LINE__ 1705 // << "monomerEntities set for MXT_MONOMER_CHEMENT_CROSS_LINK"; 1706 // else 1707 // qDebug() << __FILE__ << __LINE__ 1708 // << "monomerEntities NOT set for MXT_MONOMER_CHEMENT_CROSS_LINK"; 1709 1710 m_calcOptions.setMonomerEntities(flags); 1711 1712 1713 // When cross-links are to be accounted for, the multi-selection 1714 // region feature has to be inactivated. 1715 1716 m_ui.multiSelectionRegionCheckBox->setChecked(false); 1717 1718 updateWholeSequenceMasses(true); 1719 updateSelectedSequenceMasses(true); 1720 } 1721 1722 1723 1724 bool populateMonomerCodeList(bool reset)1725 SequenceEditorWnd::populateMonomerCodeList(bool reset) 1726 { 1727 QListWidgetItem *item = 0; 1728 1729 const PolChemDef *polChemDef = mpa_polymer->polChemDef(); 1730 1731 if (!polChemDef) 1732 return true; 1733 1734 if (reset) 1735 { 1736 while( m_ui.vignetteListWidget->count()) 1737 { 1738 item = m_ui.vignetteListWidget->takeItem(0); 1739 // qDebug() << __FILE__ << __LINE__ 1740 // << item->text().toAscii(); 1741 1742 delete item; 1743 } 1744 } 1745 1746 for (int iter = 0; iter < polChemDef->monomerList().size(); ++iter) 1747 { 1748 Monomer *monomer = polChemDef->monomerList().at(iter); 1749 1750 QString text = monomer->code() + "=" + monomer->name(); 1751 m_ui.vignetteListWidget->addItem(text); 1752 } 1753 1754 // It would be interesting to know which item is double-clicked. 1755 1756 connect(m_ui.vignetteListWidget, 1757 SIGNAL(itemDoubleClicked(QListWidgetItem *)), 1758 this, 1759 SLOT(vignetteListWidgetItemDoubleClicked(QListWidgetItem *))); 1760 1761 return true; 1762 } 1763 1764 1765 const PolChemDef * polChemDef() const1766 SequenceEditorWnd::polChemDef() const 1767 { 1768 return mpa_polymer->polChemDef(); 1769 } 1770 1771 1772 PolChemDef * polChemDef()1773 SequenceEditorWnd::polChemDef() 1774 { 1775 return mp_polChemDef; 1776 } 1777 1778 1779 Polymer* polymer()1780 SequenceEditorWnd::polymer() 1781 { 1782 return mpa_polymer; 1783 } 1784 1785 1786 QList<Prop *> * propList()1787 SequenceEditorWnd::propList() 1788 { 1789 return &m_propList; 1790 } 1791 1792 1793 const CalcOptions & calcOptions() const1794 SequenceEditorWnd::calcOptions() const 1795 { 1796 return m_calcOptions; 1797 } 1798 1799 1800 const IonizeRule & ionizeRule() const1801 SequenceEditorWnd::ionizeRule() const 1802 { 1803 return m_ionizeRule; 1804 } 1805 1806 1807 void clearCompletionsListSelection()1808 SequenceEditorWnd::clearCompletionsListSelection() 1809 { 1810 m_ui.vignetteListWidget->clearSelection(); 1811 } 1812 1813 1814 void completionsListSelectAt(int index)1815 SequenceEditorWnd::completionsListSelectAt(int index) 1816 { 1817 if (index == -1) 1818 { 1819 m_ui.vignetteListWidget->selectAll(); 1820 return; 1821 } 1822 1823 QListWidgetItem *item = m_ui.vignetteListWidget->item(index); 1824 item->setSelected(true); 1825 } 1826 1827 1828 void setWindowModified(bool isModified)1829 SequenceEditorWnd::setWindowModified(bool isModified) 1830 { 1831 emit polymerSequenceModifiedSignal(); 1832 1833 QWidget::setWindowModified(isModified); 1834 } 1835 1836 1837 void updateWindowTitle()1838 SequenceEditorWnd::updateWindowTitle() 1839 { 1840 if (mpa_polymer->filePath().isEmpty()) 1841 setWindowTitle(tr("%1 %2[*]") 1842 .arg(tr("massXpert - Polymer Sequence Editor:")) 1843 .arg(tr("Untitled"))); 1844 else 1845 { 1846 QFileInfo fileInfo(mpa_polymer->filePath()); 1847 1848 setWindowTitle(tr("%1 %2[*]") 1849 .arg(tr("massXpert - Polymer Sequence Editor:")) 1850 .arg(fileInfo.fileName())); 1851 } 1852 } 1853 1854 1855 void getsFocus()1856 SequenceEditorWnd::getsFocus() 1857 { 1858 focusInEvent(0); 1859 } 1860 1861 1862 void updateMonomerPosition(int value)1863 SequenceEditorWnd::updateMonomerPosition(int value) 1864 { 1865 QString str; 1866 1867 if (value > 0) 1868 str.setNum(value); 1869 else 1870 str = tr("N/A"); 1871 1872 m_ui.monomerPositionLineEdit->setText(str); 1873 } 1874 1875 1876 void updateWholeSequenceMasses(bool deep)1877 SequenceEditorWnd::updateWholeSequenceMasses(bool deep) 1878 { 1879 // qDebug() << __FILE__ << __LINE__ 1880 // << "updateWholeSequenceMasses"; 1881 1882 m_calcOptions.setCoordinateList(Coordinates(0, mpa_polymer->size())); 1883 m_calcOptions.setDeepCalculation(deep); 1884 1885 mpa_polymer->deionize(); 1886 mpa_polymer->calculateMasses(m_calcOptions); 1887 mpa_polymer->ionize(m_ionizeRule); 1888 1889 Application *application = static_cast<Application *>(qApp); 1890 1891 m_ui.monoWholeMassLineEdit-> 1892 setText(mpa_polymer->mono(application->locale(), 1893 MXP_POLYMER_DEC_PLACES)); 1894 m_ui.avgWholeMassLineEdit-> 1895 setText(mpa_polymer->avg(application->locale(), 1896 MXP_POLYMER_DEC_PLACES)); 1897 } 1898 1899 1900 void updateSelectedSequenceMasses(bool deep)1901 SequenceEditorWnd::updateSelectedSequenceMasses(bool deep) 1902 { 1903 // qDebug() << __FILE__ << __LINE__ 1904 // << "updateSelectedSequenceMasses"; 1905 1906 // If there is a factual selection(that is the selection is marked 1907 // by the selection mark, then the indexes are according to this schema: 1908 1909 // [ATGC] -> start: 0 end: 3 1910 1911 // while if the selection is fake, that is no actual selection is 1912 // performed, then , if cursor is located at ATGC|, then the indexes 1913 // are according to this schemaa: 1914 1915 // ATGC| -> start: 0 end: 4 1916 1917 // Because the calculations in the polymer are based on a for loop, 1918 // we need to adjust the values prior to setting them in the 1919 // calculation options vehicle. Note that the values set in start 1920 // and end are already "sorted", so that start <= end. 1921 1922 CoordinateList coordinateList; 1923 1924 // Should always return at least one item, that is the 1925 // pseudo-selection(start of sequence up to cursor index). 1926 bool realSelections = 1927 mpa_editorGraphicsView->selectionIndices(&coordinateList); 1928 1929 if (realSelections) 1930 { 1931 // We have increment all end indices for the items in the 1932 // coordinateList by one unit. See above for the explanation. 1933 // for(int iter = 0; iter < coordinateList.size(); ++iter) 1934 // { 1935 // No, we do not need to do this anymore. 1936 // coordinateList.at(iter)->incrementEnd(); 1937 // } 1938 } 1939 1940 m_calcOptions.setCoordinateList(coordinateList); 1941 1942 m_calcOptions.setDeepCalculation(deep); 1943 1944 mpa_polymer->deionize(); 1945 mpa_polymer->calculateMasses(m_calcOptions); 1946 mpa_polymer->ionize(m_ionizeRule); 1947 1948 Application *application = static_cast<Application *>(qApp); 1949 1950 m_ui.monoSelectionMassLineEdit-> 1951 setText(mpa_polymer->mono(application->locale(), 1952 MXP_OLIGOMER_DEC_PLACES)); 1953 m_ui.avgSelectionMassLineEdit-> 1954 setText(mpa_polymer->avg(application->locale(), 1955 MXP_OLIGOMER_DEC_PLACES)); 1956 1957 // At this point, we can display the selection coordinates: 1958 QString selectionPositions = coordinateList.positionsAsText(); 1959 1960 // qDebug() << __FILE__ << __LINE__ 1961 // << "positions:" << selectionPositions; 1962 1963 m_ui.selectionLineEdit->setText(selectionPositions); 1964 } 1965 1966 1967 void wholeSequenceMasses(double * mono,double * avg)1968 SequenceEditorWnd::wholeSequenceMasses(double *mono, double *avg) 1969 { 1970 QString mass; 1971 bool ok = false; 1972 Application *application = static_cast<Application *>(qApp); 1973 1974 // First get the text string and make a double out of it. 1975 1976 if(mono) 1977 { 1978 mass = m_ui.monoWholeMassLineEdit->text(); 1979 *mono = application->locale().toDouble(mass, &ok); 1980 } 1981 1982 if(avg) 1983 { 1984 mass = m_ui.avgWholeMassLineEdit->text(); 1985 *avg = application->locale().toDouble(mass, &ok); 1986 } 1987 1988 1989 } 1990 1991 1992 1993 void selectedSequenceMasses(double * mono,double * avg)1994 SequenceEditorWnd::selectedSequenceMasses(double *mono, double *avg) 1995 { 1996 QString mass; 1997 bool ok = false; 1998 Application *application = static_cast<Application *>(qApp); 1999 2000 if(mono) 2001 { 2002 mass = m_ui.monoSelectionMassLineEdit->text(); 2003 *mono = application->locale().toDouble(mass, &ok); 2004 } 2005 2006 if(avg) 2007 { 2008 mass = m_ui.avgSelectionMassLineEdit->text(); 2009 *avg = application->locale().toDouble(mass, &ok); 2010 } 2011 2012 2013 } 2014 2015 2016 2017 2018 2019 bool maybeSave()2020 SequenceEditorWnd::maybeSave() 2021 { 2022 // Returns true if we can continue(either saved ok or discard). If 2023 // save failed or cancel we return false to indicate to the caller 2024 // that something is wrong. 2025 2026 if (isWindowModified()) 2027 { 2028 QMessageBox::StandardButton ret; 2029 ret = QMessageBox::warning 2030 (this, tr("massXpert - Polymer Sequence Editor"), 2031 tr("The document %1 has been modified.\n" 2032 "Do you want to save your changes?") 2033 .arg(mpa_polymer->filePath()), 2034 QMessageBox::Save | QMessageBox::Discard 2035 | QMessageBox::Cancel); 2036 2037 if(ret == QMessageBox::Save) 2038 { 2039 // We want to save the file. If the file has no existing 2040 // file associate the save as function will be called 2041 // automatically. 2042 return save(); 2043 } 2044 else if (ret == QMessageBox::Discard) 2045 return true; 2046 else if (ret == QMessageBox::Cancel) 2047 return false; 2048 } 2049 2050 return true; 2051 } 2052 2053 2054 2055 ////////////////////////////// SLOTS /////////////////////////////// 2056 bool save()2057 SequenceEditorWnd::save() 2058 { 2059 // We must save to an xml file. It might be that the polymer 2060 // sequence is totally new, in which case the filePath() call will 2061 // return something invalid as a QFile object. In that case we ask 2062 // the saveAs() to do the job. 2063 2064 if (!QFile::exists(mpa_polymer->filePath())) 2065 return saveAs(); 2066 2067 if (!mpa_polymer->writeXmlFile()) 2068 { 2069 statusBar()->showMessage(tr("File save failed.")); 2070 2071 QMessageBox msgBox; 2072 2073 msgBox.setText("Failed to save the document."); 2074 msgBox.setInformativeText("Please, check that you have " 2075 "write permissions on the file."); 2076 msgBox.setStandardButtons(QMessageBox::Ok); 2077 2078 msgBox.exec(); 2079 2080 return false; 2081 } 2082 2083 statusBar()->showMessage(tr("File save succeeded.")); 2084 setWindowModified(false); 2085 // updateWindowTitle(); 2086 2087 return true; 2088 } 2089 2090 2091 bool saveAs()2092 SequenceEditorWnd::saveAs() 2093 { 2094 2095 // We must save the new contents of the polymer sequence to an xml 2096 // file that is not the file from which this sequence might have 2097 // been saved. 2098 2099 QString filePath = 2100 QFileDialog::getSaveFileName(this, tr("Save Polymer Sequence File"), 2101 QDir::homePath(), 2102 tr("mXp files(*.mxp *.mXp *.MXP)")); 2103 2104 if (filePath.isEmpty()) 2105 { 2106 statusBar()->showMessage(tr("Filepath is empty.")); 2107 return false; 2108 } 2109 2110 mpa_polymer->setFilePath(filePath); 2111 2112 if (!mpa_polymer->writeXmlFile()) 2113 { 2114 statusBar()->showMessage(tr("File save failed.")); 2115 2116 QMessageBox msgBox; 2117 2118 msgBox.setText("Failed to save the document."); 2119 msgBox.setInformativeText("Please, check that you have " 2120 "write permissions on the file."); 2121 msgBox.setStandardButtons(QMessageBox::Ok); 2122 2123 msgBox.exec(); 2124 2125 return false; 2126 } 2127 2128 statusBar()->showMessage(tr("File save succeeded.")); 2129 setWindowModified(false); 2130 updateWindowTitle(); 2131 2132 return true; 2133 } 2134 2135 2136 void importRaw()2137 SequenceEditorWnd::importRaw() 2138 { 2139 // Open a text file and make a QMxtSequence out of it. If errors, 2140 // then show the purification dialog. 2141 2142 Sequence sequence; 2143 2144 QString filePath; 2145 QString name; 2146 2147 2148 filePath = 2149 QFileDialog::getOpenFileName(this, tr("Import Raw Text File"), 2150 QDir::homePath(), 2151 tr("Any file type(*)")); 2152 2153 if (!QFile::exists(filePath)) 2154 return; 2155 2156 // Read the sequence. 2157 2158 QFile file(filePath); 2159 2160 if (!file.open(QFile::ReadOnly)) 2161 return; 2162 2163 QTextStream stream(&file); 2164 2165 while(!stream.atEnd()) 2166 { 2167 QString line = stream.readLine(1000); 2168 2169 // qDebug() << __FILE__ << __LINE__ 2170 // << "line:" << line; 2171 2172 sequence.appendMonomerText(line); 2173 } 2174 2175 // And now make sure the sequence is correct. 2176 2177 // qDebug() << __FILE__ << __LINE__ 2178 // << "Done streaming file." 2179 2180 QList<int> errorList ; 2181 2182 if (sequence.makeMonomerList(mpa_polymer->polChemDef(), 2183 true, &errorList) == -1) 2184 { 2185 SequencePurificationDlg *dlg = 2186 new SequencePurificationDlg(this, &sequence, &errorList); 2187 2188 dlg->show(); 2189 2190 return; 2191 } 2192 2193 // At this point we can paste... 2194 int size = sequence.monomerList().size(); 2195 int ret = mpa_editorGraphicsView->insertSequenceAtPoint(sequence); 2196 2197 if ( ret != size) 2198 { 2199 QMessageBox::critical(this, 2200 tr("massXpert - Polymer Sequence Editor"), 2201 tr("Failed to import the sequence."), 2202 QMessageBox::Ok); 2203 } 2204 } 2205 2206 2207 void importPdbProt()2208 SequenceEditorWnd::importPdbProt() 2209 { 2210 // We want to import the protein sequence data out of a PDB file. 2211 2212 // Format of a line: 2213 // SEQRES 1 A 21 GLY ILE VAL GLU GLN CYS CYS THR SER ILE CYS SER LEU 2214 2215 // PDB File Format - Contents Guide Version 3.20 (Sept 15, 2008) 2216 // http://www.wwpdb.org/docs.html 2217 // File: 2218 // ftp://ftp.wwpdb.org/pub/pdb/doc/format_descriptions/Format_v32_A4.pdf 2219 // 2220 // The monomer codes are 3 uppercase letters-long. 2221 2222 // First, get to know what the PDB file is: 2223 2224 QString filePath = 2225 QFileDialog::getOpenFileName(this, 2226 tr("massXpert - Import PDB Protein Sequence"), 2227 QDir::homePath(), 2228 tr("PDB files (*.PDB *.Pdb *.pdb)")); 2229 2230 QFile file(filePath); 2231 2232 if (!file.exists(filePath)) 2233 { 2234 QMessageBox::critical(this, 2235 tr("massXpert - Import PDB Protein Sequence"), 2236 tr("File not found."), 2237 QMessageBox::Ok); 2238 return; 2239 } 2240 2241 // Make sure we can read the sequence. 2242 2243 if (!file.open(QIODevice::ReadOnly)) 2244 return; 2245 2246 QTextStream stream(&file); 2247 2248 // Now, ensure that we can translate the ILE-formatted codes to 2249 // the codes we are currently using in our sequence. 2250 2251 int codeLength = polChemDef()->codeLength(); 2252 2253 // Load the dictionary file "pdb-protein-to-mxp.dic" (from 2254 // dataDir/dictionaries) by creating a dictionary object. 2255 2256 Application *application = static_cast<Application *>(qApp); 2257 ConfigSettings *configurationSettings = application->configSettings(); 2258 2259 QString dictionaryFilePath(configurationSettings->systemDataDir() + 2260 QDir::separator() + "dictionaries" + 2261 QDir::separator() + "pdb-protein-to-mxp.dic"); 2262 2263 MonomerDictionary dictionary; 2264 2265 dictionary.setFilePath(dictionaryFilePath); 2266 dictionary.setInputCodeLength(3); 2267 dictionary.setOutputCodeLength(codeLength); 2268 2269 if (!dictionary.loadDictionary()) 2270 { 2271 QMessageBox::critical(this, 2272 tr("massXpert - Import PDB Protein Sequence"), 2273 tr("Failed to load the dictionary."), 2274 QMessageBox::Ok); 2275 return; 2276 } 2277 2278 // At this point we have loaded the dictionary, let's process the 2279 // file contents to extract the protein sequence data out of it. 2280 2281 // Create a string list where to store all the chain sequences 2282 // parsed in the file and a parallel one where to store the 2283 // corresponding chain ID. 2284 QStringList *chainStringList = new QStringList(); 2285 QStringList *chainStringListId = new QStringList(); 2286 2287 // Create a string to hold the sequence that is going to be 2288 // extracted from the PDB file's lines. 2289 QString codes; 2290 2291 // Create a sequence object we'll use to store the monomers we 2292 // have successfully parsed in. 2293 Sequence sequence; 2294 2295 // Iterate in the file and for each line check that it matches 2296 // lines containing SEQRES records. If so, process the line to 2297 // extract the monomer codes in the style MET LEU THR GLN LYS THR 2298 2299 // Define a regular expression that will sort out from the file 2300 // all the lines that hold a SEQRES record, and specifically one 2301 // such record that holds a protein sequence (and not a nucleic 2302 // acid sequence), which we know because codes for aminoacids are 2303 // 3-letters long in the form of GLY. "MET LEU THR GLN LYS THR 2304 // LYS ASP ILE VAL LYS ALA THR $"); 2305 2306 QRegExp regExp("^SEQRES " 2307 "[0-9 ][0-9 ][0-9 ] " 2308 "[A-Z ] " 2309 "[0-9 ][0-9 ][0-9 ][0-9 ] " 2310 "([A-Z][A-Z][A-Z] ){1,13}[ ]*$"); 2311 2312 QRegExpValidator validator(regExp, 0); 2313 int pos = 0; 2314 2315 QChar currentId; 2316 2317 while (!stream.atEnd()) 2318 { 2319 // PDF file format stipulates that: 2320 2321 // Each line in the PDB entry file consists of 80 columns. The 2322 // last character in each PDB entry should be an end-of- line 2323 // indicator. 2324 2325 QString line = stream.readLine(80); 2326 2327 // qDebug() << __FILE__ << __LINE__ 2328 // << "line:" << line; 2329 2330 // Test now if the currently parsed line matches the regular 2331 // expression. 2332 2333 if (validator.validate(line, pos) != QValidator::Acceptable) 2334 { 2335 // qDebug() << __FILE__ << __LINE__ 2336 // << "line is faulty:" << line; 2337 2338 // The line does not match a protein SEQRES record. Go to 2339 // next line in the file. 2340 continue; 2341 } 2342 2343 // At this point the line is worth working on: it is a line 2344 // describing a portion of a protein sequence. 2345 2346 // Note that the file format specification stipulates that 2347 // there might be any number of chain sequences. Their ID is 2348 // the 'B' at index 11 in the line "SEQRES 29 B 403 TYR TYR 2349 // ILE CYS GLY PRO ". 2350 2351 QChar id = line.at(11); 2352 2353 if (id != currentId) 2354 { 2355 // We are initiating a new chain sequence. Store the 2356 // previously chain sequence into the string list. The 2357 // syntax is that a first string with the chain ID is 2358 // added to the string list and then its sequence. 2359 2360 if (!codes.isEmpty()) 2361 { 2362 chainStringList->append(codes); 2363 chainStringListId->append(QString(currentId)); 2364 2365 // qDebug() << __FILE__ << __LINE__ 2366 // << "appending codes:" 2367 // << codes; 2368 2369 // Now clear the string so that we can start filling 2370 // it with a new chain sequence. 2371 codes.clear(); 2372 } 2373 2374 // Now update the current id. 2375 currentId = id; 2376 } 2377 2378 // qDebug() << __FILE__ << __LINE__ 2379 // << "line is fine:" << line; 2380 2381 2382 // Create a temporary string with the line. 2383 QString tempSeq(line); 2384 2385 // qDebug() << __FILE__ << __LINE__ 2386 // << "tempSeq:" << tempSeq; 2387 2388 // From this tempSeq string, only retain the monomer codes: 2389 // This is the string: 2390 //"SEQRES 29 B 403 TYR TYR ILE CYS GLY PRO " 2391 // follows: "ILE PRO PHE MET ARG MET GLN " 2392 2393 // This is what we want to retain: 2394 // "TYR TYR ILE CYS GLY PRO ILE PRO PHE MET ARG MET GLN" 2395 2396 int firstResidueIndex = 2397 tempSeq.indexOf (QRegExp ("([A-Z][A-Z][A-Z] ){1,13}[ ]*$"), 0 ); 2398 2399 int lastResidueIndex = tempSeq.lastIndexOf(QRegExp("[A-Z][A-Z][A-Z]")); 2400 2401 int stringLength = lastResidueIndex - firstResidueIndex; 2402 2403 // qDebug() << __FILE__ << __LINE__ 2404 // << "firstResidueIndex:" << firstResidueIndex 2405 // << "lastResidueIndex:" << lastResidueIndex; 2406 2407 QString tempCodes = QString (" %1") 2408 .arg(tempSeq.mid(firstResidueIndex, stringLength + 3)); 2409 2410 // This is what tempCodes contains now (not the leading 2411 // space): " TYR TYR ILE CYS GLY PRO ILE PRO PHE MET ARG MET 2412 // GLN" 2413 2414 // qDebug() << __FILE__ << __LINE__ 2415 // << " tempCodes:" << tempCodes; 2416 2417 // Appends the codes from the currently parsed line into the 2418 // string to hold all the sequence in the file. 2419 2420 codes.append(tempCodes); 2421 } 2422 2423 // At this point all the PDB file has been read through. We still 2424 // have one ongoing codes string, if not empty which we ought to 2425 // add to the chainStringList. 2426 2427 if (!codes.isEmpty()) 2428 { 2429 chainStringList->append(codes); 2430 chainStringListId->append(QString(currentId)); 2431 2432 // qDebug() << __FILE__ << __LINE__ 2433 // << "appending codes:" 2434 // << codes; 2435 2436 // Clear the codes string to free memory. 2437 codes.clear(); 2438 } 2439 2440 // Now feed the chain string list to the translator. The returned 2441 // string list is allocated. We will transfer its ownership to the 2442 // dialog, if we use that dialog below. 2443 QStringList *translatedChainStringList = 2444 dictionary.translate(*chainStringList); 2445 2446 if (!translatedChainStringList) 2447 { 2448 QMessageBox::critical(this, 2449 tr("massXpert - Import PDB Protein Sequence"), 2450 tr("Failed to import the sequence(s)."), 2451 QMessageBox::Ok); 2452 2453 delete chainStringList; 2454 delete chainStringListId; 2455 2456 return; 2457 } 2458 2459 // for (int iter = 0 ; iter < translatedChainStringList->size(); ++iter) 2460 // { 2461 // qDebug() << __FILE__ << __LINE__ 2462 // << chainStringListId->at(iter) 2463 // << translatedChainStringList->at(iter); 2464 // } 2465 2466 // At this point, we will not need the initial list anymore, we 2467 // can free it and set it to 0. 2468 delete chainStringList; 2469 chainStringList = 0; 2470 2471 // If there is only one sequence that's been imported (the file 2472 // format allows for any number of chain sequences), then we have 2473 // nothing more than to make an actual sequence with it. 2474 2475 if (translatedChainStringList->size() == 1) 2476 { 2477 Sequence sequence(translatedChainStringList->first()); 2478 2479 // Immediately free the string lists and set them to 0 as we 2480 // are not going to use them anymore. 2481 2482 delete chainStringListId; 2483 chainStringListId = 0; 2484 delete translatedChainStringList; 2485 translatedChainStringList = 0; 2486 2487 // Now test if the sequence is correct. 2488 2489 QList<int> errorList ; 2490 2491 if (sequence.makeMonomerList(mpa_polymer->polChemDef(), 2492 true, &errorList) == -1) 2493 { 2494 SequencePurificationDlg *dlg = 2495 new SequencePurificationDlg(this, &sequence, &errorList); 2496 2497 dlg->show(); 2498 2499 return; 2500 } 2501 2502 // At this point we can paste... 2503 int size = sequence.monomerList().size(); 2504 int ret = mpa_editorGraphicsView->insertSequenceAtPoint(sequence); 2505 2506 if ( ret != size) 2507 { 2508 QMessageBox::critical(this, 2509 tr("massXpert - Polymer Sequence Editor"), 2510 tr("Failed to import the sequence."), 2511 QMessageBox::Ok); 2512 } 2513 2514 return; 2515 } 2516 2517 // If we are here, then that means that there were more than one 2518 // sequence imported from the PDB file. We have to display these 2519 // sequences to the user. 2520 2521 // First, make sure that we have the same number of items in the 2522 // chain sequence string list and in the chain id string list. 2523 2524 if (chainStringListId->size() != translatedChainStringList->size()) 2525 { 2526 QMessageBox::critical(this, 2527 tr("massXpert - Polymer Sequence Editor"), 2528 tr("Failed to import the sequence:\n" 2529 "Number of chain sequences differs " 2530 "from number of chain IDs."), 2531 QMessageBox::Ok); 2532 } 2533 2534 // We should open the window that is specialized for displaying 2535 // imported sequences to the user. 2536 2537 // Note that the translatedChainStringList ownership is transferred to 2538 // the dialog. We will not delete it. 2539 SequenceImportDlg *dlg = new SequenceImportDlg(this, 2540 translatedChainStringList, 2541 chainStringListId); 2542 dlg->show(); 2543 2544 return; 2545 } 2546 2547 2548 void clipboardCopy(QClipboard::Mode mode)2549 SequenceEditorWnd::clipboardCopy(QClipboard::Mode mode) 2550 { 2551 CoordinateList coordList; 2552 2553 if (mpa_editorGraphicsView->selectionIndices(&coordList)) 2554 { 2555 2556 // We do not do this below, because it turned out to be 2557 // impractical when working with primary selections. 2558 2559 int selectionCount = coordList.size(); 2560 2561 // There is a real selection, which is what 2562 // we want, but if there are more than one region selections, 2563 // then inform the user. 2564 2565 // if(selectionCount > 1) 2566 // { 2567 // QMessageBox::warning(this, 2568 // tr("massXpert - Polymer Sequence Editor"), 2569 // tr("The sequence exported to the clipboard " 2570 // "will comprise %1 region selections.") 2571 // .arg(selectionCount), 2572 // QMessageBox::Ok); 2573 // } 2574 2575 QString *text = new QString; 2576 2577 for(int iter = 0; iter < selectionCount; ++iter) 2578 { 2579 Coordinates *coordinates = coordList.at(iter); 2580 2581 QString *sequence = 2582 mpa_polymer->monomerText(coordinates->start(), 2583 coordinates->end(), false); 2584 2585 *text += *sequence; 2586 2587 delete sequence; 2588 } 2589 2590 QClipboard *clipboard = QApplication::clipboard(); 2591 clipboard->setText(*text, mode); 2592 2593 delete text; 2594 } 2595 } 2596 2597 2598 void clipboardCut(QClipboard::Mode mode)2599 SequenceEditorWnd::clipboardCut(QClipboard::Mode mode) 2600 { 2601 CoordinateList coordList; 2602 2603 if (mpa_editorGraphicsView->selectionIndices(&coordList)) 2604 { 2605 // There is a real selection, which is what we want, but if 2606 // there are more than one region selections than we cannot 2607 // perform the action. 2608 int selectionCount = coordList.size(); 2609 2610 if(selectionCount > 1) 2611 { 2612 QMessageBox::information(this, 2613 tr("massXpert - Polymer Sequence Editor"), 2614 tr("Cut operations are not supported " 2615 "in multi-region selection mode."), 2616 QMessageBox::Ok); 2617 2618 return; 2619 } 2620 2621 Coordinates *coordinates = coordList.last(); 2622 2623 QString *text = 2624 mpa_polymer->monomerText(coordinates->start(), 2625 coordinates->end(), false); 2626 Q_ASSERT(text); 2627 2628 QClipboard *clipboard = QApplication::clipboard(); 2629 clipboard->setText(*text, mode); 2630 2631 delete text; 2632 2633 mpa_editorGraphicsView->removeSelectedOligomer(); 2634 } 2635 } 2636 2637 2638 void clipboardPaste(QClipboard::Mode mode)2639 SequenceEditorWnd::clipboardPaste(QClipboard::Mode mode) 2640 { 2641 CoordinateList coordList; 2642 2643 if (mpa_editorGraphicsView->selectionIndices(&coordList)) 2644 { 2645 // There is a real selection, which is what we want, but if 2646 // there are more than one region selections than we cannot 2647 // perform the action. 2648 int selectionCount = coordList.size(); 2649 2650 if(selectionCount > 1) 2651 { 2652 QMessageBox::information(this, 2653 tr("massXpert - Polymer Sequence Editor"), 2654 tr("Paste operations are not supported " 2655 "in multi-region selection mode."), 2656 QMessageBox::Ok); 2657 2658 return; 2659 } 2660 2661 // There is one region selected, we have to first remove it 2662 // and then we insert the pasted sequence, which equals to a 2663 // sequence replacement. 2664 2665 mpa_editorGraphicsView->removeSelectedOligomer(); 2666 } 2667 2668 QClipboard *clipboard = QApplication::clipboard(); 2669 QString text; 2670 2671 if (mode == QClipboard::Selection) 2672 text = clipboard->text(QClipboard::Selection); 2673 else 2674 text = clipboard->text(QClipboard::Clipboard); 2675 2676 if (text.isEmpty()) 2677 return; 2678 2679 Sequence sequence(text); 2680 2681 QList<int> errorList ; 2682 2683 if (sequence.makeMonomerList(mpa_polymer->polChemDef(), 2684 true, &errorList) == -1) 2685 { 2686 SequencePurificationDlg *dlg = 2687 new SequencePurificationDlg(this, &sequence, &errorList); 2688 2689 dlg->show(); 2690 2691 return; 2692 } 2693 2694 // At this point we can paste... 2695 int size = sequence.monomerList().size(); 2696 int ret = mpa_editorGraphicsView->insertSequenceAtPoint(sequence); 2697 2698 if (ret != size) 2699 { 2700 QMessageBox::critical(this, 2701 tr("massXpert - Polymer Sequence Editor"), 2702 tr("Failed to paste the sequence."), 2703 QMessageBox::Ok); 2704 } 2705 } 2706 2707 2708 void clipboardClear(QClipboard::Mode mode)2709 SequenceEditorWnd::clipboardClear(QClipboard::Mode mode) 2710 { 2711 QClipboard *clipboard = QApplication::clipboard(); 2712 2713 clipboard->clear(mode); 2714 } 2715 2716 2717 void findSequence()2718 SequenceEditorWnd::findSequence() 2719 { 2720 SequenceEditorFindDlg *dlg = 2721 new SequenceEditorFindDlg(this, mpa_polymer); 2722 2723 dlg->show(); 2724 2725 return; 2726 } 2727 2728 2729 void vignetteSizeChanged()2730 SequenceEditorWnd::vignetteSizeChanged() 2731 { 2732 int size = m_ui.vignetteSizeSpinBox->value(); 2733 2734 if (!m_postInitialized) 2735 return; 2736 2737 mpa_editorGraphicsView->requestVignetteSize(size); 2738 } 2739 2740 2741 void nameLineEditChanged(const QString & text)2742 SequenceEditorWnd::nameLineEditChanged(const QString & text) 2743 { 2744 mpa_polymer->setName(text); 2745 setWindowModified(true); 2746 updateWindowTitle(); 2747 } 2748 2749 2750 void modifMonomer()2751 SequenceEditorWnd::modifMonomer() 2752 { 2753 MonomerModificationDlg *dlg = new MonomerModificationDlg(this); 2754 2755 dlg->show(); 2756 } 2757 2758 2759 void modifPolymer()2760 SequenceEditorWnd::modifPolymer() 2761 { 2762 2763 PolymerModificationDlg *dlg = new PolymerModificationDlg(this); 2764 2765 dlg->show(); 2766 } 2767 2768 2769 void modifLeftEnd()2770 SequenceEditorWnd::modifLeftEnd() 2771 { 2772 2773 PolymerModificationDlg *dlg = 2774 new PolymerModificationDlg(this, MXT_END_LEFT); 2775 2776 dlg->show(); 2777 } 2778 2779 2780 void modifRightEnd()2781 SequenceEditorWnd::modifRightEnd() 2782 { 2783 2784 PolymerModificationDlg *dlg = 2785 new PolymerModificationDlg(this, MXT_END_RIGHT); 2786 2787 dlg->show(); 2788 } 2789 2790 2791 2792 void crossLinkMonomers()2793 SequenceEditorWnd::crossLinkMonomers() 2794 { 2795 MonomerCrossLinkDlg *dlg = new MonomerCrossLinkDlg(this); 2796 2797 dlg->show(); 2798 2799 // Make the connection of the signal/slot pair, so that when a 2800 // crossLink changes in the polymer sequence, the 2801 // MonomerCrossLinkDlg will be triggered to redisplay the data. 2802 2803 QObject::connect(mpa_polymer, 2804 SIGNAL(crossLinkChangedSignal(Polymer *)), 2805 dlg, 2806 SLOT(crossLinkChangedSlot(Polymer *))); 2807 2808 QObject::connect(this, 2809 SIGNAL(polymerSequenceModifiedSignal()), 2810 dlg, 2811 SLOT(polymerSequenceModifiedSlot())); 2812 } 2813 2814 2815 void cleave()2816 SequenceEditorWnd::cleave() 2817 { 2818 CleavageDlg *dlg = new CleavageDlg(this, 2819 mpa_polymer, 2820 mpa_polymer->polChemDef(), 2821 m_calcOptions, 2822 &m_ionizeRule); 2823 dlg->show(); 2824 } 2825 2826 2827 void fragment()2828 SequenceEditorWnd::fragment() 2829 { 2830 // At the moment we can only perform fragmentation on single 2831 // region selections. 2832 2833 CoordinateList coordList; 2834 2835 bool res = mpa_editorGraphicsView->selectionIndices(&coordList); 2836 2837 if (!res) 2838 { 2839 QMessageBox::information(this, tr("massxpert"), 2840 tr("No oligomer is selected. " 2841 "Select an oligomer first"), 2842 QMessageBox::Ok); 2843 return; 2844 } 2845 2846 if (coordList.size() > 1) 2847 { 2848 QMessageBox::information(this, tr("massxpert"), 2849 tr("Fragmentation simulations are not " 2850 "supported\nin multi-region selection " 2851 "mode."), 2852 QMessageBox::Ok); 2853 return; 2854 } 2855 2856 if (m_calcOptions.monomerEntities() & MXT_MONOMER_CHEMENT_CROSS_LINK) 2857 { 2858 // Check what is the situation with respect to the cross-links, 2859 // which, from a fragmentation standpoint are particularly 2860 // difficult to handle. In particular, alert the user if the 2861 // select oligomer has a partial cross-link (a cross-link that 2862 // links on oligomer monomer to a monomer outside of that 2863 // oligomer). 2864 2865 int startIndex = coordList[0]->start(); 2866 int endIndex = coordList[0]->end(); 2867 2868 // Get the cross-links for the region. 2869 QList<CrossLink *> crossLinkList; 2870 2871 int partials = 0; 2872 2873 mpa_polymer->crossLinkList(startIndex, endIndex, 2874 &crossLinkList, &partials); 2875 2876 if(partials) 2877 { 2878 QMessageBox::warning(this, tr("massxpert"), 2879 tr("Fragmentation calculations do not\n" 2880 "take into account partial cross-links.\n" 2881 "These partial cross-links are ignored."), 2882 QMessageBox::Ok); 2883 } 2884 } 2885 2886 // No need to do this here, because the dialog window will have 2887 // its own calcOptions copy and will make this work anyway upon 2888 // initialization. 2889 2890 // m_calcOptions.setCoordinateList(coordList); 2891 2892 FragmentationDlg *dlg = 2893 new FragmentationDlg(this, 2894 mpa_polymer, 2895 mpa_polymer->polChemDef(), 2896 m_calcOptions, 2897 &m_ionizeRule); 2898 2899 dlg->show(); 2900 } 2901 2902 2903 void massSearch()2904 SequenceEditorWnd::massSearch() 2905 { 2906 MassSearchDlg *dlg = new MassSearchDlg(this, 2907 mpa_polymer, 2908 m_calcOptions, 2909 &m_ionizeRule); 2910 2911 dlg->show(); 2912 } 2913 2914 2915 void mzCalculation()2916 SequenceEditorWnd::mzCalculation() 2917 { 2918 // We should try to feed the mz calculation dialog with the mass 2919 // data from the sequence editor window. If there is a real 2920 // selection, than use the masses of the selected 2921 // region(s). Otherwise use the masses for the whole sequence. 2922 2923 CoordinateList coordList; 2924 double mono = 0; 2925 double avg = 0; 2926 2927 if (mpa_editorGraphicsView->selectionIndices(&coordList)) 2928 { 2929 // There is real selection, set the masses for that selection 2930 // in the newly created dialog window. 2931 2932 selectedSequenceMasses(&mono, &avg); 2933 } 2934 else 2935 { 2936 wholeSequenceMasses(&mono, &avg); 2937 qDebug() << __FILE__ << __LINE__; 2938 } 2939 2940 qDebug() << __FILE__ << __LINE__ 2941 << "mono:" << mono << "avg:" << avg; 2942 2943 2944 MzCalculationDlg *dlg = 2945 new MzCalculationDlg(this, 2946 mpa_polymer->polChemDef(), 2947 &m_ionizeRule, mono, avg); 2948 2949 dlg->show(); 2950 } 2951 2952 2953 void compositions()2954 SequenceEditorWnd::compositions() 2955 { 2956 CompositionsDlg *dlg = 2957 new CompositionsDlg(this, 2958 mpa_polymer, 2959 &m_calcOptions, 2960 &m_ionizeRule); 2961 2962 dlg->show(); 2963 } 2964 2965 2966 void pkaPhPi()2967 SequenceEditorWnd::pkaPhPi() 2968 { 2969 // Make sure we can read the data file. 2970 2971 // Where is the data file? 2972 QString filePath = mpa_polymer->polChemDef()->dirPath() + 2973 QDir::separator() + QString("pka_ph_pi.xml"); 2974 2975 // qDebug() << __FILE__ << __LINE__ 2976 // << "pkaPhPi file is" << filePath; 2977 2978 // Allocate the lists in which to store the different monomers and 2979 // modifs allocated upon parsing of the xml file. 2980 2981 QList<Monomer *> *monomerList = new(QList<Monomer *>); 2982 QList<Modif *> *modifList = new(QList<Modif *>); 2983 2984 // Create the parser using the above filePath. 2985 PkaPhPiDataParser parser(mpa_polymer->polChemDef(), 2986 filePath); 2987 2988 // Ask that the rendering be performed. 2989 if (!parser.renderXmlFile(monomerList, modifList)) 2990 { 2991 delete monomerList; 2992 delete modifList; 2993 2994 QMessageBox::warning(this, 2995 tr("massXpert - pKa pH pI"), 2996 tr("%1@%2\n" 2997 "Failed to render xml file(%3).") 2998 .arg(__FILE__) 2999 .arg(__LINE__) 3000 .arg(filePath), 3001 QMessageBox::Ok); 3002 return; 3003 } 3004 3005 // Allocate a new PkaPhPi instance that we'll pass to the 3006 // dialog. Ownership of that object is taken by the dialog, which 3007 // will free it. 3008 PkaPhPi *pkaPhPi = new PkaPhPi(*mpa_polymer, 3009 m_calcOptions, 3010 monomerList, 3011 modifList); 3012 3013 PkaPhPiDlg *dlg = new PkaPhPiDlg(this, 3014 pkaPhPi, 3015 *mpa_polymer, 3016 m_calcOptions); 3017 3018 dlg->show(); 3019 } 3020 3021 3022 void decimalPlacesOptions()3023 SequenceEditorWnd::decimalPlacesOptions() 3024 { 3025 DecimalPlacesOptionsDlg *dlg = new DecimalPlacesOptionsDlg(this); 3026 3027 dlg->show(); 3028 } 3029 3030 3031 void newCalculatorWholeSequenceMasses()3032 SequenceEditorWnd::newCalculatorWholeSequenceMasses() 3033 { 3034 // We want to start a new calculator preseeded with the whole 3035 // sequence mono/avg masses. Let's get them right away. 3036 3037 QString mono = m_ui.monoWholeMassLineEdit->text(); 3038 QString avg = m_ui.avgWholeMassLineEdit->text(); 3039 3040 newCalculator(mono, avg); 3041 } 3042 3043 3044 void newCalculatorSelectedSequenceMasses()3045 SequenceEditorWnd::newCalculatorSelectedSequenceMasses() 3046 { 3047 // We want to start a new calculator preseeded with the selected 3048 // sequence mono/avg masses. Let's get them right away. 3049 3050 QString mono = m_ui.monoSelectionMassLineEdit->text(); 3051 QString avg = m_ui.avgSelectionMassLineEdit->text(); 3052 3053 newCalculator(mono, avg); 3054 } 3055 3056 3057 void newCalculator(QString mono,QString avg)3058 SequenceEditorWnd::newCalculator(QString mono, QString avg) 3059 { 3060 // To start a new calculator, we have to get the name of the file 3061 // that contains the polymer chemistry definition. Let's get that 3062 // filePath from the polymer chemistry definition of *this* 3063 // sequence editor window. 3064 3065 QString filePath = mp_polChemDef->filePath(); 3066 3067 // Open a calculator window with the proper polymer chemistry 3068 // definition and also with the proper masses to preseed. 3069 3070 CalculatorWnd *calculatorWnd = new CalculatorWnd(filePath, mono, avg); 3071 3072 // At this time we have a calculator window that is fully 3073 // initialized and functional. We can add its pointer to the list 3074 // of such windows that is stored in the application object. 3075 Application *application = static_cast<Application *>(qApp); 3076 application->calculatorWndList()->append(calculatorWnd); 3077 } 3078 3079 3080 void crossLinksPartiallyEncompassedSlot(int count)3081 SequenceEditorWnd::crossLinksPartiallyEncompassedSlot(int count) 3082 { 3083 m_ui.incompleteCrossLinkWarningLabel->setText 3084 (tr("Incomplete cross-links: %1"). 3085 arg(count)); 3086 } 3087 3088 3089 void keyPressEvent(QKeyEvent * event)3090 SequenceEditorWnd::keyPressEvent(QKeyEvent *event) 3091 { 3092 event->accept(); 3093 } 3094 3095 3096 void updatePolymerEndsModifs()3097 SequenceEditorWnd::updatePolymerEndsModifs() 3098 { 3099 3100 QString text; 3101 3102 text = mpa_polymer->leftEndModif().name(); 3103 3104 if (!text.isEmpty()) 3105 { 3106 m_ui.leftEndModifPushButton->setText(text); 3107 } 3108 else 3109 { 3110 m_ui.leftEndModifPushButton->setText(tr("NOT_SET")); 3111 } 3112 3113 text = mpa_polymer->rightEndModif().name(); 3114 3115 if (!text.isEmpty()) 3116 { 3117 m_ui.rightEndModifPushButton->setText(text); 3118 } 3119 else 3120 { 3121 m_ui.rightEndModifPushButton->setText(tr("NOT_SET")); 3122 } 3123 } 3124 3125 void vignetteListWidgetItemDoubleClicked(QListWidgetItem * item)3126 SequenceEditorWnd::vignetteListWidgetItemDoubleClicked(QListWidgetItem *item) 3127 { 3128 QString text = item->text(); 3129 3130 // The line of text has the following format: 3131 3132 // Xcode=Name 3133 3134 // Thus, we want to get the string prior to the '=' 3135 3136 QStringList elements = text.split("="); 3137 3138 QString code = elements.first(); 3139 3140 // Now that we know the code, we can insert it at the right 3141 // place. First create a sequence with that code. 3142 3143 Sequence sequence(code); 3144 QList<int> errorList; 3145 3146 sequence.makeMonomerList(mp_polChemDef, false, &errorList); 3147 3148 mpa_editorGraphicsView->insertSequenceAtPoint(sequence); 3149 } 3150 3151 } // namespace massXpert 3152