diff --git a/CycloBranch.sln b/CycloBranch.sln index cae5bf9..a6fcc20 100644 --- a/CycloBranch.sln +++ b/CycloBranch.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CycloBranch", "CycloBranch\CycloBranch.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" diff --git a/CycloBranch/CycloBranch-Linux.pro b/CycloBranch/CycloBranch-Linux.pro new file mode 100644 index 0000000..996dcea --- /dev/null +++ b/CycloBranch/CycloBranch-Linux.pro @@ -0,0 +1,91 @@ +###################################################################### +# Automatically generated by qmake (3.0) Fri Dec 5 03:02:26 2014 +###################################################################### + +TEMPLATE = app +TARGET = CycloBranch +QT += core gui widgets printsupport svg +INCLUDEPATH += . core gui parallel +QMAKE_CXXFLAGS += -std=c++0x -DLINUX -m64 +QMAKE_LIBS += -lboost_regex +OBJECTS_DIR = build/ +MOC_DIR = moc/ + +# Input +RESOURCES = images.qrc +HEADERS += core/cAllocator.h \ + core/cBrick.h \ + core/cBricksDatabase.h \ + core/cCandidate.h \ + core/cCandidateSet.h \ + core/cDeNovoGraph.h \ + core/cDeNovoGraphNode.h \ + core/cFragmentIons.h \ + core/cParameters.h \ + core/cPeak.h \ + core/cPeaksList.h \ + core/cSequence.h \ + core/cSequenceDatabase.h \ + core/cSummaryFormula.h \ + core/cTheoreticalSpectrum.h \ + core/cTheoreticalSpectrumList.h \ + core/utilities.h \ + gui/cAboutWidget.h \ + gui/cBranchedWidget.h \ + gui/cBricksDatabaseWidget.h \ + gui/cCyclicWidget.h \ + gui/cDrawPeptideWidget.h \ + gui/cEventFilter.h \ + gui/cExportDialog.h \ + gui/cFindDialog.h \ + gui/cFragmentIonsListWidget.h \ + gui/cGraphWidget.h \ + gui/cLassoWidget.h \ + gui/cLinearWidget.h \ + gui/cMainThread.h \ + gui/cMainWindow.h \ + gui/cModificationsWidget.h \ + gui/cParametersWidget.h \ + gui/cSequenceDatabaseWidget.h \ + gui/cSpectrumDetailWidget.h \ + gui/cSpectrumSceneWidget.h \ + parallel/cGraphReaderThread.h \ + parallel/cSpectrumComparatorThread.h +SOURCES += core/cBrick.cpp \ + core/cBricksDatabase.cpp \ + core/cCandidate.cpp \ + core/cCandidateSet.cpp \ + core/cDeNovoGraph.cpp \ + core/cDeNovoGraphNode.cpp \ + core/cFragmentIons.cpp \ + core/cParameters.cpp \ + core/cPeak.cpp \ + core/cPeaksList.cpp \ + core/cSequence.cpp \ + core/cSequenceDatabase.cpp \ + core/cSummaryFormula.cpp \ + core/cTheoreticalSpectrum.cpp \ + core/cTheoreticalSpectrumList.cpp \ + core/utilities.cpp \ + gui/cAboutWidget.cpp \ + gui/cBranchedWidget.cpp \ + gui/cBricksDatabaseWidget.cpp \ + gui/cCyclicWidget.cpp \ + gui/cDrawPeptideWidget.cpp \ + gui/cEventFilter.cpp \ + gui/cExportDialog.cpp \ + gui/cFindDialog.cpp \ + gui/cFragmentIonsListWidget.cpp \ + gui/cGraphWidget.cpp \ + gui/cLassoWidget.cpp \ + gui/cLinearWidget.cpp \ + gui/cMainThread.cpp \ + gui/cMainWindow.cpp \ + gui/cModificationsWidget.cpp \ + gui/cParametersWidget.cpp \ + gui/cSequenceDatabaseWidget.cpp \ + gui/cSpectrumDetailWidget.cpp \ + gui/cSpectrumSceneWidget.cpp \ + parallel/cGraphReaderThread.cpp \ + parallel/cSpectrumComparatorThread.cpp \ + main.cpp diff --git a/CycloBranch/CycloBranch-MacOSX.pro b/CycloBranch/CycloBranch-MacOSX.pro new file mode 100644 index 0000000..822b6d9 --- /dev/null +++ b/CycloBranch/CycloBranch-MacOSX.pro @@ -0,0 +1,99 @@ +###################################################################### +# Automatically generated by qmake (3.0) Fri Dec 5 03:02:26 2014 +###################################################################### + +TEMPLATE = app +TARGET = CycloBranch +QT += core gui widgets printsupport svg +INCLUDEPATH += . core gui parallel /usr/local/Cellar/boost/1.57.0/include +QMAKE_CXXFLAGS += -std=c++0x -DMACOSX -m64 +QMAKE_LIBS += -lboost_regex +QMAKE_LIBDIR = /usr/local/Cellar/boost/1.57.0/lib +OBJECTS_DIR = build/ +MOC_DIR = moc/ +ICON = images/cb.icns + +# The following variables must be manually fixed in the 'Makefile' generated by qmake. +# The variables QMAKE_CC, QMAKE_CXX and QMAKE_LINK are ignored by qmake. +#CC = /usr/local/Cellar/gcc/4.9.2_1/bin/gcc-4.9 +#CXX = /usr/local/Cellar/gcc/4.9.2_1/bin/g++-4.9 +#LINK = /usr/local/Cellar/gcc/4.9.2_1/bin/g++-4.9 + +# Input +RESOURCES = images.qrc +HEADERS += core/cAllocator.h \ + core/cBrick.h \ + core/cBricksDatabase.h \ + core/cCandidate.h \ + core/cCandidateSet.h \ + core/cDeNovoGraph.h \ + core/cDeNovoGraphNode.h \ + core/cFragmentIons.h \ + core/cParameters.h \ + core/cPeak.h \ + core/cPeaksList.h \ + core/cSequence.h \ + core/cSequenceDatabase.h \ + core/cSummaryFormula.h \ + core/cTheoreticalSpectrum.h \ + core/cTheoreticalSpectrumList.h \ + core/utilities.h \ + gui/cAboutWidget.h \ + gui/cBranchedWidget.h \ + gui/cBricksDatabaseWidget.h \ + gui/cCyclicWidget.h \ + gui/cDrawPeptideWidget.h \ + gui/cEventFilter.h \ + gui/cExportDialog.h \ + gui/cFindDialog.h \ + gui/cFragmentIonsListWidget.h \ + gui/cGraphWidget.h \ + gui/cLassoWidget.h \ + gui/cLinearWidget.h \ + gui/cMainThread.h \ + gui/cMainWindow.h \ + gui/cModificationsWidget.h \ + gui/cParametersWidget.h \ + gui/cSequenceDatabaseWidget.h \ + gui/cSpectrumDetailWidget.h \ + gui/cSpectrumSceneWidget.h \ + parallel/cGraphReaderThread.h \ + parallel/cSpectrumComparatorThread.h +SOURCES += core/cBrick.cpp \ + core/cBricksDatabase.cpp \ + core/cCandidate.cpp \ + core/cCandidateSet.cpp \ + core/cDeNovoGraph.cpp \ + core/cDeNovoGraphNode.cpp \ + core/cFragmentIons.cpp \ + core/cParameters.cpp \ + core/cPeak.cpp \ + core/cPeaksList.cpp \ + core/cSequence.cpp \ + core/cSequenceDatabase.cpp \ + core/cSummaryFormula.cpp \ + core/cTheoreticalSpectrum.cpp \ + core/cTheoreticalSpectrumList.cpp \ + core/utilities.cpp \ + gui/cAboutWidget.cpp \ + gui/cBranchedWidget.cpp \ + gui/cBricksDatabaseWidget.cpp \ + gui/cCyclicWidget.cpp \ + gui/cDrawPeptideWidget.cpp \ + gui/cEventFilter.cpp \ + gui/cExportDialog.cpp \ + gui/cFindDialog.cpp \ + gui/cFragmentIonsListWidget.cpp \ + gui/cGraphWidget.cpp \ + gui/cLassoWidget.cpp \ + gui/cLinearWidget.cpp \ + gui/cMainThread.cpp \ + gui/cMainWindow.cpp \ + gui/cModificationsWidget.cpp \ + gui/cParametersWidget.cpp \ + gui/cSequenceDatabaseWidget.cpp \ + gui/cSpectrumDetailWidget.cpp \ + gui/cSpectrumSceneWidget.cpp \ + parallel/cGraphReaderThread.cpp \ + parallel/cSpectrumComparatorThread.cpp \ + main.cpp diff --git a/CycloBranch/CycloBranch.vcxproj b/CycloBranch/CycloBranch.vcxproj index 12d8bf3..3431970 100644 --- a/CycloBranch/CycloBranch.vcxproj +++ b/CycloBranch/CycloBranch.vcxproj @@ -139,8 +139,8 @@ Windows $(OutDir)\$(ProjectName).exe $(QTDIR)\lib;C:\boost_1_57_0\lib64-msvc-11.0;%(AdditionalLibraryDirectories) - true - qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;Qt5Svgd.lib;Qt5PrintSupport.lib;libboost_regex-vc110-mt-1_57.lib;%(AdditionalDependencies) + false + qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;Qt5Svg.lib;Qt5PrintSupport.lib;libboost_regex-vc110-mt-1_57.lib;%(AdditionalDependencies) true true UseLinkTimeCodeGeneration @@ -187,6 +187,14 @@ true true + + true + true + + + true + true + true true @@ -273,6 +281,14 @@ true true + + true + true + + + true + true + true true @@ -331,6 +347,8 @@ + + @@ -362,6 +380,42 @@ + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cExportDialog.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_PRINTSUPPORT_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtPrintSupport" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cExportDialog.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_PRINTSUPPORT_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtPrintSupport" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cExportDialog.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_PRINTSUPPORT_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtPrintSupport" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cExportDialog.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_PRINTSUPPORT_LIB -DQT_SVG_LIB "-I." "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtSvg" "-I$(QTDIR)\include\QtPrintSupport" "-IC:\boost_1_57_0" "-IC:\boost_1_57_0\boost" + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cFindDialog.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_PRINTSUPPORT_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtPrintSupport" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cFindDialog.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_PRINTSUPPORT_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtPrintSupport" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cFindDialog.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_PRINTSUPPORT_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtPrintSupport" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cFindDialog.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_PRINTSUPPORT_LIB -DQT_SVG_LIB "-I." "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtSvg" "-I$(QTDIR)\include\QtPrintSupport" "-IC:\boost_1_57_0" "-IC:\boost_1_57_0\boost" + $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing cSpectrumSceneWidget.h... diff --git a/CycloBranch/CycloBranch.vcxproj.filters b/CycloBranch/CycloBranch.vcxproj.filters index f42329c..aa5e87e 100644 --- a/CycloBranch/CycloBranch.vcxproj.filters +++ b/CycloBranch/CycloBranch.vcxproj.filters @@ -272,6 +272,24 @@ Generated Files\Release + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\gui + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\gui + @@ -340,6 +358,12 @@ Header Files\gui + + Header Files\gui + + + Header Files\gui + diff --git a/CycloBranch/core/cBricksDatabase.cpp b/CycloBranch/core/cBricksDatabase.cpp index 810fde9..e1693b7 100644 --- a/CycloBranch/core/cBricksDatabase.cpp +++ b/CycloBranch/core/cBricksDatabase.cpp @@ -57,14 +57,19 @@ void generateBricksPermutations(vector& bricks, vector& currentp } -bool cBricksDatabase::nextCombination(vector& combarray, int numberofbasicbricks, int maximumbricksincombination, double maximumcumulativemass) { +bool cBricksDatabase::nextCombination(vector& combarray, int numberofbasicbricks, int maximumbricksincombination, double maximumcumulativemass, double neutralprecursormass) { int pointer = 0; int cyFlag = 0; + double mass; + do { + combarray[pointer]++; // set combarray[pointer] to the maximum value when outside of the mass range - if ((cyFlag == 0) && (combarray[pointer] <= numberofbasicbricks) && (maximumcumulativemass > 0) && (getMassOfComposition(combarray, maximumbricksincombination) > maximumcumulativemass)) { + mass = getMassOfComposition(combarray); + + if ((cyFlag == 0) && (combarray[pointer] <= numberofbasicbricks) && (((maximumcumulativemass > 0) && (mass > maximumcumulativemass)) || (mass > neutralprecursormass))) { combarray[pointer] = numberofbasicbricks + 1; } @@ -77,27 +82,35 @@ bool cBricksDatabase::nextCombination(vector& combarray, int numberofbasicb } // skip combinations outside of the mass range - while ((combarray[pointer] <= numberofbasicbricks) && (pointer < maximumbricksincombination - 1) && (maximumcumulativemass > 0) && (getMassOfComposition(combarray, maximumbricksincombination) > maximumcumulativemass)) { + mass = getMassOfComposition(combarray); + + while ((combarray[pointer] <= numberofbasicbricks) && (pointer < maximumbricksincombination - 1) && (((maximumcumulativemass > 0) && (mass > maximumcumulativemass)) || (mass > neutralprecursormass))) { pointer++; combarray[pointer]++; for (int i = pointer - 1; i >= 0; i--) { combarray[i] = combarray[pointer]; } + + mass = getMassOfComposition(combarray); } - if ((combarray[pointer] > numberofbasicbricks) || ((maximumcumulativemass > 0) && (getMassOfComposition(combarray, maximumbricksincombination) > maximumcumulativemass))) { + if ((combarray[pointer] > numberofbasicbricks) || ((maximumcumulativemass > 0) && (mass > maximumcumulativemass)) || (mass > neutralprecursormass)) { return false; } } return true; + } else { + cyFlag = 1; pointer++; + } + } while (pointer < maximumbricksincombination); return false; @@ -178,7 +191,7 @@ int cBricksDatabase::loadFromPlainTextStream(ifstream &stream, string& errormess } // load references - #if OS_TYPE == UNX + #if OS_TYPE != WIN if ((s.size() > 0) && (s.back() == '\r')) { s = s.substr(0, s.size() - 1); } @@ -252,12 +265,14 @@ cBrick& cBricksDatabase::operator[](int position) { } -double cBricksDatabase::getMassOfComposition(vector& combarray, int maximumbricksincombination) { +double cBricksDatabase::getMassOfComposition(vector& combarray) { double mass = 0; - for (int i = 0; i < maximumbricksincombination; i++) { + int i = 0; + while (i < (int)combarray.size()) { if (combarray[i] > 0) { mass += bricks[combarray[i] - 1].getMass(); } + i++; } return mass; } diff --git a/CycloBranch/core/cBricksDatabase.h b/CycloBranch/core/cBricksDatabase.h index c2a50de..ff62d24 100644 --- a/CycloBranch/core/cBricksDatabase.h +++ b/CycloBranch/core/cBricksDatabase.h @@ -75,9 +75,10 @@ class cBricksDatabase { \param numberofbasicbricks initial number of bricks in a database \param maximumbricksincombination maximum number of combined bricks \param maximumcumulativemass maximum cummulative mass of combined bricks + \param neutralprecursormass neutral precursor mass \retval bool true when a valid vector is stored in combarray, false when all valid vectors were already generated */ - bool nextCombination(vector& combarray, int numberofbasicbricks, int maximumbricksincombination, double maximumcumulativemass); + bool nextCombination(vector& combarray, int numberofbasicbricks, int maximumbricksincombination, double maximumcumulativemass, double neutralprecursormass); /** @@ -133,10 +134,9 @@ class cBricksDatabase { /** \brief Get the mass of a composition of bricks. \param combarray reference to an input integer vector of ids - \param maximumbricksincombination maximum number of bricks in a combination \retval double cumulative mass of the bricks in the \a combarray */ - double getMassOfComposition(vector& combarray, int maximumbricksincombination); + double getMassOfComposition(vector& combarray); /** diff --git a/CycloBranch/core/cCandidate.cpp b/CycloBranch/core/cCandidate.cpp index b7cdb27..c784205 100644 --- a/CycloBranch/core/cCandidate.cpp +++ b/CycloBranch/core/cCandidate.cpp @@ -867,7 +867,7 @@ bool cCandidate::compare(cCandidate& candidate) { } -vector& cCandidate::getPath() { +vector cCandidate::getPath() { return path; } @@ -896,7 +896,7 @@ bool cCandidate::hasOnlyArtificialBricks(cBricksDatabase& brickdatabasewithcombi if (numberofinternalbricks <= 2) { cBrick b; vector intcomposition; - b.setComposition(internalcomposition,false); + b.setComposition(internalcomposition, false); b.explodeToIntComposition(intcomposition); for (int i = 0; i < (int)intcomposition.size(); i++) { if (!brickdatabasewithcombinations[intcomposition[i] - 1].isArtificial()) { @@ -909,6 +909,18 @@ bool cCandidate::hasOnlyArtificialBricks(cBricksDatabase& brickdatabasewithcombi } +bool cCandidate::hasLastBrickArtificial(cBricksDatabase& brickdatabasewithcombinations) { + cBrick b; + vector intcomposition; + b.setComposition(internalcomposition, false); + b.explodeToIntComposition(intcomposition); + if ((intcomposition.size() > 0) && brickdatabasewithcombinations[intcomposition.back() - 1].isArtificial()) { + return true; + } + return false; +} + + void cCandidate::getRotations(vector& rotations, bool includerevertedrotations) { rotations.clear(); //rotations.push_back(composition); @@ -932,7 +944,7 @@ void cCandidate::getLassoRotations(vector& lassorotations, bool incl } -string cCandidate::getSummaryFormula(cParameters& parameters, peptideType peptidetype) { +cSummaryFormula cCandidate::getSummaryFormula(cParameters& parameters, peptideType peptidetype) { cBrick b; vector bricks; b.setComposition(internalcomposition, false); @@ -977,8 +989,10 @@ string cCandidate::getSummaryFormula(cParameters& parameters, peptideType peptid partial = true; } } - - return partial?formula.getFormula() + " (partial)":formula.getFormula(); + + formula.setPartial(partial); + + return formula; } diff --git a/CycloBranch/core/cCandidate.h b/CycloBranch/core/cCandidate.h index 145b90b..6204bf1 100644 --- a/CycloBranch/core/cCandidate.h +++ b/CycloBranch/core/cCandidate.h @@ -383,9 +383,9 @@ class cCandidate { /** \brief Get a path in the de novo graph corresponding to the peptide sequence candidate. - \retval vector reference to a vector of pairs node and edge + \retval vector vector of pairs node and edge */ - vector& getPath(); + vector getPath(); /** @@ -404,6 +404,14 @@ class cCandidate { bool hasOnlyArtificialBricks(cBricksDatabase& brickdatabasewithcombinations); + /** + \brief Check if the last brick is artificial. + \param brickdatabasewithcombinations reference to an input database of bricks with combinations of bricks + \retval bool true if the last brick is artificial, false otherwise + */ + bool hasLastBrickArtificial(cBricksDatabase& brickdatabasewithcombinations); + + /** \brief Get rotations of a cyclic peptide sequence. \param rotations reference to an output vector containing rotations of a sequence @@ -424,9 +432,9 @@ class cCandidate { \brief Get the summary formula of the peptide sequence candidate. \param parameters a reference to the parameters of the application \param peptidetype the type of peptide - \retval string the summary formula + \retval cSummaryFormula the summary formula */ - string getSummaryFormula(cParameters& parameters, peptideType peptidetype); + cSummaryFormula getSummaryFormula(cParameters& parameters, peptideType peptidetype); /** diff --git a/CycloBranch/core/cDeNovoGraph.cpp b/CycloBranch/core/cDeNovoGraph.cpp index 9c9c1e8..4ae488b 100644 --- a/CycloBranch/core/cDeNovoGraph.cpp +++ b/CycloBranch/core/cDeNovoGraph.cpp @@ -22,7 +22,12 @@ cDeNovoGraph::cDeNovoGraph() { } -bool cDeNovoGraph::findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, vector& path) { +bool cDeNovoGraph::findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, vector& path, bool& terminatecomputation) { + + if (terminatecomputation) { + return false; + } + string localbrickpath; bool found; bool badpath; @@ -70,7 +75,7 @@ bool cDeNovoGraph::findPath(int sourcenodeid, int edgeid, int targetnodeid, stri ne.edgeid = i; path.push_back(ne); - found = findPath(graph[sourcenodeid][i].targetnode, i, targetnodeid, composition, localbrickpath, maximumbricksincombination, path); + found = findPath(graph[sourcenodeid][i].targetnode, i, targetnodeid, composition, localbrickpath, maximumbricksincombination, path, terminatecomputation); path.pop_back(); @@ -78,6 +83,10 @@ bool cDeNovoGraph::findPath(int sourcenodeid, int edgeid, int targetnodeid, stri //*os << graph[sourcenodeid].getMZRatio() << " "; return true; } + + if (terminatecomputation) { + return false; + } } } @@ -380,7 +389,7 @@ int cDeNovoGraph::createGraph(bool& terminatecomputation) { combarray.push_back(0); } - while (bricksdatabasewithcombinations.nextCombination(combarray, numberofbasicbricks, parameters->maximumbricksincombination, parameters->maximumcumulativemass)) { + while (bricksdatabasewithcombinations.nextCombination(combarray, numberofbasicbricks, parameters->maximumbricksincombination, parameters->maximumcumulativemass, uncharge(parameters->precursormass, parameters->precursorcharge))) { if (terminatecomputation) { return -1; } @@ -400,7 +409,7 @@ int cDeNovoGraph::createGraph(bool& terminatecomputation) { *os << "Generating combinations of bricks and generating edges... " << endl; int j = 0; - while (bricksdatabasewithcombinations.nextCombination(combarray, numberofbasicbricks, parameters->maximumbricksincombination, parameters->maximumcumulativemass)) { + while (bricksdatabasewithcombinations.nextCombination(combarray, numberofbasicbricks, parameters->maximumbricksincombination, parameters->maximumcumulativemass, uncharge(parameters->precursormass, parameters->precursorcharge))) { if (terminatecomputation) { return -1; @@ -424,7 +433,7 @@ int cDeNovoGraph::createGraph(bool& terminatecomputation) { } else { b.clear(); - b.setMass(bricksdatabasewithcombinations.getMassOfComposition(combarray, parameters->maximumbricksincombination)); + b.setMass(bricksdatabasewithcombinations.getMassOfComposition(combarray)); b.setComposition(compositionname, true); bricksdatabasewithcombinations.push_back(b); } @@ -773,6 +782,7 @@ int cDeNovoGraph::connectEdgesFormingPathsNotFinishingInPrecursor(bool& terminat graph[i].insertEdge(e); edgescreated++; + // normal brick cBrick b; b.setName(to_string(e.massdifference)); b.setAcronyms(to_string(e.massdifference)); @@ -783,6 +793,16 @@ int cDeNovoGraph::connectEdgesFormingPathsNotFinishingInPrecursor(bool& terminat b.setComposition(to_string(e.brickid), false); b.setArtificial(true); bricksdatabasewithcombinations.push_back(b); + + // water loss brick + b.setName(to_string(e.massdifference - H2O)); + b.setAcronyms(to_string(e.massdifference - H2O)); + b.setReferences(s); + b.setSummary(s); + b.setMass(e.massdifference - H2O); + b.setComposition(to_string((int)bricksdatabasewithcombinations.size() + 1), false); + b.setArtificial(true); + bricksdatabasewithcombinations.push_back(b); //} } @@ -879,7 +899,7 @@ int cDeNovoGraph::removePathsWhichCanBeSubstitutedByLongerPath(bool& terminateco cBrick b; b.setComposition(graph[i][j].composition, true); path.clear(); - if (findPath(i, j, graph[i][j].targetnode, b.getComposition(), "", parameters->maximumbricksincombination, path)) { + if (findPath(i, j, graph[i][j].targetnode, b.getComposition(), "", parameters->maximumbricksincombination, path, terminatecomputation)) { //*os << "removing edge: " << graph[i].getMZRatio() << "->" << graph[graph[i][j].targetnode].getMZRatio() << " " << bricksdatabasewithcombinations.getTagName(b.getComposition()) << endl; graph[i].removeEdge(j); edgesremoved++; @@ -887,6 +907,11 @@ int cDeNovoGraph::removePathsWhichCanBeSubstitutedByLongerPath(bool& terminateco else { j++; } + + if (terminatecomputation) { + return -1; + } + } } *os << "ok" << endl; @@ -960,6 +985,7 @@ void cDeNovoGraph::printPaths(cMainThread* os, cDeNovoGraphNode& node, vector 0) { - g += "The node " + s + " with relative intensity " + to_string(graph[i].getIntensity()) + " has " + to_string(graph[i].size()) + " outgoing edge(s).
"; + g += "The node " + s + " with relative intensity " + to_string(graph[i].getIntensity()) + " has " + to_string(graph[i].size()) + " outgoing edge(s):
"; } else { g += "The node " + s + " with relative intensity " + to_string(graph[i].getIntensity()) + " does not have any outgoing edge.
"; @@ -978,7 +1004,8 @@ string cDeNovoGraph::printGraph() { //g += graph[i].printAnnotations(); //g += "\n"; - for (int j = 0; j < (int)graph[i].size(); j++) { + for (int j = 0; j < min((int)graph[i].size(), edgesmaxreport); j++) { + s2 = to_string(graph[graph[i][j].targetnode].getMZRatio()); g += s + "->" + s2 + " using brick(s): "; if (graph[i][j].composition.compare("0") == 0) { @@ -1007,6 +1034,10 @@ string cDeNovoGraph::printGraph() { g += ")
"; } + if ((int)graph[i].size() > edgesmaxreport) { + g += "... and " + to_string((int)graph[i].size() - edgesmaxreport) + " other edge(s).
"; + } + g += "
"; } diff --git a/CycloBranch/core/cDeNovoGraph.h b/CycloBranch/core/cDeNovoGraph.h index c5b49ed..045fecf 100644 --- a/CycloBranch/core/cDeNovoGraph.h +++ b/CycloBranch/core/cDeNovoGraph.h @@ -55,7 +55,7 @@ class cDeNovoGraph { cGraphReaderThread* graphreaderthread; - bool findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, vector& path); + bool findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, vector& path, bool& terminatecomputation); // create vectors of edges from temporary unordered_sets void createVectorsOfEdges(); @@ -63,6 +63,7 @@ class cDeNovoGraph { // check whether a path leads to the precursor bool finishInPrecursor(int currentnode, double cummass); + public: /** diff --git a/CycloBranch/core/cFragmentIons.cpp b/CycloBranch/core/cFragmentIons.cpp index c10b320..9d38635 100644 --- a/CycloBranch/core/cFragmentIons.cpp +++ b/CycloBranch/core/cFragmentIons.cpp @@ -12,6 +12,7 @@ cPeriodicTableMap::cPeriodicTableMap() { table["N"] = N; table["O"] = O; table["F"] = F; + table["Ne"] = Ne; table["Na"] = Na; table["Mg"] = Mg; table["Al"] = Al; @@ -19,6 +20,7 @@ cPeriodicTableMap::cPeriodicTableMap() { table["P"] = P; table["S"] = S; table["Cl"] = Cl; + table["Ar"] = Ar; table["K"] = K; table["Ca"] = Ca; table["Sc"] = Sc; @@ -31,10 +33,81 @@ cPeriodicTableMap::cPeriodicTableMap() { table["Ni"] = Ni; table["Cu"] = Cu; table["Zn"] = Zn; + table["Ga"] = Ga; + table["Ge"] = Ge; + table["As"] = As; table["Se"] = Se; table["Br"] = Br; + table["Kr"] = Kr; + table["Rb"] = Rb; + table["Sr"] = Sr; + table["Y"] = Y; + table["Zr"] = Zr; + table["Nb"] = Nb; table["Mo"] = Mo; + table["Tc"] = Tc; + table["Ru"] = Ru; + table["Rh"] = Rh; + table["Pd"] = Pd; + table["Ag"] = Ag; + table["Cd"] = Cd; + table["In"] = In; + table["Sn"] = Sn; + table["Sb"] = Sb; + table["Te"] = Te; table["I"] = I; + table["Xe"] = Xe; + table["Cs"] = Cs; + table["Ba"] = Ba; + table["La"] = La; + table["Ce"] = Ce; + table["Pr"] = Pr; + table["Nd"] = Nd; + table["Pm"] = Pm; + table["Sm"] = Sm; + table["Eu"] = Eu; + table["Gd"] = Gd; + table["Tb"] = Tb; + table["Dy"] = Dy; + table["Ho"] = Ho; + table["Er"] = Er; + table["Tm"] = Tm; + table["Yb"] = Yb; + table["Lu"] = Lu; + table["Hf"] = Hf; + table["Ta"] = Ta; + table["W"] = W; + table["Re"] = Re; + table["Os"] = Os; + table["Ir"] = Ir; + table["Pt"] = Pt; + table["Au"] = Au; + table["Hg"] = Hg; + table["Tl"] = Tl; + table["Pb"] = Pb; + table["Bi"] = Bi; + table["Po"] = Po; + table["At"] = At; + table["Rn"] = Rn; + table["Fr"] = Fr; + table["Ra"] = Ra; + table["Ac"] = Ac; + table["Th"] = Th; + table["Pa"] = Pa; + table["U"] = U; + table["Np"] = Np; + table["Pu"] = Pu; + table["Am"] = Am; + table["Cm"] = Cm; + table["Bk"] = Bk; + table["Cf"] = Cf; + table["Es"] = Es; + table["Fm"] = Fm; + table["Md"] = Md; + table["No"] = No; + table["Lr"] = Lr; + table["R"] = R; + table["X"] = X; } @@ -717,7 +790,7 @@ int loadModificationsFromPlainTextStream(ifstream &stream, vector 0) && (s.back() == '\r')) { s = s.substr(0, s.size() - 1); } diff --git a/CycloBranch/core/cFragmentIons.h b/CycloBranch/core/cFragmentIons.h index aab7545..728e596 100644 --- a/CycloBranch/core/cFragmentIons.h +++ b/CycloBranch/core/cFragmentIons.h @@ -33,6 +33,7 @@ const double C = 12.0; const double N = 14.0030740052; const double O = 15.9949146221; const double F = 18.998404; +const double Ne = 19.992439; const double Na = 22.989771; const double Mg = 23.985043; const double Al = 26.981539; @@ -40,6 +41,7 @@ const double Si = 27.976927; const double P = 30.97376151; const double S = 31.97207069; const double Cl = 34.968853; +const double Ar = 39.962383; const double K = 38.963707; const double Ca = 39.962589; const double Sc = 44.95591; @@ -52,10 +54,81 @@ const double Co = 58.933201; const double Ni = 57.935349; const double Cu = 62.9296; const double Zn = 63.929146; +const double Ga = 68.925583; +const double Ge = 73.921181; +const double As = 74.921600; const double Se = 79.916519; const double Br = 78.918327; +const double Kr = 83.911507; +const double Rb = 84.911789; +const double Sr = 87.905617; +const double Y = 88.905846; +const double Zr = 89.904701; +const double Nb = 92.906403; const double Mo = 97.905411; +const double Tc = 97.907219; +const double Ru = 101.904388; +const double Rh = 102.905502; +const double Pd = 105.903481; +const double Ag = 106.905090; +const double Cd = 113.903358; +const double In = 114.903877; +const double Sn = 119.902199; +const double Sb = 120.903824; +const double Te = 129.906219; const double I = 126.904457; +const double Xe = 131.904160; +const double Cs = 132.905441; +const double Ba = 137.905243; +const double La = 138.906342; +const double Ce = 139.905441; +const double Pr = 140.907593; +const double Nd = 141.907700; +const double Pm = 144.912750; +const double Sm = 151.919693; +const double Eu = 152.921204; +const double Gd = 157.924103; +const double Tb = 158.925293; +const double Dy = 163.929199; +const double Ho = 164.930298; +const double Er = 165.930298; +const double Tm = 168.934204; +const double Yb = 173.938904; +const double Lu = 174.940796; +const double Hf = 179.946503; +const double Ta = 180.947998; +const double W = 183.950897; +const double Re = 186.955597; +const double Os = 191.961502; +const double Ir = 192.962906; +const double Pt = 194.964798; +const double Au = 196.966507; +const double Hg = 201.970596; +const double Tl = 204.974396; +const double Pb = 207.976593; +const double Bi = 208.980392; +const double Po = 208.982422; +const double At = 209.987137; +const double Rn = 222.017563; +const double Fr = 209.996399; +const double Ra = 226.025406; +const double Ac = 227.027740; +const double Th = 232.038055; +const double Pa = 231.035904; +const double U = 238.050781; +const double Np = 237.048172; +const double Pu = 242.058746; +const double Am = 243.061371; +const double Cm = 247.070343; +const double Bk = 247.070297; +const double Cf = 251.079575; +const double Es = 252.082977; +const double Fm = 257.095093; +const double Md = 258.098419; +const double No = 259.101044; +const double Lr = 262.109802; +const double R = 0; +const double X = 0; const double e = H - Hplus; diff --git a/CycloBranch/core/cParameters.cpp b/CycloBranch/core/cParameters.cpp index 40c8b26..c0eb7db 100644 --- a/CycloBranch/core/cParameters.cpp +++ b/CycloBranch/core/cParameters.cpp @@ -40,6 +40,7 @@ void cParameters::clear() { cyclicnterminus = false; cycliccterminus = false; enablescrambling = false; + similaritysearch = false; hitsreported = 1000; sequencetag = ""; originalsequencetag = ""; @@ -130,27 +131,40 @@ int cParameters::checkAndPrepare() { *os << "Converting the file " + peaklistfilename + " to mgf ... "; #if OS_TYPE == UNX - s = linuxinstalldir.toStdString() + "External/linux/any2mgf.sh " + peaklistfilename; + s = installdir.toStdString() + "External/linux/any2mgf.sh " + peaklistfilename; if (system(s.c_str()) != 0) { error = true; errormessage = "The file cannot be converted.\n"; errormessage += "Does the file '" + peaklistfilename + "' exist ?\n"; errormessage += "Is the directory with the file '" + peaklistfilename + "' writable ?\n"; errormessage += "Do you have FileConverter installed (sudo apt-get install topp) ?\n"; - errormessage += "Do you have 'any2mgf.sh' file located in '" + linuxinstalldir.toStdString() + "External/linux' folder ?\n"; - errormessage += "Is the file 'any2mgf.sh' executable (sudo chmod +x " + linuxinstalldir.toStdString() + "External/linux/any2mgf.sh) ? \n"; + errormessage += "Do you have 'any2mgf.sh' file located in '" + installdir.toStdString() + "External/linux' folder ?\n"; + errormessage += "Is the file 'any2mgf.sh' executable (sudo chmod +x " + installdir.toStdString() + "External/linux/any2mgf.sh) ? \n"; } #else - s = "External\\windows\\any2mgf.bat \"" + peaklistfilename + "\""; - if (system(s.c_str()) != 0) { - error = true; - errormessage = "The file cannot be converted.\n"; - errormessage += "Does the file '" + peaklistfilename + "' exist ?\n"; - errormessage += "Is the directory with the file '" + peaklistfilename + "' writable ?\n"; - errormessage += "Do you have FileConverter installed (OpenMS 1.11) ?\n"; - errormessage += "Do you have a path to FileConverter in your PATH variable (e.g., 'C:/Program Files/OpenMS-1.11/bin') ?\n"; - errormessage += "Do you have 'any2mgf.bat' file located in the '" + appname.toStdString() + "/External/windows' folder ?\n"; - } + #if OS_TYPE == OSX + s = installdir.toStdString() + "External/macosx/any2mgf.sh " + peaklistfilename; + if (system(s.c_str()) != 0) { + error = true; + errormessage = "The file cannot be converted.\n"; + errormessage += "Does the file '" + peaklistfilename + "' exist ?\n"; + errormessage += "Is the directory with the file '" + peaklistfilename + "' writable ?\n"; + errormessage += "Do you have FileConverter installed (OpenMS 1.11) ?\n"; + errormessage += "Do you have 'any2mgf.sh' file located in '" + installdir.toStdString() + "External/macosx' folder ?\n"; + errormessage += "Is the file 'any2mgf.sh' executable ? \n"; + } + #else + s = "External\\windows\\any2mgf.bat \"" + peaklistfilename + "\""; + if (system(s.c_str()) != 0) { + error = true; + errormessage = "The file cannot be converted.\n"; + errormessage += "Does the file '" + peaklistfilename + "' exist ?\n"; + errormessage += "Is the directory with the file '" + peaklistfilename + "' writable ?\n"; + errormessage += "Do you have FileConverter installed (OpenMS 1.11) ?\n"; + errormessage += "Do you have a path to FileConverter in your PATH variable (e.g., 'C:/Program Files/OpenMS-1.11/bin') ?\n"; + errormessage += "Do you have 'any2mgf.bat' file located in the '" + appname.toStdString() + "/External/windows' folder ?\n"; + } + #endif #endif if (!error) { @@ -475,6 +489,10 @@ string cParameters::printToString() { s += enablescrambling ? "on" : "off"; s += "\n"; + s += "Similarity Search: "; + s += similaritysearch ? "on" : "off"; + s += "\n"; + s += "Mode: "; switch ((modeType)mode) { case denovoengine: @@ -617,6 +635,7 @@ void cParameters::store(ofstream& os) { os.write((char *)&cyclicnterminus, sizeof(bool)); os.write((char *)&cycliccterminus, sizeof(bool)); os.write((char *)&enablescrambling, sizeof(bool)); + os.write((char *)&similaritysearch, sizeof(bool)); os.write((char *)&hitsreported, sizeof(int)); storeString(sequencetag, os); @@ -694,6 +713,7 @@ void cParameters::load(ifstream& is) { is.read((char *)&cyclicnterminus, sizeof(bool)); is.read((char *)&cycliccterminus, sizeof(bool)); is.read((char *)&enablescrambling, sizeof(bool)); + is.read((char *)&similaritysearch, sizeof(bool)); is.read((char *)&hitsreported, sizeof(int)); loadString(sequencetag, is); diff --git a/CycloBranch/core/cParameters.h b/CycloBranch/core/cParameters.h index 923b1d1..9bafc84 100644 --- a/CycloBranch/core/cParameters.h +++ b/CycloBranch/core/cParameters.h @@ -221,6 +221,12 @@ class cParameters { bool enablescrambling; + /** + \brief True when the similarity search is enabled. + */ + bool similaritysearch; + + /** \brief Maximum number of reported hits. */ diff --git a/CycloBranch/core/cSequence.cpp b/CycloBranch/core/cSequence.cpp index 26dcbbb..c777eea 100644 --- a/CycloBranch/core/cSequence.cpp +++ b/CycloBranch/core/cSequence.cpp @@ -164,6 +164,17 @@ string cSequence::getNameWithReferenceAsHTMLString() { } } + // KEGG Compounds (undocumented) + if (!correctreference) { + rx = "^C[0-9]{5}$"; + if (regex_search(reference, rx)) { + s += ""; + s += name; + s += ""; + correctreference = true; + } + } + } catch (regex_error& /*e*/) { // nothing to do @@ -182,7 +193,7 @@ void cSequence::setSummaryFormula(const string& formula) { } -string& cSequence::getSummaryFormula() { - return summary.getFormula(); +string cSequence::getSummaryFormula() { + return summary.getSummary(); } diff --git a/CycloBranch/core/cSequence.h b/CycloBranch/core/cSequence.h index bd2d2df..c84c94d 100644 --- a/CycloBranch/core/cSequence.h +++ b/CycloBranch/core/cSequence.h @@ -179,7 +179,7 @@ class cSequence { \brief Get the summary formula. \retval string summary formula */ - string& getSummaryFormula(); + string getSummaryFormula(); }; diff --git a/CycloBranch/core/cSequenceDatabase.cpp b/CycloBranch/core/cSequenceDatabase.cpp index 00a0748..91ad447 100644 --- a/CycloBranch/core/cSequenceDatabase.cpp +++ b/CycloBranch/core/cSequenceDatabase.cpp @@ -124,7 +124,7 @@ void cSequenceDatabase::loadFromPlainTextStream(ifstream &stream) { } // load reference - #if OS_TYPE == UNX + #if OS_TYPE != WIN if ((s.size() > 0) && (s.back() == '\r')) { s = s.substr(0, s.size() - 1); } diff --git a/CycloBranch/core/cSummaryFormula.cpp b/CycloBranch/core/cSummaryFormula.cpp index 352643e..86337c8 100644 --- a/CycloBranch/core/cSummaryFormula.cpp +++ b/CycloBranch/core/cSummaryFormula.cpp @@ -84,26 +84,38 @@ cSummaryFormula::cSummaryFormula() { } -cSummaryFormula::cSummaryFormula(string& formula) { - this->formula = formula; +cSummaryFormula::cSummaryFormula(string& formula, bool partial) { + setFormula(formula, partial); } void cSummaryFormula::clear() { formula = ""; + partial = false; } -void cSummaryFormula::setFormula(const string& formula) { +void cSummaryFormula::setFormula(const string& formula, bool partial) { this->formula = formula; + this->partial = partial; } -string& cSummaryFormula::getFormula() { +string cSummaryFormula::getSummary() { return formula; } +bool cSummaryFormula::isPartial() { + return partial; +} + + +void cSummaryFormula::setPartial(bool partial) { + this->partial = partial; +} + + void cSummaryFormula::addFormula(string& formula) { if ((int)formula.size() == 0) { return; @@ -247,10 +259,12 @@ double cSummaryFormula::getMass() { void cSummaryFormula::store(ofstream& os) { storeString(formula, os); + os.write((char *)&partial, sizeof(bool)); } void cSummaryFormula::load(ifstream& is) { loadString(formula, is); + is.read((char *)&partial, sizeof(bool)); } diff --git a/CycloBranch/core/cSummaryFormula.h b/CycloBranch/core/cSummaryFormula.h index f6dc553..eb36771 100644 --- a/CycloBranch/core/cSummaryFormula.h +++ b/CycloBranch/core/cSummaryFormula.h @@ -21,6 +21,8 @@ using namespace boost; */ class cSummaryFormula { + bool partial; + string formula; void explodeSummary(map& atoms, string& summary); @@ -36,9 +38,10 @@ class cSummaryFormula { /** \brief The constructor. - \brief formula a chemical formula + \param formula a chemical formula + \param partial true when the formula is incomplete */ - cSummaryFormula(string& formula); + cSummaryFormula(string& formula, bool partial = false); /** @@ -50,15 +53,30 @@ class cSummaryFormula { /** \brief Set the formula. \param formula a chemical formula + \param partial true when the formula is incomplete + */ + void setFormula(const string& formula, bool partial = false); + + + /** + \brief Get the summary formula as a string. + \retval string formula as a string + */ + string getSummary(); + + + /** + \brief Check if the formula is incomplete or not. + \retval bool true when the formula is incomplete, false when the formula is complete */ - void setFormula(const string& formula); + bool isPartial(); /** - \brief Get the formula. - \retval string reference to the formula + \brief Set the formula as partial. + \param partial true if the formula is incomplete */ - string& getFormula(); + void setPartial(bool partial); /** diff --git a/CycloBranch/core/cTheoreticalSpectrum.cpp b/CycloBranch/core/cTheoreticalSpectrum.cpp index 7a53ba6..d72487f 100644 --- a/CycloBranch/core/cTheoreticalSpectrum.cpp +++ b/CycloBranch/core/cTheoreticalSpectrum.cpp @@ -156,13 +156,67 @@ void cTheoreticalSpectrum::generatePrecursorIon(vector& intcomposition, cBr peak.iontype = (fragmentIonType)i; if (writedescription) { + string str; + if (parameters->precursorcharge > 0) { - peak.description = to_string(j) + "+ " + parameters->fragmentdefinitions[(fragmentIonType)i].name + ":"; + peak.description = parameters->fragmentdefinitions[(fragmentIonType)i].name + ":"; + + if (!parameters->precursoradduct.empty()) { + str = "+" + parameters->precursoradduct; + if (j > 1) { + str += "+"; + if (j > 2) { + str += to_string(j - 1); + } + str += "H"; + } + peak.description.replace(peak.description.find("+zH"), 3, str); + } + else { + str = "+"; + if (j > 1) { + str += to_string(j); + } + str += "H"; + peak.description.replace(peak.description.find("+zH"), 3, str); + } + + str = "]"; + if (j > 1) { + str += to_string(j); + } + str += "+"; + peak.description.replace(peak.description.find("]+"), 2, str); } else { - peak.description = to_string(j) + "- " + parameters->fragmentdefinitions[(fragmentIonType)i].name + ":"; - peak.description.replace(peak.description.find("+z"), 2, "-z"); - peak.description.replace(peak.description.find("]+"), 2, "]-"); + peak.description = parameters->fragmentdefinitions[(fragmentIonType)i].name + ":"; + + if (!parameters->precursoradduct.empty()) { + str = "-" + parameters->precursoradduct; + if (j > 1) { + str += "-"; + if (j > 2) { + str += to_string(j - 1); + } + str += "H"; + } + peak.description.replace(peak.description.find("+zH"), 3, str); + } + else { + str = "-"; + if (j > 1) { + str += to_string(j); + } + str += "H"; + peak.description.replace(peak.description.find("+zH"), 3, str); + } + + str = "]"; + if (j > 1) { + str += to_string(j); + } + str += "-"; + peak.description.replace(peak.description.find("]+"), 2, str); } } @@ -703,7 +757,7 @@ int cTheoreticalSpectrum::compareLinear(cPeaksList& sortedpeaklist, cBricksDatab clearFalseHits(series, parameters->fragmentionsfortheoreticalspectra); for (int i = 0; i < theoreticalpeaksrealsize; i++) { - if ((theoreticalpeaks[i].matched > 0) && ((series.count(parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent) == 0) || (series[parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent][theoreticalpeaks[i].seriesid] == 0))) { + if ((theoreticalpeaks[i].matched > 0) && (theoreticalpeaks[i].rotationid != -1) && ((series.count(parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent) == 0) || (series[parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent][theoreticalpeaks[i].seriesid] == 0))) { experimentalpeakmatches[theoreticalpeaks[i].matchedid].erase(experimentalpeakmatches[theoreticalpeaks[i].matchedid].find(i)); experimentalpeaks[theoreticalpeaks[i].matchedid].matched--; @@ -1101,7 +1155,6 @@ int cTheoreticalSpectrum::compareLasso(cPeaksList& sortedpeaklist, cBricksDataba int theoreticalpeaksrealsize = 0; vector lassorotations; - // normalize the candidate candidate.getLassoRotations(lassorotations, false); int numberofbricks = getNumberOfBricks(candidate.getComposition()); @@ -1109,12 +1162,14 @@ int cTheoreticalSpectrum::compareLasso(cPeaksList& sortedpeaklist, cBricksDataba if (lassorotations[i].getBranchEnd() == numberofbricks - 1) { vector v; v.push_back(lassorotations[i].getComposition()); - candidate.setCandidate(v, candidate.getPath(), candidate.getStartModifID(), candidate.getEndModifID(), candidate.getMiddleModifID(), lassorotations[i].getBranchStart(), lassorotations[i].getBranchEnd()); + string name = candidate.getName(); + vector cpath = candidate.getPath(); + candidate.setCandidate(v, cpath, candidate.getStartModifID(), candidate.getEndModifID(), candidate.getMiddleModifID(), lassorotations[i].getBranchStart(), lassorotations[i].getBranchEnd()); + candidate.setName(name); break; } } - // get branch-cyclic rotations candidate.getLassoRotations(lassorotations, true); @@ -1421,7 +1476,7 @@ int cTheoreticalSpectrum::compareLinearPolysaccharide(cPeaksList& sortedpeaklist clearFalseHits(series, parameters->fragmentionsfortheoreticalspectra); for (int i = 0; i < theoreticalpeaksrealsize; i++) { - if ((theoreticalpeaks[i].matched > 0) && ((series.count(parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent) == 0) || (series[parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent][theoreticalpeaks[i].seriesid] == 0))) { + if ((theoreticalpeaks[i].matched > 0) && (theoreticalpeaks[i].rotationid != -1) && ((series.count(parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent) == 0) || (series[parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent][theoreticalpeaks[i].seriesid] == 0))) { experimentalpeakmatches[theoreticalpeaks[i].matchedid].erase(experimentalpeakmatches[theoreticalpeaks[i].matchedid].find(i)); experimentalpeaks[theoreticalpeaks[i].matchedid].matched--; diff --git a/CycloBranch/core/utilities.cpp b/CycloBranch/core/utilities.cpp index f8868c3..73d9619 100644 --- a/CycloBranch/core/utilities.cpp +++ b/CycloBranch/core/utilities.cpp @@ -4,8 +4,15 @@ QString appname = "CycloBranch"; -QString appversion = "v. 1.0.1106 (64-bit)"; -QString linuxinstalldir = "/usr/share/cyclobranch/"; +QString appversion = "v. 1.0.1216 (64-bit)"; + +#if OS_TYPE == UNX + QString installdir = "/usr/share/cyclobranch/"; +#endif + +#if OS_TYPE == OSX + QString installdir = ""; +#endif void storeString(string& s, ofstream& os) { @@ -120,7 +127,7 @@ void parseBranch(peptideType peptidetype, string& composition, vector& v if (s[i] == '(') { if (i > 0) { b.clear(); - b.setComposition(s.substr(0, i - 1), false); + b.setComposition(s.substr(0, i), false); branchstart = getNumberOfBricks(b.getComposition()); s[i] = '-'; } @@ -135,7 +142,7 @@ void parseBranch(peptideType peptidetype, string& composition, vector& v for (int i = 0; i < (int)s.size(); i++) { if (s[i] == ')') { b.clear(); - b.setComposition(s.substr(0, i - 1), false); + b.setComposition(s.substr(0, i), false); branchend = getNumberOfBricks(b.getComposition()) - 1; if (i < (int)s.size() - 1) { s[i] = '-'; diff --git a/CycloBranch/core/utilities.h b/CycloBranch/core/utilities.h index bdff4c4..daf0cdc 100644 --- a/CycloBranch/core/utilities.h +++ b/CycloBranch/core/utilities.h @@ -18,13 +18,21 @@ class cBrick; #define WIN 0 // Windows #define UNX 1 // Linux/UNIX +#define OSX 2 // Mac OS X -#ifdef UNIX + +#ifdef LINUX #define OS_TYPE UNX #define sscanf_s sscanf #define sprintf_s sprintf #else - #define OS_TYPE WIN + #ifdef MACOSX + #define OS_TYPE OSX + #define sscanf_s sscanf + #define sprintf_s sprintf + #else + #define OS_TYPE WIN + #endif #endif @@ -58,9 +66,9 @@ extern QString appversion; /** - \brief A directory where the application is installed in Linux. + \brief A directory where the application is installed under Linux or OSX. */ -extern QString linuxinstalldir; +extern QString installdir; /** diff --git a/CycloBranch/gui/cAboutWidget.cpp b/CycloBranch/gui/cAboutWidget.cpp index 0fc521d..3f354a6 100644 --- a/CycloBranch/gui/cAboutWidget.cpp +++ b/CycloBranch/gui/cAboutWidget.cpp @@ -32,7 +32,7 @@ cAboutWidget::cAboutWidget(QWidget* parent) { message->setReadOnly(true); message->setAcceptRichText(true); message->setOpenExternalLinks(true); - message->setHtml("
" + splash + "" + appname + " " + appversion + "

