diff --git a/src/pappsomspp/processing/tandem/tandemwrapper.cpp b/src/pappsomspp/processing/tandem/tandemwrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a7e71da611232102f787ab81fed8021bcfd3353 --- /dev/null +++ b/src/pappsomspp/processing/tandem/tandemwrapper.cpp @@ -0,0 +1,200 @@ +/** + * \file tandemwrapper.cpp + * \date 25/01/2020 + * \author Olivier Langella + * \brief run tandem directly on Bruker's data + */ + +/******************************************************************************* + * Copyright (c) 2020 Olivier Langella <Olivier.Langella@u-psud.fr>. + * + * This file is part of PAPPSOms-tools. + * + * PAPPSOms-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PAPPSOms-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PAPPSOms-tools. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include "tandemwrapper.h" +#include <QCommandLineParser> +#include <QDateTime> +#include <QTimer> +#include <QFile> +#include <pappsomspp/pappsoexception.h> +#include "tandemwrapperlib/tandemwrapperrun.h" + + +TandemWrapper::TandemWrapper(QObject *parent) : QObject(parent) +{ + // get the instance of the main application + app = QCoreApplication::instance(); + // setup everything here + // create any global objects + // setup debug and warning mode +} + +// 10ms after the application starts this method will run +// all QT messaging is running at this point so threads, signals and slots +// will all work as expected. +void +TandemWrapper::run() +{ + qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}")); + /* ./src/pt-mzxmlconverter -i + /gorgone/pappso/fichiers_fabricants/Bruker/tims_doc/tdf-sdk/example_data/200ngHeLaPASEF_2min_compressed.d/analysis.tdf + -o + /gorgone/pappso/versions_logiciels_pappso/xtpcpp/bruker/200ngHeLaPASEF_2min.mzXML + */ + + //./src/pt-mzxmlconverter -i + /// gorgone/pappso/fichiers_fabricants/Bruker/tims_doc/tdf-sdk/example_data/200ngHeLaPASEF_2min_compressed.d/analysis.tdf + //-o /tmp/test.xml + + + QTextStream errorStream(stderr, QIODevice::WriteOnly); + QTextStream outputStream(stdout, QIODevice::WriteOnly); + + try + { + qDebug(); + QCommandLineParser parser; + + // throw pappso::PappsoException("test"); + parser.setApplicationDescription( + QString("%1 ") + .arg(QCoreApplication::applicationName()) + .append(PAPPSOMSPP_NAME) + .append(" ") + .append(PAPPSOMSPP_VERSION) + .append(" tandem run on Bruker's data")); + parser.addHelpOption(); + parser.addVersionOption(); + QCommandLineOption tandemOption( + QStringList() << "tandem", + QCoreApplication::translate("tandem", + "tandem executable binary file <tandem>."), + QCoreApplication::translate("tandem", "tandem")); + + + QCommandLineOption tmpDirOption( + QStringList() << "t" + << "tmp", + QCoreApplication::translate("tmp", "temporary directory")); + + QCommandLineOption centroidOption( + QStringList() << "centroid", + QCoreApplication::translate("centroid", + "centroid function parameters <centroid>."), + QCoreApplication::translate("centroid", "centroid")); + + + parser.addOption(tandemOption); + parser.addOption(tmpDirOption); + parser.addOption(centroidOption); + + qDebug(); + + // Process the actual command line arguments given by the user + parser.process(*app); + + // QCoreApplication * app(this); + // Add your main code here + qDebug(); + const QDateTime dt_begin = QDateTime::currentDateTime(); + const QStringList args = parser.positionalArguments(); + + + TandemWrapperRun tandem_run(parser.value(tandemOption), + parser.value(tmpDirOption), + parser.value(centroidOption)); + + if(args.size() > 0) + { + tandem_run.run(args[0], outputStream, errorStream); + } + + qDebug(); + } + catch(pappso::PappsoException &error) + { + errorStream << "Oops! an error occurred in PAPPSO MS tools. Dont Panic :" + << endl; + errorStream << error.qwhat() << endl; + exit(1); + app->exit(1); + } + + catch(std::exception &error) + { + errorStream << "Oops! an error occurred in PAPPSO MS tools. Dont Panic :" + << endl; + errorStream << error.what() << endl; + exit(1); + app->exit(1); + } + + + // you must call quit when complete or the program will stay in the + // messaging loop + quit(); +} + +// call this routine to quit the application +void +TandemWrapper::quit() +{ + // you can do some cleanup here + // then do emit finished to signal CoreApplication to quit + emit finished(); +} + +// shortly after quit is called the CoreApplication will signal this routine +// this is a good place to delete any objects that were created in the +// constructor and/or to stop any threads +void +TandemWrapper::aboutToQuitApp() +{ + // stop threads + // sleep(1); // wait for threads to stop. + // delete any objects +} + + +int +main(int argc, char **argv) +{ + // QTextStream consoleErr(stderr); + // QTextStream consoleOut(stdout, QIODevice::WriteOnly); + // ConsoleOut::setCout(new QTextStream(stdout, QIODevice::WriteOnly)); + // ConsoleOut::setCerr(new QTextStream(stderr, QIODevice::WriteOnly)); + qDebug(); + QCoreApplication app(argc, argv); + qDebug(); + QCoreApplication::setApplicationName("tandemwrapper"); + QCoreApplication::setApplicationVersion(PAPPSOMSPP_VERSION); + QLocale::setDefault(QLocale::system()); + + // create the main class + TandemWrapper myMain; + // connect up the signals + QObject::connect(&myMain, SIGNAL(finished()), &app, SLOT(quit())); + QObject::connect( + &app, SIGNAL(aboutToQuit()), &myMain, SLOT(aboutToQuitApp())); + qDebug(); + + + // This code will start the messaging engine in QT and in + // 10ms it will start the execution in the MainClass.run routine; + QTimer::singleShot(10, &myMain, SLOT(run())); + return app.exec(); +} diff --git a/src/pappsomspp/processing/tandem/tandemwrapper.h b/src/pappsomspp/processing/tandem/tandemwrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..36b6c472fd83fbff4c13a20353ec0de1c877ed7e --- /dev/null +++ b/src/pappsomspp/processing/tandem/tandemwrapper.h @@ -0,0 +1,67 @@ +/** + * \file tandemwrapper.h + * \date 25/01/2020 + * \author Olivier Langella + * \brief run tandem directly on Bruker's data + */ + +/******************************************************************************* + * Copyright (c) 2020 Olivier Langella <Olivier.Langella@u-psud.fr>. + * + * This file is part of PAPPSOms-tools. + * + * PAPPSOms-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PAPPSOms-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PAPPSOms-tools. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#pragma once + +#include <QDebug> + +#include <QObject> +#include <QCoreApplication> +#include "../../config.h" + +class TandemWrapper : public QObject +{ + Q_OBJECT + + private: + QCoreApplication *app; + + public: + explicit TandemWrapper(QObject *parent = 0); + ///////////////////////////////////////////////////////////// + /// Call this to quit application + ///////////////////////////////////////////////////////////// + void quit(); + + signals: + ///////////////////////////////////////////////////////////// + /// Signal to finish, this is connected to Application Quit + ///////////////////////////////////////////////////////////// + void finished(); + + public slots: + ///////////////////////////////////////////////////////////// + /// This is the slot that gets called from main to start everything + /// but, everthing is set up in the Constructor + ///////////////////////////////////////////////////////////// + void run(); + + ///////////////////////////////////////////////////////////// + /// slot that get signal when that application is about to quit + ///////////////////////////////////////////////////////////// + void aboutToQuitApp(); +}; diff --git a/src/pappsomspp/processing/tandem/tandemwrapperlib/tandemwrapperrun.cpp b/src/pappsomspp/processing/tandem/tandemwrapperlib/tandemwrapperrun.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e88649fcd0a0e749fe851fc6f7a558358e081889 --- /dev/null +++ b/src/pappsomspp/processing/tandem/tandemwrapperlib/tandemwrapperrun.cpp @@ -0,0 +1,366 @@ +/** + * \file lib/tandemwrapperrun.cpp + * \date 25/01/2020 + * \author Olivier Langella + * \brief actually does really run tandem directly on Bruker's data + */ + +/******************************************************************************* + * Copyright (c) 2020 Olivier Langella <Olivier.Langella@u-psud.fr>. + * + * This file is part of PAPPSOms-tools. + * + * PAPPSOms-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PAPPSOms-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PAPPSOms-tools. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include "tandemwrapperrun.h" +#include <QDebug> +#include <QFileInfo> +#include <QSettings> +#include <pappsomspp/pappsoexception.h> +#include <pappsomspp/msfile/msfileaccessor.h> +#include <pappsomspp/msrun/private/timsmsrunreaderms2.h> +#include <pappsomspp/processing/filters/filterpseudocentroid.h> +#include <pappsomspp/msrun/mzxmloutput.h> +#include "xtandeminputsaxhandler.h" + +TandemWrapperRun::TandemWrapperRun(const QString &tandem_binary, + const QString &tmp_dir, + const QString ¢roid_options) +{ + + setTandemBinaryPath(tandem_binary); + m_centroidOptions = centroid_options; +} + +TandemWrapperRun::~TandemWrapperRun() +{ +} + +void +TandemWrapperRun::setTandemBinaryPath(const QString &tandem_binary_path) +{ + + m_tandemBinary = tandem_binary_path; + QSettings settings; + if(m_tandemBinary.isEmpty()) + { + m_tandemBinary = + settings.value("path/tandem_binary", "/usr/bin/tandem").toString(); + } + // check for tandem executable + m_tandemVersion = checkXtandemVersion(m_tandemBinary); + + qDebug() << m_tandemVersion; + settings.setValue("path/tandem_binary", m_tandemBinary); +} + + +const QString +TandemWrapperRun::checkXtandemVersion(const QString &tandem_bin_path) +{ + qDebug(); + // check tandem path + QFileInfo tandem_exe(tandem_bin_path); + if(!tandem_exe.exists()) + { + // dir.path() returns the unique directory path + throw pappso::PappsoException( + QObject::tr( + "X!Tandem software not found at %1.\nPlease check the X!Tandem " + "installation on your computer and set tandem.exe path.") + .arg(tandem_exe.absoluteFilePath())); + } + if(!tandem_exe.isReadable()) + { + // dir.path() returns the unique directory path + throw pappso::PappsoException( + QObject::tr("Please check permissions on X!Tandem software found at %1 " + "(file not readable).") + .arg(tandem_exe.absoluteFilePath())); + } + if(!tandem_exe.isExecutable()) + { + // dir.path() returns the unique directory path + throw pappso::PappsoException( + QObject::tr("Please check permissions on X!Tandem software found at %1 " + "(file not executable).") + .arg(tandem_exe.absoluteFilePath())); + } + + + QString version_return; + QStringList arguments; + + arguments << "-v"; + + QProcess *xt_process = new QProcess(); + // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath()); + + xt_process->start(tandem_bin_path, arguments); + + if(!xt_process->waitForStarted()) + { + throw pappso::PappsoException( + QObject::tr("X!Tandem %1 process failed to start") + .arg(m_tandemVersion)); + } + + while(xt_process->waitForReadyRead(1000)) + { + } + /* + if (!xt_process->waitForFinished(_max_xt_time_ms)) { + throw pappso::PappsoException(QObject::tr("can't wait for X!Tandem process + to finish : timeout at %1").arg(_max_xt_time_ms)); + } + */ + QByteArray result = xt_process->readAll(); + + + qDebug() << result.constData(); + + // X! TANDEM Jackhammer TPP (2013.06.15.1 - LabKey, Insilicos, ISB) + + QRegExp parse_version("(.*) TANDEM ([A-Z,a-z, ]+) \\(([^ ,^\\)]*)(.*)"); + qDebug() << parse_version; + // Pattern patt = Pattern.compile("X! TANDEM [A-Z]+ \\((.*)\\)", + // Pattern.CASE_INSENSITIVE); + + if(parse_version.exactMatch(result.constData())) + { + version_return = QString("X!Tandem %1 %2") + .arg(parse_version.capturedTexts()[2]) + .arg(parse_version.capturedTexts()[3]); //.join(" "); + } + else + { + throw pappso::PappsoException( + QObject::tr("This executable %1 may not be a valid X!Tandem software. " + "Please check your X!Tandem installation.") + .arg(tandem_bin_path)); + } + + QProcess::ExitStatus Status = xt_process->exitStatus(); + delete xt_process; + if(Status != 0) + { + // != QProcess::NormalExit + throw pappso::PappsoException( + QObject::tr("error executing X!Tandem Status != 0 : %1 %2\n%3") + .arg(tandem_bin_path) + .arg(arguments.join(" ").arg(result.data()))); + } + qDebug(); + return version_return; +} + + +bool +TandemWrapperRun::shouldIstop() +{ + return false; +} + + +void +TandemWrapperRun::readyReadStandardOutput() +{ + *mp_outputStream << m_xtProcess->readAllStandardOutput(); +} + +void +TandemWrapperRun::readyReadStandardError() +{ + *mp_errorStream << m_xtProcess->readAllStandardError(); +} + +void +TandemWrapperRun::writeFinalTandemOutput(const QString &tmp_tandem_output, + const QString &final_tandem_output) +{ +} + + +void +TandemWrapperRun::wrapTandemInputFile(const QString &tandem_input_file) +{ + // read original tandem input file + // store original ms data file name + // create new mzXML data file in temporary directory + // create new tandem input file based on new mzXML file + QString mzxml_data_file_name = "/tmp/msdata.mzxml"; + QString wrapped_tandem_input = "/tmp/input_tandem.xml"; + QString wrapped_tandem_output = "/tmp/output_tandem.xml"; + + XtandemInputSaxHandler wrap_input( + mzxml_data_file_name, wrapped_tandem_input, wrapped_tandem_output); + + QFile qfile(tandem_input_file); + QXmlInputSource xmlInputSource(&qfile); + QXmlSimpleReader simplereader; + simplereader.setContentHandler(&wrap_input); + simplereader.setErrorHandler(&wrap_input); + + if(simplereader.parse(xmlInputSource)) + { + } + else + { + throw pappso::PappsoException( + QObject::tr("Error reading %1 X!Tandem input file :\n %2") + .arg(tandem_input_file) + .arg(wrap_input.errorString())); + } + + // convert to mzXML + QString original_msdata_file_name = wrap_input.getOriginalMsDataFileName(); + convertOrginalMsData2mzXmlData(original_msdata_file_name, + mzxml_data_file_name); + + // launch tandem + runTandem(wrapped_tandem_input); + + // rewrite tandem result file + writeFinalTandemOutput(wrapped_tandem_output, + wrap_input.getOriginalTandemOutputFileName()); +} + +void +TandemWrapperRun::convertOrginalMsData2mzXmlData(const QString &origin, + const QString &target) const +{ + qDebug(); + pappso::MsFileAccessor origin_access(origin, "runa1"); + origin_access.setPreferedFileReaderType(pappso::MzFormat::brukerTims, + pappso::FileReaderType::tims_ms2); + origin_access.getMsRunIds(); + + pappso::MsRunReaderSPtr p_reader; + p_reader = origin_access.msRunReaderSp(origin_access.getMsRunIds().front()); + if(!m_centroidOptions.isEmpty()) + { + pappso::TimsMsRunReaderMs2 *tims2_reader = + dynamic_cast<pappso::TimsMsRunReaderMs2 *>(p_reader.get()); + if(tims2_reader != nullptr) + { + qDebug(); + QStringList option_list = m_centroidOptions.split(" "); + std::shared_ptr<pappso::FilterPseudoCentroid> ms2filter = + std::make_shared<pappso::FilterPseudoCentroid>( + option_list.at(0).toDouble(), + option_list.at(1).toDouble(), + option_list.at(2).toDouble(), + option_list.at(3).toDouble()); + + tims2_reader->setMs2FilterCstSPtr(ms2filter); + qDebug(); + } + } + + + pappso::MzxmlOutput *p_mzxml_output; + QFile output_file(target); + // qDebug() << " TsvDirectoryWriter::writeSheet " << + // QFileInfo(*_p_ofile).absoluteFilePath(); + if(output_file.open(QIODevice::WriteOnly)) + { + p_mzxml_output = + new pappso::MzxmlOutput(QTextStream(&output_file).device()); + + p_mzxml_output->maskMs1(true); + + p_mzxml_output->setReadAhead(true); + + p_mzxml_output->write(p_reader.get()); + + p_mzxml_output->close(); + } + else + { + throw pappso::PappsoException( + tr("unable to write into %1 mzXML output file").arg(target)); + } + + qDebug(); +} + +void +TandemWrapperRun::run(const QString &tandem_input_file, + QTextStream &output_stream, + QTextStream &error_stream) +{ + mp_outputStream = &output_stream; + mp_errorStream = &error_stream; + + wrapTandemInputFile(tandem_input_file); + mp_outputStream = nullptr; + mp_errorStream = nullptr; +} + +void +TandemWrapperRun::runTandem(const QString &tandem_input_file) +{ + + m_xtProcess = new QProcess(); + QStringList arguments; + arguments << tandem_input_file; + // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath()); + m_xtProcess->start(m_tandemBinary, arguments); + + qDebug() << m_tandemBinary << " " << m_xtProcess->arguments(); + + connect(m_xtProcess, + &QProcess::readyReadStandardOutput, + this, + &TandemWrapperRun::readyReadStandardOutput); + connect(m_xtProcess, + &QProcess::readyReadStandardError, + this, + &TandemWrapperRun::readyReadStandardError); + + + if(!m_xtProcess->waitForStarted()) + { + throw pappso::PappsoException( + QObject::tr("X!Tandem process failed to start")); + } + + while(m_xtProcess->waitForFinished(m_maxTandemRunTimeMs)) + { + //_p_monitor->appendText(xt_process->readAll().data()); + // data.append(xt_process->readAll()); + if(shouldIstop()) + { + m_xtProcess->kill(); + delete m_xtProcess; + throw pappso::PappsoException( + QObject::tr("X!Tandem stopped by the user processing on file %1") + .arg(tandem_input_file)); + } + } + + QProcess::ExitStatus Status = m_xtProcess->exitStatus(); + + delete m_xtProcess; + if(Status != 0) + { + // != QProcess::NormalExit + throw pappso::PappsoException( + QObject::tr("error executing X!Tandem Status != 0 : %1") + .arg(m_tandemBinary)); + } + m_xtProcess = nullptr; +} diff --git a/src/pappsomspp/processing/tandem/tandemwrapperlib/tandemwrapperrun.h b/src/pappsomspp/processing/tandem/tandemwrapperlib/tandemwrapperrun.h new file mode 100644 index 0000000000000000000000000000000000000000..416bf87da97ec5fa06a39f70ee77622529c6da74 --- /dev/null +++ b/src/pappsomspp/processing/tandem/tandemwrapperlib/tandemwrapperrun.h @@ -0,0 +1,107 @@ +/** + * \file lib/tandemwrapperrun.h + * \date 25/01/2020 + * \author Olivier Langella + * \brief actually does really run tandem directly on Bruker's data + */ + +/******************************************************************************* + * Copyright (c) 2020 Olivier Langella <Olivier.Langella@u-psud.fr>. + * + * This file is part of PAPPSOms-tools. + * + * PAPPSOms-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PAPPSOms-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PAPPSOms-tools. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#pragma once + +#include <QDebug> +#include <QObject> +#include <QProcess> + +/** + * @todo write docs + */ +class TandemWrapperRun : public QObject +{ + Q_OBJECT + public: + /** @brief prepare a tandem run + * @param tandem_binary file path to tandem.exe if not set, a default value is + * given in QSettings + * @param tmp_dir temporary directory, where to write mzXML file conversion if + * not set, a default value is given in QSettings + * @param centroid_options controls the way MS2 spectrum are centroided from + * raw bruker's data if not set, a default value is given in QSettings + */ + TandemWrapperRun(const QString &tandem_binary, + const QString &tmp_dir, + const QString ¢roid_options); + + /** @brief run a tandem job + * @param tandem_input_file tandem xml input file + * @param output_stream standard output where to write tandem stdout + * @param error_stream standard error where to write tandem stderr + */ + void run(const QString &tandem_input_file, + QTextStream &output_stream, + QTextStream &error_stream); + + /** + * Destructor + */ + ~TandemWrapperRun(); + + private: + void setTandemBinaryPath(const QString &tandem_binary_path); + bool shouldIstop(); + const QString checkXtandemVersion(const QString &tandem_bin_path); + void wrapTandemInputFile(const QString &tandem_input_file); + + void convertOrginalMsData2mzXmlData(const QString &origin, + const QString &target) const; + + + /** @brief run a tandem job + * @param tandem_input_file tandem xml input file + */ + void runTandem(const QString &tandem_input_file); + + /** @brief tandem output modification + * tandem output is modified to contain the Bruker's file as input and + * centroidization parameters + * @param tmp_tandem_output raw tandem output filename + * @param final_tandem_output final destination file for modified tandem + * output + */ + void writeFinalTandemOutput(const QString &tmp_tandem_output, + const QString &final_tandem_output); + + + private slots: + void readyReadStandardOutput(); + void readyReadStandardError(); + + private: + QString m_tandemBinary; + QString m_tandemVersion; + QString m_tmpDir; + QString m_centroidOptions; + int m_maxTandemRunTimeMs = (60000 * 60 * 24); // 1 day + QProcess *m_xtProcess = nullptr; + + QTextStream *mp_outputStream = nullptr; + QTextStream *mp_errorStream = nullptr; +}; diff --git a/src/pappsomspp/processing/tandem/tandemwrapperlib/xtandeminputsaxhandler.cpp b/src/pappsomspp/processing/tandem/tandemwrapperlib/xtandeminputsaxhandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d46f082250aa813da1506250818f2a2f910cfcb8 --- /dev/null +++ b/src/pappsomspp/processing/tandem/tandemwrapperlib/xtandeminputsaxhandler.cpp @@ -0,0 +1,306 @@ +/** + * \file lib/xtandeminputsaxhandler.cpp + * \date 25/01/2020 + * \author Olivier Langella + * \brief rewrites tandem xml input file with temporary files + */ + +/******************************************************************************* + * Copyright (c) 2020 Olivier Langella <Olivier.Langella@u-psud.fr>. + * + * This file is part of PAPPSOms-tools. + * + * PAPPSOms-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PAPPSOms-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PAPPSOms-tools. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + + +#include "xtandeminputsaxhandler.h" +#include <pappsomspp/pappsoexception.h> +#include <QFileInfo> + +XtandemInputSaxHandler::XtandemInputSaxHandler( + const QString &destinationMzXmlFile, + const QString &destinationTandemInputFile, + const QString &destinationTandemOutputFile) + : m_destinationTandemInputFile(destinationTandemInputFile) +{ + m_destinationMzXmlFileName = destinationMzXmlFile; + m_destinationTandemOutputFileName = destinationTandemOutputFile; + m_destinationTandemInputFileName = + QFileInfo(destinationTandemInputFile).absoluteFilePath(); + + m_destinationTandemInputFile.open(QIODevice::WriteOnly); + p_writeXmlTandemInput = new QXmlStreamWriter(); + p_writeXmlTandemInput->setDevice(&m_destinationTandemInputFile); +} + +XtandemInputSaxHandler::~XtandemInputSaxHandler() +{ + m_destinationTandemInputFile.close(); + delete p_writeXmlTandemInput; +} + +void +XtandemInputSaxHandler::writeOpenTag(const QString &qName, + const QXmlAttributes &attributes) +{ + p_writeXmlTandemInput->writeStartElement(qName); + for(std::size_t i = 0; i < attributes.length(); i++) + { + p_writeXmlTandemInput->writeAttribute(attributes.qName(i), + attributes.value(i)); + } +} + +bool +XtandemInputSaxHandler::startElement(const QString &namespaceURI, + const QString &localName, + const QString &qName, + const QXmlAttributes &attributes) +{ + /* +<?xml version="1.0" encoding="UTF-8"?> +<bioml label="20191222_18_EF1_test_condor_22janv_third_step.xml"> +<note type="heading">Paths</note> +<note type="input" label="list path, default +parameters">/gorgone/pappso/jouy/presets/metapappso/Lumos_04112019_PROTEOCARDIS_THIRD_STEP_AB.xml</note> +<note type="input" label="list path, taxonomy +information">/gorgone/pappso/jouy/users/Celine/2019_Lumos/20191222_107_Juste_APD/metapappso_condor/params/xtandem_database_third_step_test_condor_22janv.database</note> +<note type="input" label="spectrum, +path">/gorgone/pappso/jouy/raw/2019_Lumos/20191222_107_Juste/20191222_18_EF1.mzXML</note> +<note type="heading">Protein general</note> +<note type="input" label="protein, taxon">usedefined</note> +<note type="heading">Output</note> +<note type="input" label="output, +path">/gorgone/pappso/jouy/users/Celine/2019_Lumos/20191222_107_Juste_APD/metapappso_condor/test_run/20191222_18_EF1_third_step_test_condor_22janv.xml</note> +</bioml> +*/ + m_tagStack.push_back(qName); + bool is_ok = true; + + try + { + m_currentText.clear(); + //<bioml label="example api document"> + if(m_tagStack.size() == 1) + { + if(qName != "bioml") + { + m_errorString = QObject::tr( + "ERROR in XtandemInputSaxHandler::startElement " + "root tag %1 is not <bioml>") + .arg(qName); + m_isTandemParameter = false; + return false; + } + else + { + + m_isTandemParameter = true; + // label="20191222_18_EF1_test_condor_22janv_third_step.xml" + m_labelName = attributes.value("label"); + + writeOpenTag(qName, attributes); + } + } + // startElement_group + + if(qName == "note") + { + is_ok = startElement_note(attributes); + } + } + catch(pappso::PappsoException exception_pappso) + { + m_errorString = QObject::tr( + "ERROR in XtandemInputSaxHandler::startElement " + "tag %1, PAPPSO exception:\n%2") + .arg(qName) + .arg(exception_pappso.qwhat()); + return false; + } + catch(std::exception exception_std) + { + m_errorString = QObject::tr( + "ERROR in XtandemInputSaxHandler::startElement " + "tag %1, std exception:\n%2") + .arg(qName) + .arg(exception_std.what()); + return false; + } + return is_ok; +} + +bool +XtandemInputSaxHandler::endElement(const QString &namespaceURI, + const QString &localName, + const QString &qName) +{ + + bool is_ok = true; + // endElement_peptide_list + try + { + + if(qName == "note") + { + is_ok = endElement_note(); + } + else + { + p_writeXmlTandemInput->writeCharacters(m_currentText); + p_writeXmlTandemInput->writeEndElement(); + } + } + catch(pappso::PappsoException exception_pappso) + { + m_errorString = QObject::tr( + "ERROR in XtandemInputSaxHandler::endElement tag " + "%1, PAPPSO exception:\n%2") + .arg(qName) + .arg(exception_pappso.qwhat()); + return false; + } + catch(std::exception exception_std) + { + m_errorString = QObject::tr( + "ERROR in XtandemInputSaxHandler::endElement tag " + "%1, std exception:\n%2") + .arg(qName) + .arg(exception_std.what()); + return false; + } + + m_currentText.clear(); + m_tagStack.pop_back(); + + return is_ok; +} + +bool +XtandemInputSaxHandler::startDocument() +{ + + p_writeXmlTandemInput->setAutoFormatting(true); + p_writeXmlTandemInput->writeStartDocument("1.0"); + return true; +} + +bool +XtandemInputSaxHandler::endDocument() +{ + p_writeXmlTandemInput->writeEndDocument(); + return true; +} + +bool +XtandemInputSaxHandler::characters(const QString &str) +{ + m_currentText += str; + return true; +} + + +bool +XtandemInputSaxHandler::error(const QXmlParseException &exception) +{ + m_errorString = QObject::tr( + "Parse error at line %1, column %2 :\n" + "%3") + .arg(exception.lineNumber()) + .arg(exception.columnNumber()) + .arg(exception.message()); + qDebug() << m_errorString; + return false; +} + + +bool +XtandemInputSaxHandler::fatalError(const QXmlParseException &exception) +{ + m_errorString = QObject::tr( + "Parse error at line %1, column %2 :\n" + "%3") + .arg(exception.lineNumber()) + .arg(exception.columnNumber()) + .arg(exception.message()); + qDebug() << m_errorString; + return false; +} + +QString +XtandemInputSaxHandler::errorString() const +{ + return m_errorString; +} + + +bool +XtandemInputSaxHandler::startElement_note(QXmlAttributes attributes) +{ + // qDebug() << "XtandemParamSaxHandler::startElement_note begin " << + // <note type="input" + // label="output,path">/gorgone/pappso/jouy/users/Celine/2019_Lumos/20191222_107_Juste_APD/metapappso_condor/test_run/20191222_18_EF1_third_step_test_condor_22janv.xml</note> + + writeOpenTag("note", attributes); + m_currentLabel = ""; + + if(attributes.value("type") == "input") + { + m_currentLabel = attributes.value("label"); + } + + // qDebug() << "XtandemParamSaxHandler::startElement_note _current_label " << + // _current_label; + return true; +} + +bool +XtandemInputSaxHandler::endElement_note() +{ + // qDebug() << "XtandemParamSaxHandler::endElement_note begin " << + // _current_label << " " << _current_text.simplified(); + if(m_currentLabel == "output, path") + { + m_originTandemOutpuFileName = m_currentText; + p_writeXmlTandemInput->writeCharacters(m_destinationTandemOutputFileName); + } + else if(m_currentLabel == "spectrum, path") + { + //<note type="input" + // label="spectrum,path">/gorgone/pappso/jouy/raw/2019_Lumos/20191222_107_Juste/20191222_18_EF1.mzXML</note> + m_originMzDataFileName = m_currentText; + p_writeXmlTandemInput->writeCharacters(m_destinationMzXmlFileName); + } + else + { + p_writeXmlTandemInput->writeCharacters(m_currentText); + } + p_writeXmlTandemInput->writeEndElement(); + return true; +} + + +const QString & +XtandemInputSaxHandler::getOriginalMsDataFileName() const +{ + return m_originMzDataFileName; +} + +const QString & +XtandemInputSaxHandler::getOriginalTandemOutputFileName() const +{ + return m_originTandemOutpuFileName; +} diff --git a/src/pappsomspp/processing/tandem/tandemwrapperlib/xtandeminputsaxhandler.h b/src/pappsomspp/processing/tandem/tandemwrapperlib/xtandeminputsaxhandler.h new file mode 100644 index 0000000000000000000000000000000000000000..697f3296f31f9d7942016dda28a947dee252fd52 --- /dev/null +++ b/src/pappsomspp/processing/tandem/tandemwrapperlib/xtandeminputsaxhandler.h @@ -0,0 +1,95 @@ +/** + * \file lib/xtandeminputsaxhandler.h + * \date 25/01/2020 + * \author Olivier Langella + * \brief rewrites tandem xml input file with temporary files + */ + +/******************************************************************************* + * Copyright (c) 2020 Olivier Langella <Olivier.Langella@u-psud.fr>. + * + * This file is part of PAPPSOms-tools. + * + * PAPPSOms-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PAPPSOms-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PAPPSOms-tools. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#pragma once + +#include <QDebug> +#include <QXmlDefaultHandler> +#include <QXmlStreamWriter> +/** + * @todo write docs + */ +class XtandemInputSaxHandler : public QXmlDefaultHandler +{ + public: + /** + * Default constructor + */ + XtandemInputSaxHandler(const QString &destinationMzXmlFile, + const QString &destinationTandemInputFile, + const QString &destinationTandemOutputFile); + + /** + * Destructor + */ + ~XtandemInputSaxHandler(); + + + bool startElement(const QString &namespaceURI, + const QString &localName, + const QString &qName, + const QXmlAttributes &attributes) override; + + bool endElement(const QString &namespaceURI, + const QString &localName, + const QString &qName) override; + + bool startDocument() override; + + bool endDocument() override; + + bool characters(const QString &str) override; + + bool fatalError(const QXmlParseException &exception) override; + bool error(const QXmlParseException &exception) override; + + QString errorString() const; + + const QString &getOriginalMsDataFileName() const; + const QString &getOriginalTandemOutputFileName() const; + + private: + bool startElement_note(QXmlAttributes attributes); + bool endElement_note(); + void writeOpenTag(const QString &qName, const QXmlAttributes &attributes); + + + private: + QString m_destinationMzXmlFileName; + QString m_originMzDataFileName; + QString m_destinationTandemInputFileName; + QString m_originTandemOutpuFileName; + QString m_destinationTandemOutputFileName; + QFile m_destinationTandemInputFile; + QXmlStreamWriter *p_writeXmlTandemInput; + std::vector<QString> m_tagStack; + bool m_isTandemParameter = false; + QString m_errorString; + QString m_currentText; + QString m_currentLabel; + QString m_labelName; +};