--- /dev/null
+#-------------------------------------------------
+#
+# Project created by QtCreator 2013-10-28T18:00:16
+#
+#-------------------------------------------------
+
+QT += core gui
+QT -= qml_debug
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = Anyanka
+TEMPLATE = app
+
+unix {
+ LIBS += -ldl
+ QMAKE_CXXFLAGS += -std=c++11 -Wall
+}
+
+INCLUDEPATH += libAGRE
+# Add project root directory to work around VC11 include path scheme
+INCLUDEPATH += "./"
+
+SOURCES += main.cpp\
+ datafilesloader.cpp \
+ agreinterface.cpp \
+ datamanager.cpp \
+ signal.cpp \
+ singlerundata.cpp \
+ gui/mainwindow.cpp \
+ logger.cpp \
+ gui/signalview.cpp \
+ locallogger.cpp \
+ gui/graphview.cpp \
+ signalcontroller.cpp \
+ integratedpeak.cpp \
+ sequence.cpp \
+ sequenceselectormodel.cpp \
+ singlerunsselectormodel.cpp \
+ signaldatatablemodel.cpp \
+ gui/graphviewcontextmenu.cpp \
+ integrator.cpp \
+ integrationtablemodel.cpp \
+ gui/aboutanyanka.cpp \
+ globalinfo.cpp
+
+HEADERS += \
+ datafilesloader.h \
+ agreinterface.h \
+ datamanager.h \
+ signal.h \
+ singlerundata.h \
+ gui/mainwindow.h \
+ logger.h \
+ gui/signalview.h \
+ locallogger.h \
+ gui/graphview.h \
+ signalcontroller.h \
+ metatypes.h \
+ mathhelpers.h \
+ integratedpeak.h \
+ sequence.h \
+ sequenceselectormodel.h \
+ singlerunsselectormodel.h \
+ signaldatatablemodel.h \
+ gui/graphviewcontextmenu.h \
+ integrator.h \
+ integrationtablemodel.h \
+ gui/aboutanyanka.h \
+ globalinfo.h
+
+FORMS += \
+ gui/mainwindow.ui \
+ gui/signalview.ui \
+ gui/aboutanyanka.ui
+
+RESOURCES += \
+ imgresources.qrc
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "agreinterface.h"
+#include "logger.h"
+#include <QDebug>
+#ifdef Q_OS_UNIX
+#include <dlfcn.h>
+#elif defined Q_OS_WIN32
+#include <windows.h>
+#endif
+
+#ifdef Q_OS_UNIX
+#define __LIBRARY_NAME "libAGRE.so"
+#elif defined Q_OS_WIN
+#define __LIBRARY_NAME "libAGRE.dll"
+#endif
+
+#ifdef Q_OS_UNIX
+IAGRE_Reader* (*AGREInterface::m_create_reader)(bool)(nullptr);
+#elif defined Q_OS_WIN
+IAGRE_Reader* (__cdecl* AGREInterface::m_create_reader)(bool)(NULL);
+#endif
+AGREInterface* AGREInterface::m_instance(nullptr);
+
+const QString AGREInterface::AGRE_LIBRARY_NAME(__LIBRARY_NAME);
+const QString AGREInterface::ME_SENDER_STR("AGREInterface");
+
+/* Public static methods */
+
+AGREInterface* AGREInterface::instance()
+{
+ if (m_instance == nullptr)
+ m_instance = new AGREInterface();
+ return m_instance;
+}
+
+AGREInterface::AGREInterface(QObject* parent) :
+ QObject(parent),
+ m_inited(false),
+ m_lastAGREError(AGRE_ReturnCode::SUCCESS),
+ m_readerIFace(nullptr)
+{
+}
+
+AGREInterface::ReturnCode AGREInterface::initialize()
+{
+ if (m_inited)
+ return ReturnCode::SUCCESS;
+
+#ifdef Q_OS_UNIX
+ m_libagre_handle = dlopen(__LIBRARY_NAME, RTLD_LAZY);
+ if (m_libagre_handle == nullptr) {
+#elif defined Q_OS_WIN
+ m_libagre_handle = LoadLibrary(TEXT(__LIBRARY_NAME));
+ if (m_libagre_handle == NULL) {
+#endif
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Library " + AGRE_LIBRARY_NAME + " could not have been loaded.");
+ return ReturnCode::E_NO_LIBRARY;
+ }
+
+#ifdef Q_OS_UNIX
+ m_create_reader = (IAGRE_Reader* (*)(bool))dlsym(m_libagre_handle, "create_agre_reader");
+ if (m_create_reader == nullptr) {
+#elif defined Q_OS_WIN
+ m_create_reader = (IAGRE_Reader* (__cdecl*)(bool))GetProcAddress(static_cast<HINSTANCE>(m_libagre_handle), "create_agre_reader");
+ if (m_create_reader == NULL) {
+#endif
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "create_agre_reader symbol could not have been resloved.");
+ return ReturnCode::E_CANNOT_RESOLVE;
+ }
+
+
+ m_readerIFace = m_create_reader(true);
+ if (m_readerIFace == nullptr) {
+ m_create_reader = nullptr;
+#ifdef Q_OS_UNIX
+ dlclose(m_libagre_handle);
+#elif defined Q_OS_WIN
+ FreeLibrary(static_cast<HINSTANCE>(m_libagre_handle));
+#endif
+ return ReturnCode::E_CANNOT_GET_IFACE;
+ }
+
+ m_inited = true;
+ return ReturnCode::SUCCESS;
+}
+
+/* ENDOF public static methods */
+
+/* Public methods */
+
+const std::vector<std::string>* AGREInterface::debugAGREInfo()
+{
+ if (!m_inited)
+ return nullptr;
+
+ return &m_readerIFace->debug_info_list();
+}
+
+AGREInterface::ReturnCode AGREInterface::readFile(const std::string& fileName, std::shared_ptr<AGRE_MeasurementInfo>& minfo)
+{
+ AGRE_ReturnCode ret;
+
+ if (!m_inited)
+ return ReturnCode::E_NOT_INITED;
+ ret = m_readerIFace->read_file(fileName, minfo);
+ if (ret != AGRE_ReturnCode::SUCCESS) {
+ m_lastAGREError = ret;
+ return ReturnCode::E_CANNOT_READ_FILE;
+ }
+
+ return ReturnCode::SUCCESS;
+}
+
+AGREInterface::~AGREInterface()
+{
+ m_inited = false;
+
+ m_readerIFace->destroy_agre_reader();
+#ifdef Q_OS_UNIX
+ dlclose(m_libagre_handle);
+#elif defined Q_OS_WIN
+ FreeLibrary(static_cast<HMODULE>(m_libagre_handle));
+#endif
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+
+#ifndef AGREINTERFACE_H
+#define AGREINTERFACE_H
+
+#include <iagre_reader.h>
+#include <QtCore/QObject>
+
+class AGREInterface : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(AGREInterface)
+
+public:
+ enum class ReturnCode {
+ SUCCESS,
+ E_NO_LIBRARY,
+ E_CANNOT_RESOLVE,
+ E_CANNOT_GET_IFACE,
+ E_NOT_INITED,
+ E_CANNOT_READ_FILE
+ };
+
+ const std::vector<std::string>* debugAGREInfo();
+ AGRE_ReturnCode lastAGREError() { AGRE_ReturnCode r = m_lastAGREError; m_lastAGREError = AGRE_ReturnCode::SUCCESS; return r; }
+ ReturnCode initialize();
+ static AGREInterface* instance();
+ ReturnCode readFile(const std::string& fileName, std::shared_ptr<AGRE_MeasurementInfo>& minfo);
+
+ static const QString AGRE_LIBRARY_NAME;
+ static const QString ME_SENDER_STR;
+
+private:
+ explicit AGREInterface(QObject* parent = 0);
+ ~AGREInterface();
+
+ bool m_inited;
+ AGRE_ReturnCode m_lastAGREError;
+ IAGRE_Reader* m_readerIFace;
+
+#ifdef Q_OS_UNIX
+ static IAGRE_Reader* (*m_create_reader)(bool collect_debug);
+#elif defined Q_OS_WIN
+ static IAGRE_Reader* (__cdecl* m_create_reader)(bool collect_debug);
+#endif
+ void* m_libagre_handle;
+
+ static AGREInterface* m_instance;
+
+signals:
+
+public slots:
+
+};
+
+#endif // AGREINTERFACE_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "datafilesloader.h"
+#include "logger.h"
+#include <QtWidgets/QMessageBox>
+#include <QDebug>
+
+const QString DataFilesLoader::ME_SENDER_STR("DataFilesLoader");
+
+DataFilesLoader::DataFilesLoader(QObject *parent) :
+ QObject(parent)
+{
+ m_supportedFileTypes << "*.ch";
+}
+
+DataFilesLoader::ReturnCode DataFilesLoader::loadSingleRun(const QDir& path, std::vector<std::shared_ptr<AGRE_MeasurementInfo>>& dataFiles)
+{
+ for (const QString& s : path.entryList(m_supportedFileTypes, QDir::Files | QDir::NoDotAndDotDot)) {
+ std::shared_ptr<AGRE_MeasurementInfo> minfo = nullptr;
+ QString absPath = path.absoluteFilePath(s);
+
+ AGREInterface::ReturnCode ret = AGREInterface::instance()->readFile(absPath.toStdString(), minfo);
+ if (ret == AGREInterface::ReturnCode::SUCCESS)
+ dataFiles.push_back(minfo);
+ else if (ret == AGREInterface::ReturnCode::E_NOT_INITED) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "AGREInterface has not been initialized.");
+ QMessageBox::critical(nullptr, "AGREInterface error", "AGRE interface has not been initialized. This should not happen!\n"
+ "Application cannot continue.");
+ exit(1);
+ } else {
+ QString errDesc = errorToString(AGREInterface::instance()->lastAGREError());
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, "Error reading file '" + s + "'" + errDesc);
+ const std::vector<std::string>* const dbgMsgs = AGREInterface::instance()->debugAGREInfo();
+ if (dbgMsgs == nullptr)
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Null pointer to debug messages list. This should not happen!\n");
+ else {
+ for (const std::string& s : *dbgMsgs)
+ Logger::log(Logger::Level::INFO, ME_SENDER_STR, QString("AGRE debug:") + QString(s.c_str()));
+ }
+ QMessageBox::warning(nullptr, "Error reading file '" + s + "'", errDesc);
+ return ReturnCode::E_READ_ERROR;
+ }
+ }
+
+ if (dataFiles.size() == 0)
+ return ReturnCode::E_NO_FILES;
+
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, QString::number(dataFiles.size()) + " files were found and successfully parsed");
+
+ return ReturnCode::SUCCESS;
+}
+
+QString DataFilesLoader::errorToString(const AGRE_ReturnCode errorCode)
+{
+ switch (errorCode) {
+ case AGRE_ReturnCode::E_CANNOT_OPEN_FILE:
+ return "Cannot open file.";
+ case AGRE_ReturnCode::E_CORRUPTED_FILE:
+ return "File is corrupted.";
+ case AGRE_ReturnCode::E_INVALID_FILE:
+ return "File does not appear to be a ChemStation data file.";
+ case AGRE_ReturnCode::E_OUT_OF_RANGE:
+ return "File is too short to be a ChemStation data file.";
+ case AGRE_ReturnCode::E_READ_FAILED:
+ return "An error occured during reading.";
+ default:
+ return "Unspecified error " + QString::number(static_cast<int>(errorCode));
+ }
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef DATAFILESLOADER_H
+#define DATAFILESLOADER_H
+
+#include "agreinterface.h"
+#include <QtCore/QDir>
+#include <QtCore/QObject>
+
+class DataFilesLoader : public QObject
+{
+ Q_OBJECT
+public:
+ enum class ReturnCode {
+ SUCCESS,
+ E_NO_FILES,
+ E_READ_ERROR,
+ E_FATAL
+ };
+
+ explicit DataFilesLoader(QObject* parent = 0);
+ ReturnCode loadSingleRun(const QDir& path, std::vector<std::shared_ptr<AGRE_MeasurementInfo>>& dataFiles);
+
+private:
+ QStringList m_supportedFileTypes;
+
+ QString errorToString(const AGRE_ReturnCode errorCode);
+
+ static const QString ME_SENDER_STR;
+
+signals:
+
+public slots:
+
+};
+
+#endif // DATAFILESLOADER_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "datamanager.h"
+#include "logger.h"
+#include <QtWidgets/QMessageBox>
+
+#include <QDebug>
+
+const QString DataManager::ME_SENDER_STR("DataManager");
+const char DataManager::UNIT_KILOVOLTS_TEXT[] = {0x4B, 0x56, 0x00};
+const char DataManager::UNIT_MICROAMPERES_TEXT[] = {static_cast<char>(0xB5), 0x41, 0x00};
+const char DataManager::UNIT_MILLIAU_TEXT[] = {0x6D, 0x41, 0x55, 0x00};
+const char DataManager::UNIT_MILLIVOLTS_TEXT[] = {0x6D, 0x56, 0x00};
+const char DataManager::UNIT_WATTS_TEXT[] = {0x57, 0x00};
+const QStringList DataManager::DATA_DIR_SUFFIX = { "*.D" };
+
+DataManager::DataManager(QObject* parent) :
+ QObject(parent),
+ m_sequenceRejected(false)
+{
+ m_sequences.push_back(std::make_pair<const QString, std::shared_ptr<Sequence>>("Single runs", std::shared_ptr<Sequence>(new Sequence())));
+ m_seqSelModel.setSequences(&m_sequences);
+ m_sigNameCodec = QTextCodec::codecForName("ISO-8859-1");
+}
+
+std::shared_ptr<Sequence> DataManager::sequenceByKey(const QString& key)
+{
+ for (NameSequencePair p : m_sequences) {
+ if (p.first.compare(key) == 0)
+ return p.second;
+ }
+ return nullptr;
+}
+
+int DataManager::sequenceIdxByKey(const QString& key)
+{
+ int idx = 0;
+ for (NameSequencePair p : m_sequences) {
+ qDebug() << p.first << key;
+ if (p.first.compare(key) == 0)
+ return idx;
+ idx++;
+ }
+ return -1;
+}
+
+Signal::Equipment DataManager::equipmentFromFiletype(AGRE_Filetype filetype)
+{
+ switch (filetype) {
+ case AGRE_Filetype::CE_CCD:
+ case AGRE_Filetype::CE_CURRENT:
+ case AGRE_Filetype::CE_DAD:
+ case AGRE_Filetype::CE_POWER:
+ case AGRE_Filetype::CE_VOLTAGE:
+ return Signal::Equipment::CE;
+ default:
+ throw std::invalid_argument("Invalid type of file");
+ }
+}
+
+Signal::Resource DataManager::resourceFromFiletype(AGRE_Filetype filetype)
+{
+ switch (filetype) {
+ case AGRE_Filetype::CE_CCD:
+ return Signal::Resource::CE_CCD;
+ case AGRE_Filetype::CE_CURRENT:
+ return Signal::Resource::CE_CURRENT;
+ case AGRE_Filetype::CE_DAD:
+ return Signal::Resource::CE_DAD;
+ case AGRE_Filetype::CE_POWER:
+ return Signal::Resource::CE_POWER;
+ case AGRE_Filetype::CE_VOLTAGE:
+ return Signal::Resource::CE_VOLTAGE;
+ default:
+ throw std::invalid_argument("Invalid type of signal");
+ }
+}
+
+std::string DataManager::signalControllerKey(const QString& main, const QString& resource)
+{
+ return std::string(main.toStdString() + "_" + resource.toStdString());
+}
+
+Signal::YUnit DataManager::yunitFromUnitStr(const std::string& unit_str)
+{
+ static const QString LATIN_KILOVOLTS = QString::fromLatin1(DataManager::UNIT_KILOVOLTS_TEXT);
+ static const QString LATIN_MICROAMPERS = QString::fromLatin1(DataManager::UNIT_MICROAMPERES_TEXT);
+ static const QString LATIN_MILLIAU = QString::fromLatin1(DataManager::UNIT_MILLIAU_TEXT);
+ static const QString LATIN_MILLIVOLTS = QString::fromLatin1(DataManager::UNIT_MILLIVOLTS_TEXT);
+ static const QString LATIN_WATTS = QString::fromLatin1(DataManager::UNIT_WATTS_TEXT);
+ QString str = m_sigNameCodec->toUnicode(unit_str.c_str());
+
+ if (QString::compare(str, LATIN_MILLIVOLTS) == 0)
+ return Signal::YUnit::MILLIVOLTS;
+ else if (QString::compare(str, LATIN_KILOVOLTS) == 0)
+ return Signal::YUnit::KILOVOLTS;
+ else if (QString::compare(str, LATIN_MICROAMPERS) == 0)
+ return Signal::YUnit::MICROAMPERES;
+ else if (QString::compare(str, LATIN_MILLIAU) == 0)
+ return Signal::YUnit::MILLIAU;
+ else if (QString::compare(str, LATIN_WATTS) == 0)
+ return Signal::YUnit::WATTS;
+ else
+ throw std::invalid_argument(str.toStdString());
+}
+
+std::shared_ptr<SingleRunData> DataManager::loadSingleRun(QDir& dir)
+{
+ std::vector<std::shared_ptr<AGRE_MeasurementInfo>> dataFiles;
+ std::shared_ptr<SingleRunData> singleRun;
+ std::vector<std::shared_ptr<Signal>> sigs;
+ DataFilesLoader::ReturnCode ret;
+ LocalLoggerPtr llog = Logger::createLocalLog();
+ llog->setPrintLevel(Logger::Level::WARNING);
+
+ ret = m_dfl.loadSingleRun(dir, dataFiles);
+ if (ret == DataFilesLoader::ReturnCode::E_NO_FILES) {
+ QMessageBox::warning(nullptr, ME_SENDER_STR, "Directory " + dir.path() + " does not contain any ChemStation data files.");
+ return nullptr;
+ }
+ if (ret != DataFilesLoader::ReturnCode::SUCCESS) {
+ return nullptr;
+ }
+
+ QStringList operatorNames;
+ QStringList methodNames;
+ QStringList sampleInfos;
+ QList<QDate> dates;
+ QList<QTime> times;
+ for (std::shared_ptr<AGRE_MeasurementInfo> mi : dataFiles) {
+ Signal::Equipment eqp;
+ Signal::Resource res;
+ double samplingRate;
+ Signal::YUnit yu;
+ QDate date(mi->year, mi->month, mi->day);
+ QTime time(mi->hour, mi->minute, mi->second);
+ QString operatorName;
+ QString methodName;
+ QString sampleInfo;
+
+ operatorName = QString::fromStdString(mi->operator_name);
+ methodName = QString::fromStdString(mi->method_name);
+ sampleInfo = QString::fromStdString(mi->sample_info);
+
+ try {
+ eqp = equipmentFromFiletype(mi->file_type);
+ } catch (std::invalid_argument& ia) {
+ llog->log(Logger::ERROR, ME_SENDER_STR, ia.what());
+ continue;
+ }
+ try {
+ res = resourceFromFiletype(mi->file_type);
+ } catch (std::invalid_argument& ia) {
+ llog->log(Logger::ERROR, ME_SENDER_STR, ia.what());
+ continue;
+ }
+ try {
+ yu = yunitFromUnitStr(mi->y_units);
+ } catch (std::invalid_argument& ia) {
+ llog->log(Logger::ERROR, ME_SENDER_STR, QString("Invalid units ") + ia.what());
+ continue;
+ }
+ samplingRate = mi->sampling_rate;
+
+ /* Fill values */
+ std::vector<Signal::TimeValuePair> values;
+ for (const AGRE_TimeValuePair& tvp : mi->val_tbl) {
+ Signal::TimeValuePair stvp(tvp.first, tvp.second);
+ values.push_back(stvp);
+ }
+ std::shared_ptr<Signal> _s(new Signal(eqp, res, samplingRate, yu, mi->dad_wavelength_abs, mi->dad_wavelength_ref, values));
+ sigs.push_back(_s);
+
+ if (!date.isValid()) {
+ llog->log(Logger::WARNING, ME_SENDER_STR, QString("Date ") + date.toString() + QString("is invalid."));
+ } else
+ dates.append(date);
+ if (!time.isValid()) {
+ llog->log(Logger::WARNING, ME_SENDER_STR, QString("Time ") + time.toString() + QString("is invalid."));
+ } else
+ times.append(time);
+
+ operatorNames.append(operatorName);
+ methodNames.append(methodName);
+ sampleInfos.append(sampleInfo);
+ }
+
+ /* Check that all common run informaton are the same */
+ for (int i = 1; i < operatorNames.size(); i++) {
+ if (QString::compare(operatorNames.at(i-1), operatorNames.at(i)) != 0) {
+ QString w;
+ w += "Operator name in file " + QString::number(i-1) + " (" + operatorNames.at(i-1) + ") does not match that in file " + QString::number(i) + " (" + operatorNames.at(i) + ")";
+ llog->log(Logger::WARNING, ME_SENDER_STR, w);
+ }
+ }
+ for (int i = 1; i < methodNames.size(); i++) {
+ if (QString::compare(methodNames.at(i-1), methodNames.at(i)) != 0) {
+ QString w;
+ w += "Method name in file " + QString::number(i-1) + " (" + methodNames.at(i-1) + ") does not match that in file " + QString::number(i) + " (" + methodNames.at(i) + ")";
+ llog->log(Logger::WARNING, ME_SENDER_STR, w);
+ }
+ }
+ for (int i = 1; i < sampleInfos.size(); i++) {
+ if (QString::compare(sampleInfos.at(i-1), sampleInfos.at(i)) != 0) {
+ QString w;
+ w += "Sample info in file " + QString::number(i-1) + " (" + sampleInfos.at(i-1) + ") does not match that in file " + QString::number(i) + " (" + sampleInfos.at(i) + ")";
+ llog->log(Logger::WARNING, ME_SENDER_STR, w);
+ }
+ }
+ for (int i = 1; i < dates.size(); i++) {
+ if (dates.at(i-1) != dates.at(i)) {
+ QString w;
+ w += "Date in file " + QString::number(i-1) + " (" + dates.at(i-1).toString() + ") does not match that in file " + QString::number(i) + " (" + dates.at(i).toString() + ")";
+ llog->log(Logger::WARNING, ME_SENDER_STR, w);
+ }
+ }
+ for (int i = 1; i < times.size(); i++) {
+ if (times.at(i-1) != times.at(i)) {
+ QString w;
+ w += "Date in file " + QString::number(i-1) + " (" + times.at(i-1).toString() + ") does not match that in file" + QString::number(i) + " (" + times.at(i).toString() + ")";
+ llog->log(Logger::WARNING, ME_SENDER_STR, w);
+ }
+ }
+
+ singleRun = std::shared_ptr<SingleRunData>(new SingleRunData(methodNames.at(0), operatorNames.at(0), sampleInfos.at(0), dates.at(0), times.at(0), sigs,
+ dir.dirName(), this));
+
+ Logger::log(Logger::DEBUG, ME_SENDER_STR, "Single run successfully parsed");
+
+ return singleRun;
+}
+
+void DataManager::showOneSignal(std::shared_ptr<SignalController> ctrl)
+{
+ SignalView* swp = new SignalView();
+
+ swp->setDataTableModel(ctrl->dataTableModel());
+ swp->setIntegrationTableModel(ctrl->integrationTableModel());
+ swp->setTypeText(ctrl->signal()->resourceToString());
+ swp->setXUnits(ctrl->signal()->xunitToString());
+ swp->setYUnits(ctrl->signal()->yunitToString());
+ connect(swp, SIGNAL(crosshairErased()), ctrl.get(), SLOT(onViewCrosshairErased()));
+ connect(swp, SIGNAL(crosshairMoved(int,int)), ctrl.get(), SLOT(onViewCrosshairMoved(int,int)));
+ connect(swp, SIGNAL(integrated(int,int,int,int)), ctrl.get(), SLOT(onViewIntegrated(int,int,int,int)));
+ connect(swp, SIGNAL(redrawNeeded()), ctrl.get(), SLOT(onViewRedrawNeeded()));
+ connect(swp, SIGNAL(resized(int,int)), ctrl.get(), SLOT(onViewResized(int,int)));
+ connect(swp, SIGNAL(showContextMenu(int,int,QPoint)), ctrl.get(), SLOT(onViewShowContextMenu(int,int,QPoint)));
+ connect(swp, SIGNAL(zoomed(int,int,int,int)), ctrl.get(), SLOT(onViewZoomed(int,int,int,int)));
+ connect(ctrl.get(), SIGNAL(guiDrawGraph(double*,size_t,double,double)), swp, SLOT(onUpdateGraph(double*,size_t,double,double)));
+ connect(ctrl.get(), SIGNAL(viewCtxMenuClosed()), swp, SLOT(onCtxMenuClosed()));
+ connect(ctrl.get(), SIGNAL(viewDrawIntegration(int,double,int,double,int,double,QString,QString,bool)), swp,
+ SLOT(onDrawIntegration(int,double,int,double,int,double,QString,QString,bool)));
+ connect(ctrl.get(), SIGNAL(viewUpdateCurrentValues(double,double)), swp, SLOT(onUpdateCurrentValues(double,double)));
+ connect(ctrl.get(), SIGNAL(viewRemoveCurrentValues()), swp, SLOT(onRemoveCurrentValues()));
+ emit addToDashboard(swp);
+
+ ctrl->draw();
+}
+
+/* Public slots */
+
+void DataManager::onLoadSequence(const QString& dir)
+{
+ QDir rootDir(dir);
+ QString uniqueName;
+ int nameSuffix = 1;
+ bool isUnique = false;
+ std::shared_ptr<Sequence> nSeq(new Sequence());
+
+ for (const QString& subPath : rootDir.entryList(DATA_DIR_SUFFIX, QDir::Dirs | QDir::NoDotAndDotDot)) {
+ QDir subDir(rootDir.absoluteFilePath(subPath));
+ std::shared_ptr<SingleRunData> srdata = loadSingleRun(subDir);
+ if (srdata == nullptr)
+ continue;
+
+ nSeq->add(subPath, srdata);
+ }
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, "Single runs loaded, count: " + QString::number(nSeq->count()));
+ if (nSeq->count() < 1) {
+ QMessageBox::warning(nullptr, "Data loading", "This directory does not appear to contain ChemStation sequence.");
+ return;
+ }
+
+ /* Generate unique name for the sequence */
+ uniqueName = rootDir.dirName();
+ while (!isUnique) {
+ for (const NameSequencePair& nsp : m_sequences) {
+ if (nsp.first.compare(uniqueName) == 0) {
+ if (nameSuffix == 1)
+ uniqueName += QString("_1");
+ else
+ uniqueName.replace(uniqueName.length()-1, 1, QString::number(nameSuffix));
+ nameSuffix++;
+ } else
+ isUnique = true;
+ }
+ }
+
+ /* Create signal controllers */
+ for (const SingleRunPair& srp : *nSeq) {
+ std::shared_ptr<SingleRunData> srdata = srp.second;
+ for (size_t idx = 0; idx < srdata->signalCount(); idx++) {
+ std::shared_ptr<SignalController> controller(new SignalController(srdata->signalAt(idx)));
+ nSeq->addController(signalControllerKey(srdata->dirName(), srdata->signalAt(idx)->uidString()), controller);
+ }
+ qDebug() << srp.first;
+ }
+
+ m_sequences.push_back(NameSequencePair(uniqueName, nSeq));
+ m_seqSelModel.seqenceAdded();
+
+ emit setActiveSequenceIndex(m_sequences.size()-1);
+}
+
+void DataManager::onLoadSingleRun(const QString& str)
+{
+ QString uniqueName;
+ int nameSuffix = 1;
+ std::shared_ptr<Sequence> srseq = m_sequences.at(0).second;
+ QDir dir(str);
+ std::shared_ptr<SingleRunData> srdata = loadSingleRun(dir);
+ if (srdata == nullptr)
+ return;
+
+ /* Generate unique name for the single run data */
+ uniqueName = dir.dirName();
+ while (srseq->find(uniqueName) != srseq->end()) {
+ Logger::log(Logger::Level::INFO, ME_SENDER_STR, "[" + uniqueName + "]: Already there, adjusting.");
+ if (nameSuffix == 1) {
+ uniqueName += QString("_1");
+ } else {
+ uniqueName.replace(uniqueName.length()-1, 1, QString::number(nameSuffix));
+ }
+ nameSuffix++;
+ }
+
+ /* Create signal controllers */
+ for (size_t idx = 0; idx < srdata->signalCount(); idx++) {
+ std::shared_ptr<SignalController> controller(new SignalController(srdata->signalAt(idx)));
+ srseq->addController(signalControllerKey(srdata->dirName(), srdata->signalAt(idx)->uidString()), controller);
+ }
+
+ srseq->add(uniqueName, srdata);
+ srseq->setSelectedRunKey(uniqueName);
+ emit setActiveSequenceIndex(0);
+}
+
+void DataManager::onSequenceSelected(const QString& key)
+{
+ if (m_sequenceRejected) {
+ m_sequenceRejected = false;
+ return;
+ }
+
+ m_activeSequence = sequenceByKey(key);
+ if (m_activeSequence == nullptr) {
+ Logger::log(Logger::Level::ERROR, ME_SENDER_STR, "[" + key + "]: No such sequence.");
+ m_activeSequence = sequenceByKey(m_prevSequenceKey);
+ m_sequenceRejected = true;
+ emit setActiveSequenceIndex(sequenceIdxByKey(m_prevSequenceKey));
+ return;
+ }
+
+ if (m_activeSequence->count() < 1) {
+ Logger::log(Logger::Level::ERROR, ME_SENDER_STR, "There are no runs in sequence [" + key + "].");
+ QMessageBox::information(nullptr, "Data manager", "Sequence '" + key + "' does not contain any runs.");
+ /* Revert to previous sequence */
+ m_activeSequence = sequenceByKey(m_prevSequenceKey);
+ m_sequenceRejected = true;
+ emit setActiveSequenceIndex(sequenceIdxByKey(m_prevSequenceKey));
+ return;
+ }
+
+ m_prevSequenceKey = key;
+ m_singleSelModel.setSingleRuns(m_activeSequence->allRuns());
+ emit setActiveSingleRunIndex(m_activeSequence->selectedRunIdx());
+}
+
+void DataManager::onSingleRunSelected(const QString& key)
+{
+ qDebug() << "SRKEY" << key;
+ if (m_activeSequence == nullptr)
+ return;
+
+ std::vector<SingleRunPair>::iterator it = m_activeSequence->find(key);
+ if (it == m_activeSequence->end()) {
+ Logger::log(Logger::Level::ERROR, ME_SENDER_STR, "[" + key + "]: No such single run.");
+ return;
+ }
+
+ m_activeSequence->setSelectedRunKey(key);
+
+ std::shared_ptr<SingleRunData> srdata = it->second;
+ emit cleanDashboard();
+ for (size_t idx = 0; idx < srdata->signalCount(); idx++) {
+ std::shared_ptr<SignalController> controller = m_activeSequence->controller(signalControllerKey(srdata->dirName(), srdata->signalAt(idx)->uidString()));
+ if (controller == nullptr) {
+ Logger::log(Logger::Level::ERROR, ME_SENDER_STR, "[" + srdata->dirName() + srdata->signalAt(idx)->uidString() + "]: No such controller.");
+ continue;
+ }
+ showOneSignal(controller);
+ }
+
+ emit setSingleRunInfo(srdata->methodName(), srdata->operatorName(), srdata->sampleInfo(), srdata->date().toString() +" "+ srdata->time().toString());
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, "Single run changed.");
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef DATAMANAGER_H
+#define DATAMANAGER_H
+
+#include "datafilesloader.h"
+#include "gui/signalview.h"
+#include "sequence.h"
+#include "sequenceselectormodel.h"
+#include "singlerunsselectormodel.h"
+#include <exception>
+#include <QtCore/QDate>
+#include <QtCore/QObject>
+#include <QtCore/QTextCodec>
+#include <QtCore/QTime>
+#include "metatypes.h"
+
+
+class DataManager : public QObject
+{
+ Q_OBJECT
+public:
+ explicit DataManager(QObject* parent = nullptr);
+ SequenceSelectorModel* sequenceSelectorModel() { return &m_seqSelModel; }
+ SingleRunsSelectorModel* singleRunsSelectorModel() { return &m_singleSelModel; }
+
+private:
+ Signal::Equipment equipmentFromFiletype(AGRE_Filetype filetype);
+ std::shared_ptr<Sequence> sequenceByKey(const QString& key);
+ int sequenceIdxByKey(const QString& key);
+ std::shared_ptr<SingleRunData> loadSingleRun(QDir& dir);
+ Signal::Resource resourceFromFiletype(AGRE_Filetype filetype);
+ std::string signalControllerKey(const QString& main, const QString& resource) ;
+ void showOneSignal(std::shared_ptr<SignalController> ctrl);
+ Signal::YUnit yunitFromUnitStr(const std::string& unit_str);
+
+ std::shared_ptr<Sequence> m_activeSequence;
+ QString m_prevSequenceKey;
+ QString m_prevSingleRunKey;
+ SequenceSelectorModel m_seqSelModel;
+ bool m_sequenceRejected;
+ SingleRunsSelectorModel m_singleSelModel;
+ QTextCodec* m_sigNameCodec;
+ std::vector<NameSequencePair> m_sequences;
+ DataFilesLoader m_dfl;
+
+ static const QString ME_SENDER_STR;
+ static const char UNIT_KILOVOLTS_TEXT[];
+ static const char UNIT_MICROAMPERES_TEXT[];
+ static const char UNIT_MILLIAU_TEXT[];
+ static const char UNIT_MILLIVOLTS_TEXT[];
+ static const char UNIT_WATTS_TEXT[];
+
+ static const QStringList DATA_DIR_SUFFIX;
+
+signals:
+ void addToDashboard(SignalView* sw);
+ void cleanDashboard();
+ void setActiveSequenceIndex(const int idx);
+ void setActiveSingleRunIndex(const int idx);
+ void setSingleRunInfo(const QString& method, const QString& operatorname, const QString& sample, const QString& datetime);
+
+public slots:
+ void onLoadSequence(const QString& dir);
+ void onLoadSingleRun(const QString& dir);
+ void onSequenceSelected(const QString& key);
+ void onSingleRunSelected(const QString& key);
+
+
+};
+
+#endif // DATAMANAGER_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "globalinfo.h"
+
+const int GlobalInfo::APP_VERSION_MAJ(0);
+const int GlobalInfo::APP_VERSION_MIN(1);
+const QString GlobalInfo::APP_VERSION_REV("a");
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef GLOBALINFO_H
+#define GLOBALINFO_H
+
+#include <QtCore/QString>
+
+class GlobalInfo {
+private:
+ GlobalInfo(){}
+
+public:
+ static QString APP_VERSION_STRING() { return QString::number(GlobalInfo::APP_VERSION_MAJ) + "." + QString::number(GlobalInfo::APP_VERSION_MIN) +
+ GlobalInfo::APP_VERSION_REV; }
+
+ static const int APP_VERSION_MAJ;
+ static const int APP_VERSION_MIN;
+ static const QString APP_VERSION_REV;
+};
+
+#endif // GLOBALINFO_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "aboutanyanka.h"
+#include "ui_aboutanyanka.h"
+
+#include <QDebug>
+
+AboutAnyanka::AboutAnyanka(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::AboutAnyanka)
+{
+ ui->setupUi(this);
+ ui->ql_version->setText(GlobalInfo::APP_VERSION_STRING());
+ ui->ql_qtVersion->setText(qVersion());
+ ui->ql_qtLogo->setPixmap(QPixmap("://resources/Qt_master_logo.png").scaled(ui->ql_qtLogo->size(), Qt::KeepAspectRatio,
+ Qt::SmoothTransformation));
+}
+
+AboutAnyanka::~AboutAnyanka()
+{
+ delete ui;
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef ABOUTANYANKA_H
+#define ABOUTANYANKA_H
+
+#include "globalinfo.h"
+#include <QtWidgets/QDialog>
+
+namespace Ui {
+ class AboutAnyanka;
+}
+
+class AboutAnyanka : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AboutAnyanka(QWidget* parent = nullptr);
+ ~AboutAnyanka();
+
+private:
+ Ui::AboutAnyanka *ui;
+};
+
+#endif // ABOUTANYANKA_H
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AboutAnyanka</class>
+ <widget class="QDialog" name="AboutAnyanka">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>363</width>
+ <height>313</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <widget class="QLabel" name="ql_appName">
+ <property name="geometry">
+ <rect>
+ <x>115</x>
+ <y>13</y>
+ <width>121</width>
+ <height>41</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>22</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Anyanka</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="ql_versionCap">
+ <property name="geometry">
+ <rect>
+ <x>135</x>
+ <y>60</y>
+ <width>53</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Version:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="ql_version">
+ <property name="geometry">
+ <rect>
+ <x>185</x>
+ <y>60</y>
+ <width>41</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>-</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="ql_qtLogo">
+ <property name="geometry">
+ <rect>
+ <x>115</x>
+ <y>100</y>
+ <width>131</width>
+ <height>111</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>logo</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="ql_qtVersionCap">
+ <property name="geometry">
+ <rect>
+ <x>90</x>
+ <y>280</y>
+ <width>151</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Using Qt 5 libraries version:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="ql_qtVersion">
+ <property name="geometry">
+ <rect>
+ <x>244</x>
+ <y>280</y>
+ <width>41</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>-</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="ql_bunnies">
+ <property name="geometry">
+ <rect>
+ <x>62</x>
+ <y>240</y>
+ <width>240</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>11</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>"Fear nothing except for bunnies!"</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "gui/graphview.h"
+
+GraphView::GraphView(QWidget *parent) :
+ QLabel(parent)
+{
+ setMouseTracking(true);
+}
+
+void GraphView::leaveEvent(QEvent *)
+{
+ emit mouseCursorLeft();
+}
+
+void GraphView::mouseMoveEvent(QMouseEvent* ev)
+{
+ emit mouseMoved(ev->x(), ev->y());
+}
+
+void GraphView::mousePressEvent(QMouseEvent* ev)
+{
+ emit mouseButtonTriggered(ev->x(), ev->y(), ev->button(), ev->type(), ev->globalPos());
+}
+
+void GraphView::resizeEvent(QResizeEvent* ev)
+{
+ if (ev->size().width() > 1 && ev->size().height() > 1)
+ emit redrawNeeded();
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef GRAPHVIEW_H
+#define GRAPHVIEW_H
+
+#include <QtGui/QMouseEvent>
+#include <QtWidgets/QLabel>
+
+class GraphView : public QLabel
+{
+ Q_OBJECT
+public:
+ explicit GraphView(QWidget* parent = nullptr);
+ void leaveEvent(QEvent* );
+ void mouseMoveEvent(QMouseEvent* ev);
+ void mousePressEvent(QMouseEvent* ev);
+
+private:
+ void resizeEvent(QResizeEvent* ev);
+
+public slots:
+
+signals:
+ void mouseCursorLeft();
+ void mouseMoved(const int x, const int y);
+ void mouseButtonTriggered(const int x, const int y, Qt::MouseButton button, QEvent::Type type, const QPoint& globalPos);
+ void redrawNeeded();
+};
+
+#endif // GRAPHVIEW_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "graphviewcontextmenu.h"
+
+GraphViewContextMenu::GraphViewContextMenu(QWidget* parent) :
+ QMenu(parent)
+{
+ m_acZoomOut = addAction("Zoom out");
+ addSeparator();
+ m_acDeletePeak = addAction("Delete peak");
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+
+#ifndef GRAPHVIEWCONTEXTMENU_H
+#define GRAPHVIEWCONTEXTMENU_H
+
+#include <QtWidgets/QMenu>
+
+class GraphViewContextMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ explicit GraphViewContextMenu(QWidget* parent = nullptr);
+
+ QAction* m_acDeletePeak;
+ QAction* m_acZoomOut;
+
+private:
+
+signals:
+
+public slots:
+
+};
+
+#endif // GRAPHVIEWCONTEXTMENU_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+
+#include "gui/mainwindow.h"
+#include "ui_mainwindow.h"
+#include <QVBoxLayout>
+
+#include <QDebug>
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+ m_dashboard = new QSplitter(Qt::Vertical, this);
+ m_dashboard->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding);
+ ui->qsca_dataView->setWidget(m_dashboard);
+
+ connectActions();
+
+ m_loadDataFileDialog = new QFileDialog(this);
+ m_loadDataFileDialog->setFileMode(QFileDialog::Directory);
+ m_loadDataFileDialog->setOptions(QFileDialog::ReadOnly);
+}
+
+/* Public methods */
+void MainWindow::setSequenceListModel(SequenceSelectorModel* model)
+{
+ ui->qcbox_sequence->setModel(model);
+}
+
+void MainWindow::setSingleRunsListModel(SingleRunsSelectorModel* model)
+{
+ ui->qcbox_singleRun->setModel(model);
+}
+
+/* Private methods */
+
+#ifdef Q_OS_UNIX
+void MainWindow::connectActions() noexcept
+#elif defined Q_OS_WIN
+void MainWindow::connectActions()
+#endif
+{
+ /* Controls panel */
+ connect(ui->qpb_integrate, SIGNAL(pressed()), this, SLOT(onIntegrateSelected()));
+ connect(ui->qpb_zoom, SIGNAL(pressed()), this, SLOT(onZoomSelected()));
+ connect(ui->actionLoad_single_run, SIGNAL(triggered()), this, SLOT(onLoadSingleRun()));
+ connect(ui->actionLoad_sequence, SIGNAL(triggered()), this, SLOT(onLoadSequence()));
+ connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(onAboutAnyanka()));
+ connect(ui->qcbox_sequence, SIGNAL(currentIndexChanged(QString)), this, SLOT(onSequenceSelected(QString)));
+ connect(ui->qcbox_singleRun, SIGNAL(currentIndexChanged(QString)), this, SLOT(onSingleRunSelected(QString)));
+}
+
+/* Public slots */
+void MainWindow::onAddToDashboard(SignalView* sw)
+{
+ if (ui->qpb_integrate->isChecked())
+ sw->setControlMode(GraphControlModes::INTEGRATE);
+ else if(ui->qpb_zoom->isChecked())
+ sw->setControlMode(GraphControlModes::ZOOM);
+
+ //m_itemsOnDashboard.push_back(sw);
+ connect(this, SIGNAL(controlModeChanged(GraphControlModes)), sw, SLOT(onControlModeChanged(GraphControlModes)));
+ m_dashboard->addWidget(sw);
+}
+
+void MainWindow::onCleanDashboard()
+{
+ while (m_dashboard->count() > 0)
+ delete m_dashboard->widget(0);
+}
+
+void MainWindow::onSetActiveSequenceIndex(const int idx)
+{
+ if (ui->qcbox_sequence->currentIndex() == idx)
+ emit onSequenceSelected(ui->qcbox_sequence->currentText());
+ else
+ ui->qcbox_sequence->setCurrentIndex(idx);
+}
+
+void MainWindow::onSetActiveSingleRunIndex(const int idx)
+{
+ ui->qcbox_singleRun->setCurrentIndex(idx);
+}
+
+void MainWindow::onSetSingleRunInfo(const QString &method, const QString &operatorname, const QString &sample, const QString &datetime)
+{
+ ui->qle_methodName->setText(method);
+ ui->qle_operatorName->setText(operatorname);
+ ui->qle_sampleInfo->setText(sample);
+ ui->qle_dateTime->setText(datetime);
+}
+
+/* Private slots */
+void MainWindow::onAboutAnyanka()
+{
+ AboutAnyanka aa(this);
+ aa.exec();
+}
+
+void MainWindow::onIntegrateSelected()
+{
+ emit controlModeChanged(GraphControlModes::INTEGRATE);
+}
+void MainWindow::onLoadSequence()
+{
+ if (m_loadDataFileDialog->exec() == QDialog::Accepted)
+ emit loadSequence(m_loadDataFileDialog->selectedFiles()[0]);
+}
+
+void MainWindow::onLoadSingleRun()
+{
+ if (m_loadDataFileDialog->exec() == QDialog::Accepted) {
+ qDebug() << "Chosen file" << m_loadDataFileDialog->selectedFiles();
+ emit loadSingleRun(m_loadDataFileDialog->selectedFiles()[0]);
+ }
+}
+
+void MainWindow::onZoomSelected()
+{
+ emit controlModeChanged(GraphControlModes::ZOOM);
+}
+
+/* Private slots */
+void MainWindow::onSequenceSelected(const QString &str)
+{
+ emit sequenceSelected(str);
+}
+
+void MainWindow::onSingleRunSelected(const QString &str)
+{
+ emit singleRunSelected(str);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include "aboutanyanka.h"
+#include "sequenceselectormodel.h"
+#include "singlerunsselectormodel.h"
+#include "signalview.h"
+#include <memory>
+#include <QtWidgets/QFileDialog>
+#include <QtWidgets/QMainWindow>
+#include <QtWidgets/QSplitter>
+#include "metatypes.h"
+
+namespace Ui {
+ class MainWindow;
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget* parent = 0);
+ ~MainWindow();
+ void setSequenceListModel(SequenceSelectorModel* model);
+ void setSingleRunsListModel(SingleRunsSelectorModel* model);
+
+private:
+#ifdef Q_OS_UNIX
+ void connectActions() noexcept;
+#elif defined Q_OS_WIN
+ void connectActions();
+#endif
+
+ //std::vector<SignalView*> m_itemsOnDashboard;
+ QSplitter* m_dashboard;
+ QFileDialog* m_loadDataFileDialog;
+ Ui::MainWindow *ui;
+
+public slots:
+ void onAddToDashboard(SignalView* sw);
+ void onCleanDashboard();
+ void onSetActiveSequenceIndex(const int idx);
+ void onSetActiveSingleRunIndex(const int idx);
+ void onSetSingleRunInfo(const QString& method, const QString& operatorname, const QString& sample, const QString& datetime);
+
+private slots:
+ void onAboutAnyanka();
+ void onIntegrateSelected();
+ void onLoadSequence();
+ void onLoadSingleRun();
+ void onSequenceSelected(const QString& str);
+ void onSingleRunSelected(const QString& str);
+ void onZoomSelected();
+
+signals:
+ void controlModeChanged(GraphControlModes mode);
+ void loadSequence(const QString& dir);
+ void loadSingleRun(const QString& dir);
+ void sequenceSelected(const QString& str);
+ void singleRunSelected(const QString& str);
+};
+
+#endif // MAINWINDOW_H
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Anyanka</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="ql_sequence">
+ <property name="text">
+ <string>Sequence:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="ql_singleRun">
+ <property name="text">
+ <string>Run:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="qcbox_sequence"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="qcbox_singleRun"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="qgbox_controls">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QPushButton" name="qpb_zoom">
+ <property name="text">
+ <string>Zoom</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="autoExclusive">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QPushButton" name="qpb_integrate">
+ <property name="text">
+ <string>Integrate</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="autoExclusive">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="qf_singleRunInfo">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="1" column="0">
+ <widget class="QLabel" name="ql_sampleInfo">
+ <property name="text">
+ <string>Sample info:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="ql_operatorName">
+ <property name="text">
+ <string>Operator:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="ql_methodName">
+ <property name="text">
+ <string>Method name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QLineEdit" name="qle_operatorName">
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLineEdit" name="qle_methodName">
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QLineEdit" name="qle_sampleInfo">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QLabel" name="ql_dateTime">
+ <property name="text">
+ <string>Date/Time:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QLineEdit" name="qle_dateTime">
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="qsca_dataView">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>780</width>
+ <height>336</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>19</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuData">
+ <property name="title">
+ <string>Data</string>
+ </property>
+ <addaction name="actionLoad_single_run"/>
+ <addaction name="actionLoad_sequence"/>
+ </widget>
+ <widget class="QMenu" name="menuHelp">
+ <property name="title">
+ <string>Help</string>
+ </property>
+ <addaction name="actionAbout"/>
+ </widget>
+ <addaction name="menuData"/>
+ <addaction name="menuHelp"/>
+ </widget>
+ <widget class="QStatusBar" name="statusbar">
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <action name="actionLoad_single_run">
+ <property name="text">
+ <string>Load single run</string>
+ </property>
+ </action>
+ <action name="actionLoad_sequence">
+ <property name="text">
+ <string>Load sequence</string>
+ </property>
+ </action>
+ <action name="actionAbout">
+ <property name="text">
+ <string>About</string>
+ </property>
+ </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+
+#include "gui/signalview.h"
+#include "ui_signalview.h"
+#include "mathhelpers.h"
+#include <cmath>
+#include <QtGui/QFontMetrics>
+#include <QtGui/QPainter>
+
+#include <QDebug>
+
+SignalView::SignalView(QWidget *parent) :
+ QWidget(parent),
+ m_graph(nullptr),
+ m_graphPlain(nullptr),
+ m_graphData(nullptr),
+ m_ctxMenuOpen(false),
+ m_mouseMode(SignalView::MouseMode::CROSSHAIR),
+ ui(new Ui::SignalView)
+{
+ ui->setupUi(this);
+ m_graphPainter = new QPainter();
+ m_graphCrosshairX = -1;
+ m_graphCrosshairY = -1;
+ m_integrateStartX = -1;
+
+ connect(ui->qw_graphView, SIGNAL(mouseCursorLeft()), this, SLOT(onGraphViewMouseCursorLeft()));
+ connect(ui->qw_graphView, SIGNAL(mouseMoved(int,int)), this, SLOT(onGraphViewMouseMoved(int,int)));
+ connect(ui->qw_graphView, SIGNAL(mouseButtonTriggered(int,int,Qt::MouseButton,QEvent::Type,QPoint)), this,
+ SLOT(onMouseButtonTriggered(int,int,Qt::MouseButton,QEvent::Type,QPoint)));
+ connect(ui->qw_graphView, SIGNAL(redrawNeeded()), this, SLOT(onGraphRedrawNeeded()));
+}
+
+/* Public functions */
+void SignalView::setControlMode(GraphControlModes mode)
+{
+ m_graphCtrlMode = mode;
+}
+
+void SignalView::setDataTableModel(SignalDataTableModel* model)
+{
+ ui->qtblv_signalDataTable->setModel(model);
+}
+
+void SignalView::setIntegrationTableModel(IntegrationTableModel *model)
+{
+ ui->qtblv_integrationTable->setModel(model);
+}
+
+void SignalView::setTypeText(const QString &text)
+{
+ ui->ql_signalType->setText(text);
+}
+
+void SignalView::setXUnits(const QString &text)
+{
+ ui->ql_xUnits->setText(text);
+}
+
+void SignalView::setYUnits(const QString &text)
+{
+ ui->ql_yUnits->setText(text);
+}
+
+/* Private functions */
+
+void SignalView::drawCrosshair(const int x, const int y)
+{
+ int w, h;
+ if (m_graph == nullptr)
+ return;
+ w = ui->qw_graphView->width();
+ h = ui->qw_graphView->height();
+
+ m_graphPainter->begin(m_graph);
+ m_graphPainter->setPen(Qt::black);
+ /* Draw new crosshair */
+ m_graphPainter->drawLine(0, y, w, y); /* Horizontal */
+ m_graphPainter->drawLine(x, 0, x, h); /* Vertical */
+ m_graphPainter->end();
+
+ m_graphCrosshairX = x;
+ m_graphCrosshairY = y;
+
+ ui->qw_graphView->setPixmap(*m_graph);
+
+}
+
+void SignalView::drawIntegrationBaseline(const int x, const int y)
+{
+ if (m_graph == nullptr)
+ return;
+ m_graphPainter->begin(m_graph);
+ /* Draw new line */
+ m_graphPainter->setPen(Qt::black);
+ m_graphPainter->drawLine(m_integrateStartX, m_integrateStartY, x, y);
+ m_graphPainter->end();
+
+ m_integrateStopX = x;
+ m_integrateStopY = y;
+
+ ui->qw_graphView->setPixmap(*m_graph);
+}
+
+void SignalView::drawZoomRect(const int x, const int y)
+{
+ int startX, startY, stopX, stopY;
+ if (m_graph == nullptr)
+ return;
+
+ if (x < m_zoomRectStartX) {
+ startX = x;
+ stopX = m_zoomRectStartX;
+ } else {
+ startX = m_zoomRectStartX;
+ stopX = x;
+ }
+ if (y < m_zoomRectStartY) {
+ startY = y;
+ stopY = m_zoomRectStartY;
+ } else {
+ startY = m_zoomRectStartY;
+ stopY = y;
+ }
+
+ eraseZoomRect();
+
+ m_graphPainter->begin(m_graph);
+ m_graphPainter->setPen(Qt::green);
+ // Top line
+ m_graphPainter->drawLine(startX, startY, stopX, startY);
+ // Left line
+ m_graphPainter->drawLine(startX, startY, startX, stopY);
+ // Right line
+ m_graphPainter->drawLine(stopX, startY, stopX, stopY);
+ // Bottom line
+ m_graphPainter->drawLine(startX, stopY, stopX, stopY);
+
+ m_zoomRectLastX = x;
+ m_zoomRectLastY = y;
+
+ m_graphPainter->end();
+
+ ui->qw_graphView->setPixmap(*m_graph);
+}
+
+void SignalView::eraseCrosshair(bool apply)
+{
+ int w, h;
+ if (m_graph == nullptr)
+ return;
+ w = ui->qw_graphView->width();
+ h = ui->qw_graphView->height();
+
+ if (m_graphCrosshairX != -1 || m_graphCrosshairY != -1) {
+ m_graphPainter->begin(m_graph);
+ m_graphPainter->drawPixmap(m_graphCrosshairX, 0, *m_graphPlain, m_graphCrosshairX, 0, 1, h);
+ m_graphPainter->drawPixmap(0, m_graphCrosshairY, *m_graphPlain, 0, m_graphCrosshairY, w, 1);
+ m_graphPainter->end();
+ if (apply)
+ ui->qw_graphView->setPixmap(*m_graph);
+ }
+}
+
+void SignalView::eraseIntegrationBaseline(bool apply)
+{
+ int lstartX, lstartY, lstopX, lstopY;
+ int w, h;
+
+ if (m_graph == nullptr)
+ return;
+ if (m_integrateStartX < 0)
+ return;
+
+ w = ui->qw_graphView->width();
+ h = ui->qw_graphView->height();
+
+ if (m_integrateStartX > m_integrateStopX) {
+ lstartX = (m_integrateStopX > 1) ? m_integrateStopX - 1 : 0;
+ lstopX = (m_integrateStartX < w-1) ? m_integrateStartX + 1 : w-1;
+ } else {
+ lstartX = (m_integrateStartX > 1) ? m_integrateStartX -1 : 0;
+ lstopX = (m_integrateStopX < w-1) ? m_integrateStopX + 1 : w-1;
+ }
+ if (m_integrateStartY > m_integrateStopY) {
+ lstartY = (m_integrateStopY > 1) ? m_integrateStopY - 1 : 0;
+ lstopY = (m_integrateStartY < h-1) ? m_integrateStartY + 1 : h-1;
+ } else {
+ lstartY = (m_integrateStartY > 1) ? m_integrateStartY - 1 : 0;
+ lstopY = (m_integrateStopY < h-1) ? m_integrateStopY + 1 : h-1;
+ }
+
+ m_graphPainter->begin(m_graph);
+ m_graphPainter->drawPixmap(lstartX, lstartY, *m_graphPlain, lstartX, lstartY, lstopX - lstartX+1, lstopY - lstartY+1); //FIXME: +1 should not be needed!
+ m_graphPainter->end();
+
+ if (apply)
+ ui->qw_graphView->setPixmap(*m_graph);
+}
+
+void SignalView::eraseZoomRect(bool apply)
+{
+ int lstartX, lstartY, lstopX, lstopY;
+ if (m_graph == nullptr)
+ return;
+
+ if (m_zoomRectLastX < m_zoomRectStartX) {
+ lstartX = m_zoomRectLastX;
+ lstopX = m_zoomRectStartX;
+ } else {
+ lstartX = m_zoomRectStartX;
+ lstopX = m_zoomRectLastX;
+ }
+ if (m_zoomRectLastY < m_zoomRectStartY) {
+ lstartY = m_zoomRectLastY;
+ lstopY = m_zoomRectStartY;
+ } else {
+ lstartY = m_zoomRectStartY;
+ lstopY = m_zoomRectLastY;
+ }
+
+ m_graphPainter->begin(m_graph);
+ /* Erase any existing lines */
+ // TODO: It might not be necessary to erase all lines every time - OPTIMIZE THIS !!!
+ // Top line
+ m_graphPainter->drawPixmap(lstartX, lstartY, *m_graphPlain, lstartX, lstartY, lstopX - lstartX, 1);
+ // Left line
+ m_graphPainter->drawPixmap(lstartX, lstartY, *m_graphPlain, lstartX, lstartY, 1, lstopY - lstartY);
+ // Right line
+ m_graphPainter->drawPixmap(lstopX, lstartY, *m_graphPlain, lstopX, lstartY, 1, lstopY - lstartY + 1);
+ // Bottom line
+ m_graphPainter->drawPixmap(lstartX, lstopY, *m_graphPlain, lstartX, lstopY, lstopX - lstartX + 1, 1);
+ m_graphPainter->end();
+
+ if (apply)
+ ui->qw_graphView->setPixmap(*m_graph);
+}
+
+void SignalView::redrawGraph()
+{
+ int w = ui->qw_graphView->width();
+ int h = ui->qw_graphView->height();
+ uint lastColumn = 0;
+ double yAvg = 0;
+ double yStep;
+ QPixmap* fresh = new QPixmap(w, h);
+
+ if (m_graphData == nullptr)
+ return;
+ if (w < 1 || h < 1)
+ return;
+
+ fresh->fill(Qt::white);
+ m_graphPainter->begin(fresh);
+ m_graphPainter->setPen(QColor(Qt::blue));
+
+ /* Scaling */
+ yStep = static_cast<double>(h) / fabs(m_graphMax - m_graphMin);
+
+ /* Downscale to grid */
+ if (w < m_graphLen) {
+ double columnsPerPixel = static_cast<double>(m_graphLen) / w;
+ uint columnsPerLastPixel = 0;
+ int* block = new int[w];
+ //qDebug() << "CPP" << columnsPerPixel << "yStep" << yStep << "Dims" << h << w << "Data" << w*columnsPerPixel << m_graphLen;
+ for (uint i = 0; i < m_graphLen; i++) {
+ uint column = i / columnsPerPixel;
+ if (column != lastColumn) {
+ yAvg /= columnsPerLastPixel;
+ block[lastColumn] = h - yStep * (yAvg -m_graphMin);
+ //qDebug() << "YAVG" << block[lastColumn] << "CPLP" << columnsPerLastPixel;
+ yAvg = 0;
+ columnsPerLastPixel= 0;
+ lastColumn = column;
+ }
+ yAvg += m_graphData[i];
+ columnsPerLastPixel++;
+ }
+ /* Add the last column */
+ yAvg /= columnsPerLastPixel;
+ block[w-1] = h - yStep * (yAvg - m_graphMin);
+ /* Draw the pixmap */
+ for (int i = 1; i < w; i++)
+ m_graphPainter->drawLine(i-1, floor(block[i-1]+0.5), i, floor(block[i]+0.5));
+ //qDebug() << "LAST YAVG" << block[m_graphLen-1] << "CPLP" << columnsPerLastPixel;
+ delete[] block;
+ } else { /* Upscale to grid */
+ double pixelsPerValue = static_cast<double>(w) / m_graphLen;
+ uint cPixX;
+ uint pPixX = 0;
+ uint cPixY;
+ uint pPixY = floor((h - yStep * (m_graphData[0] - m_graphMin)) + 0.5);
+ for (int i = 1; i < m_graphLen; i++) {
+ cPixX= floor(i * pixelsPerValue + 0.5);
+ cPixY = h - yStep * (m_graphData[i] - m_graphMin);
+ //qDebug() << "Upscale" << pPixX << pPixY << cPixX << cPixY;
+ m_graphPainter->drawLine(pPixX, pPixY, cPixX, cPixY);
+ pPixX = cPixX;
+ pPixY = cPixY;
+ }
+ }
+
+ m_graphPainter->end();
+ if (m_graphPlain != nullptr)
+ delete m_graphPlain;
+ m_graphPlain = new QPixmap(*fresh);
+ ui->qw_graphView->setPixmap(*fresh);
+ if (m_graph != nullptr)
+ delete m_graph;
+ m_graph = fresh;
+}
+
+void SignalView::resizeEvent(QResizeEvent* ev)
+{
+ Q_UNUSED(ev);
+
+ emit resized(ui->qw_graphView->width(), ui->qw_graphView->height());
+ emit redrawNeeded();
+}
+
+void SignalView::onUpdateCurrentValues(double x, double y)
+{
+ ui->qle_xValue->setText(QString::number(x));
+ ui->qle_yValue->setText(QString::number(y));
+}
+
+void SignalView::onRemoveCurrentValues()
+{
+ ui->qle_xValue->setText("-");
+ ui->qle_yValue->setText("-");
+}
+
+/* Public slots */
+void SignalView::onControlModeChanged(GraphControlModes mode)
+{
+ m_graphCtrlMode = mode;
+}
+
+void SignalView::onDrawIntegration(const int fromX, const double fromY, const int toX, const double toY, const int peakX, const double peakY, const QString& time,
+ const QString& area, const bool valley)
+{
+ int w, h;
+ int startX, startY, stopX, stopY, peakStartX, peakStartY;
+ double yStep, xStep;
+ double dStartY, dStopY;
+ QFont font("arial", 10);
+ QFontMetrics fm(font);
+ int textWidth;
+ if (m_graphPlain == nullptr)
+ return;
+
+ w = ui->qw_graphView->width();
+ h = ui->qw_graphView->height();
+ xStep = static_cast<double>(w) / m_graphLen;
+ yStep = static_cast<double>(h) / (m_graphMax - m_graphMin);
+ startX = floor(fromX * xStep + 0.5);
+ stopX = floor(toX * xStep + 0.5);
+ startY = floor((h - yStep * (fromY - m_graphMin)) + 0.5);
+ stopY = floor((h - yStep * (toY - m_graphMin)) + 0.5);
+ peakStartX = floor(peakX * xStep + 0.5);
+ peakStartY = floor(h - yStep * (peakY - m_graphMin) + 0.5);
+
+ dStartY = h - yStep * (fromY - m_graphMin);
+ dStopY = h - yStep * (toY - m_graphMin);
+
+ /*qDebug("Drawing peak");
+ qDebug() << "RSX" << fromX << "RSY" << fromY << "REX" << toX << "REY" << toY;
+ qDebug() << "X step" << xStep << "Y step" << yStep;
+ qDebug() << "SX" << startX << "SY" << startY << "EX" << stopX << "EY" << stopY << "w/h" << w << h;
+ qDebug() << "DSY" << dStartY << "DEY" << dStopY << "Slope I" << (toY-fromY)/(toX-fromX) << "Slope D" << (dStopY-dStartY)/(toX-fromX);
+ qDebug("---");*/
+
+ m_graphPainter->begin(m_graphPlain);
+ m_graphPainter->setPen(Qt::red);
+ m_graphPainter->drawLine(startX, startY, stopX, stopY);
+
+ /* Draw AREA and TIME caption */
+ m_graphPainter->setFont(font);
+ m_graphPainter->setPen(Qt::black);
+ textWidth = fm.width(time);
+ if (peakStartY - textWidth < 2)
+ peakStartY += textWidth - peakStartY + 2;
+ m_graphPainter->save();
+ m_graphPainter->translate(peakStartX, peakStartY);
+ m_graphPainter->rotate(-90);
+ m_graphPainter->drawText(0, 0, time);
+ m_graphPainter->rotate(+90);
+ m_graphPainter->restore();
+ m_graphPainter->drawText(peakStartX + 5, peakStartY, area);
+
+ m_graphPainter->end();
+ m_graphPainter->begin(m_graph);
+ m_graphPainter->drawPixmap(0, 0, *m_graphPlain, 0, 0, w, h);
+ m_graphPainter->end();
+ ui->qw_graphView->setPixmap(*m_graph);
+}
+
+void SignalView::onUpdateGraph(double* data, size_t len, double min, double max)
+{
+ if (m_graphData != nullptr)
+ delete[] m_graphData;
+ m_graphData = data;
+ m_graphLen = len;
+ m_graphMin = min;
+ m_graphMax = max;
+
+ redrawGraph();
+}
+/* ENDOF public slots */
+
+/* Private slots*/
+void SignalView::onGraphViewMouseCursorLeft()
+{
+ if(m_graph == nullptr)
+ return;
+
+ ui->qw_graphView->setPixmap(*m_graphPlain);
+
+ emit crosshairErased();
+}
+
+void SignalView::onGraphRedrawNeeded()
+{
+ emit redrawNeeded();
+}
+
+void SignalView::onMouseButtonTriggered(const int x, const int y, Qt::MouseButton button, QEvent::Type type, const QPoint& globalPos)
+{
+ if (m_ctxMenuOpen)
+ return;
+
+ switch (button) {
+ case Qt::LeftButton:
+ switch (m_mouseMode) {
+ case SignalView::MouseMode::CROSSHAIR:
+ if (m_graphCtrlMode == GraphControlModes::ZOOM) {
+ m_zoomRectStartX = x;
+ m_zoomRectStartY = y;
+ m_zoomRectLastX = x;
+ m_zoomRectLastY = y;
+ m_mouseMode = SignalView::MouseMode::ZOOM;
+ } else if (m_graphCtrlMode == GraphControlModes::INTEGRATE) {
+ m_integrateStartX = x;
+ m_integrateStartY = y;
+ m_integrateStopX = x;
+ m_integrateStopY = y;
+ eraseCrosshair();
+ m_graphCrosshairX = -1;
+ m_mouseMode = SignalView::MouseMode::INTEGRATE;
+ }
+ break;
+ case SignalView::MouseMode::ZOOM:
+ if (m_zoomRectLastX < m_zoomRectStartX)
+ std::swap(m_zoomRectLastX, m_zoomRectStartX);
+ if (m_zoomRectLastY < m_zoomRectStartY)
+ std::swap(m_zoomRectLastY, m_zoomRectStartY);
+ emit zoomed(m_zoomRectStartX, m_zoomRectStartY, m_zoomRectLastX, m_zoomRectLastY);
+ m_mouseMode = SignalView::MouseMode::CROSSHAIR;
+ break;
+ case SignalView::MouseMode::INTEGRATE:
+ if (m_integrateStartX > m_integrateStopX)
+ std::swap(m_integrateStartX, m_integrateStopX);
+ emit integrated(m_integrateStartX, m_integrateStartY, m_integrateStopX, m_integrateStopY);
+ eraseIntegrationBaseline(true);
+ m_integrateStartX = -1;
+ m_mouseMode = SignalView::MouseMode::CROSSHAIR;
+ break;
+ }
+ break;
+ case Qt::RightButton:
+ switch (m_mouseMode) {
+ case SignalView::MouseMode::CROSSHAIR:
+ m_ctxMenuOpen = true;
+ emit showContextMenu(x, y, globalPos);
+ break;
+ case SignalView::MouseMode::ZOOM:
+ eraseZoomRect(true);
+ m_mouseMode = SignalView::MouseMode::CROSSHAIR;
+ break;
+ case SignalView::MouseMode::INTEGRATE:
+ eraseIntegrationBaseline(true);
+ m_mouseMode = SignalView::MouseMode::CROSSHAIR;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void SignalView::onGraphViewMouseMoved(const int x, const int y)
+{
+ switch (m_mouseMode) {
+ case SignalView::MouseMode::CROSSHAIR:
+ eraseCrosshair();
+ drawCrosshair(x, y);
+ break;
+ case SignalView::MouseMode::ZOOM:
+ eraseCrosshair();
+ drawZoomRect(x, y);
+ break;
+ case SignalView::MouseMode::INTEGRATE:
+ eraseIntegrationBaseline();
+ drawIntegrationBaseline(x, y);
+ break;
+ }
+
+ emit crosshairMoved(x, y);
+}
+
+SignalView::~SignalView()
+{
+ if (m_graphPainter->isActive())
+ m_graphPainter->end();
+ delete ui;
+ if (m_graph != nullptr)
+ delete m_graph;
+ if (m_graphPlain != nullptr)
+ delete m_graphPlain;
+ if (m_graphData != nullptr)
+ delete[] m_graphData;
+
+ delete m_graphPainter;
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef SIGNALVIEW_H
+#define SIGNALVIEW_H
+
+#include "graphview.h"
+#include "integrationtablemodel.h"
+#include "signaldatatablemodel.h"
+#include <memory>
+#include <QtWidgets/QWidget>
+#include "../metatypes.h"
+
+namespace Ui {
+ class SignalView;
+}
+
+class SignalView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ enum class MouseMode {
+ CROSSHAIR,
+ ZOOM,
+ INTEGRATE
+ };
+
+ explicit SignalView(QWidget* parent = nullptr);
+ ~SignalView();
+ void setControlMode(GraphControlModes mode);
+ void setDataTableModel (SignalDataTableModel* model);
+ void setIntegrationTableModel(IntegrationTableModel* model);
+ void setTypeText(const QString& text);
+ void setXUnits(const QString& text);
+ void setYUnits(const QString& text);
+
+private:
+ void drawCrosshair(const int x, const int y);
+ void drawIntegrationBaseline(const int x, const int y);
+ void drawZoomRect(const int x, const int y);
+ void eraseCrosshair(bool apply = false);
+ void eraseIntegrationBaseline(bool apply = false);
+ void eraseZoomRect(bool apply = false);
+ void redrawGraph();
+ void resizeEvent(QResizeEvent* ev);
+
+ QPainter* m_graphPainter;
+ /* Dataset to plot */
+ QPixmap* m_graph;
+ QPixmap* m_graphPlain;
+ double* m_graphData;
+ double m_graphMin;
+ double m_graphMax;
+ size_t m_graphLen;
+ /* Crosshair */
+ int m_graphCrosshairX;
+ int m_graphCrosshairY;
+ /* Integration baseline */
+ int m_integrateStartX;
+ int m_integrateStartY;
+ int m_integrateStopX;
+ int m_integrateStopY;
+ /* Zooming rectangle */
+ int m_zoomRectStartX;
+ int m_zoomRectStartY;
+ int m_zoomRectLastX;
+ int m_zoomRectLastY;
+
+ bool m_ctxMenuOpen;
+ GraphControlModes m_graphCtrlMode;
+ MouseMode m_mouseMode;
+ Ui::SignalView* ui;
+
+public slots:
+ void onControlModeChanged(GraphControlModes mode);
+ void onCtxMenuClosed() { m_ctxMenuOpen = false; }
+ void onDrawIntegration(const int fromX, const double fromY, const int toX, const double toY, const int peakX, const double peakY,
+ const QString& time, const QString& area, const bool valley);
+ void onMouseButtonTriggered(const int x, const int y, Qt::MouseButton button, QEvent::Type type, const QPoint& globalPos);
+ void onUpdateCurrentValues(double x, double y);
+ void onRemoveCurrentValues();
+ void onUpdateGraph(double* arr, size_t len, double min, double max);
+
+private slots:
+ void onGraphRedrawNeeded();
+ void onGraphViewMouseCursorLeft();
+ void onGraphViewMouseMoved(const int x, const int y);
+
+signals:
+ void crosshairErased();
+ void crosshairMoved(const int x, const int y);
+ void integrated(const int fromX, const int fromY, const int toX, const int toY);
+ void redrawNeeded();
+ void resized(const int x, const int y);
+ void showContextMenu(const int x, const int y, const QPoint& globalPos);
+ void unzoomed();
+ void zoomed(const int fromX, const int fromY, const int toX, const int toY);
+};
+
+#endif // SIGNALVIEW_H
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SignalView</class>
+ <widget class="QWidget" name="SignalView">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>475</width>
+ <height>366</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="ql_signalTypeCap">
+ <property name="text">
+ <string>Type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="ql_signalType">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="qtw_tabs">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="tabShape">
+ <enum>QTabWidget::Rounded</enum>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="elideMode">
+ <enum>Qt::ElideNone</enum>
+ </property>
+ <widget class="QWidget" name="qtab_graph">
+ <attribute name="title">
+ <string>Graph</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="GraphView" name="qw_graphView" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="2">
+ <widget class="QLineEdit" name="qle_xValue">
+ <property name="text">
+ <string>-</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="5">
+ <widget class="QLineEdit" name="qle_yValue">
+ <property name="text">
+ <string>-</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QLabel" name="ql_yValCap">
+ <property name="text">
+ <string>Y:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="ql_xUnits">
+ <property name="text">
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="6">
+ <widget class="QLabel" name="ql_yUnits">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="ql_xValueCap">
+ <property name="text">
+ <string>X:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="qtab_data">
+ <attribute name="title">
+ <string>Data</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QTableView" name="qtblv_signalDataTable"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="qtab_integration">
+ <attribute name="title">
+ <string>Integration</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QTableView" name="qtblv_integrationTable"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>GraphView</class>
+ <extends>QWidget</extends>
+ <header>gui/graphview.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+<RCC>
+ <qresource prefix="/">
+ <file>resources/Qt_master_logo.png</file>
+ </qresource>
+</RCC>
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "integratedpeak.h"
+
+IntegratedPeak::IntegratedPeak(IntegratedPeak::Type type, double auc, size_t peakIdx, double peakTime, double peakVal,
+ size_t fromIdx, size_t toIdx, double fromTime, double toTime, double fromY, double toY, QObject* parent) :
+ QObject(parent),
+ m_auc(auc),
+ m_fromIdx(fromIdx),
+ m_fromTime(fromTime),
+ m_fromY(fromY),
+ m_peakIdx(peakIdx),
+ m_peakTime(peakTime),
+ m_peakVal(peakVal),
+ m_toIdx(toIdx),
+ m_toTime(toTime),
+ m_toY(toY),
+ m_type(type)
+{
+}
+
+double IntegratedPeak::baselineSlope() const
+{
+ return (m_toY - m_fromY) / (m_toIdx - m_fromIdx);
+}
+
+double IntegratedPeak::height() const
+{
+ return fabs(m_peakVal - (baselineSlope() * (m_peakIdx - m_fromIdx) + m_fromY));
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+
+#ifndef INTEGRATEDPEAK_H
+#define INTEGRATEDPEAK_H
+
+#include <QtCore/QObject>
+
+class IntegratedPeak : public QObject
+{
+ Q_OBJECT
+public:
+ enum class Type {
+ PEAK,
+ VALLEY
+ };
+
+ explicit IntegratedPeak(Type type, double auc, size_t peakIdx, double peakTime, double peakVal, size_t fromIdx, size_t toIdx, double fromTime, double toTime,
+ double fromY, double toY, QObject* parent = nullptr);
+ double auc() const { return m_auc; }
+ double baselineSlope() const;
+ size_t fromIdx() const { return m_fromIdx; }
+ double fromY() const { return m_fromY; }
+ double fromTime() const { return m_fromTime;}
+ double height() const;
+ size_t peakIdx() const { return m_peakIdx; }
+ double peakTime() const { return m_peakTime; }
+ size_t toIdx() const { return m_toIdx; }
+ double toTime() const { return m_toTime; }
+ double toY() const { return m_toY; }
+ Type type() const { return m_type; }
+ double width() const { return m_toTime - m_fromTime; }
+
+private:
+ const double m_auc;
+ const size_t m_fromIdx;
+ const double m_fromTime;
+ const double m_fromY;
+ const size_t m_peakIdx;
+ const double m_peakTime;
+ const double m_peakVal;
+ const size_t m_toIdx;
+ const double m_toTime;
+ const double m_toY;
+ const Type m_type;
+
+public slots:
+signals:
+
+};
+
+#endif // INTEGRATEDPEAK_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "integrationtablemodel.h"
+
+IntegrationTableModel::IntegrationTableModel(const std::shared_ptr<Integrator> integrator, QObject* parent) :
+ QAbstractTableModel(parent),
+ m_integrator(integrator)
+{}
+
+QVariant IntegrationTableModel::data(const QModelIndex& index, int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+ if (index.row() >= m_integrator->peakCount())
+ return QVariant();
+
+ const std::shared_ptr<IntegratedPeak> peak = m_integrator->peakByIdx(index.row());
+ switch (index.column()) {
+ case 0:
+ return QString::number(peak->peakTime(), 'f', 4);
+ case 1:
+ return QString::number(peak->auc(), 'f', 4);
+ case 2:
+ return QString::number(peak->height(), 'f', 4);
+ case 3:
+ return QString::number(peak->width(), 'f', 4);
+ }
+ return QVariant();
+}
+
+QVariant IntegrationTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
+ switch (section) {
+ case 0:
+ return QString("Time");
+ case 1:
+ return QString("Area");
+ case 2:
+ return QString("Height");
+ case 3:
+ return QString("Width");
+ }
+ }
+ return QVariant();
+}
+
+int IntegrationTableModel::rowCount(const QModelIndex& parent) const
+{
+ Q_UNUSED(parent);
+
+ if (m_integrator == nullptr)
+ return 0;
+
+ return m_integrator->peakCount();
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef INTEGRATIONTABLEMODEL_H
+#define INTEGRATIONTABLEMODEL_H
+
+#include "integrator.h"
+#include <memory>
+#include <QtCore/QAbstractTableModel>
+
+class IntegrationTableModel : public QAbstractTableModel
+{
+public:
+ IntegrationTableModel(const std::shared_ptr<Integrator> integrator, QObject* parent = nullptr);
+ QVariant data(const QModelIndex& index, int role) const;
+ void doneReset() { endResetModel(); }
+ int columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 4; }
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ void prepReset() { beginResetModel(); }
+ int rowCount(const QModelIndex& parent) const;
+
+private:
+ const std::shared_ptr<Integrator> m_integrator;
+};
+
+#endif // INTEGRATIONTABLEMODEL_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "integrator.h"
+#include "logger.h"
+
+const QString Integrator::ME_SENDER_STR("Integrator");
+
+Integrator::Integrator(std::shared_ptr<Signal> signal, QObject* parent) :
+ QObject(parent),
+ m_signal(signal)
+{}
+
+Integrator::ReturnCode Integrator::deletePeak(size_t idx)
+{
+ std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::iterator it = m_peaks.begin();
+ while (it != m_peaks.end() && it->first <= idx) {
+ if (it->first <= idx && it->second->toIdx() > idx) { /* Peak is surrounding the cursor */
+ m_peaks.erase(it);
+ return ReturnCode::SUCCESS;
+ }
+ it++;
+ }
+ return ReturnCode::E_NO_PEAK;
+}
+
+Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr<IntegratedPeak>& peak)
+{
+ size_t peakValueIdx;
+ size_t startIntersIdx, stopIntersIdx;
+ size_t i;
+ double auc = 0.0;
+ double slope;
+ double startYVal, stopYVal;
+ bool expectDownward;
+ IntegratedPeak::Type peakType;
+
+ if (startIdx > m_signal->valuesCount()-1) {
+ Logger::log(Logger::Level::ERROR, ME_SENDER_STR, "Invalid startIdx value " + QString::number(startIdx));
+ return ReturnCode::E_INVAL;
+ }
+ if (stopIdx > m_signal->valuesCount()-1) {
+ Logger::log(Logger::Level::ERROR, ME_SENDER_STR, "Invalid stopIdx value " + QString::number(stopIdx));
+ return ReturnCode::E_INVAL;
+ }
+
+ slope = (stopY - startY) / (stopIdx - startIdx);
+ /* Try to find first intersection */
+ if (startY < m_signal->valueAt(startIdx)) {
+ expectDownward = true;
+ //qDebug() << "Expecting downward peak";
+ } else {
+ expectDownward = false;
+ //qDebug() << "Expecting upward peak";
+ }
+ for (i = startIdx; i <= stopIdx; i++) {
+ double value = m_signal->valueAt(i);
+ double blY = slope * (i - startIdx) + startY;
+
+ if (expectDownward && blY > value) { /* Found first intersection */
+ startIntersIdx = i-1;
+ startYVal = blY;
+ break;
+ } else if (!expectDownward && blY < value) { /* Found first intersection */
+ startIntersIdx = i-1;
+ startYVal = blY;
+ break;
+ }
+ }
+ if (i > stopIdx) {
+ Logger::log(Logger::Level::INFO, ME_SENDER_STR, "First intersection not found.");
+ return ReturnCode::E_NO_FIRST_INTERSECT;
+ }
+
+ /* Try to find second intersection */
+ for (; i <= stopIdx; i++) {
+ double value = m_signal->valueAt(i);
+ double blY = slope * (i - startIdx) + startY;
+
+ if (expectDownward && blY <= value) {
+ stopIntersIdx = i;
+ stopYVal = blY;
+ break;
+ } else if (!expectDownward && blY >= value) {
+ stopIntersIdx = i;
+ stopYVal = blY;
+ break;
+ }
+ }
+ if (i > stopIdx) {
+ Logger::log(Logger::Level::INFO, ME_SENDER_STR, "Second intersection not found.");
+ return ReturnCode::E_NO_SECOND_INTERSECT;
+ }
+
+ /* Integrate */
+ peakValueIdx = startIntersIdx;
+ for (i = startIntersIdx+1; i < stopIntersIdx; i++) {
+ double blXA = slope * (i - startIntersIdx - 1) + startY;
+ double blXB = slope * (i - startIntersIdx) + startY;
+ double valA = m_signal->valueAt(i-1);
+ double valB = m_signal->valueAt(i);
+ double tA = m_signal->timeAt(i-1);
+ double tB = m_signal->timeAt(i);
+ double avgH = (valB + valA)/2 - (blXB + blXA)/2;
+ double area = avgH * (tB - tA);
+ auc += area;
+ if (expectDownward && valB < m_signal->valueAt(peakValueIdx)) peakValueIdx = i;
+ else if (!expectDownward && valB > m_signal->valueAt(peakValueIdx)) peakValueIdx = i;
+ //qDebug() << area << auc;
+ }
+ /* Convert AUC to positive and seconds */
+ auc = fabs(auc) * 60;
+
+ /* Add peak to list */
+ if (expectDownward) peakType = IntegratedPeak::Type::VALLEY;
+ else peakType = IntegratedPeak::Type::PEAK;
+
+ /*qDebug("Peak integrated");
+ qDebug() << "SXC" << fromX << "SYC" << fromY << "EXC" << toX << "EYC" << toY << "Slope" << slope;
+ qDebug() << "1st(X, Y, vY)" << startIntersIdx << m_signal->valueAt(startIntersIdx) << startYVal;
+ qDebug() << "2nd(X, Y, vY)" << stopIntersIdx << m_signal->valueAt(stopIntersIdx) << stopYVal;
+ qDebug("---");*/
+
+ peak = std::shared_ptr<IntegratedPeak>(new IntegratedPeak(peakType, auc, peakValueIdx, m_signal->timeAt(peakValueIdx), m_signal->valueAt(peakValueIdx),
+ startIntersIdx, stopIntersIdx, m_signal->timeAt(startIntersIdx), m_signal->timeAt(stopIntersIdx),
+ startYVal, stopYVal));
+ m_peaks.insert(std::pair<size_t, std::shared_ptr<IntegratedPeak>>(startIdx, peak));
+
+ return ReturnCode::SUCCESS;
+}
+
+const std::shared_ptr<IntegratedPeak> Integrator::peakByIdx(const int idx) const
+{
+ std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator it = m_peaks.begin();
+ std::advance(it, idx);
+
+ return it->second;
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef INTEGRATOR_H
+#define INTEGRATOR_H
+
+#include "integratedpeak.h"
+#include "signal.h"
+#include <map>
+#include <memory>
+#include <QtCore/QObject>
+
+class Integrator : public QObject
+{
+ Q_OBJECT
+public:
+ enum class ReturnCode {
+ SUCCESS,
+ E_NO_FIRST_INTERSECT,
+ E_NO_SECOND_INTERSECT,
+ E_INVAL,
+ E_NO_PEAK
+ };
+
+ explicit Integrator(std::shared_ptr<Signal> signal, QObject* parent = nullptr);
+ ReturnCode deletePeak(size_t idx);
+ ReturnCode integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr<IntegratedPeak>& peak);
+ const std::shared_ptr<IntegratedPeak> peakByIdx(const int idx) const;
+ std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator peaksCBegin() const { return m_peaks.cbegin(); }
+ std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator peaksCEnd() const { return m_peaks.cend(); }
+ size_t peakCount() const { return m_peaks.size(); }
+
+private:
+ std::multimap<size_t, std::shared_ptr<IntegratedPeak>> m_peaks;
+ std::shared_ptr<Signal> m_signal;
+
+ static const QString ME_SENDER_STR;
+
+signals:
+
+public slots:
+
+};
+
+#endif // INTEGRATOR_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "locallogger.h"
+
+/* Static methods */
+LocalLoggerPtr LocalLogger::create(QObject* parent)
+{
+ return std::shared_ptr<LocalLogger>(new LocalLogger(parent));
+}
+
+/* ENDOF static methods */
+
+LocalLogger::LocalLogger(QObject* parent) : Logger(parent)
+{
+}
+
+void LocalLogger::log(Level level, const QString& sender, const QString& message, bool global)
+{
+ LoggedInfo li = std::make_tuple(QDateTime::currentMSecsSinceEpoch(), level, sender, message);
+ this->m_lock.lock();
+ this->m_logged.push_back(li);
+ this->m_lock.unlock();
+
+ if (global)
+ Logger::log(level, sender, message, true);
+ if (level >= m_printLogLevel)
+ readLast();
+}
+
+void LocalLogger::read(Level level, uint length)
+{
+ Logger::read(level, length, this);
+}
+
+void LocalLogger::readLast()
+{
+ Logger::readLast(this);
+}
+
+LocalLogger::~LocalLogger()
+{
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+
+#ifndef LOCALLOGGER_H
+#define LOCALLOGGER_H
+
+#include "logger.h"
+
+class LocalLogger : public Logger
+{
+public:
+ static LocalLoggerPtr create(QObject* parent);
+ ~LocalLogger();
+ void log(Level level, const QString& sender, const QString& message, bool global = false);
+ void read(Level level, uint length = 0);
+ void readLast();
+ void setPrintLevel(Level level) { m_printLogLevel = level; }
+
+private:
+ LocalLogger(QObject* parent = nullptr);
+};
+
+#endif // LOCALLOGGER_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "logger.h"
+
+#include <QDebug>
+
+Logger* Logger::s_globalInstance(nullptr);
+
+/* Static methods */
+LocalLoggerPtr Logger::createLocalLog()
+{
+ LocalLoggerPtr localLogger(LocalLogger::create(s_globalInstance));
+
+ return localLogger;
+}
+
+void Logger::initializeGlobal()
+{
+ if (Logger::s_globalInstance == nullptr)
+ Logger::s_globalInstance = new Logger();
+}
+
+const QString Logger::levelToString(Level level)
+{
+ switch (level) {
+ case DEBUG:
+ return "DEBUG";
+ case INFO:
+ return "INFO";
+ case WARNING:
+ return "WARNING";
+ case ERROR:
+ return "ERROR";
+ case CRITICAL:
+ return "CRITICAL";
+ default:
+ return "UNKNOWN!";
+ }
+}
+
+void Logger::log(Level level, const QString& sender, const QString& message, bool suppressPrint)
+{
+ LoggedInfo li = std::make_tuple(QDateTime::currentMSecsSinceEpoch(), level, sender, message);
+ s_globalInstance->m_lock.lock();
+ s_globalInstance->m_logged.push_back(li);
+ s_globalInstance->m_lock.unlock();
+
+ if (level >= s_globalInstance->m_printLogLevel && !suppressPrint)
+ readLast();
+}
+
+void Logger::read(Level level, uint length, Logger* logger)
+{
+ Logger* _logger;
+ size_t logSize;
+ size_t from, to;
+
+ if (logger == nullptr)
+ _logger = s_globalInstance;
+ else
+ _logger = logger;
+ logSize = _logger->m_logged.size();
+
+ if (logSize < 1)
+ return;
+
+ if (length == 0) {
+ from = 0;
+ to = logSize - 1;
+ } else if (logSize < length) {
+ from = 0;
+ to = logSize - 1;
+ } else {
+ from = logSize - length - 1;
+ to = logSize - 1;
+ }
+
+ while (from <= to) {
+ const LoggedInfo& li = _logger->m_logged.at(from);
+ if (std::get<1>(li) >= level) {
+ QString out;
+ out = QString::number(std::get<0>(li));
+ out += " - " + Logger::levelToString(std::get<1>(li));
+ out += ": " + std::get<2>(li);
+ out += ":: " + std::get<3>(li);
+ qDebug() << out;
+ }
+ from++;
+ }
+}
+
+void Logger::readLast(Logger* logger)
+{
+ Logger* _logger;
+ QString out;
+
+ if (logger == nullptr)
+ _logger = s_globalInstance;
+ else
+ _logger = logger;
+
+ const LoggedInfo& li = _logger->m_logged.back();
+ out = QString::number(std::get<0>(li)) + " - " + Logger::levelToString(std::get<1>(li)) + ": " + std::get<2>(li) + ":: " + std::get<3>(li);
+ qDebug() << out;
+}
+
+/* ENDOF static methods */
+
+Logger::Logger(QObject* parent) : QObject(parent)
+{
+}
+
+Logger::~Logger()
+{
+ Logger::read(Logger::Level::DEBUG);
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+
+#ifndef LOGGER_H
+#define LOGGER_H
+
+#include <memory>
+#include <mutex>
+#include <vector>
+#include <QtCore/QObject>
+#include <QtCore/QDateTime>
+
+class LocalLogger;
+typedef std::shared_ptr<LocalLogger> LocalLoggerPtr;
+
+class Logger : public QObject
+{
+ Q_OBJECT
+public:
+ enum Level {
+ DEBUG = 0,
+ INFO = 1,
+ WARNING = 2,
+ ERROR = 3,
+ CRITICAL = 4
+ };
+
+ ~Logger();
+ static LocalLoggerPtr createLocalLog();
+ static void initializeGlobal();
+ static void log(Level level, const QString& sender, const QString& message, bool suppressPrint = false);
+ static void read(Level level, uint length = 0, Logger* logger = nullptr);
+ static void readLast(Logger* logger = nullptr);
+ static void setPrintLevel(Level level) { s_globalInstance->m_printLogLevel = level; }
+
+protected:
+ typedef std::tuple<uint64_t, Level, const QString, const QString> LoggedInfo;
+
+ static const QString levelToString(Level level);
+
+ explicit Logger(QObject* parent = nullptr);
+
+ std::mutex m_lock;
+ std::vector<LoggedInfo> m_logged;
+ Level m_printLogLevel;
+
+ static Logger* s_globalInstance;
+
+};
+
+#include "locallogger.h"
+#endif // LOGGER_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "gui/mainwindow.h"
+#include "datamanager.h"
+#include "logger.h"
+#include <QApplication>
+#include <QtWidgets/QMessageBox>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+#warning Revisit the metatype shared_ptr<SignalView> registration
+ qRegisterMetaType<std::shared_ptr<SignalView>>();
+
+ Logger::initializeGlobal();
+ Logger::setPrintLevel(Logger::Level::DEBUG);
+ std::unique_ptr<DataManager> dMgr;
+ std::unique_ptr<MainWindow> mWin;
+
+ AGREInterface::ReturnCode aRet = AGREInterface::instance()->initialize();
+ if (aRet == AGREInterface::ReturnCode::E_NO_LIBRARY) {
+ QMessageBox::critical(nullptr, "Dependencies error", "Library " + AGREInterface::AGRE_LIBRARY_NAME + " could not have been found.\n"
+ "The application cannot continue.");
+ return 1;
+ } else if (aRet == AGREInterface::ReturnCode::E_CANNOT_RESOLVE) {
+ QMessageBox::critical(nullptr, "libAGRE error", "Some symbols from " + AGREInterface::AGRE_LIBRARY_NAME + " could not have been resolved.\n"
+ "The application cannot continue.");
+ return 1;
+ } else if (aRet == AGREInterface::ReturnCode::E_CANNOT_GET_IFACE) {
+ QMessageBox::critical(nullptr, "libAGRE error", "An error occured during data reader initialization.\nThe application cannot continue.");
+ return 1;
+ }
+
+ dMgr = std::unique_ptr<DataManager>(new DataManager);
+ mWin = std::unique_ptr<MainWindow>(new MainWindow);
+ mWin->setSequenceListModel(dMgr->sequenceSelectorModel());
+ mWin->setSingleRunsListModel(dMgr->singleRunsSelectorModel());
+ /* Default to no sequence on load */
+ mWin->onSetActiveSequenceIndex(-1);
+ /* Connect SIGNALS/SLOTS */
+ QObject::connect(dMgr.get(), SIGNAL(addToDashboard(SignalView*)), mWin.get(), SLOT(onAddToDashboard(SignalView*)));
+ QObject::connect(dMgr.get(), SIGNAL(cleanDashboard()), mWin.get(), SLOT(onCleanDashboard()));
+ QObject::connect(dMgr.get(), SIGNAL(setActiveSequenceIndex(int)), mWin.get(), SLOT(onSetActiveSequenceIndex(int)));
+ QObject::connect(dMgr.get(), SIGNAL(setActiveSingleRunIndex(int)), mWin.get(), SLOT(onSetActiveSingleRunIndex(int)));
+ QObject::connect(dMgr.get(), SIGNAL(setSingleRunInfo(QString,QString,QString,QString)), mWin.get(), SLOT(onSetSingleRunInfo(QString,QString,QString,QString)));
+ QObject::connect(mWin.get(), SIGNAL(loadSingleRun(QString)), dMgr.get(), SLOT(onLoadSingleRun(QString)));
+ QObject::connect(mWin.get(), SIGNAL(loadSequence(QString)), dMgr.get(), SLOT(onLoadSequence(QString)));
+ QObject::connect(mWin.get(), SIGNAL(sequenceSelected(QString)), dMgr.get(), SLOT(onSequenceSelected(QString)));
+ QObject::connect(mWin.get(), SIGNAL(singleRunSelected(QString)), dMgr.get(), SLOT(onSingleRunSelected(QString)));
+
+ mWin->show();
+
+ return a.exec();
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef MATHHELPERS_H
+#define MATHHELPERS_H
+
+template <typename T> T average(T* vals, size_t len) {
+ T sum = 0;
+ for (int i = 0; i < len; i++)
+ sum += vals[i];
+ return sum / len;
+}
+
+#endif // MATHHELPERS_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef METATYPES_H
+#define METATYPES_H
+
+class SignalView;
+typedef std::shared_ptr<SignalView> SignalViewPtr;
+Q_DECLARE_METATYPE(SignalViewPtr);
+
+enum class GraphControlModes {
+ ZOOM,
+ INTEGRATE
+};
+Q_DECLARE_METATYPE(GraphControlModes);
+
+#endif // METATYPES_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "sequence.h"
+
+Sequence::Sequence(QObject* parent) :
+ QObject(parent)
+{
+}
+
+Sequence::Sequence(std::vector<SingleRunPair>& singleRuns, QObject* parent) :
+ QObject(parent),
+ m_selectedRunKey(""),
+ m_singleRuns(singleRuns)
+{
+}
+
+int Sequence::add(QString name, std::shared_ptr<SingleRunData> value)
+{
+ m_singleRuns.push_back(SingleRunPair(name, value));
+ m_selectedRunKey = name;
+ return m_singleRuns.size()-1;
+}
+
+void Sequence::addController(const std::string& uid, std::shared_ptr<SignalController> controller)
+{
+ m_signalCtrls[uid] = controller;
+}
+
+SingleRunPair Sequence::at(const size_t idx)
+{
+ return m_singleRuns.at(idx);
+}
+
+std::shared_ptr<SignalController> Sequence::controller(const std::string& uid)
+{
+ std::unordered_map<std::string, std::shared_ptr<SignalController>>::iterator it;
+ it = m_signalCtrls.find(uid);
+ if (it == m_signalCtrls.end())
+ return nullptr;
+ else
+ return it->second;
+}
+
+std::vector<SingleRunPair>::iterator Sequence::find(const QString& key)
+{
+ std::vector<SingleRunPair>::iterator it = m_singleRuns.begin();
+ while (it != m_singleRuns.end()) {
+ if (it->first == key)
+ return it;
+ it++;
+ }
+ return m_singleRuns.end();
+}
+
+void Sequence::remove(const QString& key)
+{
+ std::vector<SingleRunPair>::iterator it = m_singleRuns.begin();
+ while (it++ != m_singleRuns.end()) {
+ if (it->first == key)
+ m_singleRuns.erase(it);
+ }
+}
+
+void Sequence::removeAt(const size_t idx)
+{
+ if (m_singleRuns.size() > idx)
+ m_singleRuns.erase(m_singleRuns.begin()+idx);
+}
+
+int Sequence::selectedRunIdx() const
+{
+ int idx = 0;
+ for (const SingleRunPair& p : m_singleRuns) {
+ if (p.first.compare(m_selectedRunKey) == 0)
+ return idx;
+ idx++;
+ }
+ return -1;
+}
+
+int Sequence::singleRunToIdx(const QString& key) const
+{
+ int idx = 0;
+ for (const SingleRunPair& p : m_singleRuns) {
+ if (p.first.compare(key) == 0)
+ return idx;
+ idx++;
+ }
+ return -1;
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef SEQUENCE_H
+#define SEQUENCE_H
+
+#include "signalcontroller.h"
+#include "singlerundata.h"
+#include <unordered_map>
+#include <utility>
+#include <vector>
+#include <QtCore/QObject>
+
+typedef std::pair<QString, std::shared_ptr<SingleRunData>> SingleRunPair;
+
+class Sequence : public QObject
+{
+ Q_OBJECT
+public:
+ explicit Sequence(QObject* parent = nullptr);
+ explicit Sequence(std::vector<SingleRunPair>& singleRuns, QObject* parent = nullptr);
+ int add(QString name, std::shared_ptr<SingleRunData> value);
+ void addController(const std::string& uid, std::shared_ptr<SignalController> controller);
+ const std::vector<SingleRunPair>* allRuns() const { return &m_singleRuns; }
+ SingleRunPair at(size_t idx);
+ std::vector<SingleRunPair>::iterator begin() { return m_singleRuns.begin(); }
+ std::vector<SingleRunPair>::const_iterator cbegin() const { return m_singleRuns.cbegin(); }
+ std::vector<SingleRunPair>::const_iterator cend() const { return m_singleRuns.cend(); }
+ std::shared_ptr<SignalController> controller(const std::string& uid);
+ size_t count() const { return m_singleRuns.size(); }
+ std::vector<SingleRunPair>::iterator end() { return m_singleRuns.end(); }
+ std::vector<SingleRunPair>::iterator find(const QString& key);
+ void remove(const QString& key);
+ void removeAt(const size_t idx);
+ const QString& selectedRunKey() const { return m_selectedRunKey; }
+ int selectedRunIdx() const;
+ int singleRunToIdx(const QString& key) const;
+ void setSelectedRunKey(const QString& key) { m_selectedRunKey = key; }
+
+private:
+ QString m_selectedRunKey;
+ std::unordered_map<std::string, std::shared_ptr<SignalController>> m_signalCtrls;
+ std::vector<SingleRunPair> m_singleRuns;
+
+signals:
+
+public slots:
+
+};
+
+#endif // SEQUENCE_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "sequenceselectormodel.h"
+
+SequenceSelectorModel::SequenceSelectorModel(QObject* parent) :
+ QAbstractListModel(parent),
+ m_activeSequences(nullptr)
+{
+}
+
+SequenceSelectorModel::SequenceSelectorModel(const std::vector<NameSequencePair>* sequences, QObject* parent) :
+ QAbstractListModel(parent),
+ m_activeSequences(sequences)
+{
+}
+
+QVariant SequenceSelectorModel::data(const QModelIndex& index, int role) const
+{
+ int seqIdx = 0;
+ if (role != Qt::DisplayRole)
+ return QVariant();
+ if (m_activeSequences == nullptr)
+ return QVariant();
+
+ std::vector<NameSequencePair>::const_iterator cit = m_activeSequences->cbegin();
+ while (cit != m_activeSequences->cend()) {
+ if (seqIdx == index.row())
+ return cit->first;
+ seqIdx++; cit++;
+ }
+ return QVariant();
+}
+
+int SequenceSelectorModel::rowCount(const QModelIndex& parent) const
+{
+ Q_UNUSED(parent);
+
+ if (m_activeSequences == nullptr)
+ return 0;
+ else
+ return m_activeSequences->size();
+}
+
+void SequenceSelectorModel::seqenceAdded()
+{
+ beginInsertRows(QModelIndex(), m_activeSequences->size()-1, m_activeSequences->size()-1);
+ endInsertRows();
+}
+
+void SequenceSelectorModel::setSequences(const std::vector<NameSequencePair>* sequences)
+{
+ beginResetModel();
+ m_activeSequences = sequences;
+ endResetModel();
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef SEQUENCESELECTORMODEL_H
+#define SEQUENCESELECTORMODEL_H
+
+#include "sequence.h"
+#include <mutex>
+#include <QtCore/QAbstractListModel>
+
+typedef std::pair<const QString, std::shared_ptr<Sequence>> NameSequencePair;
+
+class SequenceSelectorModel : public QAbstractListModel
+{
+public:
+ SequenceSelectorModel(QObject* parent = nullptr);
+ SequenceSelectorModel(const std::vector<NameSequencePair>* sequences, QObject* parent = nullptr);
+ QVariant data(const QModelIndex& index, int role) const;
+ void seqenceAdded();
+ int rowCount(const QModelIndex& parent) const;
+ void setSequences(const std::vector<NameSequencePair>* sequence);
+
+private:
+ const std::vector<NameSequencePair>* m_activeSequences;
+};
+
+#endif // SEQUENCESELECTORMODEL_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "signal.h"
+#include <cfloat>
+
+const QString Signal::RES_ABSORBANCE("Absorbance");
+const QString Signal::RES_CCD("CCD");
+const QString Signal::RES_CURRENT("Current");
+const QString Signal::RES_DAD("Absorbance");
+const QString Signal::RES_POWER("Power");
+const QString Signal::RES_VOLTAGE("Voltage");
+const QString Signal::KILOVOTLS_SI("KV");
+const QString Signal::MICROAMPERES_SI("\u03BCA");
+const QString Signal::MILLIAU_SI("mAU");
+const QString Signal::MILLIVOLTS_SI("mV");
+const QString Signal::WATTS_SI("W");
+
+Signal::Signal(const Equipment equipment, const Resource resource, const double samplingRate, const YUnit yunit, uint16_t wavelengthAbs, uint16_t wavelengthRef,
+ const std::vector<TimeValuePair>& values, QObject* parent) :
+ QObject(parent),
+ m_equipment(equipment),
+ m_resource(resource),
+ m_samplingRate(samplingRate),
+ m_values(values),
+ m_wavelengthAbs(wavelengthAbs),
+ m_wavelengthRef(wavelengthRef),
+ m_xunit(XUnit::MINUTE),
+ m_yunit(yunit)
+{
+ m_min = DBL_MAX;
+ m_max = DBL_MIN;
+ for (Signal::TimeValuePair tvp : values) {
+ if (tvp.second < m_min) m_min = tvp.second;
+ if (tvp.second > m_max) m_max = tvp.second;
+ }
+}
+
+std::vector<Signal::TimeValuePair>::const_iterator Signal::iteratorFrom(const size_t idx) const
+{
+ return m_values.cbegin()+idx-1;
+}
+
+Signal::TimeValuePair Signal::pairAt(const size_t idx) const
+{
+ if (idx >= m_values.size())
+ return m_values.back();
+ else
+ return m_values.at(idx);
+}
+
+QString Signal::resourceToString() const {
+ switch (m_resource) {
+ case Resource::CE_ABSORBANCE:
+ return RES_ABSORBANCE;
+ case Resource::CE_CCD:
+ return RES_CCD;
+ case Resource::CE_CURRENT:
+ return RES_CURRENT;
+ case Resource::CE_DAD:
+ return RES_DAD;
+ case Resource::CE_POWER:
+ return RES_POWER;
+ case Resource::CE_VOLTAGE:
+ return RES_VOLTAGE;
+ default:
+ return "?";
+ }
+}
+
+double Signal::timeAt(const size_t idx) const
+{
+ if (idx >= m_values.size())
+ return m_values.back().first;
+ else
+ return m_values.at(idx).first;
+}
+
+QString Signal::uidString() const
+{
+ return resourceToString() + QString::number(m_wavelengthAbs) + QString::number(m_wavelengthRef);
+}
+
+double Signal::valueAt(const size_t idx) const
+{
+ if (idx >= m_values.size())
+ return m_values.back().second;
+ else
+ return m_values.at(idx).second;
+}
+
+QString Signal::xunitToString() const
+{
+ switch (m_xunit) {
+ case XUnit::MINUTE:
+ return "min";
+ default:
+ return "?";
+ }
+}
+
+QString Signal::yunitToString() const
+{
+ switch (m_yunit) {
+ case YUnit::KILOVOLTS:
+ return KILOVOTLS_SI;
+ case YUnit::MICROAMPERES:
+ return MICROAMPERES_SI;
+ case YUnit::MILLIAU:
+ return MILLIAU_SI;
+ case YUnit::MILLIVOLTS:
+ return MILLIVOLTS_SI;
+ case YUnit::WATTS:
+ return WATTS_SI;
+ default:
+ return "?";
+ }
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef SIGNAL_H
+#define SIGNAL_H
+
+#include <vector>
+#include <QtCore/QObject>
+
+class Signal : public QObject
+{
+ Q_OBJECT
+public:
+ typedef std::pair<double, double> TimeValuePair;
+ enum class Equipment {
+ CE
+ };
+ enum class Resource {
+ CE_ABSORBANCE,
+ CE_CCD,
+ CE_CURRENT,
+ CE_DAD,
+ CE_POWER,
+ CE_VOLTAGE
+ };
+ enum class XUnit {
+ MINUTE
+ };
+ enum class YUnit {
+ KILOVOLTS,
+ MICROAMPERES,
+ MILLIAU,
+ MILLIVOLTS,
+ WATTS
+ };
+
+ explicit Signal(const Equipment equipment, const Resource resource, const double samplingRate, const YUnit yunit, const uint16_t wavelengthAbs,
+ const uint16_t wavelengthRef, const std::vector<TimeValuePair>& values, QObject* parent = nullptr);
+ Equipment equipment() const { return m_equipment; }
+ std::vector<TimeValuePair>::const_iterator iteratorFrom(const size_t idx) const;
+ double maximum() const { return m_max; }
+ double minimum() const { return m_min; }
+ TimeValuePair pairAt(const size_t idx) const;
+ Resource resource() const { return m_resource; }
+ QString resourceToString() const;
+ double timeAt(const size_t idx) const;
+ double samplingRate() const { return m_samplingRate; }
+ QString uidString() const;
+ double valueAt(const size_t idx) const;
+ std::vector<TimeValuePair>::const_iterator valuesBegin() const { return m_values.begin(); }
+ size_t valuesCount() const { return m_values.size(); }
+ std::vector<TimeValuePair>::const_iterator valuesEnd() const { return m_values.end(); }
+ uint16_t wavelengthAbsorbed() const { return m_wavelengthAbs; }
+ uint16_t wavelengthReference() const { return m_wavelengthRef; }
+ XUnit xunit() const { return m_xunit; }
+ QString xunitToString() const;
+ YUnit yunit() const { return m_yunit; }
+ QString yunitToString() const;
+
+private:
+ const Equipment m_equipment;
+ double m_max;
+ double m_min;
+ const Resource m_resource;
+ const double m_samplingRate;
+ const std::vector<TimeValuePair> m_values;
+ const uint16_t m_wavelengthAbs;
+ const uint16_t m_wavelengthRef;
+ const XUnit m_xunit;
+ const YUnit m_yunit;
+
+ static const QString RES_ABSORBANCE;
+ static const QString RES_CCD;
+ static const QString RES_CURRENT;
+ static const QString RES_DAD;
+ static const QString RES_POWER;
+ static const QString RES_VOLTAGE;
+ static const QString KILOVOTLS_SI;
+ static const QString MICROAMPERES_SI;
+ static const QString MILLIAU_SI;
+ static const QString MILLIVOLTS_SI;
+ static const QString WATTS_SI;
+
+signals:
+
+public slots:
+
+};
+
+#endif // SIGNAL_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "signalcontroller.h"
+#include "logger.h"
+#include <cfloat>
+
+#include <QDebug>
+
+const QString SignalController::ME_SENDER_STR("SignalController");
+
+SignalController::SignalController(std::shared_ptr<Signal> signal, QObject* parent) :
+ QObject(parent),
+ m_signal(signal)
+{
+ m_integrator = std::shared_ptr<Integrator>(new Integrator(signal));
+ m_integTblModel = new IntegrationTableModel(m_integrator);
+ m_dtblModel = new SignalDataTableModel(signal);
+
+ m_yMin = m_signal->minimum() - m_signal->minimum()*0.05;
+ m_yMax = m_signal->maximum() + m_signal->maximum()*0.05;
+ m_fromIdx = 0; m_toIdx = m_signal->valuesCount()-1;
+
+ connect(m_ctxMenu.m_acZoomOut, SIGNAL(triggered()), this, SLOT(onCtxMenuUnzoom()));
+ connect(m_ctxMenu.m_acDeletePeak, SIGNAL(triggered()), this, SLOT(onCtxMenuDeletePeak()));
+}
+
+/* Public methods */
+void SignalController::draw()
+{
+ drawGraph();
+ drawAllPeaks();
+}
+
+/* Private methods */
+
+void SignalController::drawAllPeaks()
+{
+ std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator cit = m_integrator->peaksCBegin();
+ while (cit != m_integrator->peaksCEnd())
+ drawIntegratedPeak((cit++)->second);
+}
+
+void SignalController::drawFullGraph()
+{
+ m_yMin = m_signal->minimum() - m_signal->minimum()*0.05;
+ m_yMax = m_signal->maximum() + m_signal->maximum()*0.05;
+ if (m_signal->valuesCount() < 1)
+ return;
+ m_fromIdx = 0; m_toIdx = m_signal->valuesCount()-1;
+
+ qDebug() << m_yMin << m_yMax;
+
+ drawGraph();
+}
+
+void SignalController::drawGraph()
+{
+ double* arr;
+ size_t len;
+
+ if (m_fromIdx > m_toIdx) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "From index lower than to index");
+ return;
+ }
+ if (m_fromIdx == m_toIdx)
+ return; //Nothing to zoom to
+ if (m_toIdx >= m_signal->valuesCount() || m_fromIdx >= m_signal->valuesCount()) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Invalid value index");
+ return;
+ }
+ len = m_toIdx - m_fromIdx;
+
+ arr = new double[len];
+ for (uint idx = 0; idx < len; idx++)
+ arr[idx] = m_signal->valueAt(idx + m_fromIdx);
+
+ emit guiDrawGraph(arr, len, m_yMin, m_yMax);
+}
+
+void SignalController::drawIntegratedPeak(const std::shared_ptr<IntegratedPeak> peak)
+{
+ int fromX, toX;
+ double fromY, toY;
+ bool valley;
+ if (peak->toIdx() < m_fromIdx || peak->fromIdx() > m_toIdx) /* Peak is not in view X-wise, skip it */
+ return;
+
+ /* Check if the start of the baseline is in view */
+ if (peak->fromIdx()-1 >= m_fromIdx) {
+ fromX = peak->fromIdx() - m_fromIdx;
+ fromY = peak->fromY();
+ } else {
+ fromX = 0;
+ double bls = peak->baselineSlope();
+ fromY = bls * (m_fromIdx - peak->fromIdx()) + peak->fromY();
+ qDebug() << "Start OOR" << fromY << bls;
+ }
+ /* Check if the end of the baseline is in view */
+ if (peak->toIdx() <= m_toIdx) {
+ toX = peak->toIdx() - m_fromIdx;
+ toY = peak->toY();
+ } else {
+ double bls = peak->baselineSlope();
+ toX = m_toIdx - m_fromIdx;
+ toY = bls * (m_toIdx - peak->fromIdx()) + peak->fromY();
+ qDebug() << "Stop OOR" << toY << bls;
+ }
+
+ /*qDebug("Drawing integration");
+ qDebug() << "SX" << fromX << "SY" << fromY << "EX" << toX << "EY" << toY;
+ qDebug() << "Slope P" << peak->baselineSlope() << "Slope M" << (toY-fromY)/(toX-fromX);
+ qDebug("---");*/
+
+ const QString peakTime = QString::number(peak->peakTime(), 'f', 4);
+ const QString peakArea = QString("A: ") + QString::number(peak->auc(), 'f', 4);
+ if (peak->type() == IntegratedPeak::Type::PEAK)
+ valley = false;
+ else
+ valley = true;
+ emit viewDrawIntegration(fromX, fromY, toX, toY, peak->peakIdx() - m_fromIdx, m_signal->valueAt(peak->peakIdx()), peakTime, peakArea, valley);
+}
+
+bool SignalController::updateConstraints(const int fromX, const int fromY, const int toX, const int toY)
+{
+ size_t xRange = m_toIdx - m_fromIdx;
+ double yRange;
+ if (m_viewWidth < 1) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Invalid viewWidth value " + QString::number(m_viewWidth));
+ return false;
+ }
+ if (m_viewHeight < 1) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Invalid viewHeight value " + QString::number(m_viewHeight));
+ return false;
+ }
+ if (fromX > toX) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "fromX > toX");
+ return false;
+ }
+ if (fromY > toY) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "fromY > toY");
+ return false;
+ }
+
+ m_toIdx = (xRange * toX) / m_viewWidth + m_fromIdx;
+ m_fromIdx = (xRange * fromX) / m_viewWidth + m_fromIdx;
+
+ yRange = m_yMax - m_yMin;
+ m_yMin = (yRange * toY / -m_viewHeight) + m_yMax;
+ m_yMax = (yRange * fromY / -m_viewHeight) + m_yMax;
+
+ //qDebug() << fromX << fromY << toX << toY;
+ //qDebug() << m_fromIdx << m_toIdx << m_yMin << m_yMax;
+
+ return true;
+}
+
+double SignalController::yValToCoord(double y)
+{
+ return m_viewHeight / (m_yMax - m_yMin) * (y - m_yMin);
+}
+
+/* Public slots */
+
+void SignalController::onCtxMenuUnzoom()
+{
+ drawFullGraph();
+ drawAllPeaks();
+}
+
+void SignalController::onCtxMenuDeletePeak()
+{
+ size_t xRange = m_toIdx - m_fromIdx;
+ size_t idx = (xRange * m_ctxMenuX) / m_viewWidth + m_fromIdx;
+
+ m_integTblModel->prepReset();
+ Integrator::ReturnCode ret = m_integrator->deletePeak(idx);
+
+ switch (ret) {
+ case Integrator::ReturnCode::SUCCESS:
+ onViewRedrawNeeded();
+ break;
+ case Integrator::ReturnCode::E_NO_PEAK:
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, "No peak to delete.");
+ break;
+ default:
+ break;
+ }
+ m_integTblModel->doneReset();
+
+}
+
+void SignalController::onViewCrosshairErased()
+{
+ emit viewRemoveCurrentValues();
+}
+
+void SignalController::onViewCrosshairMoved(const int x, const int y)
+{
+ Q_UNUSED(y);
+
+ size_t xRange = m_toIdx - m_fromIdx;
+ int valueIdx = (xRange * x) / m_viewWidth + m_fromIdx;
+ Signal::TimeValuePair tvp = m_signal->pairAt(valueIdx);
+ emit viewUpdateCurrentValues(tvp.first, tvp.second);
+}
+
+void SignalController::onViewIntegrated(const int fromX, const int fromY, const int toX, const int toY)
+{
+ size_t xRange = m_toIdx - m_fromIdx;
+ size_t startIdx = (xRange * fromX) / m_viewWidth + m_fromIdx;
+ size_t stopIdx = (xRange * toX) / m_viewWidth + m_fromIdx;
+ double yRange = m_yMax - m_yMin;
+ double blStartY = (yRange * (m_viewHeight - fromY) / m_viewHeight) + m_yMin;
+ double blStopY = (yRange * (m_viewHeight - toY) / m_viewHeight) + m_yMin;
+ Integrator::ReturnCode ret;
+ std::shared_ptr<IntegratedPeak> peak;
+
+ m_integTblModel->prepReset();
+ ret = m_integrator->integrate(startIdx, stopIdx, blStartY, blStopY, peak);
+
+ switch (ret) {
+ case Integrator::ReturnCode::SUCCESS:
+ drawIntegratedPeak(peak);
+ break;
+ case Integrator::ReturnCode::E_NO_FIRST_INTERSECT:
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, "no first intersect");
+ break;
+ case Integrator::ReturnCode::E_NO_SECOND_INTERSECT:
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, "no first intersect");
+ break;
+ default:
+ break;
+ }
+ m_integTblModel->doneReset();
+}
+
+void SignalController::onViewRedrawNeeded()
+{
+ drawGraph();
+ drawAllPeaks();
+}
+
+void SignalController::onViewResized(const int w, const int h)
+{
+ m_viewHeight = h;
+ m_viewWidth = w;
+}
+
+void SignalController::onViewShowContextMenu(const int x, const int y, const QPoint& globalPos)
+{
+ m_ctxMenuX = x; m_ctxMenuY = y;
+ m_ctxMenu.exec(globalPos);
+ emit viewCtxMenuClosed();
+}
+
+void SignalController::onViewZoomed(const int fromX, const int fromY, const int toX, const int toY)
+{
+ if (!updateConstraints(fromX, fromY, toX, toY))
+ return;
+ drawGraph();
+ drawAllPeaks();
+}
+
+SignalController::~SignalController()
+{
+ delete m_dtblModel;
+ delete m_integTblModel;
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef SIGNALCONTROLLER_H
+#define SIGNALCONTROLLER_H
+
+#include "gui/graphviewcontextmenu.h"
+#include "integrationtablemodel.h"
+#include "integrator.h"
+#include "signal.h"
+#include "signaldatatablemodel.h"
+#include <memory>
+#include <QtCore/QObject>
+
+class SignalController : public QObject
+{
+ Q_OBJECT
+public:
+ explicit SignalController(std::shared_ptr<Signal> signal, QObject* parent = nullptr);
+ ~SignalController();
+ void draw();
+ SignalDataTableModel* dataTableModel() { return m_dtblModel; }
+ IntegrationTableModel* integrationTableModel() { return m_integTblModel;}
+ const std::shared_ptr<Signal> signal() const { return m_signal; }
+
+private:
+ GraphViewContextMenu m_ctxMenu;
+ int m_ctxMenuX;
+ int m_ctxMenuY;
+ SignalDataTableModel* m_dtblModel;
+ uint m_fromIdx;
+ uint m_toIdx;
+ IntegrationTableModel* m_integTblModel;
+ std::shared_ptr<Integrator> m_integrator;
+ std::shared_ptr<Signal> m_signal;
+ int m_viewHeight;
+ int m_viewWidth;
+ double m_yMax;
+ double m_yMin;
+
+ void drawAllPeaks();
+ void drawFullGraph();
+ void drawGraph();
+ void drawIntegratedPeak(const std::shared_ptr<IntegratedPeak> peak);
+ bool updateConstraints(const int fromX, const int fromY, const int toX, const int toY);
+ double yValToCoord(double y);
+
+ static const QString ME_SENDER_STR;
+
+public slots:
+ void onCtxMenuUnzoom();
+ void onCtxMenuDeletePeak();
+ void onViewCrosshairErased();
+ void onViewCrosshairMoved(const int x, const int y);
+ void onViewIntegrated(const int fromX, const int fromY, const int toX, const int toY);
+ void onViewRedrawNeeded();
+ void onViewResized(const int w, const int h);
+ void onViewShowContextMenu(const int x, const int y, const QPoint& globalPos);
+ void onViewZoomed(const int fromX, const int fromY, const int toX, const int toY);
+
+signals:
+ void viewCtxMenuClosed();
+ void viewDrawIntegration(const int fromX, const double fromY, const int toX, const double toY, const int peakX, const double peakY, const QString& peakTime,
+ const QString& peakArea, const bool valley);
+ void viewUpdateCurrentValues(double x, double y);
+ void viewRemoveCurrentValues();
+ void guiDrawGraph(double* data, size_t len, double min, double max);
+ void fillDataList();
+
+
+};
+
+#endif // SIGNALCONTROLLER_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "signaldatatablemodel.h"
+
+SignalDataTableModel::SignalDataTableModel(std::shared_ptr<Signal> signal, QObject* parent) :
+ QAbstractTableModel(parent),
+ m_signal(signal)
+{}
+
+QVariant SignalDataTableModel::data(const QModelIndex& index, int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+ if (index.row() >= m_signal->valuesCount())
+ return QVariant();
+
+ if (index.column() == 0)
+ return m_signal->timeAt(index.row());
+ else if (index.column() == 1)
+ return m_signal->valueAt(index.row());
+
+ return QVariant();
+}
+
+QVariant SignalDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
+ switch (section) {
+ case 0:
+ return QString("Time ") + m_signal->xunitToString() + QString("]");
+ case 1:
+ return QString("Value [") + m_signal->yunitToString() + QString("]");
+ default:
+ return QVariant();
+ }
+ }
+ return QVariant();
+}
+
+int SignalDataTableModel::rowCount(const QModelIndex& parent) const
+{
+ Q_UNUSED(parent);
+
+ if (m_signal == nullptr)
+ return 0;
+ else
+ return m_signal->valuesCount();
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef SIGNALDATATABLEMODEL_H
+#define SIGNALDATATABLEMODEL_H
+
+#include "signal.h"
+#include <memory>
+#include <QtCore/QAbstractTableModel>
+
+class SignalDataTableModel : public QAbstractTableModel
+{
+public:
+ SignalDataTableModel(std::shared_ptr<Signal> signal, QObject* parent = nullptr);
+ QVariant data(const QModelIndex& index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ int columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 2; }
+ int rowCount(const QModelIndex& parent) const;
+
+private:
+ std::shared_ptr<Signal> m_signal;
+};
+
+#endif // SIGNALDATATABLEMODEL_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "singlerundata.h"
+
+SingleRunData::SingleRunData(const QString& methodName, const QString& operatorName, const QString& sampleInfo, const QDate date, const QTime time,
+ std::vector<std::shared_ptr<Signal>>& sigs, const QString& dirname, QObject *parent) :
+ QObject(parent),
+ m_date(date),
+ m_dirName(dirname),
+ m_methodName(methodName),
+ m_operatorName(operatorName),
+ m_sampleInfo(sampleInfo),
+ m_signals(sigs),
+ m_time(time)
+{
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef SINGLERUNDATA_H
+#define SINGLERUNDATA_H
+
+#include "signal.h"
+#include <memory>
+#include <QtCore/QDate>
+#include <QtCore/QObject>
+#include <QtCore/QTime>
+
+class SingleRunData : public QObject
+{
+ Q_OBJECT
+public:
+ explicit SingleRunData(const QString& methodName, const QString& operatorName, const QString& sampleInfo, const QDate date, const QTime time,
+ std::vector<std::shared_ptr<Signal>>& sigs, const QString& dirname, QObject *parent = 0);
+ QDate date() const { return m_date; }
+ QString dirName() const { return m_dirName; }
+ QString methodName() const { return m_methodName; }
+ QString operatorName() const { return m_operatorName; }
+ QString sampleInfo() const { return m_sampleInfo; }
+ std::shared_ptr<Signal> signalAt(size_t idx) { return m_signals.at(idx); }
+ size_t signalCount() const { return m_signals.size(); }
+ QTime time() const { return m_time; }
+
+private:
+ const QDate m_date;
+ const QString m_dirName;
+ const QString m_methodName;
+ const QString m_operatorName;
+ const QString m_sampleInfo;
+ std::vector<std::shared_ptr<Signal>> m_signals;
+ const QTime m_time;
+
+signals:
+
+public slots:
+
+};
+
+#endif // SINGLERUNDATA_H
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "singlerunsselectormodel.h"
+
+#include <QDebug>
+
+SingleRunsSelectorModel::SingleRunsSelectorModel(QObject *parent) :
+ QAbstractListModel(parent),
+ m_singleRuns(nullptr)
+{
+}
+
+QVariant SingleRunsSelectorModel::data(const QModelIndex& index, int role) const
+{
+ int runIdx = 0;
+ if (role != Qt::DisplayRole)
+ return QVariant();
+ if (m_singleRuns == nullptr)
+ return QVariant();
+
+ std::vector<SingleRunPair>::const_iterator cit = m_singleRuns->cbegin();
+ while (cit != m_singleRuns->cend()) {
+ if (runIdx == index.row())
+ return cit->first;
+ runIdx++; cit++;
+ }
+ return QVariant();
+}
+
+int SingleRunsSelectorModel::rowCount(const QModelIndex& parent) const
+{
+ Q_UNUSED(parent);
+
+ if (m_singleRuns == nullptr)
+ return 0;
+ else
+ return m_singleRuns->size();
+}
+
+void SingleRunsSelectorModel::setSingleRuns(const std::vector<SingleRunPair>* singleRuns)
+{
+ beginResetModel();
+ m_singleRuns = singleRuns;
+ endResetModel();
+}
--- /dev/null
+/*
+ Copyright (c) 2013 Michal Malý <madcatxster@prifuk.cz>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef SINGLERUNSSELECTORMODEL_H
+#define SINGLERUNSSELECTORMODEL_H
+
+#include "sequence.h"
+#include <QAbstractListModel>
+
+class SingleRunsSelectorModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ explicit SingleRunsSelectorModel(QObject* parent = nullptr);
+ QVariant data(const QModelIndex& index, int role) const;
+ int rowCount(const QModelIndex& parent) const;
+ void setSingleRuns(const std::vector<SingleRunPair>* singleRuns);
+
+private:
+ const std::vector<SingleRunPair>* m_singleRuns;
+
+signals:
+
+public slots:
+
+};
+
+#endif // SINGLERUNSSELECTORMODEL_H