" + title + developers /*+ licence*/ + acknowledgement); + message->setHtml("
" + splash + "" + appname + " " + appversion + "

" + title + developers + licence + acknowledgement); buttonbox = new QDialogButtonBox(QDialogButtonBox::Ok); //buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); @@ -62,7 +62,7 @@ void cAboutWidget::closeEvent(QCloseEvent *event) { void cAboutWidget::keyPressEvent(QKeyEvent *event) { - if(event->key() == Qt::Key_Escape) { + if (event->key() == Qt::Key_Escape) { hide(); } } diff --git a/CycloBranch/gui/cBranchedWidget.cpp b/CycloBranch/gui/cBranchedWidget.cpp index ea01478..f551660 100644 --- a/CycloBranch/gui/cBranchedWidget.cpp +++ b/CycloBranch/gui/cBranchedWidget.cpp @@ -41,7 +41,6 @@ void cBranchedWidget::exportToPDF(QString filename, bool postscript) { QString errstr = "The file cannot be created."; #if OS_TYPE == UNX errstr += "\nDo you have a properly configured print server (sudo apt-get install cups-pdf) ?"; - errstr += "\nIf you cannot create a ps file, you can create a pdf file and then use pdf2ps tool."; #endif msgBox.setText(errstr); msgBox.exec(); @@ -89,6 +88,7 @@ void cBranchedWidget::exportToSVG(QString filename) { return; } + painter.fillRect(QRect(0, 0, width(), height()), Qt::white); paint(painter); painter.end(); } diff --git a/CycloBranch/gui/cBricksDatabaseWidget.cpp b/CycloBranch/gui/cBricksDatabaseWidget.cpp index 81dec94..ed58bfa 100644 --- a/CycloBranch/gui/cBricksDatabaseWidget.cpp +++ b/CycloBranch/gui/cBricksDatabaseWidget.cpp @@ -15,6 +15,7 @@ #include #include #include +#include int numberOfOccurrences(const string& s, char c) { @@ -43,17 +44,44 @@ cBricksDatabaseWidget::cBricksDatabaseWidget(QWidget* parent) { close->setToolTip("Close the window."); load = new QPushButton(tr("Load")); load->setToolTip("Load the database of building blocks."); - save = new QPushButton(QString("Save")); + save = new QPushButton(QString(" Save ")); save->setToolTip("Save the database of building blocks in the current file. When a file has not been loaded yet, the \"Save As ...\" file dialog is opened."); saveas = new QPushButton(tr("Save As...")); saveas->setToolTip("Save the database of building blocks into a file."); + rowsfilterline = new QLineEdit(); + rowsfilterline->setMinimumWidth(250); + rowsfilterline->setToolTip("Text to Find"); + rowsfiltercasesensitive = new QCheckBox(); + rowsfiltercasesensitive->setToolTip("Case Sensitive"); + rowsfilterbutton = new QPushButton("Filter"); + rowsfilterbutton->setToolTip("Filter Search Results"); + rowsfilterbutton->setMinimumWidth(50); + rowsfilterclearbutton = new QPushButton("Clear"); + rowsfilterclearbutton->setToolTip("Clear Form and Reset Search Results"); + rowsfilterclearbutton->setMinimumWidth(50); + + rowsfilterhbox = new QHBoxLayout(); + rowsfilterhbox->addWidget(rowsfilterline); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfiltercasesensitive); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfilterbutton); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfilterclearbutton); + + rowsfilterwidget = new QWidget(); + rowsfilterwidget->setLayout(rowsfilterhbox); + rowsfilterwidget->setMaximumWidth(420); + buttons = new QHBoxLayout(); buttons->addWidget(close); - buttons->addStretch(1); + buttons->addStretch(); buttons->addWidget(insertrow); buttons->addWidget(removechecked); - buttons->addStretch(10); + buttons->addStretch(); + buttons->addWidget(rowsfilterwidget); + buttons->addStretch(); buttons->addWidget(load); buttons->addWidget(save); buttons->addWidget(saveas); @@ -91,11 +119,13 @@ cBricksDatabaseWidget::cBricksDatabaseWidget(QWidget* parent) { connect(database->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(headerItemDoubleClicked(int))); connect(database, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(itemChanged(QTableWidgetItem *))); connect(insertrow, SIGNAL(released()), this, SLOT(addRow())); - connect(removechecked, SIGNAL(released()), this, SLOT(removeEmptyRows())); + connect(removechecked, SIGNAL(released()), this, SLOT(removeCheckedRows())); connect(close, SIGNAL(released()), this, SLOT(closeWindow())); connect(load, SIGNAL(released()), this, SLOT(loadDatabase())); connect(save, SIGNAL(released()), this, SLOT(saveDatabase())); connect(saveas, SIGNAL(released()), this, SLOT(saveDatabaseAs())); + connect(rowsfilterbutton, SIGNAL(released()), this, SLOT(filterRows())); + connect(rowsfilterclearbutton, SIGNAL(released()), this, SLOT(resetFilter())); setLayout(mainlayout); @@ -106,10 +136,12 @@ cBricksDatabaseWidget::cBricksDatabaseWidget(QWidget* parent) { #if OS_TYPE == WIN lastdir = "./BrickDatabases/"; #else - lastdir = linuxinstalldir + "BrickDatabases/"; + lastdir = installdir + "BrickDatabases/"; #endif bricks.clear(); + + setDataModified(false); } @@ -128,6 +160,14 @@ cBricksDatabaseWidget::~cBricksDatabaseWidget() { delete load; delete save; delete saveas; + + delete rowsfilterline; + delete rowsfiltercasesensitive; + delete rowsfilterbutton; + delete rowsfilterclearbutton; + delete rowsfilterhbox; + delete rowsfilterwidget; + delete database; delete buttons; delete mainlayout; @@ -230,20 +270,55 @@ bool cBricksDatabaseWidget::checkFormula(int row, const string& summary) { return false; } if (database->item(row, 4)) { - database->item(row, 4)->setData(Qt::DisplayRole, formula.getMass()); + database->item(row, 4)->setData(Qt::DisplayRole, to_string(formula.getMass()).c_str()); } return true; } +void cBricksDatabaseWidget::setDataModified(bool datamodified) { + if (datamodified == this->datamodified) { + return; + } + + this->datamodified = datamodified; + + if (datamodified) { + save->setText("*" + save->text()); + } + else { + if ((save->text().size() > 0) && (save->text().at(0) == '*')) { + save->setText(save->text().toStdString().substr(1).c_str()); + } + } +} + + void cBricksDatabaseWidget::keyPressEvent(QKeyEvent *event) { - if(event->key() == Qt::Key_Escape) { - hide(); + if (event->key() == Qt::Key_Escape) { + closeWindow(); + } + + if ((event->key() == Qt::Key_Enter) || (event->key() == Qt::Key_Return)) { + if (rowsfilterline->hasFocus()) { + filterRows(); + } } } void cBricksDatabaseWidget::closeWindow() { + if (datamodified) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, appname, "Save changes ?", QMessageBox::Yes|QMessageBox::No); + + if (reply == QMessageBox::Yes) { + if (!saveDatabase()) { + return; + } + } + } + hide(); } @@ -256,7 +331,7 @@ void cBricksDatabaseWidget::loadDatabase() { string errormessage; databasefile = filename; - save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); inputstream.open(filename.toStdString().c_str()); @@ -293,7 +368,7 @@ void cBricksDatabaseWidget::loadDatabase() { database->item(i, 3)->setText(bricks[i].getSummary().c_str()); database->setItem(i, 4, widgetitemallocator.getNewItem()); - database->item(i, 4)->setData(Qt::DisplayRole, bricks[i].getMass()); + database->item(i, 4)->setData(Qt::DisplayRole, to_string(bricks[i].getMass()).c_str()); database->setItem(i, 5, widgetitemallocator.getNewItem()); database->item(i, 5)->setText(bricks[i].getReferencesAsString().c_str()); @@ -315,6 +390,8 @@ void cBricksDatabaseWidget::loadDatabase() { progress.setValue(bricks.size()); + setDataModified(false); + } inputstream.close(); @@ -323,15 +400,15 @@ void cBricksDatabaseWidget::loadDatabase() { } -void cBricksDatabaseWidget::saveDatabase() { +bool cBricksDatabaseWidget::saveDatabase() { + bool saved = false; if (!checkTable()) { - return; + return saved; } if (databasefile.compare("") == 0) { - saveDatabaseAs(); - return; + return saveDatabaseAs(); } outputstream.open(databasefile.toStdString().c_str()); @@ -352,9 +429,15 @@ void cBricksDatabaseWidget::saveDatabase() { bricks.clear(); string s; - removeEmptyRows(); + removeCheckedRows(); for (int i = 0; i < database->rowCount(); i++) { + + if (database->isRowHidden(i)) { + progress.setValue(i); + continue; + } + b.clear(); for (int j = 0; j < database->columnCount(); j++) { switch (j) @@ -397,15 +480,20 @@ void cBricksDatabaseWidget::saveDatabase() { progress.setValue(progress.maximum()); + setDataModified(false); + + saved = true; + } outputstream.close(); -} + return saved; +} -void cBricksDatabaseWidget::saveDatabaseAs() { +bool cBricksDatabaseWidget::saveDatabaseAs() { if (!checkTable()) { - return; + return false; } QString filename = QFileDialog::getSaveFileName(this, tr("Save the Database of Building Blocks As..."), lastdir, tr("Database of Building Blocks (*.txt)")); @@ -414,9 +502,11 @@ void cBricksDatabaseWidget::saveDatabaseAs() { lastdir = filename; databasefile = filename; - save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); - saveDatabase(); + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + return saveDatabase(); } + + return false; } @@ -440,11 +530,12 @@ void cBricksDatabaseWidget::addRow() { } -void cBricksDatabaseWidget::removeEmptyRows() { +void cBricksDatabaseWidget::removeCheckedRows() { int i = 0; while (i < database->rowCount()) { if (((QCheckBox *)(database->cellWidget(i, 0)))->isChecked()) { removeRow(i); + setDataModified(true); } else { i++; @@ -466,10 +557,14 @@ void cBricksDatabaseWidget::itemChanged(QTableWidgetItem* item) { b.setReferences(database->item(item->row(), 5)->text().toStdString()); ((QLabel *)database->cellWidget(item->row(), 6))->setText(b.getAcronymsWithReferencesAsHTMLString().c_str()); } + + setDataModified(true); } void cBricksDatabaseWidget::headerItemDoubleClicked(int index) { + setDataModified(true); + if (headersort[index] == -1) { database->sortByColumn(index, Qt::AscendingOrder); headersort[index] = 1; @@ -486,3 +581,56 @@ void cBricksDatabaseWidget::headerItemDoubleClicked(int index) { } } + +void cBricksDatabaseWidget::filterRows() { + Qt::CaseSensitivity casesensitive = rowsfiltercasesensitive->isChecked()?Qt::CaseSensitive:Qt::CaseInsensitive; + QString str = rowsfilterline->text(); + int rowcount = database->rowCount(); + bool match; + int i, j; + + QProgressDialog progress("Updating...", /*"Cancel"*/0, 0, rowcount, this); + cEventFilter filter; + progress.installEventFilter(&filter); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + + for (i = 0; i < rowcount; i++) { + match = false; + for (j = 0; j < database->columnCount(); j++) { + // ignore non-text fields + if ((j == 0) || (j == 6)) { + continue; + } + + if (database->item(i, j)->text().contains(str, casesensitive)) { + match = true; + break; + } + } + database->setRowHidden(i, !match); + progress.setValue(i); + } + + progress.setValue(rowcount); +} + + +void cBricksDatabaseWidget::resetFilter() { + rowsfilterline->setText(""); + int rowcount = database->rowCount(); + + QProgressDialog progress("Updating...", /*"Cancel"*/0, 0, rowcount, this); + cEventFilter filter; + progress.installEventFilter(&filter); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + + for (int i = 0; i < rowcount; i++) { + database->setRowHidden(i, false); + progress.setValue(i); + } + + progress.setValue(rowcount); +} + diff --git a/CycloBranch/gui/cBricksDatabaseWidget.h b/CycloBranch/gui/cBricksDatabaseWidget.h index 673abe1..5b5b03b 100644 --- a/CycloBranch/gui/cBricksDatabaseWidget.h +++ b/CycloBranch/gui/cBricksDatabaseWidget.h @@ -22,6 +22,8 @@ class QVBoxLayout; class QTableWidget; class QTableWidgetItem; class QPushButton; +class QCheckBox; +class QLineEdit; /** @@ -64,6 +66,7 @@ class cBricksDatabaseWidget : public QWidget private: + QWidget* parent; QPushButton* insertrow; QPushButton* removechecked; @@ -71,6 +74,14 @@ class cBricksDatabaseWidget : public QWidget QPushButton* load; QPushButton* save; QPushButton* saveas; + + QWidget* rowsfilterwidget; + QHBoxLayout* rowsfilterhbox; + QLineEdit* rowsfilterline; + QCheckBox* rowsfiltercasesensitive; + QPushButton* rowsfilterbutton; + QPushButton* rowsfilterclearbutton; + QTableWidget* database; QHBoxLayout* buttons; QVBoxLayout* mainlayout; @@ -85,6 +96,8 @@ class cBricksDatabaseWidget : public QWidget cAllocator widgetitemallocator; + bool datamodified; + void deleteTable(bool enableprogress); void removeRow(int row); @@ -93,6 +106,7 @@ class cBricksDatabaseWidget : public QWidget bool checkFormula(int row, const string& summary); + void setDataModified(bool datamodified); protected: @@ -110,18 +124,22 @@ private slots: void loadDatabase(); - void saveDatabase(); + bool saveDatabase(); - void saveDatabaseAs(); + bool saveDatabaseAs(); void addRow(); - void removeEmptyRows(); + void removeCheckedRows(); void itemChanged(QTableWidgetItem* item); void headerItemDoubleClicked(int index); + void filterRows(); + + void resetFilter(); + }; #endif diff --git a/CycloBranch/gui/cCyclicWidget.cpp b/CycloBranch/gui/cCyclicWidget.cpp index 491397e..bffbf38 100644 --- a/CycloBranch/gui/cCyclicWidget.cpp +++ b/CycloBranch/gui/cCyclicWidget.cpp @@ -317,7 +317,6 @@ void cCyclicWidget::exportToPDF(QString filename, bool postscript) { QString errstr = "The file cannot be created."; #if OS_TYPE == UNX errstr += "\nDo you have a properly configured print server (sudo apt-get install cups-pdf) ?"; - errstr += "\nIf you cannot create a ps file, you can create a pdf file and then use pdf2ps tool."; #endif msgBox.setText(errstr); msgBox.exec(); @@ -365,6 +364,7 @@ void cCyclicWidget::exportToSVG(QString filename) { return; } + painter.fillRect(QRect(0, 0, width(), height()), Qt::white); paint(painter); painter.end(); } diff --git a/CycloBranch/gui/cDrawPeptideWidget.cpp b/CycloBranch/gui/cDrawPeptideWidget.cpp index 9744319..2c659de 100644 --- a/CycloBranch/gui/cDrawPeptideWidget.cpp +++ b/CycloBranch/gui/cDrawPeptideWidget.cpp @@ -239,7 +239,7 @@ void cDrawPeptideWidget::setSequence(int peptidetypeindex, QString sequence) { void cDrawPeptideWidget::keyPressEvent(QKeyEvent *event) { - if(event->key() == Qt::Key_Escape) { + if (event->key() == Qt::Key_Escape) { hide(); } } @@ -574,6 +574,9 @@ void cDrawPeptideWidget::sequenceChanged() { } if ((peptidetype == branched) || (peptidetype == lasso)) { + branchstart = theoreticalspectrum.getCandidate().getBranchStart(); + branchend = theoreticalspectrum.getCandidate().getBranchEnd(); + numberofblocksbackbone->setValue((int)v.size() - branchend + branchstart); numberofblocksbranch->setValue(branchend - branchstart); branchposition->setValue(branchstart + 1); @@ -644,7 +647,8 @@ void cDrawPeptideWidget::drawPeptide(vector& composition, cBricksDatabas if (lassorotations[i].getBranchEnd() == numberofbricks - 1) { vector v; v.push_back(lassorotations[i].getComposition()); - theoreticalspectrum.getCandidate().setCandidate(v, theoreticalspectrum.getCandidate().getPath(), theoreticalspectrum.getCandidate().getStartModifID(), theoreticalspectrum.getCandidate().getEndModifID(), theoreticalspectrum.getCandidate().getMiddleModifID(), lassorotations[i].getBranchStart(), lassorotations[i].getBranchEnd()); + vector cpath = theoreticalspectrum.getCandidate().getPath(); + theoreticalspectrum.getCandidate().setCandidate(v, cpath, theoreticalspectrum.getCandidate().getStartModifID(), theoreticalspectrum.getCandidate().getEndModifID(), theoreticalspectrum.getCandidate().getMiddleModifID(), lassorotations[i].getBranchStart(), lassorotations[i].getBranchEnd()); break; } } diff --git a/CycloBranch/gui/cExportDialog.cpp b/CycloBranch/gui/cExportDialog.cpp new file mode 100644 index 0000000..6eb0bd9 --- /dev/null +++ b/CycloBranch/gui/cExportDialog.cpp @@ -0,0 +1,52 @@ +#include "gui/cExportDialog.h" + +#include "gui/cSpectrumDetailWidget.h" + + +cExportDialog::cExportDialog(QWidget* parent) { + this->parent = parent; + + exportspectrum = new QRadioButton(); + exportspectrum->setChecked(true); + exportpeptide = new QRadioButton(); + exportbutton = new QPushButton("Export"); + connect(exportbutton, SIGNAL(released()), this, SLOT(processExport())); + + exportbox = new QHBoxLayout(); + exportbox->addWidget(exportspectrum); + exportbox->addWidget(exportbutton); + + formlayout = new QFormLayout(); + formlayout->addRow("Export spectrum: ", exportbox); + formlayout->addRow("Export peptide: ", exportpeptide); + + setLayout(formlayout); + setWindowTitle("Export Image"); + setMinimumSize(300, 50); +} + + +cExportDialog::~cExportDialog() { + delete exportspectrum; + delete exportbutton; + delete exportbox; + + delete exportpeptide; + + delete formlayout; +} + + +void cExportDialog::processExport() { + close(); + + QTextDocument::FindFlags flags = 0; + + if (exportspectrum->isChecked()) { + ((cSpectrumDetailWidget *)parent)->exportImage(true); + } + else if (exportpeptide->isChecked()) { + ((cSpectrumDetailWidget *)parent)->exportImage(false); + } +} + diff --git a/CycloBranch/gui/cExportDialog.h b/CycloBranch/gui/cExportDialog.h new file mode 100644 index 0000000..132cec4 --- /dev/null +++ b/CycloBranch/gui/cExportDialog.h @@ -0,0 +1,59 @@ +/** + \file cExportDialog.h + \brief The implementation of a dialog to export spectrum/peptide image. +*/ + + +#ifndef _CEXPORTDIALOG_H +#define _CEXPORTDIALOG_H + +#include +#include +#include +#include +#include +#include + + +/** + \brief The implementation of a dialog to export spectrum/peptide image. +*/ +class cExportDialog : public QDialog +{ + Q_OBJECT + +private: + + QWidget* parent; + + QHBoxLayout* exportbox; + + QFormLayout* formlayout; + QPushButton* exportbutton; + QRadioButton* exportspectrum; + QRadioButton* exportpeptide; + +public: + + + /** + \brief The constructor. + \param parent pointer to a parent widget + */ + cExportDialog(QWidget* parent = (QWidget *)0); + + + /** + \brief The destructor. + */ + ~cExportDialog(); + + +private slots: + + + void processExport(); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cFindDialog.cpp b/CycloBranch/gui/cFindDialog.cpp new file mode 100644 index 0000000..0b9cc42 --- /dev/null +++ b/CycloBranch/gui/cFindDialog.cpp @@ -0,0 +1,58 @@ +#include "gui/cFindDialog.h" + +#include "gui/cSpectrumDetailWidget.h" + + +cFindDialog::cFindDialog(QWidget* parent) { + this->parent = parent; + + searchline = new QLineEdit(); + searchbutton = new QPushButton("Find"); + connect(searchbutton, SIGNAL(released()), this, SLOT(findAll())); + + matchcase = new QCheckBox(); + matchwholeword = new QCheckBox(); + + searchbox = new QHBoxLayout(); + searchbox->addWidget(searchline); + searchbox->addWidget(searchbutton); + + formlayout = new QFormLayout(); + formlayout->addRow("Find what: ", searchbox); + formlayout->addRow("Match case: ", matchcase); + formlayout->addRow("Match whole word: ", matchwholeword); + + setLayout(formlayout); + setWindowTitle("Find Text"); + setMinimumSize(400, 50); +} + + +cFindDialog::~cFindDialog() { + delete searchline; + delete searchbutton; + delete searchbox; + + delete matchcase; + delete matchwholeword; + + delete formlayout; +} + + +void cFindDialog::findAll() { + close(); + + QTextDocument::FindFlags flags = 0; + + if (matchcase->isChecked()) { + flags |= QTextDocument::FindCaseSensitively; + } + + if (matchwholeword->isChecked()) { + flags |= QTextDocument::FindWholeWords; + } + + ((cSpectrumDetailWidget *)parent)->findAll(searchline->text(), flags); +} + diff --git a/CycloBranch/gui/cFindDialog.h b/CycloBranch/gui/cFindDialog.h new file mode 100644 index 0000000..6ec2407 --- /dev/null +++ b/CycloBranch/gui/cFindDialog.h @@ -0,0 +1,62 @@ +/** + \file cFindDialog.h + \brief The implementation of a find dialog. +*/ + + +#ifndef _CFINDDIALOG_H +#define _CFINDDIALOG_H + +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + \brief The implementation of a find dialog. +*/ +class cFindDialog : public QDialog +{ + Q_OBJECT + +private: + + QWidget* parent; + + QHBoxLayout* searchbox; + + QFormLayout* formlayout; + QLineEdit* searchline; + QPushButton* searchbutton; + QCheckBox* matchcase; + QCheckBox* matchwholeword; + +public: + + + /** + \brief The constructor. + \param parent pointer to a parent widget + */ + cFindDialog(QWidget* parent = (QWidget *)0); + + + /** + \brief The destructor. + */ + ~cFindDialog(); + + +private slots: + + + void findAll(); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cGraphWidget.cpp b/CycloBranch/gui/cGraphWidget.cpp index dde3d75..201f2fc 100644 --- a/CycloBranch/gui/cGraphWidget.cpp +++ b/CycloBranch/gui/cGraphWidget.cpp @@ -64,7 +64,7 @@ void cGraphWidget::load(ifstream& is) { void cGraphWidget::keyPressEvent(QKeyEvent *event) { - if(event->key() == Qt::Key_Escape) { + if (event->key() == Qt::Key_Escape) { hide(); } } diff --git a/CycloBranch/gui/cLassoWidget.cpp b/CycloBranch/gui/cLassoWidget.cpp index 3806b29..c742d1e 100644 --- a/CycloBranch/gui/cLassoWidget.cpp +++ b/CycloBranch/gui/cLassoWidget.cpp @@ -86,7 +86,6 @@ void cLassoWidget::exportToPDF(QString filename, bool postscript) { QString errstr = "The file cannot be created."; #if OS_TYPE == UNX errstr += "\nDo you have a properly configured print server (sudo apt-get install cups-pdf) ?"; - errstr += "\nIf you cannot create a ps file, you can create a pdf file and then use pdf2ps tool."; #endif msgBox.setText(errstr); msgBox.exec(); @@ -134,6 +133,7 @@ void cLassoWidget::exportToSVG(QString filename) { return; } + painter.fillRect(QRect(0, 0, width(), height()), Qt::white); paint(painter); painter.end(); } diff --git a/CycloBranch/gui/cLinearWidget.cpp b/CycloBranch/gui/cLinearWidget.cpp index cdda0a9..b1d7c30 100644 --- a/CycloBranch/gui/cLinearWidget.cpp +++ b/CycloBranch/gui/cLinearWidget.cpp @@ -62,7 +62,6 @@ void cLinearWidget::exportToPDF(QString filename, bool postscript) { QString errstr = "The file cannot be created."; #if OS_TYPE == UNX errstr += "\nDo you have a properly configured print server (sudo apt-get install cups-pdf) ?"; - errstr += "\nIf you cannot create a ps file, you can create a pdf file and then use pdf2ps tool."; #endif msgBox.setText(errstr); msgBox.exec(); @@ -110,6 +109,7 @@ void cLinearWidget::exportToSVG(QString filename) { return; } + painter.fillRect(QRect(0, 0, width(), height()), Qt::white); paint(painter); painter.end(); } diff --git a/CycloBranch/gui/cMainThread.cpp b/CycloBranch/gui/cMainThread.cpp index d5da33b..3204a2b 100644 --- a/CycloBranch/gui/cMainThread.cpp +++ b/CycloBranch/gui/cMainThread.cpp @@ -357,7 +357,7 @@ void cMainThread::run() { // set candidate and check precursor mass error c.setCandidate(v, netmp, startmodifid, endmodifid, middlemodifid, branchstart, branchend); - if (!calculatesummaries && !isInPpmMassErrorTolerance(charge(uncharge(parameters.precursormass, parameters.precursorcharge), (parameters.precursorcharge > 0)?1:-1), c.getPrecursorMass(parameters.bricksdatabase, ¶meters), parameters.precursormasserrortolerance)) { + if (!calculatesummaries && !parameters.similaritysearch && !isInPpmMassErrorTolerance(charge(uncharge(parameters.precursormass, parameters.precursorcharge), (parameters.precursorcharge > 0)?1:-1), c.getPrecursorMass(parameters.bricksdatabase, ¶meters), parameters.precursormasserrortolerance)) { continue; } @@ -365,7 +365,7 @@ void cMainThread::run() { candidates.getSet().insert(c); if (calculatesummaries) { - *os << c.getSummaryFormula(parameters, parameters.sequencedatabase[i].getPeptideType()) << endl; + *os << c.getSummaryFormula(parameters, parameters.sequencedatabase[i].getPeptideType()).getSummary() << endl; } } @@ -375,7 +375,7 @@ void cMainThread::run() { return; } - *os << "Number of candidates in the precursor mass error tolerance found: " << candidates.size() << endl; + *os << "Number of candidates found: " << candidates.size() << endl; graphreaderisworking = false; diff --git a/CycloBranch/gui/cMainWindow.cpp b/CycloBranch/gui/cMainWindow.cpp index c8bd9e3..217ddcf 100644 --- a/CycloBranch/gui/cMainWindow.cpp +++ b/CycloBranch/gui/cMainWindow.cpp @@ -77,11 +77,17 @@ cMainWindow::cMainWindow() { actionDrawPeptide->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P)); + actionShowIsomers = new QAction(QIcon(":/images/icons/95.png"), tr("Show &Isomers"), this); + actionShowIsomers->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_I)); + actionShowIsomers->setCheckable(true); + actionGraph = new QAction(QIcon(":/images/icons/32.png"), tr("De Novo &Graph"), this); actionGraph->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_G)); actionLog = new QAction(QIcon(":/images/icons/2.png"), tr("&Log Window"), this); actionLog->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L)); + actionLog->setCheckable(true); + actionLog->setChecked(true); actionHTMLDocumentation = new QAction(QIcon(":/images/icons/3.png"), tr("&HTML Documentation"), this); @@ -113,6 +119,7 @@ cMainWindow::cMainWindow() { toolbarTools->addAction(actionDrawPeptide); toolbarView = addToolBar(tr("View")); + toolbarView->addAction(actionShowIsomers); toolbarView->addAction(actionGraph); toolbarView->addAction(actionLog); @@ -121,6 +128,34 @@ cMainWindow::cMainWindow() { toolbarHelp->addAction(actionPDFManual); toolbarHelp->addAction(actionAbout); + rowsfilterline = new QLineEdit(); + rowsfilterline->setMinimumWidth(250); + rowsfilterline->setToolTip("Text to Find"); + rowsfiltercasesensitive = new QCheckBox(); + rowsfiltercasesensitive->setToolTip("Case Sensitive"); + rowsfilterbutton = new QPushButton("Filter"); + rowsfilterbutton->setToolTip("Filter Search Results"); + rowsfilterbutton->setMinimumWidth(50); + rowsfilterclearbutton = new QPushButton("Clear"); + rowsfilterclearbutton->setToolTip("Clear Form and Reset Search Results"); + rowsfilterclearbutton->setMinimumWidth(50); + + rowsfilterhbox = new QHBoxLayout(); + rowsfilterhbox->addWidget(rowsfilterline); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfiltercasesensitive); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfilterbutton); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfilterclearbutton); + + rowsfilterwidget = new QWidget(); + rowsfilterwidget->setLayout(rowsfilterhbox); + rowsfilterwidget->setMaximumWidth(420); + + toolbarFilter = addToolBar(tr("Filter")); + toolbarFilter->addWidget(rowsfilterwidget); + // widgets results = new QTableWidget(0, 0, this); @@ -153,12 +188,16 @@ cMainWindow::cMainWindow() { connect(actionSequenceDatabase, SIGNAL(triggered()), this, SLOT(showSequenceDatabase())); connect(actionModifications, SIGNAL(triggered()), this, SLOT(showModifications())); connect(actionDrawPeptide, SIGNAL(triggered()), this, SLOT(showDrawPeptideWidget())); + connect(actionShowIsomers, SIGNAL(triggered()), this, SLOT(updateSpectra())); connect(actionGraph, SIGNAL(triggered()), this, SLOT(showGraph())); connect(actionLog, SIGNAL(triggered()), this, SLOT(showHideLog())); connect(actionHTMLDocumentation, SIGNAL(triggered()), this, SLOT(showHTMLDocumentation())); connect(actionPDFManual, SIGNAL(triggered()), this, SLOT(showPDFManual())); connect(actionAbout, SIGNAL(triggered()), this, SLOT(showAbout())); + connect(rowsfilterbutton, SIGNAL(released()), this, SLOT(filterResults())); + connect(rowsfilterclearbutton, SIGNAL(released()), this, SLOT(resetFilter())); + // add subitems to the items in main menu // menuFile->addAction(actionOpen); menuFile->addAction(actionOpenResults); @@ -177,8 +216,9 @@ cMainWindow::cMainWindow() { menuTools->addAction(actionModifications); menuTools->addSeparator(); menuTools->addAction(actionDrawPeptide); - menuView->addAction(actionGraph); + menuView->addAction(actionShowIsomers); menuView->addSeparator(); + menuView->addAction(actionGraph); menuView->addAction(actionLog); menuHelp->addAction(actionHTMLDocumentation); menuHelp->addAction(actionPDFManual); @@ -222,7 +262,7 @@ cMainWindow::cMainWindow() { // set the size of main window resize(1280, 700); - resultsbasecolumncount = 8; + resultsbasecolumncount = 9; resultsspecificcolumncount = 0; dbsearchspecificcolumncount = 0; @@ -238,13 +278,108 @@ cMainWindow::cMainWindow() { } +cMainWindow::~cMainWindow() { + deleteResults(); + + delete rowsfilterline; + delete rowsfiltercasesensitive; + delete rowsfilterbutton; + delete rowsfilterclearbutton; + delete rowsfilterhbox; + delete rowsfilterwidget; + + delete results; + delete logWindow; + delete splitter; + + delete about; + delete graph; + delete bricksdatabasewidget; + delete sequencedatabasewidget; + delete modificationswidget; + delete drawpeptidewidget; + delete parameterswidget; + + delete actionOpenResults; + delete actionSaveResults; + delete actionExportToCsv; + delete actionExportToHTML; + delete actionQuit; + delete actionProperties; + delete actionRun; + delete actionBricksDatabase; + delete actionSequenceDatabase; + delete actionModifications; + delete actionDrawPeptide; + delete actionShowIsomers; + delete actionGraph; + delete actionLog; + delete actionHTMLDocumentation; + delete actionPDFManual; + delete actionAbout; + + delete menuFile; + delete menuSearch; + delete menuTools; + delete menuView; + delete menuHelp; + + delete menuBar; +} + + +void cMainWindow::keyPressEvent(QKeyEvent *event) { + if ((event->key() == Qt::Key_Enter) || (event->key() == Qt::Key_Return)) { + if (rowsfilterline->hasFocus()) { + filterResults(); + } + else { + if ((results->currentRow() >= 0) && !results->isRowHidden(results->currentRow())) { + resultsCellClicked(results->currentRow(), 0); + } + } + } +} + + void cMainWindow::closeEvent(QCloseEvent *event) { quitApplication(); event->ignore(); } -void cMainWindow::reportSpectrum(int id, cTheoreticalSpectrum& theoreticalspectrum) { +void cMainWindow::preparePeptideSequence(int row, string& peptidesequence, bool reportisomers) { + int spectrumindex = results->item(row, 1)->data(Qt::DisplayRole).toInt() - 1; + string tmpsequence; + bool copy; + + if (!reportisomers) { + tmpsequence = stripHTML(theoreticalspectrumlist[spectrumindex].getCandidate().getAcronymPeptideNameWithHTMLReferences()); + peptidesequence = ""; + copy = true; + for (int j = 0; j < (int)tmpsequence.size(); j++) { + if (tmpsequence[j] == '/') { + copy = false; + } + if (tmpsequence[j] == ']') { + copy = true; + } + if (copy) { + peptidesequence += tmpsequence[j]; + } + } + } + else { + peptidesequence = stripHTML(theoreticalspectrumlist[spectrumindex].getCandidate().getAcronymPeptideNameWithHTMLReferences()); + } + +} + + +void cMainWindow::reportSpectrum(int id, cTheoreticalSpectrum& theoreticalspectrum, bool reportisomers) { + string peptidesequence; + cSummaryFormula formula; + int row = results->rowCount(); results->insertRow(row); @@ -261,57 +396,63 @@ void cMainWindow::reportSpectrum(int id, cTheoreticalSpectrum& theoreticalspectr } results->setItem(row, 2 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 2 + dbsearchspecificcolumncount)->setText(stripHTML(theoreticalspectrum.getCandidate().getAcronymPeptideNameWithHTMLReferences()).c_str()); + preparePeptideSequence(row, peptidesequence, reportisomers); + results->item(row, 2 + dbsearchspecificcolumncount)->setText(peptidesequence.c_str()); + + formula = theoreticalspectrum.getCandidate().getSummaryFormula(parameters, parameters.peptidetype); results->setItem(row, 3 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 3 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getCandidate().getSummaryFormula(parameters, parameters.peptidetype).c_str()); + results->item(row, 3 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, formula.isPartial()?string(formula.getSummary() + " (partial)").c_str():formula.getSummary().c_str()); results->setItem(row, 4 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 4 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, getNumberOfBricks(theoreticalspectrum.getCandidate().getComposition())); + results->item(row, 4 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, to_string(formula.getMass()).c_str()); + + results->setItem(row, 5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->item(row, 5 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, getNumberOfBricks(theoreticalspectrum.getCandidate().getComposition())); switch (parameters.peptidetype) { case linear: - results->setItem(row, 5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 5 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str()); results->setItem(row, 6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 6 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str()); + results->item(row, 6 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str()); + results->setItem(row, 7 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->item(row, 7 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str()); break; case branched: - results->setItem(row, 5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 5 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str()); results->setItem(row, 6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 6 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str()); + results->item(row, 6 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str()); results->setItem(row, 7 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 7 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str()); + results->item(row, 7 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str()); + results->setItem(row, 8 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->item(row, 8 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str()); break; case cyclic: - results->setItem(row, 5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 5 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedBricks()); + results->setItem(row, 6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->item(row, 6 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedBricks()); break; case lasso: - results->setItem(row, 5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 5 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str()); + results->setItem(row, 6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->item(row, 6 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str()); break; case linearpolysaccharide: - results->setItem(row, 5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 5 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str()); results->setItem(row, 6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 6 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str()); + results->item(row, 6 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str()); + results->setItem(row, 7 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->item(row, 7 + dbsearchspecificcolumncount)->setText(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str()); break; case other: default: break; } - results->setItem(row, 5 + dbsearchspecificcolumncount + resultsspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 5 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedPeaks()); - results->setItem(row, 6 + dbsearchspecificcolumncount + resultsspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 6 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getRatioOfMatchedPeaks()*100); + results->item(row, 6 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedPeaks()); results->setItem(row, 7 + dbsearchspecificcolumncount + resultsspecificcolumncount, widgetitemallocator.getNewItem()); - results->item(row, 7 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getWeightedIntensityScore()); + results->item(row, 7 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setData(Qt::DisplayRole, to_string(theoreticalspectrum.getRatioOfMatchedPeaks()*100).c_str()); + + results->setItem(row, 8 + dbsearchspecificcolumncount + resultsspecificcolumncount, widgetitemallocator.getNewItem()); + results->item(row, 8 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setData(Qt::DisplayRole, to_string(theoreticalspectrum.getWeightedIntensityScore()).c_str()); for (int i = 0; i < (int)parameters.fragmentionsfortheoreticalspectra.size(); i++) { results->setItem(row, resultsbasecolumncount + dbsearchspecificcolumncount + resultsspecificcolumncount + i, widgetitemallocator.getNewItem()); @@ -338,10 +479,10 @@ void cMainWindow::reportSpectrum(int id, cTheoreticalSpectrum& theoreticalspectr results->item(row, 2)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedPeaks()); results->setItem(row, 3, widgetitemallocator.getNewItem()); - results->item(row, 3)->setData(Qt::DisplayRole, theoreticalspectrum.getRatioOfMatchedPeaks()*100); + results->item(row, 3)->setData(Qt::DisplayRole, to_string(theoreticalspectrum.getRatioOfMatchedPeaks()*100).c_str()); results->setItem(row, 4, widgetitemallocator.getNewItem()); - results->item(row, 4)->setData(Qt::DisplayRole, theoreticalspectrum.getWeightedIntensityScore()); + results->item(row, 4)->setData(Qt::DisplayRole, to_string(theoreticalspectrum.getWeightedIntensityScore()).c_str()); } @@ -474,6 +615,15 @@ void cMainWindow::enableButtonsHandlingResults(bool enable) { actionSaveResults->setEnabled(enable); actionExportToCsv->setEnabled(enable); actionExportToHTML->setEnabled(enable); + + if (parameters.mode == dereplication) { + actionShowIsomers->setEnabled(false); + rowsfilterwidget->setEnabled(false); + } + else { + actionShowIsomers->setEnabled(enable); + rowsfilterwidget->setEnabled(enable); + } } @@ -537,56 +687,62 @@ void cMainWindow::reportSpectra() { results->setHorizontalHeaderItem(2, widgetitemallocator.getNewItem()); results->horizontalHeaderItem(2)->setText("Name"); } + results->setHorizontalHeaderItem(2 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); results->horizontalHeaderItem(2 + dbsearchspecificcolumncount)->setText("Peptide Sequence"); + results->setHorizontalHeaderItem(3 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); results->horizontalHeaderItem(3 + dbsearchspecificcolumncount)->setText("Summary Formula"); + results->setHorizontalHeaderItem(4 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(4 + dbsearchspecificcolumncount)->setText("Number of Bricks"); + results->horizontalHeaderItem(4 + dbsearchspecificcolumncount)->setText("Monoisotopic Mass"); + + results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->horizontalHeaderItem(5 + dbsearchspecificcolumncount)->setText("Number of Bricks"); switch (parameters.peptidetype) { case linear: - results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(5 + dbsearchspecificcolumncount)->setText("N-terminal Modification"); results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(6 + dbsearchspecificcolumncount)->setText("C-terminal Modification"); + results->horizontalHeaderItem(6 + dbsearchspecificcolumncount)->setText("N-terminal Modification"); + results->setHorizontalHeaderItem(7 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->horizontalHeaderItem(7 + dbsearchspecificcolumncount)->setText("C-terminal Modification"); break; case branched: - results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(5 + dbsearchspecificcolumncount)->setText("N-terminal Modification"); results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(6 + dbsearchspecificcolumncount)->setText("Branch Modification"); + results->horizontalHeaderItem(6 + dbsearchspecificcolumncount)->setText("N-terminal Modification"); results->setHorizontalHeaderItem(7 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(7 + dbsearchspecificcolumncount)->setText("C-terminal Modification"); + results->horizontalHeaderItem(7 + dbsearchspecificcolumncount)->setText("Branch Modification"); + results->setHorizontalHeaderItem(8 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->horizontalHeaderItem(8 + dbsearchspecificcolumncount)->setText("C-terminal Modification"); break; case cyclic: - results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(5 + dbsearchspecificcolumncount)->setText("Matched Bricks"); + results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->horizontalHeaderItem(6 + dbsearchspecificcolumncount)->setText("Matched Bricks"); break; case lasso: - results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(5 + dbsearchspecificcolumncount)->setText("Branch Modification"); + results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->horizontalHeaderItem(6 + dbsearchspecificcolumncount)->setText("Branch Modification"); break; case linearpolysaccharide: - results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(5 + dbsearchspecificcolumncount)->setText("N-terminal Modification"); results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(6 + dbsearchspecificcolumncount)->setText("C-terminal Modification"); + results->horizontalHeaderItem(6 + dbsearchspecificcolumncount)->setText("N-terminal Modification"); + results->setHorizontalHeaderItem(7 + dbsearchspecificcolumncount, widgetitemallocator.getNewItem()); + results->horizontalHeaderItem(7 + dbsearchspecificcolumncount)->setText("C-terminal Modification"); break; case other: default: break; } - results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount + resultsspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(5 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setText("Matched Peaks"); - results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount + resultsspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(6 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setText("Ratio of Matched Peaks [%]"); - + results->horizontalHeaderItem(6 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setText("Matched Peaks"); + results->setHorizontalHeaderItem(7 + dbsearchspecificcolumncount + resultsspecificcolumncount, widgetitemallocator.getNewItem()); - results->horizontalHeaderItem(7 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setText("Sum of Relative Intensities"); + results->horizontalHeaderItem(7 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setText("Ratio of Matched Peaks [%]"); + + results->setHorizontalHeaderItem(8 + dbsearchspecificcolumncount + resultsspecificcolumncount, widgetitemallocator.getNewItem()); + results->horizontalHeaderItem(8 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setText("Sum of Relative Intensities"); for (int i = 0; i < (int)parameters.fragmentionsfortheoreticalspectra.size(); i++) { results->setHorizontalHeaderItem(resultsbasecolumncount + dbsearchspecificcolumncount + resultsspecificcolumncount + i, widgetitemallocator.getNewItem()); @@ -623,7 +779,6 @@ void cMainWindow::reportSpectra() { resultsheadersort[i] = -1; } - QProgressDialog progress("Preparing the report...", /*"Cancel"*/0, 0, theoreticalspectrumlist.size(), this); cEventFilter filter; progress.installEventFilter(&filter); @@ -632,8 +787,9 @@ void cMainWindow::reportSpectra() { spectradetails.clear(); spectradetails.resize(theoreticalspectrumlist.size()); + bool reportisomers = actionShowIsomers->isChecked(); for (int i = 0; i < theoreticalspectrumlist.size(); i++) { - reportSpectrum(i, theoreticalspectrumlist[i]); + reportSpectrum(i, theoreticalspectrumlist[i], reportisomers); progress.setValue(i); //if (progress.wasCanceled()) { // break; @@ -649,6 +805,40 @@ void cMainWindow::reportSpectra() { } +void cMainWindow::updateSpectra() { + + if ((parameters.mode == denovoengine) || (parameters.mode == singlecomparison) || (parameters.mode == databasesearch)) { + + bool reportisomers = actionShowIsomers->isChecked(); + string peptidesequence; + + QProgressDialog progress("Updating the report...", /*"Cancel"*/0, 0, theoreticalspectrumlist.size(), this); + cEventFilter filter; + progress.installEventFilter(&filter); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + + for (int i = 0; i < results->rowCount(); i++) { + preparePeptideSequence(i, peptidesequence, reportisomers); + results->item(i, 2 + dbsearchspecificcolumncount)->setText(peptidesequence.c_str()); + + progress.setValue(i); + //if (progress.wasCanceled()) { + // break; + //} + } + + for (int i = 0; i < results->columnCount(); i++) { + results->resizeColumnToContents(i); + } + + progress.setValue(theoreticalspectrumlist.size()); + + } + +} + + void cMainWindow::deleteResults() { widgetitemallocator.reset(); results->setColumnCount(0); @@ -714,6 +904,11 @@ void cMainWindow::exportToCsv() { out << endl; for (int i = 0; i < results->rowCount(); i++) { + + if (results->isRowHidden(i)) { + continue; + } + for (int j = 0; j < results->columnCount(); j++) { out << "\"" << results->item(i, j)->data(Qt::DisplayRole).toString() << "\""; if (j < results->columnCount() - 1) { @@ -785,7 +980,15 @@ void cMainWindow::exportToHTML() { } out << "\n"; + int spectrumindex; for (int i = 0; i < results->rowCount(); i++) { + + if (results->isRowHidden(i)) { + continue; + } + + spectrumindex = results->item(i, 1)->data(Qt::DisplayRole).toInt() - 1; + out << "\n"; @@ -811,8 +1014,8 @@ void cMainWindow::exportToHTML() { out << results->columnCount(); out << "\">\n"; - out << "

" << spectradetails[i].getTheoreticalSpectrum().getCoverageBySeries().c_str(); - out << "
" << spectradetails[i].getDetailsAsHTMLString().c_str() << "

\n"; + out << "

" << spectradetails[spectrumindex].getTheoreticalSpectrum().getCoverageBySeries().c_str(); + out << "
" << spectradetails[spectrumindex].getDetailsAsHTMLString().c_str() << "

\n"; out << "\n"; @@ -853,7 +1056,7 @@ void cMainWindow::showHTMLDocumentation() { #if OS_TYPE == WIN QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo("docs/html/userguide.html").absoluteFilePath())); #else - QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(linuxinstalldir + "docs/html/userguide.html").absoluteFilePath())); + QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(installdir + "docs/html/userguide.html").absoluteFilePath())); #endif } @@ -862,7 +1065,7 @@ void cMainWindow::showPDFManual() { #if OS_TYPE == WIN QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo("docs/refman.pdf").absoluteFilePath())); #else - QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(linuxinstalldir + "docs/refman.pdf").absoluteFilePath())); + QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(installdir + "docs/refman.pdf").absoluteFilePath())); #endif } @@ -989,6 +1192,15 @@ void cMainWindow::openResultsFile() { parameters.load(infile); parameterswidget->setAndRestoreParameters(parameters); + if (parameters.mode == dereplication) { + actionShowIsomers->setEnabled(false); + rowsfilterwidget->setEnabled(false); + } + else { + actionShowIsomers->setEnabled(true); + rowsfilterwidget->setEnabled(true); + } + // load theoretical spectra infile.read((char *)&size, sizeof(int)); @@ -1039,6 +1251,13 @@ void cMainWindow::insertSequence(int peptidetypeindex, QString sequence) { void cMainWindow::quitApplication() { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, appname, "Quit ?", QMessageBox::Yes|QMessageBox::No); + + if (reply != QMessageBox::Yes) { + return; + } + emit stopComputation(); quitapp = true; @@ -1048,6 +1267,54 @@ void cMainWindow::quitApplication() { } +void cMainWindow::filterResults() { + Qt::CaseSensitivity casesensitive = rowsfiltercasesensitive->isChecked()?Qt::CaseSensitive:Qt::CaseInsensitive; + QString str = rowsfilterline->text(); + int rowcount = results->rowCount(); + bool match; + int i, j; + + QProgressDialog progress("Updating the report...", /*"Cancel"*/0, 0, rowcount, this); + cEventFilter filter; + progress.installEventFilter(&filter); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + + for (i = 0; i < rowcount; i++) { + match = false; + for (j = 0; j < results->columnCount(); j++) { + if (results->item(i, j)->text().contains(str, casesensitive)) { + match = true; + break; + } + } + results->setRowHidden(i, !match); + progress.setValue(i); + } + + progress.setValue(rowcount); +} + + +void cMainWindow::resetFilter() { + rowsfilterline->setText(""); + int rowcount = results->rowCount(); + + QProgressDialog progress("Updating the report...", /*"Cancel"*/0, 0, rowcount, this); + cEventFilter filter; + progress.installEventFilter(&filter); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + + for (int i = 0; i < rowcount; i++) { + results->setRowHidden(i, false); + progress.setValue(i); + } + + progress.setValue(rowcount); +} + + /* void cMainWindow::showContextMenu(const QPoint &pt) { QMenu *menu = logWindow->createStandardContextMenu(); @@ -1057,45 +1324,3 @@ void cMainWindow::showContextMenu(const QPoint &pt) { } */ - -cMainWindow::~cMainWindow() { - deleteResults(); - - delete menuBar; - - delete menuFile; - delete menuSearch; - delete menuTools; - delete menuView; - delete menuHelp; - - delete actionOpenResults; - delete actionSaveResults; - delete actionExportToCsv; - delete actionExportToHTML; - delete actionQuit; - delete actionProperties; - delete actionRun; - delete actionBricksDatabase; - delete actionSequenceDatabase; - delete actionModifications; - delete actionDrawPeptide; - delete actionGraph; - delete actionLog; - delete actionHTMLDocumentation; - delete actionPDFManual; - delete actionAbout; - - delete results; - delete logWindow; - delete splitter; - - delete about; - delete graph; - delete bricksdatabasewidget; - delete sequencedatabasewidget; - delete modificationswidget; - delete drawpeptidewidget; - delete parameterswidget; -} - diff --git a/CycloBranch/gui/cMainWindow.h b/CycloBranch/gui/cMainWindow.h index d95dcd3..259d309 100644 --- a/CycloBranch/gui/cMainWindow.h +++ b/CycloBranch/gui/cMainWindow.h @@ -53,6 +53,15 @@ class cMainWindow : public QMainWindow ~cMainWindow(); +protected: + + /** + \brief Handle a key press event. + \param event pointer to QKeyEvent + */ + void keyPressEvent(QKeyEvent *event); + + private: // main menu @@ -71,6 +80,7 @@ class cMainWindow : public QMainWindow QToolBar* toolbarTools; QToolBar* toolbarView; QToolBar* toolbarHelp; + QToolBar* toolbarFilter; // subitems in the menu QAction* actionOpenResults; @@ -85,12 +95,20 @@ class cMainWindow : public QMainWindow QAction* actionSequenceDatabase; QAction* actionModifications; QAction *actionDrawPeptide; + QAction* actionShowIsomers; QAction* actionGraph; QAction* actionLog; QAction* actionHTMLDocumentation; QAction* actionPDFManual; QAction* actionAbout; + QWidget* rowsfilterwidget; + QHBoxLayout* rowsfilterhbox; + QLineEdit* rowsfilterline; + QCheckBox* rowsfiltercasesensitive; + QPushButton* rowsfilterbutton; + QPushButton* rowsfilterclearbutton; + QTableWidget* results; cTheoreticalSpectrumList theoreticalspectrumlist; vector spectradetails; @@ -125,7 +143,9 @@ class cMainWindow : public QMainWindow void closeEvent(QCloseEvent *event); - void reportSpectrum(int id, cTheoreticalSpectrum& theoreticalspectrum); + void preparePeptideSequence(int row, string& peptidesequence, bool reportisomers); + + void reportSpectrum(int id, cTheoreticalSpectrum& theoreticalspectrum, bool reportisomers); void deleteResults(); @@ -166,6 +186,8 @@ private slots: void reportSpectra(); + void updateSpectra(); + void resultsCellClicked(int row, int column); void setGraph(string s); @@ -192,6 +214,10 @@ private slots: void quitApplication(); + void filterResults(); + + void resetFilter(); + //void showContextMenu(const QPoint &pt); signals: diff --git a/CycloBranch/gui/cModificationsWidget.cpp b/CycloBranch/gui/cModificationsWidget.cpp index cc175be..2b3b1f2 100644 --- a/CycloBranch/gui/cModificationsWidget.cpp +++ b/CycloBranch/gui/cModificationsWidget.cpp @@ -14,6 +14,7 @@ #include #include #include +#include cModificationsWidget::cModificationsWidget(QWidget* parent) { @@ -31,17 +32,44 @@ cModificationsWidget::cModificationsWidget(QWidget* parent) { close->setToolTip("Close the window."); load = new QPushButton(tr("Load")); load->setToolTip("Load modifications."); - save = new QPushButton(QString("Save")); + save = new QPushButton(QString(" Save ")); save->setToolTip("Save modifications in the current file. When a file has not been loaded yet, the \"Save As ...\" file dialog is opened."); saveas = new QPushButton(tr("Save As...")); saveas->setToolTip("Save modifications into a file."); + rowsfilterline = new QLineEdit(); + rowsfilterline->setMinimumWidth(250); + rowsfilterline->setToolTip("Text to Find"); + rowsfiltercasesensitive = new QCheckBox(); + rowsfiltercasesensitive->setToolTip("Case Sensitive"); + rowsfilterbutton = new QPushButton("Filter"); + rowsfilterbutton->setToolTip("Filter Search Results"); + rowsfilterbutton->setMinimumWidth(50); + rowsfilterclearbutton = new QPushButton("Clear"); + rowsfilterclearbutton->setToolTip("Clear Form and Reset Search Results"); + rowsfilterclearbutton->setMinimumWidth(50); + + rowsfilterhbox = new QHBoxLayout(); + rowsfilterhbox->addWidget(rowsfilterline); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfiltercasesensitive); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfilterbutton); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfilterclearbutton); + + rowsfilterwidget = new QWidget(); + rowsfilterwidget->setLayout(rowsfilterhbox); + rowsfilterwidget->setMaximumWidth(420); + buttons = new QHBoxLayout(); buttons->addWidget(close); - buttons->addStretch(1); + buttons->addStretch(); buttons->addWidget(insertrow); buttons->addWidget(removechecked); - buttons->addStretch(10); + buttons->addStretch(); + buttons->addWidget(rowsfilterwidget); + buttons->addStretch(); buttons->addWidget(load); buttons->addWidget(save); buttons->addWidget(saveas); @@ -71,11 +99,13 @@ cModificationsWidget::cModificationsWidget(QWidget* parent) { connect(database->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(headerItemDoubleClicked(int))); connect(database, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(itemChanged(QTableWidgetItem *))); connect(insertrow, SIGNAL(released()), this, SLOT(addRow())); - connect(removechecked, SIGNAL(released()), this, SLOT(removeEmptyRows())); + connect(removechecked, SIGNAL(released()), this, SLOT(removeCheckedRows())); connect(close, SIGNAL(released()), this, SLOT(closeWindow())); connect(load, SIGNAL(released()), this, SLOT(loadDatabase())); connect(save, SIGNAL(released()), this, SLOT(saveDatabase())); connect(saveas, SIGNAL(released()), this, SLOT(saveDatabaseAs())); + connect(rowsfilterbutton, SIGNAL(released()), this, SLOT(filterRows())); + connect(rowsfilterclearbutton, SIGNAL(released()), this, SLOT(resetFilter())); setLayout(mainlayout); @@ -86,10 +116,12 @@ cModificationsWidget::cModificationsWidget(QWidget* parent) { #if OS_TYPE == WIN lastdir = "./Modifications/"; #else - lastdir = linuxinstalldir + "Modifications/"; + lastdir = installdir + "Modifications/"; #endif modifications.clear(); + + setDataModified(false); } @@ -108,6 +140,14 @@ cModificationsWidget::~cModificationsWidget() { delete load; delete save; delete saveas; + + delete rowsfilterline; + delete rowsfiltercasesensitive; + delete rowsfilterbutton; + delete rowsfilterclearbutton; + delete rowsfilterhbox; + delete rowsfilterwidget; + delete database; delete buttons; delete mainlayout; @@ -195,20 +235,55 @@ bool cModificationsWidget::checkFormula(int row, const string& summary) { return false; } if (database->item(row, 3)) { - database->item(row, 3)->setData(Qt::DisplayRole, formula.getMass()); + database->item(row, 3)->setData(Qt::DisplayRole, to_string(formula.getMass()).c_str()); } return true; } +void cModificationsWidget::setDataModified(bool datamodified) { + if (datamodified == this->datamodified) { + return; + } + + this->datamodified = datamodified; + + if (datamodified) { + save->setText("*" + save->text()); + } + else { + if ((save->text().size() > 0) && (save->text().at(0) == '*')) { + save->setText(save->text().toStdString().substr(1).c_str()); + } + } +} + + void cModificationsWidget::keyPressEvent(QKeyEvent *event) { - if(event->key() == Qt::Key_Escape) { - hide(); + if (event->key() == Qt::Key_Escape) { + closeWindow(); + } + + if ((event->key() == Qt::Key_Enter) || (event->key() == Qt::Key_Return)) { + if (rowsfilterline->hasFocus()) { + filterRows(); + } } } void cModificationsWidget::closeWindow() { + if (datamodified) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, appname, "Save changes ?", QMessageBox::Yes|QMessageBox::No); + + if (reply == QMessageBox::Yes) { + if (!saveDatabase()) { + return; + } + } + } + hide(); } @@ -221,7 +296,7 @@ void cModificationsWidget::loadDatabase() { string errormessage; databasefile = filename; - save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); inputstream.open(filename.toStdString().c_str()); @@ -255,15 +330,17 @@ void cModificationsWidget::loadDatabase() { database->item(i, 2)->setText(modifications[i].summary.c_str()); database->setItem(i, 3, widgetitemallocator.getNewItem()); - database->item(i, 3)->setData(Qt::DisplayRole, modifications[i].massdifference); + database->item(i, 3)->setData(Qt::DisplayRole, to_string(modifications[i].massdifference).c_str()); checkbox = new QCheckBox(); + connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxModified(int))); if (modifications[i].nterminal) { checkbox->setChecked(true); } database->setCellWidget(i, 4, checkbox); checkbox = new QCheckBox(); + connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxModified(int))); if (modifications[i].cterminal) { checkbox->setChecked(true); } @@ -281,6 +358,8 @@ void cModificationsWidget::loadDatabase() { progress.setValue((int)modifications.size()); + setDataModified(false); + } inputstream.close(); @@ -289,15 +368,15 @@ void cModificationsWidget::loadDatabase() { } -void cModificationsWidget::saveDatabase() { +bool cModificationsWidget::saveDatabase() { + bool saved = false; if (!checkTable()) { - return; + return saved; } if (databasefile.compare("") == 0) { - saveDatabaseAs(); - return; + return saveDatabaseAs(); } outputstream.open(databasefile.toStdString().c_str()); @@ -317,9 +396,15 @@ void cModificationsWidget::saveDatabase() { fragmentDescription modification; modifications.clear(); - removeEmptyRows(); + removeCheckedRows(); for (int i = 0; i < database->rowCount(); i++) { + + if (database->isRowHidden(i)) { + progress.setValue(i); + continue; + } + modification.clear(); for (int j = 0; j < database->columnCount(); j++) { switch (j) @@ -358,15 +443,20 @@ void cModificationsWidget::saveDatabase() { progress.setValue(progress.maximum()); + setDataModified(false); + + saved = true; + } outputstream.close(); -} + return saved; +} -void cModificationsWidget::saveDatabaseAs() { +bool cModificationsWidget::saveDatabaseAs() { if (!checkTable()) { - return; + return false; } QString filename = QFileDialog::getSaveFileName(this, tr("Save Modifications As..."), lastdir, tr("Modifications (*.txt)")); @@ -375,9 +465,11 @@ void cModificationsWidget::saveDatabaseAs() { lastdir = filename; databasefile = filename; - save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); - saveDatabase(); + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + return saveDatabase(); } + + return false; } @@ -389,16 +481,27 @@ void cModificationsWidget::addRow() { database->setItem(row, 1, widgetitemallocator.getNewItem()); database->setItem(row, 2, widgetitemallocator.getNewItem()); database->setItem(row, 3, widgetitemallocator.getNewItem()); - database->setCellWidget(row, 4, new QCheckBox()); - database->setCellWidget(row, 5, new QCheckBox()); + + QCheckBox* checkbox; + + checkbox = new QCheckBox(); + connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxModified(int))); + database->setCellWidget(row, 4, checkbox); + + checkbox = new QCheckBox(); + connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxModified(int))); + database->setCellWidget(row, 5, checkbox); + + setDataModified(true); } -void cModificationsWidget::removeEmptyRows() { +void cModificationsWidget::removeCheckedRows() { int i = 0; while (i < database->rowCount()) { if (((QCheckBox *)(database->cellWidget(i, 0)))->isChecked()) { removeRow(i); + setDataModified(true); } else { i++; @@ -412,10 +515,14 @@ void cModificationsWidget::itemChanged(QTableWidgetItem* item) { if (item->column() == 2) { checkFormula(item->row(), item->text().toStdString()); } + + setDataModified(true); } void cModificationsWidget::headerItemDoubleClicked(int index) { + setDataModified(true); + if (headersort[index] == -1) { database->sortByColumn(index, Qt::AscendingOrder); headersort[index] = 1; @@ -432,3 +539,61 @@ void cModificationsWidget::headerItemDoubleClicked(int index) { } } + +void cModificationsWidget::filterRows() { + Qt::CaseSensitivity casesensitive = rowsfiltercasesensitive->isChecked()?Qt::CaseSensitive:Qt::CaseInsensitive; + QString str = rowsfilterline->text(); + int rowcount = database->rowCount(); + bool match; + int i, j; + + QProgressDialog progress("Updating...", /*"Cancel"*/0, 0, rowcount, this); + cEventFilter filter; + progress.installEventFilter(&filter); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + + for (i = 0; i < rowcount; i++) { + match = false; + for (j = 0; j < database->columnCount(); j++) { + // ignore non-text fields + if ((j == 0) || (j == 4) || (j == 5)) { + continue; + } + + if (database->item(i, j)->text().contains(str, casesensitive)) { + match = true; + break; + } + } + database->setRowHidden(i, !match); + progress.setValue(i); + } + + progress.setValue(rowcount); +} + + +void cModificationsWidget::resetFilter() { + rowsfilterline->setText(""); + int rowcount = database->rowCount(); + + QProgressDialog progress("Updating...", /*"Cancel"*/0, 0, rowcount, this); + cEventFilter filter; + progress.installEventFilter(&filter); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + + for (int i = 0; i < rowcount; i++) { + database->setRowHidden(i, false); + progress.setValue(i); + } + + progress.setValue(rowcount); +} + + +void cModificationsWidget::checkBoxModified(int state) { + setDataModified(true); +} + diff --git a/CycloBranch/gui/cModificationsWidget.h b/CycloBranch/gui/cModificationsWidget.h index 3deb65f..ff9fd69 100644 --- a/CycloBranch/gui/cModificationsWidget.h +++ b/CycloBranch/gui/cModificationsWidget.h @@ -23,6 +23,8 @@ class QVBoxLayout; class QTableWidget; class QTableWidgetItem; class QPushButton; +class QLineEdit; +class QCheckBox; /** @@ -56,6 +58,7 @@ class cModificationsWidget : public QWidget private: + QWidget* parent; QPushButton* insertrow; QPushButton* removechecked; @@ -63,6 +66,14 @@ class cModificationsWidget : public QWidget QPushButton* load; QPushButton* save; QPushButton* saveas; + + QWidget* rowsfilterwidget; + QHBoxLayout* rowsfilterhbox; + QLineEdit* rowsfilterline; + QCheckBox* rowsfiltercasesensitive; + QPushButton* rowsfilterbutton; + QPushButton* rowsfilterclearbutton; + QTableWidget* database; QHBoxLayout* buttons; QVBoxLayout* mainlayout; @@ -77,6 +88,8 @@ class cModificationsWidget : public QWidget cAllocator widgetitemallocator; + bool datamodified; + void deleteTable(bool enableprogress); void removeRow(int row); @@ -85,6 +98,7 @@ class cModificationsWidget : public QWidget bool checkFormula(int row, const string& summary); + void setDataModified(bool datamodified); protected: @@ -102,18 +116,24 @@ private slots: void loadDatabase(); - void saveDatabase(); + bool saveDatabase(); - void saveDatabaseAs(); + bool saveDatabaseAs(); void addRow(); - void removeEmptyRows(); + void removeCheckedRows(); void itemChanged(QTableWidgetItem* item); void headerItemDoubleClicked(int index); + void filterRows(); + + void resetFilter(); + + void checkBoxModified(int state); + }; #endif diff --git a/CycloBranch/gui/cParametersWidget.cpp b/CycloBranch/gui/cParametersWidget.cpp index bd2a3f3..dff9ca3 100644 --- a/CycloBranch/gui/cParametersWidget.cpp +++ b/CycloBranch/gui/cParametersWidget.cpp @@ -19,6 +19,7 @@ #include #include #include +#include cParametersWidget::cParametersWidget(QWidget* parent) { @@ -63,7 +64,7 @@ cParametersWidget::cParametersWidget(QWidget* parent) { peaklistline = new QLineEdit(); peaklistbutton = new QPushButton("Select"); - #if OS_TYPE == UNX + #if OS_TYPE != WIN peaklistline->setToolTip("Select the peaklist. Following formats are supported: txt, mgf, mzML, mzXML."); peaklistbutton->setToolTip("Select the peaklist. Following formats are supported: txt, mgf, mzML, mzXML."); #else @@ -208,6 +209,10 @@ cParametersWidget::cParametersWidget(QWidget* parent) { enablescrambling->setToolTip("When checked, scrambled fragment ions of cyclic peptides are generated in theoretical spectra."); miscformlayout->addRow(tr("Enable Scrambling: "), enablescrambling); + similaritysearch = new QCheckBox(); + similaritysearch->setToolTip("It enables similarity search when a peaklist is searched against a database of sequences.\nThis feature disables filtering of peptide sequence candidates by precursor mass.\nIt may be useful to determine a peptide family when a similar peptide is contained in the database."); + miscformlayout->addRow(tr("Enable Similarity Search: "), similaritysearch); + miscgroupbox = new QGroupBox("Miscellaneous"); miscgroupbox->setLayout(miscformlayout); @@ -312,13 +317,21 @@ cParametersWidget::cParametersWidget(QWidget* parent) { hlayout = new QHBoxLayout(); + hlayout->setContentsMargins(0, 0, 0, 0); hlayout->addLayout(vlayout1); hlayout->addLayout(vlayout2); + hlayoutwidget = new QWidget(); + hlayoutwidget->setLayout(hlayout); + + hlayoutscroll = new QScrollArea(); + hlayoutscroll->setWidgetResizable(true); + hlayoutscroll->setFrameShape(QFrame::NoFrame); + hlayoutscroll->setWidget(hlayoutwidget); + vlayout = new QVBoxLayout(); - vlayout->addLayout(hlayout); - vlayout->addStretch(1); + vlayout->addWidget(hlayoutscroll); vlayout->addLayout(buttons); setLayout(vlayout); @@ -355,12 +368,12 @@ cParametersWidget::cParametersWidget(QWidget* parent) { lastdirselectmodifications = "./Modifications/"; lastdirselectsequencedatabase = "./SequenceDatabases/"; #else - lastdirloadsettings = linuxinstalldir + "Settings/"; - lastdirsavesettings = linuxinstalldir + "Settings/"; - lastdirselectpeaklist = linuxinstalldir + "PeakLists/"; - lastdirselectbricksdatabase = linuxinstalldir + "BrickDatabases/"; - lastdirselectmodifications = linuxinstalldir + "Modifications/"; - lastdirselectsequencedatabase = linuxinstalldir + "SequenceDatabases/"; + lastdirloadsettings = installdir + "Settings/"; + lastdirsavesettings = installdir + "Settings/"; + lastdirselectpeaklist = installdir + "PeakLists/"; + lastdirselectbricksdatabase = installdir + "BrickDatabases/"; + lastdirselectmodifications = installdir + "Modifications/"; + lastdirselectsequencedatabase = installdir + "SequenceDatabases/"; #endif } @@ -407,6 +420,7 @@ cParametersWidget::~cParametersWidget() { delete cyclicnterminus; delete cycliccterminus; delete enablescrambling; + delete similaritysearch; delete miscformlayout; delete miscgroupbox; @@ -435,6 +449,8 @@ cParametersWidget::~cParametersWidget() { delete vlayout1; delete vlayout2; delete hlayout; + delete hlayoutwidget; + delete hlayoutscroll; delete vlayout; } @@ -477,7 +493,7 @@ void cParametersWidget::setTag(int peptidetypeindex, QString tag) { void cParametersWidget::keyPressEvent(QKeyEvent *event) { - if(event->key() == Qt::Key_Escape) { + if (event->key() == Qt::Key_Escape) { restoreParameters(); } } @@ -518,6 +534,7 @@ void cParametersWidget::loadSettings() { settings.value("cyclicnterminus", 0).toInt() == 0 ? cyclicnterminus->setChecked(false) : cyclicnterminus->setChecked(true); settings.value("cycliccterminus", 0).toInt() == 0 ? cycliccterminus->setChecked(false) : cycliccterminus->setChecked(true); settings.value("enablescrambling", 0).toInt() == 0 ? enablescrambling->setChecked(false) : enablescrambling->setChecked(true); + settings.value("similaritysearch", 0).toInt() == 0 ? similaritysearch->setChecked(false) : similaritysearch->setChecked(true); mode->setCurrentIndex(settings.value("mode", 0).toInt()); sequencedatabaseline->setText(settings.value("sequencedatabase", "").toString()); @@ -578,6 +595,7 @@ void cParametersWidget::saveSettings() { cyclicnterminus->isChecked() ? settings.setValue("cyclicnterminus", 1) : settings.setValue("cyclicnterminus", 0); cycliccterminus->isChecked() ? settings.setValue("cycliccterminus", 1) : settings.setValue("cycliccterminus", 0); enablescrambling->isChecked() ? settings.setValue("enablescrambling", 1) : settings.setValue("enablescrambling", 0); + similaritysearch->isChecked() ? settings.setValue("similaritysearch", 1) : settings.setValue("similaritysearch", 0); settings.setValue("mode", mode->currentIndex()); settings.setValue("sequencedatabase", sequencedatabaseline->text()); @@ -615,7 +633,7 @@ void cParametersWidget::saveSettingsAs() { void cParametersWidget::peaklistButtonReleased() { - #if OS_TYPE == UNX + #if OS_TYPE != WIN QString filename = QFileDialog::getOpenFileName(this, tr("Select Peaklist..."), lastdirselectpeaklist, tr("Peak Lists (*.txt *.mgf *.mzML *.mzXML)")); #else QString filename = QFileDialog::getOpenFileName(this, tr("Select Peaklist..."), lastdirselectpeaklist, tr("Peak Lists (*.txt *.mgf *.mzML *.mzXML *.baf)")); @@ -723,6 +741,7 @@ bool cParametersWidget::updateParameters() { parameters.cyclicnterminus = cyclicnterminus->isChecked(); parameters.cycliccterminus = cycliccterminus->isChecked(); parameters.enablescrambling = enablescrambling->isChecked(); + parameters.similaritysearch = similaritysearch->isChecked(); parameters.mode = (modeType)mode->currentIndex(); parameters.sequencedatabasefilename = sequencedatabaseline->text().toStdString(); @@ -813,6 +832,7 @@ void cParametersWidget::restoreParameters() { cyclicnterminus->setChecked(parameters.cyclicnterminus); cycliccterminus->setChecked(parameters.cycliccterminus); enablescrambling->setChecked(parameters.enablescrambling); + similaritysearch->setChecked(parameters.similaritysearch); mode->setCurrentIndex(parameters.mode); sequencedatabaseline->setText(parameters.sequencedatabasefilename.c_str()); @@ -955,6 +975,7 @@ void cParametersWidget::updateSettingsWhenModeChanged(int index) { sequencedatabaseline->setDisabled(true); sequencedatabasebutton->setDisabled(true); blindedges->setDisabled(false); + similaritysearch->setDisabled(true); maximumnumberofthreads->setDisabled(false); scoretype->setDisabled(false); hitsreported->setDisabled(false); @@ -984,6 +1005,7 @@ void cParametersWidget::updateSettingsWhenModeChanged(int index) { sequencedatabaseline->setDisabled(true); sequencedatabasebutton->setDisabled(true); blindedges->setDisabled(true); + similaritysearch->setDisabled(true); maximumnumberofthreads->setDisabled(true); scoretype->setDisabled(true); hitsreported->setDisabled(true); @@ -1011,6 +1033,7 @@ void cParametersWidget::updateSettingsWhenModeChanged(int index) { modificationsline->setDisabled(false); modificationsbutton->setDisabled(false); blindedges->setDisabled(true); + similaritysearch->setDisabled(false); sequencedatabaseline->setDisabled(false); sequencedatabasebutton->setDisabled(false); maximumnumberofthreads->setDisabled(false); @@ -1040,6 +1063,7 @@ void cParametersWidget::updateSettingsWhenModeChanged(int index) { modificationsline->setDisabled(true); modificationsbutton->setDisabled(true); blindedges->setDisabled(true); + similaritysearch->setDisabled(true); sequencedatabaseline->setDisabled(false); sequencedatabasebutton->setDisabled(false); maximumnumberofthreads->setDisabled(true); diff --git a/CycloBranch/gui/cParametersWidget.h b/CycloBranch/gui/cParametersWidget.h index a3bf011..46bff4d 100644 --- a/CycloBranch/gui/cParametersWidget.h +++ b/CycloBranch/gui/cParametersWidget.h @@ -37,6 +37,7 @@ class QCheckBox; class QTableWidget; class QListWidget; class QMessageBox; +class QScrollArea; /** @@ -109,6 +110,8 @@ class cParametersWidget : public QWidget QVBoxLayout* vlayout2; QVBoxLayout* vlayout; QHBoxLayout* hlayout; + QWidget* hlayoutwidget; + QScrollArea* hlayoutscroll; QString settingsfile; QString oldsettingsfile; @@ -154,6 +157,7 @@ class cParametersWidget : public QWidget QCheckBox* cyclicnterminus; QCheckBox* cycliccterminus; QCheckBox* enablescrambling; + QCheckBox* similaritysearch; QFormLayout* applicationformlayout; QGroupBox* applicationgroupbox; diff --git a/CycloBranch/gui/cSequenceDatabaseWidget.cpp b/CycloBranch/gui/cSequenceDatabaseWidget.cpp index 7d70122..963bf63 100644 --- a/CycloBranch/gui/cSequenceDatabaseWidget.cpp +++ b/CycloBranch/gui/cSequenceDatabaseWidget.cpp @@ -16,6 +16,7 @@ #include #include #include +#include cSequenceDatabaseWidget::cSequenceDatabaseWidget(QWidget* parent) { @@ -33,17 +34,44 @@ cSequenceDatabaseWidget::cSequenceDatabaseWidget(QWidget* parent) { close->setToolTip("Close the window."); load = new QPushButton(tr("Load")); load->setToolTip("Load the database of sequences."); - save = new QPushButton(QString("Save")); + save = new QPushButton(QString(" Save ")); save->setToolTip("Save the database of sequences in the current file. When a file has not been loaded yet, the \"Save As ...\" file dialog is opened."); saveas = new QPushButton(tr("Save As...")); saveas->setToolTip("Save the database of sequences into a file."); + rowsfilterline = new QLineEdit(); + rowsfilterline->setMinimumWidth(250); + rowsfilterline->setToolTip("Text to Find"); + rowsfiltercasesensitive = new QCheckBox(); + rowsfiltercasesensitive->setToolTip("Case Sensitive"); + rowsfilterbutton = new QPushButton("Filter"); + rowsfilterbutton->setToolTip("Filter Search Results"); + rowsfilterbutton->setMinimumWidth(50); + rowsfilterclearbutton = new QPushButton("Clear"); + rowsfilterclearbutton->setToolTip("Clear Form and Reset Search Results"); + rowsfilterclearbutton->setMinimumWidth(50); + + rowsfilterhbox = new QHBoxLayout(); + rowsfilterhbox->addWidget(rowsfilterline); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfiltercasesensitive); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfilterbutton); + rowsfilterhbox->addStretch(); + rowsfilterhbox->addWidget(rowsfilterclearbutton); + + rowsfilterwidget = new QWidget(); + rowsfilterwidget->setLayout(rowsfilterhbox); + rowsfilterwidget->setMaximumWidth(420); + buttons = new QHBoxLayout(); buttons->addWidget(close); - buttons->addStretch(1); + buttons->addStretch(); buttons->addWidget(insertrow); buttons->addWidget(removechecked); - buttons->addStretch(10); + buttons->addStretch(); + buttons->addWidget(rowsfilterwidget); + buttons->addStretch(); buttons->addWidget(load); buttons->addWidget(save); buttons->addWidget(saveas); @@ -78,11 +106,13 @@ cSequenceDatabaseWidget::cSequenceDatabaseWidget(QWidget* parent) { connect(database->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(headerItemDoubleClicked(int))); connect(database, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(itemChanged(QTableWidgetItem *))); connect(insertrow, SIGNAL(released()), this, SLOT(addRow())); - connect(removechecked, SIGNAL(released()), this, SLOT(removeEmptyRows())); + connect(removechecked, SIGNAL(released()), this, SLOT(removeCheckedRows())); connect(close, SIGNAL(released()), this, SLOT(closeWindow())); connect(load, SIGNAL(released()), this, SLOT(loadDatabase())); connect(save, SIGNAL(released()), this, SLOT(saveDatabase())); connect(saveas, SIGNAL(released()), this, SLOT(saveDatabaseAs())); + connect(rowsfilterbutton, SIGNAL(released()), this, SLOT(filterRows())); + connect(rowsfilterclearbutton, SIGNAL(released()), this, SLOT(resetFilter())); setLayout(mainlayout); @@ -93,10 +123,12 @@ cSequenceDatabaseWidget::cSequenceDatabaseWidget(QWidget* parent) { #if OS_TYPE == WIN lastdir = "./SequenceDatabases/"; #else - lastdir = linuxinstalldir + "SequenceDatabases/"; + lastdir = installdir + "SequenceDatabases/"; #endif sequences.clear(); + + setDataModified(false); } @@ -115,6 +147,14 @@ cSequenceDatabaseWidget::~cSequenceDatabaseWidget() { delete load; delete save; delete saveas; + + delete rowsfilterline; + delete rowsfiltercasesensitive; + delete rowsfilterbutton; + delete rowsfilterclearbutton; + delete rowsfilterhbox; + delete rowsfilterwidget; + delete database; delete buttons; delete mainlayout; @@ -222,7 +262,7 @@ bool cSequenceDatabaseWidget::checkFormula(int row, const string& summary) { return false; } if (database->item(row, 4)) { - database->item(row, 4)->setData(Qt::DisplayRole, formula.getMass()); + database->item(row, 4)->setData(Qt::DisplayRole, to_string(formula.getMass()).c_str()); } return true; } @@ -290,14 +330,49 @@ bool cSequenceDatabaseWidget::checkSequence(int row) { } +void cSequenceDatabaseWidget::setDataModified(bool datamodified) { + if (datamodified == this->datamodified) { + return; + } + + this->datamodified = datamodified; + + if (datamodified) { + save->setText("*" + save->text()); + } + else { + if ((save->text().size() > 0) && (save->text().at(0) == '*')) { + save->setText(save->text().toStdString().substr(1).c_str()); + } + } +} + + void cSequenceDatabaseWidget::keyPressEvent(QKeyEvent *event) { - if(event->key() == Qt::Key_Escape) { - hide(); + if (event->key() == Qt::Key_Escape) { + closeWindow(); + } + + if ((event->key() == Qt::Key_Enter) || (event->key() == Qt::Key_Return)) { + if (rowsfilterline->hasFocus()) { + filterRows(); + } } } void cSequenceDatabaseWidget::closeWindow() { + if (datamodified) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, appname, "Save changes ?", QMessageBox::Yes|QMessageBox::No); + + if (reply == QMessageBox::Yes) { + if (!saveDatabase()) { + return; + } + } + } + hide(); } @@ -309,7 +384,7 @@ void cSequenceDatabaseWidget::loadDatabase() { lastdir = filename; databasefile = filename; - save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); inputstream.open(filename.toStdString().c_str()); @@ -342,6 +417,7 @@ void cSequenceDatabaseWidget::loadDatabase() { combo->addItem(QString(getStringFromPeptideType((peptideType)j).c_str())); } combo->setCurrentIndex((int)sequences[i].getPeptideType()); + connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(comboBoxModified(int))); database->setCellWidget(i, 1, combo); database->setItem(i, 2, widgetitemallocator.getNewItem()); @@ -352,7 +428,7 @@ void cSequenceDatabaseWidget::loadDatabase() { formula.setFormula(sequences[i].getSummaryFormula()); database->setItem(i, 4, widgetitemallocator.getNewItem()); - database->item(i, 4)->setData(Qt::DisplayRole, formula.getMass()); + database->item(i, 4)->setData(Qt::DisplayRole, to_string(formula.getMass()).c_str()); database->setItem(i, 5, widgetitemallocator.getNewItem()); database->item(i, 5)->setText(sequences[i].getSequence().c_str()); @@ -385,6 +461,8 @@ void cSequenceDatabaseWidget::loadDatabase() { } progress.setValue(sequences.size()); + + setDataModified(false); } @@ -394,15 +472,15 @@ void cSequenceDatabaseWidget::loadDatabase() { } -void cSequenceDatabaseWidget::saveDatabase() { +bool cSequenceDatabaseWidget::saveDatabase() { + bool saved = false; if (!checkTable()) { - return; + return saved; } if (databasefile.compare("") == 0) { - saveDatabaseAs(); - return; + return saveDatabaseAs(); } outputstream.open(databasefile.toStdString().c_str()); @@ -423,9 +501,15 @@ void cSequenceDatabaseWidget::saveDatabase() { sequences.clear(); string s; - removeEmptyRows(); + removeCheckedRows(); for (int i = 0; i < database->rowCount(); i++) { + + if (database->isRowHidden(i)) { + progress.setValue(i); + continue; + } + seq.clear(); for (int j = 0; j < database->columnCount(); j++) { switch (j) @@ -483,15 +567,20 @@ void cSequenceDatabaseWidget::saveDatabase() { progress.setValue(progress.maximum()); + setDataModified(false); + + saved = true; + } outputstream.close(); -} + return saved; +} -void cSequenceDatabaseWidget::saveDatabaseAs() { +bool cSequenceDatabaseWidget::saveDatabaseAs() { if (!checkTable()) { - return; + return false; } QString filename = QFileDialog::getSaveFileName(this, tr("Save the Database of Sequences As..."), lastdir, tr("Database of Sequences (*.txt)")); @@ -500,9 +589,11 @@ void cSequenceDatabaseWidget::saveDatabaseAs() { lastdir = filename; databasefile = filename; - save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); - saveDatabase(); + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + return saveDatabase(); } + + return false; } @@ -518,6 +609,7 @@ void cSequenceDatabaseWidget::addRow() { combo->addItem(QString(getStringFromPeptideType((peptideType)i).c_str())); } combo->setCurrentIndex((int)other); + connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(comboBoxModified(int))); database->setCellWidget(row, 1, combo); database->setItem(row, 2, widgetitemallocator.getNewItem()); @@ -536,11 +628,12 @@ void cSequenceDatabaseWidget::addRow() { } -void cSequenceDatabaseWidget::removeEmptyRows() { +void cSequenceDatabaseWidget::removeCheckedRows() { int i = 0; while (i < database->rowCount()) { if (((QCheckBox *)(database->cellWidget(i, 0)))->isChecked()) { removeRow(i); + setDataModified(true); } else { i++; @@ -567,10 +660,14 @@ void cSequenceDatabaseWidget::itemChanged(QTableWidgetItem* item) { seq.setReference(database->item(item->row(), 9)->text().toStdString()); ((QLabel *)database->cellWidget(item->row(), 10))->setText(seq.getNameWithReferenceAsHTMLString().c_str()); } + + setDataModified(true); } void cSequenceDatabaseWidget::headerItemDoubleClicked(int index) { + setDataModified(true); + if (headersort[index] == -1) { database->sortByColumn(index, Qt::AscendingOrder); headersort[index] = 1; @@ -587,3 +684,61 @@ void cSequenceDatabaseWidget::headerItemDoubleClicked(int index) { } } + +void cSequenceDatabaseWidget::filterRows() { + Qt::CaseSensitivity casesensitive = rowsfiltercasesensitive->isChecked()?Qt::CaseSensitive:Qt::CaseInsensitive; + QString str = rowsfilterline->text(); + int rowcount = database->rowCount(); + bool match; + int i, j; + + QProgressDialog progress("Updating...", /*"Cancel"*/0, 0, rowcount, this); + cEventFilter filter; + progress.installEventFilter(&filter); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + + for (i = 0; i < rowcount; i++) { + match = false; + for (j = 0; j < database->columnCount(); j++) { + // ignore non-text fields + if ((j == 0) || (j == 1) || (j == 10)) { + continue; + } + + if (database->item(i, j)->text().contains(str, casesensitive)) { + match = true; + break; + } + } + database->setRowHidden(i, !match); + progress.setValue(i); + } + + progress.setValue(rowcount); +} + + +void cSequenceDatabaseWidget::resetFilter() { + rowsfilterline->setText(""); + int rowcount = database->rowCount(); + + QProgressDialog progress("Updating...", /*"Cancel"*/0, 0, rowcount, this); + cEventFilter filter; + progress.installEventFilter(&filter); + progress.setMinimumDuration(0); + progress.setWindowModality(Qt::WindowModal); + + for (int i = 0; i < rowcount; i++) { + database->setRowHidden(i, false); + progress.setValue(i); + } + + progress.setValue(rowcount); +} + + +void cSequenceDatabaseWidget::comboBoxModified(int index) { + setDataModified(true); +} + diff --git a/CycloBranch/gui/cSequenceDatabaseWidget.h b/CycloBranch/gui/cSequenceDatabaseWidget.h index 204c984..e206bcb 100644 --- a/CycloBranch/gui/cSequenceDatabaseWidget.h +++ b/CycloBranch/gui/cSequenceDatabaseWidget.h @@ -23,6 +23,8 @@ class QVBoxLayout; class QTableWidget; class QTableWidgetItem; class QPushButton; +class QLineEdit; +class QCheckBox; /** @@ -64,6 +66,7 @@ class cSequenceDatabaseWidget : public QWidget private: + QWidget* parent; QPushButton* insertrow; QPushButton* removechecked; @@ -71,6 +74,14 @@ class cSequenceDatabaseWidget : public QWidget QPushButton* load; QPushButton* save; QPushButton* saveas; + + QWidget* rowsfilterwidget; + QHBoxLayout* rowsfilterhbox; + QLineEdit* rowsfilterline; + QCheckBox* rowsfiltercasesensitive; + QPushButton* rowsfilterbutton; + QPushButton* rowsfilterclearbutton; + QTableWidget* database; QHBoxLayout* buttons; QVBoxLayout* mainlayout; @@ -85,6 +96,8 @@ class cSequenceDatabaseWidget : public QWidget cAllocator widgetitemallocator; + bool datamodified; + void deleteTable(bool enableprogress); void removeRow(int row); @@ -95,6 +108,8 @@ class cSequenceDatabaseWidget : public QWidget bool checkSequence(int row); + void setDataModified(bool datamodified); + protected: @@ -112,18 +127,24 @@ private slots: void loadDatabase(); - void saveDatabase(); + bool saveDatabase(); - void saveDatabaseAs(); + bool saveDatabaseAs(); void addRow(); - void removeEmptyRows(); + void removeCheckedRows(); void itemChanged(QTableWidgetItem* item); void headerItemDoubleClicked(int index); + void filterRows(); + + void resetFilter(); + + void comboBoxModified(int index); + }; #endif diff --git a/CycloBranch/gui/cSpectrumDetailWidget.cpp b/CycloBranch/gui/cSpectrumDetailWidget.cpp index 6327cd4..875e075 100644 --- a/CycloBranch/gui/cSpectrumDetailWidget.cpp +++ b/CycloBranch/gui/cSpectrumDetailWidget.cpp @@ -148,8 +148,6 @@ cSpectrumDetailWidget::~cSpectrumDetailWidget() { break; } - delete actionExportPeptide; - } delete hsplitter1; @@ -158,6 +156,9 @@ cSpectrumDetailWidget::~cSpectrumDetailWidget() { delete vsplitter; delete actionExportSpectrum; + delete actionFind; + delete actionPrevious; + delete actionNext; delete actionZoomIn; delete actionZoomOut; delete actionZoomReset; @@ -166,6 +167,9 @@ cSpectrumDetailWidget::~cSpectrumDetailWidget() { delete actionHideScrambled; delete actionMouseMzSelection; + delete finddialog; + delete exportdialog; + } } @@ -219,19 +223,37 @@ void cSpectrumDetailWidget::prepareToShow(peptideType peptidetype) { toolbarExport->setMovable(false); toolbarExport->setFloatable(false); - actionExportSpectrum = new QAction(QIcon(":/images/icons/54.png"), tr("Export Spectrum"), this); + actionExportSpectrum = new QAction(QIcon(":/images/icons/66.png"), tr("Export Image"), this); actionExportSpectrum->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); - actionExportSpectrum->setToolTip("Export Spectrum (Ctrl + E)"); + actionExportSpectrum->setToolTip("Export Image (Ctrl + E)"); toolbarExport->addAction(actionExportSpectrum); - connect(actionExportSpectrum, SIGNAL(triggered()), this, SLOT(exportSpectrum())); + connect(actionExportSpectrum, SIGNAL(triggered()), this, SLOT(openExportDialog())); + + + toolbarFind = addToolBar(tr("Find")); + toolbarFind->setMovable(false); + toolbarFind->setFloatable(false); + + actionFind = new QAction(QIcon(":/images/icons/65.png"), tr("Find Text"), this); + actionFind->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F)); + actionFind->setToolTip("Find Text (Ctrl + F)"); + toolbarFind->addAction(actionFind); + connect(actionFind, SIGNAL(triggered()), this, SLOT(openFindDialog())); + + actionPrevious = new QAction(QIcon(":/images/icons/56.png"), tr("Find Previous"), this); + actionPrevious->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_1)); + actionPrevious->setToolTip("Find Previous (Ctrl + 1)"); + toolbarFind->addAction(actionPrevious); + connect(actionPrevious, SIGNAL(triggered()), this, SLOT(movePrevious())); + actionPrevious->setDisabled(true); + + actionNext = new QAction(QIcon(":/images/icons/57.png"), tr("Find Next"), this); + actionNext->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_2)); + actionNext->setToolTip("Find Next (Ctrl + 2)"); + toolbarFind->addAction(actionNext); + connect(actionNext, SIGNAL(triggered()), this, SLOT(moveNext())); + actionNext->setDisabled(true); - if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { - actionExportPeptide = new QAction(QIcon(":/images/icons/57.png"), tr("Export Peptide"), this); - actionExportPeptide->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P)); - actionExportPeptide->setToolTip("Export Peptide (Ctrl + P)"); - toolbarExport->addAction(actionExportPeptide); - connect(actionExportPeptide, SIGNAL(triggered()), this, SLOT(exportPeptide())); - } toolbarZoom = addToolBar(tr("Zoom")); toolbarZoom->setMovable(false); @@ -521,6 +543,9 @@ void cSpectrumDetailWidget::prepareToShow(peptideType peptidetype) { setCentralWidget(vsplitter); centralWidget()->setContentsMargins(10, 10, 10, 10); + finddialog = new cFindDialog(this); + exportdialog = new cExportDialog(this); + resize(1280, 700); if (parameters && theoreticalspectrum) { @@ -555,6 +580,7 @@ void cSpectrumDetailWidget::prepareToShow(peptideType peptidetype) { spectrumscene->initialize(parameters, theoreticalspectrum); textbrowser->setHtml(getDetailsAsHTMLString().c_str()); + } preparedToShow = true; @@ -563,12 +589,88 @@ void cSpectrumDetailWidget::prepareToShow(peptideType peptidetype) { } +void cSpectrumDetailWidget::findAll(const QString& str, QTextDocument::FindFlags opt) { + + currentfinditem = 0; + + // textbrowser + QList extraSelections; + textbrowser->moveCursor(QTextCursor::Start); + QColor color = QColor(Qt::yellow); + + while (textbrowser->find(str, opt)) { + QTextEdit::ExtraSelection extra; + extra.format.setBackground(color); + + extra.cursor = textbrowser->textCursor(); + extraSelections.append(extra); + } + + textbrowser->setExtraSelections(extraSelections); + + + // textedit + extraSelections.clear(); + textedit->moveCursor(QTextCursor::Start); + + while (textedit->find(str, opt)) { + QTextEdit::ExtraSelection extra; + extra.format.setBackground(color); + + extra.cursor = textedit->textCursor(); + extraSelections.append(extra); + } + + textedit->setExtraSelections(extraSelections); + + + if (textbrowser->extraSelections().size() + textedit->extraSelections().size() == 0) { + actionPrevious->setDisabled(true); + actionNext->setDisabled(true); + + QMessageBox msgBox; + QString errstr = "No results were found."; + msgBox.setWindowTitle("Find Text"); + msgBox.setText(errstr); + msgBox.exec(); + } + else { + actionPrevious->setDisabled(false); + actionNext->setDisabled(false); + } + + + // order changed because of setFocus() + if (textedit->extraSelections().size() > 0) { + textedit->setTextCursor(textedit->extraSelections().at(0).cursor); + textedit->setFocus(); + } + + + if (textbrowser->extraSelections().size() > 0) { + textbrowser->setTextCursor(textbrowser->extraSelections().at(0).cursor); + textbrowser->setFocus(); + } + +} + + +void cSpectrumDetailWidget::exportImage(bool exportspectrum) { + if (exportspectrum) { + exportSpectrum(); + } + else { + exportPeptide(); + } +} + + void cSpectrumDetailWidget::keyPressEvent(QKeyEvent *event) { - if(event->key() == Qt::Key_Escape) { + if (event->key() == Qt::Key_Escape) { hide(); } - if(event->key() == Qt::Key_Enter) { + if ((event->key() == Qt::Key_Enter) || (event->key() == Qt::Key_Return)) { setMZInterval(); } } @@ -586,10 +688,10 @@ void cSpectrumDetailWidget::setMZInterval() { void cSpectrumDetailWidget::exportSpectrum() { - #if OS_TYPE == UNX + #if OS_TYPE == WIN QString filename = QFileDialog::getSaveFileName(this, tr("Export Spectrum..."), "./", "PDF Files (*.pdf);; PS Files (*.ps);; PNG Files (*.png);; SVG Files (*.svg)"); #else - QString filename = QFileDialog::getSaveFileName(this, tr("Export Spectrum..."), "./", "PDF Files (*.pdf);; PS Files (*.ps);; PNG Files (*.png)"); + QString filename = QFileDialog::getSaveFileName(this, tr("Export Spectrum..."), "./", "PDF Files (*.pdf);; PNG Files (*.png);; SVG Files (*.svg)"); #endif if (!filename.isEmpty()) { regex rx; @@ -601,11 +703,13 @@ void cSpectrumDetailWidget::exportSpectrum() { selected = true; } - rx = ".+\\.ps$"; - if (!selected && (regex_search(filename.toStdString(), rx))) { - spectrumscene->exportToPDF(filename, true); - selected = true; - } + #if OS_TYPE == WIN + rx = ".+\\.ps$"; + if (!selected && (regex_search(filename.toStdString(), rx))) { + spectrumscene->exportToPDF(filename, true); + selected = true; + } + #endif rx = ".+\\.png$"; if (!selected && (regex_search(filename.toStdString(), rx))) { @@ -613,13 +717,11 @@ void cSpectrumDetailWidget::exportSpectrum() { selected = true; } - #if OS_TYPE == UNX - rx = ".+\\.svg$"; - if (!selected && (regex_search(filename.toStdString(), rx))) { - spectrumscene->exportToSVG(filename); - selected = true; - } - #endif + rx = ".+\\.svg$"; + if (!selected && (regex_search(filename.toStdString(), rx))) { + spectrumscene->exportToSVG(filename); + selected = true; + } if (!selected) { QMessageBox msgBox; @@ -632,10 +734,10 @@ void cSpectrumDetailWidget::exportSpectrum() { void cSpectrumDetailWidget::exportPeptide() { - #if OS_TYPE == UNX + #if OS_TYPE == WIN QString filename = QFileDialog::getSaveFileName(this, tr("Export Peptide..."), "./", "PDF Files (*.pdf);; PS Files (*.ps);; PNG Files (*.png);; SVG Files (*.svg)"); #else - QString filename = QFileDialog::getSaveFileName(this, tr("Export Peptide..."), "./", "PDF Files (*.pdf);; PS Files (*.ps);; PNG Files (*.png)"); + QString filename = QFileDialog::getSaveFileName(this, tr("Export Peptide..."), "./", "PDF Files (*.pdf);; PNG Files (*.png);; SVG Files (*.svg)"); #endif if (!filename.isEmpty() && parameters) { regex rx; @@ -649,11 +751,13 @@ void cSpectrumDetailWidget::exportPeptide() { selected = true; } - rx = ".+\\.ps$"; - if (!selected && (regex_search(filename.toStdString(), rx))) { - linearwidget->exportToPDF(filename, true); - selected = true; - } + #if OS_TYPE == WIN + rx = ".+\\.ps$"; + if (!selected && (regex_search(filename.toStdString(), rx))) { + linearwidget->exportToPDF(filename, true); + selected = true; + } + #endif rx = ".+\\.png$"; if (!selected && (regex_search(filename.toStdString(), rx))) { @@ -661,13 +765,11 @@ void cSpectrumDetailWidget::exportPeptide() { selected = true; } - #if OS_TYPE == UNX - rx = ".+\\.svg$"; - if (!selected && (regex_search(filename.toStdString(), rx))) { - linearwidget->exportToSVG(filename); - selected = true; - } - #endif + rx = ".+\\.svg$"; + if (!selected && (regex_search(filename.toStdString(), rx))) { + linearwidget->exportToSVG(filename); + selected = true; + } break; case cyclic: rx = ".+\\.pdf$"; @@ -676,26 +778,25 @@ void cSpectrumDetailWidget::exportPeptide() { selected = true; } - rx = ".+\\.ps$"; + #if OS_TYPE == WIN + rx = ".+\\.ps$"; + if (!selected && (regex_search(filename.toStdString(), rx))) { + cyclicwidget->exportToPDF(filename, true); + selected = true; + } + #endif + + rx = ".+\\.png$"; if (!selected && (regex_search(filename.toStdString(), rx))) { - cyclicwidget->exportToPDF(filename, true); + cyclicwidget->exportToPNG(filename); selected = true; } - - rx = ".+\\.png$"; + rx = ".+\\.svg$"; if (!selected && (regex_search(filename.toStdString(), rx))) { - cyclicwidget->exportToPNG(filename); + cyclicwidget->exportToSVG(filename); selected = true; } - - #if OS_TYPE == UNX - rx = ".+\\.svg$"; - if (!selected && (regex_search(filename.toStdString(), rx))) { - cyclicwidget->exportToSVG(filename); - selected = true; - } - #endif break; case branched: rx = ".+\\.pdf$"; @@ -704,12 +805,13 @@ void cSpectrumDetailWidget::exportPeptide() { selected = true; } - rx = ".+\\.ps$"; - if (!selected && (regex_search(filename.toStdString(), rx))) { - branchedwidget->exportToPDF(filename, true); - selected = true; - } - + #if OS_TYPE == WIN + rx = ".+\\.ps$"; + if (!selected && (regex_search(filename.toStdString(), rx))) { + branchedwidget->exportToPDF(filename, true); + selected = true; + } + #endif rx = ".+\\.png$"; if (!selected && (regex_search(filename.toStdString(), rx))) { @@ -717,13 +819,11 @@ void cSpectrumDetailWidget::exportPeptide() { selected = true; } - #if OS_TYPE == UNX - rx = ".+\\.svg$"; - if (!selected && (regex_search(filename.toStdString(), rx))) { - branchedwidget->exportToSVG(filename); - selected = true; - } - #endif + rx = ".+\\.svg$"; + if (!selected && (regex_search(filename.toStdString(), rx))) { + branchedwidget->exportToSVG(filename); + selected = true; + } break; case lasso: rx = ".+\\.pdf$"; @@ -732,26 +832,25 @@ void cSpectrumDetailWidget::exportPeptide() { selected = true; } - rx = ".+\\.ps$"; + #if OS_TYPE == WIN + rx = ".+\\.ps$"; + if (!selected && (regex_search(filename.toStdString(), rx))) { + lassowidget->exportToPDF(filename, true); + selected = true; + } + #endif + + rx = ".+\\.png$"; if (!selected && (regex_search(filename.toStdString(), rx))) { - lassowidget->exportToPDF(filename, true); + lassowidget->exportToPNG(filename); selected = true; } - - rx = ".+\\.png$"; + rx = ".+\\.svg$"; if (!selected && (regex_search(filename.toStdString(), rx))) { - lassowidget->exportToPNG(filename); + lassowidget->exportToSVG(filename); selected = true; } - - #if OS_TYPE == UNX - rx = ".+\\.svg$"; - if (!selected && (regex_search(filename.toStdString(), rx))) { - lassowidget->exportToSVG(filename); - selected = true; - } - #endif break; case linearpolysaccharide: break; @@ -770,3 +869,48 @@ void cSpectrumDetailWidget::exportPeptide() { } } + +void cSpectrumDetailWidget::openFindDialog() { + finddialog->exec(); +} + + +void cSpectrumDetailWidget::openExportDialog() { + if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { + exportdialog->exec(); + } + else { + exportSpectrum(); + } +} + + +void cSpectrumDetailWidget::movePrevious() { + int count = textbrowser->extraSelections().size() + textedit->extraSelections().size(); + currentfinditem = (currentfinditem + count - 1)%count; + + if (currentfinditem < textbrowser->extraSelections().size()) { + textbrowser->setFocus(); + textbrowser->setTextCursor(textbrowser->extraSelections().at(currentfinditem).cursor); + } + else { + textedit->setFocus(); + textedit->setTextCursor(textedit->extraSelections().at(currentfinditem - textbrowser->extraSelections().size()).cursor); + } +} + + +void cSpectrumDetailWidget::moveNext() { + int count = textbrowser->extraSelections().size() + textedit->extraSelections().size(); + currentfinditem = (currentfinditem + 1)%count; + + if (currentfinditem < textbrowser->extraSelections().size()) { + textbrowser->setFocus(); + textbrowser->setTextCursor(textbrowser->extraSelections().at(currentfinditem).cursor); + } + else { + textedit->setFocus(); + textedit->setTextCursor(textedit->extraSelections().at(currentfinditem - textbrowser->extraSelections().size()).cursor); + } +} + diff --git a/CycloBranch/gui/cSpectrumDetailWidget.h b/CycloBranch/gui/cSpectrumDetailWidget.h index 6c0063c..2595315 100644 --- a/CycloBranch/gui/cSpectrumDetailWidget.h +++ b/CycloBranch/gui/cSpectrumDetailWidget.h @@ -9,12 +9,15 @@ #include #include +#include #include "core/cTheoreticalSpectrum.h" #include "gui/cLinearWidget.h" #include "gui/cCyclicWidget.h" #include "gui/cBranchedWidget.h" #include "gui/cLassoWidget.h" #include "gui/cSpectrumSceneWidget.h" +#include "gui/cFindDialog.h" +#include "gui/cExportDialog.h" // forward declaration @@ -103,6 +106,21 @@ class cSpectrumDetailWidget : public QMainWindow \param peptidetype a type of peptide */ void prepareToShow(peptideType peptidetype); + + + /** + \brief Find all occurrences of \a str and highlight them. + \param str search string + \param opt search options + */ + void findAll(const QString& str, QTextDocument::FindFlags opt = 0); + + + /** + \brief Export spectrum/peptide image. + \param exportspectrum if true, a spectrum image is exported; if false, a peptide image is exported + */ + void exportImage(bool exportspectrum); protected: @@ -117,6 +135,7 @@ class cSpectrumDetailWidget : public QMainWindow private: QToolBar* toolbarExport; + QToolBar* toolbarFind; QToolBar* toolbarZoom; QToolBar* toolbarHide; QToolBar* toolbarMz; @@ -124,7 +143,9 @@ class cSpectrumDetailWidget : public QMainWindow QToolBar* toolbarTrotation; QAction* actionExportSpectrum; - QAction* actionExportPeptide; + QAction* actionFind; + QAction* actionPrevious; + QAction* actionNext; QAction* actionZoomIn; QAction* actionZoomOut; QAction* actionZoomReset; @@ -169,6 +190,10 @@ class cSpectrumDetailWidget : public QMainWindow bool preparedToShow; cParameters* parameters; + cFindDialog* finddialog; + cExportDialog* exportdialog; + int currentfinditem; + signals: @@ -190,6 +215,14 @@ private slots: void exportPeptide(); + void openFindDialog(); + + void openExportDialog(); + + void movePrevious(); + + void moveNext(); + }; #endif \ No newline at end of file diff --git a/CycloBranch/gui/cSpectrumSceneWidget.cpp b/CycloBranch/gui/cSpectrumSceneWidget.cpp index eaa1420..fe11e10 100644 --- a/CycloBranch/gui/cSpectrumSceneWidget.cpp +++ b/CycloBranch/gui/cSpectrumSceneWidget.cpp @@ -100,7 +100,6 @@ void cSpectrumSceneWidget::exportToPDF(QString filename, bool postscript) { QString errstr = "The file cannot be created."; #if OS_TYPE == UNX errstr += "\nDo you have a properly configured print server (sudo apt-get install cups-pdf) ?"; - errstr += "\nIf you cannot create a ps file, you can create a pdf file and then use pdf2ps tool."; #endif msgBox.setText(errstr); msgBox.exec(); @@ -128,6 +127,7 @@ void cSpectrumSceneWidget::exportToSVG(QString filename) { return; } + painter.fillRect(QRect(0, 0, scene->width(), scene->height()), Qt::white); scene->render(&painter); painter.end(); } @@ -437,9 +437,11 @@ void cSpectrumSceneWidget::redrawScene() { sprintf_s(tmpbuf,"%.3f\0",visiblepeaks[i].mzratio); s = tmpbuf; hits.push_back(s); + QGraphicsLineItem* line; if (hits.size() > 1) { - scene->addLine(x, h - bottommargin - 2, x, h - bottommargin - std::max((int)y, 5), QPen(Qt::red, 2, Qt::SolidLine)); + line = scene->addLine(x, h - bottommargin - 2, x, h - bottommargin - std::max((int)y, 5), QPen(Qt::red, 2, Qt::SolidLine)); + line->setZValue(1); hiddenitems.clear(); sumh = 0; diff --git a/CycloBranch/images.qrc b/CycloBranch/images.qrc index 74aa3b2..1361d37 100644 --- a/CycloBranch/images.qrc +++ b/CycloBranch/images.qrc @@ -26,7 +26,10 @@ images/icons/84.png images/icons/80.png images/icons/57.png - images/icons/54.png images/icons/64.png + images/icons/95.png + images/icons/65.png + images/icons/56.png + images/icons/66.png diff --git a/CycloBranch/images/cb.icns b/CycloBranch/images/cb.icns new file mode 100644 index 0000000..46626aa Binary files /dev/null and b/CycloBranch/images/cb.icns differ diff --git a/CycloBranch/images/icons/56.png b/CycloBranch/images/icons/56.png new file mode 100644 index 0000000..98b5811 Binary files /dev/null and b/CycloBranch/images/icons/56.png differ diff --git a/CycloBranch/images/icons/65.png b/CycloBranch/images/icons/65.png new file mode 100644 index 0000000..f1ee417 Binary files /dev/null and b/CycloBranch/images/icons/65.png differ diff --git a/CycloBranch/images/icons/66.png b/CycloBranch/images/icons/66.png new file mode 100644 index 0000000..67c373a Binary files /dev/null and b/CycloBranch/images/icons/66.png differ diff --git a/CycloBranch/images/icons/95.png b/CycloBranch/images/icons/95.png new file mode 100644 index 0000000..ab9248a Binary files /dev/null and b/CycloBranch/images/icons/95.png differ diff --git a/CycloBranch/main.cpp b/CycloBranch/main.cpp index e4c75dc..563dfe6 100644 --- a/CycloBranch/main.cpp +++ b/CycloBranch/main.cpp @@ -20,9 +20,9 @@ int main(int argc, char** argv) { QApplication app(argc, argv); Q_INIT_RESOURCE(images); - #if OS_TYPE == UNX + #if OS_TYPE != WIN setlocale(LC_NUMERIC,"C"); - chdir(linuxinstalldir.toStdString().c_str()); + chdir(installdir.toStdString().c_str()); #endif qRegisterMetaType("cParameters"); qRegisterMetaType >("vector"); diff --git a/CycloBranch/parallel/cGraphReaderThread.cpp b/CycloBranch/parallel/cGraphReaderThread.cpp index 8c9e5da..fb488f2 100644 --- a/CycloBranch/parallel/cGraphReaderThread.cpp +++ b/CycloBranch/parallel/cGraphReaderThread.cpp @@ -74,6 +74,16 @@ int cGraphReaderThread::getCandidatesIter(bool cterminalstartingnode, cCandidate } else { cCandidate candidate(composition, perspectivepath, startmodifID, endmodifID, middlemodifID, middlepos); + + if (!cterminalstartingnode && (((parameters->peptidetype == linear) && !parameters->cyclicnterminus && !parameters->cycliccterminus) || (parameters->peptidetype == branched) || (parameters->peptidetype == linearpolysaccharide))) { + if ((candidate.hasLastBrickArtificial(*bricksdatabasewithcombinations)) && (composition.size() > 0)) { + int bid = atoi(composition.back().c_str()) + 1; + composition.pop_back(); + composition.push_back(to_string(bid)); + candidate.setCandidate(composition, perspectivepath, startmodifID, endmodifID, middlemodifID, middlepos); + } + } + if ((candidate.getComposition().compare("") != 0) && (!candidate.hasOnlyArtificialBricks(*bricksdatabasewithcombinations))) { if (isInPpmMassErrorTolerance(precursormass, candidate.getPrecursorMass(*bricksdatabasewithcombinations, parameters), parameters->precursormasserrortolerance)) { diff --git a/CycloBranch/readme-macosx-compile.txt b/CycloBranch/readme-macosx-compile.txt new file mode 100644 index 0000000..5a71b33 --- /dev/null +++ b/CycloBranch/readme-macosx-compile.txt @@ -0,0 +1,18 @@ +Tested on OS X Mountain Lion: + +1) Prerequisities: +- download and install Xcode 4.6.2 (release date 15.4.2013) +- download and install Command Line Tools for Xcode 4.6.2 (OS X Mountain Lion) +- download and install Qt 5.2.1 +- download and install brew and type "brew doctor" +- install boost 1.57.0 using "brew install boost" +- install gcc using "brew install gcc" + +2) Execute the following commands in the directory where CycloBranch is unpacked: +- type "/opt/local/share/Qt5.2.1/5.2.1/clang_64/bin/qmake" +- open "Makefile" using a text editor and correct the following lines: +CC = /usr/local/Cellar/gcc/4.9.2_1/bin/gcc-4.9 +CXX = /usr/local/Cellar/gcc/4.9.2_1/bin/g++-4.9 +LINK = /usr/local/Cellar/gcc/4.9.2_1/bin/g++-4.9 +- type "make" +