From c711c5f8c44d2c350f43aea9df0bbfe2945d3492 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Michal=20Mal=C3=BD?= Date: Wed, 12 Mar 2014 12:47:38 +0100 Subject: [PATCH] - Extend support for saving user data to JSON-formatted files. - Minor code refactoring --- datamanager.cpp | 84 ++++++++++++++----------------------- datamanager.h | 4 +- main.cpp | 7 +++- sequence.cpp | 2 +- sequence.h | 14 +++---- signalcontroller.cpp | 8 +++- signalcontroller.h | 4 ++ singlerundata.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++- singlerundata.h | 20 ++++++--- 9 files changed, 170 insertions(+), 71 deletions(-) diff --git a/datamanager.cpp b/datamanager.cpp index 0e4061e..9f4b1bc 100644 --- a/datamanager.cpp +++ b/datamanager.cpp @@ -25,7 +25,6 @@ #include "logger.h" #include "gui/exportgraphtoimagedialog.h" #include "gui/exportrawdatadialog.h" -#include #include #include @@ -49,6 +48,27 @@ DataManager::DataManager(QObject* parent) : m_sigNameCodec = QTextCodec::codecForName("ISO-8859-1"); } +void DataManager::saveUserDataOnExit() +{ + for (NameSequencePair& nsp : m_sequences) { + const QString seqName = nsp.first; + std::shared_ptr seq = nsp.second; + SingleRunsMap::const_iterator it = seq->begin(); + + while (it != seq->end()) { + std::shared_ptr sr = it->second; + if (sr->userDataModified()) { + const QString srName = QString::fromStdString(it->first); + int ret = QMessageBox::question(nullptr, "Save changes?" , "User data in sequence " + seqName + ", signal " + srName + " have been modified. " + "Would you like to save the changes?", QMessageBox::Yes, QMessageBox::No); + if (ret == QMessageBox::Yes) + sr->saveUserDataToJSON(); + } + ++it; + } + } +} + /* Private functions */ void DataManager::generateIntegDataWriteList(DataFileExporter::WriteList& writeList, const std::shared_ptr sr, const std::vector &keys) @@ -202,6 +222,11 @@ Signal::Resource DataManager::resourceFromFiletype(AGRE_Filetype filetype) } } +bool DataManager::saveSingleRunUserData(std::shared_ptr sr) +{ + return sr->saveUserDataToJSON(); +} + std::string DataManager::signalControllerKey(const QString& main, const QString& resource) { return std::string(main.toStdString() + "_" + resource.toStdString()); @@ -234,8 +259,8 @@ std::shared_ptr DataManager::loadSingleRun(QDir& dir) { std::vector> dataFiles; std::shared_ptr singleRun; - std::unordered_map> sigs; - std::unordered_map> ctrls; + SignalsMap sigs; + SignalControllersMap ctrls; DataFilesLoader::ReturnCode ret; LocalLoggerPtr llog = Logger::createLocalLog(); llog->setPrintLevel(Logger::Level::WARNING); @@ -315,25 +340,6 @@ std::shared_ptr DataManager::loadSingleRun(QDir& dir) _c = std::shared_ptr(new SignalController(_s)); - /* Try to read saved user data from JSON file */ - QFile jsonFile(dir.path() + "/" + "ank_" + QString::fromStdString(_s->descriptiveName()) + ".json"); - if (jsonFile.exists()) { - if (jsonFile.open(QFile::ReadOnly)) { - QByteArray bytes = jsonFile.readAll(); - QJsonDocument jsonDoc = QJsonDocument::fromJson(bytes); - QJsonObject jso = jsonDoc.object(); - - if (!_c->deserialize(jso)) { - llog->log(Logger::Level::WARNING, ME_SENDER_STR, "Failed to deserialize saved user data for " + QString::fromStdString(_s->descriptiveName())); - QMessageBox::warning(nullptr, "Load single run", "Saved user data for signal " + QString::fromStdString(_s->descriptiveName()) + - "could not have been read properly."); - } - } else - llog->log(Logger::Level::WARNING, ME_SENDER_STR, "Cannot open saved user data file " + QString::fromStdString(_s->descriptiveName()) + - " for reading."); - } else - llog->log(Logger::Level::DEBUG, ME_SENDER_STR, "No user data file for " + QString::fromStdString(_s->descriptiveName())); - sigs[_s->descriptiveName()] = _s; ctrls[_s->descriptiveName()] = _c; } @@ -377,7 +383,7 @@ std::shared_ptr DataManager::loadSingleRun(QDir& dir) singleRun = std::shared_ptr(new SingleRunData(methodNames.at(0), operatorNames.at(0), sampleInfos.at(0), dates.at(0), times.at(0), sigs, ctrls, dir.dirName(), dir.absolutePath(), this)); - + singleRun->readUserDataFromJSON(); Logger::log(Logger::DEBUG, ME_SENDER_STR, "Single run successfully parsed"); @@ -398,19 +404,6 @@ void DataManager::showOneSignal(std::shared_ptr ctrl) swp->setXUnits(QString::fromStdString(ctrl->signal()->xunitToString())); swp->setYUnits(QString::fromStdString(ctrl->signal()->yunitToString())); - /*connect(swp->m_graphView, SIGNAL(crosshairErased()), ctrl.get(), SLOT(onViewCrosshairErased())); - connect(swp->m_graphView, SIGNAL(crosshairMoved(int,int)), ctrl.get(), SLOT(onViewCrosshairMoved(int,int))); - connect(swp->m_graphView, SIGNAL(integrated(int,int,int,int)), ctrl.get(), SLOT(onViewIntegrated(int,int,int,int))); - connect(swp->m_graphView, SIGNAL(redrawNeeded()), ctrl.get(), SLOT(onViewRedrawNeeded())); - connect(swp->m_graphView, SIGNAL(resized(int,int)), ctrl.get(), SLOT(onViewResized(int,int))); - connect(swp->m_graphView, SIGNAL(showContextMelnuReq(int,int,QPoint)), ctrl.get(), SLOT(onViewShowContextMenu(int,int,QPoint))); - connect(swp->m_graphView, SIGNAL(zoomed(int,int,int,int)), ctrl.get(), SLOT(onViewZoomed(int,int,int,int))); - connect(ctrl.get(), SIGNAL(viewDrawGraph(double*,size_t,double,double)), swp->m_graphView, SLOT(onUpdateGraph(double*,size_t,double,double))); - connect(ctrl.get(), SIGNAL(viewCtxMenuClosed()), swp->m_graphView, SLOT(onCtxMenuClosed())); - connect(ctrl.get(), SIGNAL(viewDrawIntegration(int,double,int,double,int,double,QString,QString)), swp->m_graphView, - SLOT(onDrawIntegration(int,double,int,double,int,double,QString,QString))); - connect(ctrl.get(), SIGNAL(viewUpdateCurrentValues(double,double)), swp, SLOT(onUpdateCurrentValues(double,double))); - connect(ctrl.get(), SIGNAL(viewRemoveCurrentValues()), swp, SLOT(onRemoveCurrentValues()));*/ emit addToDashboard(swp); swp->m_graphView->refresh(); @@ -578,28 +571,11 @@ void DataManager::onLoadSingleRun(const QString& str) void DataManager::onSaveChanges() { std::shared_ptr sr = m_activeSequence->selectedRun(); - std::unordered_map>::const_iterator cit; if (m_activeSequence == nullptr) return; - const std::unordered_map>& ctrls = sr->allControllers(); - cit = ctrls.cbegin(); - - while (cit != ctrls.cend()) { - QJsonValue val = cit->second->serialize(); - QJsonDocument doc(val.toObject()); - QFile f(sr->absPath() + "/" + "ank_" + QString::fromStdString(cit->first) + ".json"); - QByteArray bytes = doc.toJson(); - - f.open(QFile::WriteOnly); - f.write(bytes.data(), bytes.size()); - - qDebug() << val; - f.close(); - ++cit; - } - + sr->saveUserDataToJSON(); } void DataManager::onSequenceSelected(const QString& key) diff --git a/datamanager.h b/datamanager.h index 0775feb..f095e85 100644 --- a/datamanager.h +++ b/datamanager.h @@ -44,6 +44,7 @@ class DataManager : public QObject Q_OBJECT public: explicit DataManager(QObject* parent = nullptr); + void saveUserDataOnExit(); SequenceSelectorModel* sequenceSelectorModel() { return &m_seqSelModel; } SingleRunsSelectorModel* singleRunsSelectorModel() { return &m_singleSelModel; } @@ -56,7 +57,8 @@ private: std::shared_ptr loadSingleRun(QDir& dir); void processDataExport(GeneratorFunc genfunc); Signal::Resource resourceFromFiletype(AGRE_Filetype filetype); - std::string signalControllerKey(const QString& main, const QString& resource) ; + bool saveSingleRunUserData(std::shared_ptr sr); + std::string signalControllerKey(const QString& main, const QString& resource); void showOneSignal(std::shared_ptr ctrl); Signal::YUnit yunitFromUnitStr(const std::string& unit_str); diff --git a/main.cpp b/main.cpp index fe29bd1..b544f21 100644 --- a/main.cpp +++ b/main.cpp @@ -31,6 +31,7 @@ int main(int argc, char *argv[]) { + int ret; QApplication a(argc, argv); #ifndef COMPILER_MSVC11 @@ -80,5 +81,9 @@ int main(int argc, char *argv[]) mWin->show(); - return a.exec(); + ret = a.exec(); + + dMgr->saveUserDataOnExit(); + + return ret; } diff --git a/sequence.cpp b/sequence.cpp index a5fc15f..67da087 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -27,7 +27,7 @@ Sequence::Sequence(QObject* parent) : { } -Sequence::Sequence(std::unordered_map>& singleRuns, QObject* parent) : +Sequence::Sequence(SingleRunsMap& singleRuns, QObject* parent) : QObject(parent), m_selectedRunKey("") { diff --git a/sequence.h b/sequence.h index 8e040f5..1448578 100644 --- a/sequence.h +++ b/sequence.h @@ -31,26 +31,26 @@ #include #include +typedef std::unordered_map> SingleRunsMap; + class Sequence : public QObject { Q_OBJECT public: explicit Sequence(QObject* parent = nullptr); - explicit Sequence(std::unordered_map>& singleRuns, QObject* parent = nullptr); + explicit Sequence(SingleRunsMap& singleRuns, QObject* parent = nullptr); int add(const std::string name, std::shared_ptr value); std::vector allRunKeys() const; std::shared_ptr at(const std::string& key); - std::unordered_map>::iterator begin() { return m_singleRuns.begin(); } - std::unordered_map>::const_iterator cbegin() const { return m_singleRuns.cbegin(); } - std::unordered_map>::const_iterator cend() const { return m_singleRuns.cend(); } + SingleRunsMap::iterator begin() { return m_singleRuns.begin(); } + SingleRunsMap::const_iterator cbegin() const { return m_singleRuns.cbegin(); } + SingleRunsMap::const_iterator cend() const { return m_singleRuns.cend(); } std::shared_ptr controller(const std::string& uid); size_t count() const { return m_singleRuns.size(); } - std::unordered_map>::iterator end() { return m_singleRuns.end(); } + SingleRunsMap::iterator end() { return m_singleRuns.end(); } void remove(const std::string& key); std::string selectedRunKey() const { return m_selectedRunKey; } std::shared_ptr selectedRun(); - //int selectedRunIdx() const; - //int singleRunToIdx(const QString& key) const; bool setSelectedRun(const std::string& key); private: diff --git a/signalcontroller.cpp b/signalcontroller.cpp index ce2fd6d..63406b0 100644 --- a/signalcontroller.cpp +++ b/signalcontroller.cpp @@ -37,7 +37,8 @@ const QString SignalController::KEY_PEAKS("peaks"); SignalController::SignalController(std::shared_ptr signal, QObject* parent) : QObject(parent), JSONSerializable(), - m_signal(signal) + m_signal(signal), + m_userDataModified(false) { m_integrator = std::shared_ptr(new Integrator(signal)); m_integTblModel = new IntegrationTableModel(m_integrator); @@ -67,6 +68,9 @@ PeakDrawData SignalController::deletePeak(const double x) Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, __QFUNC__ + " no peak to delete (idx " + QString::number(idx) + ")"); return PeakDrawData(); } + + m_userDataModified = true; + emit userDataModified(); return genPeakDrawData(peak); } @@ -231,6 +235,8 @@ PeakDrawData SignalController::integratePeak(const double fromX, const double fr switch (ret) { case Integrator::ReturnCode::SUCCESS: + emit userDataModified(); + m_userDataModified = true; return genPeakDrawData(peak); break; case Integrator::ReturnCode::E_NO_FIRST_INTERSECT: diff --git a/signalcontroller.h b/signalcontroller.h index e4b9b3d..5a3db71 100644 --- a/signalcontroller.h +++ b/signalcontroller.h @@ -108,6 +108,8 @@ public: void setGUIViewport(const double fromX, const double fromY, const double toX, const double toY); virtual QJsonValue serialize() const; const std::shared_ptr signal() const { return m_signal; } + bool userDataStatus() const { return m_userDataModified; } + void userDataSaved() { m_userDataModified = false; } const std::shared_ptr cIntegrator() const { return m_integrator; } double idxToRel(const size_t idx); @@ -125,6 +127,7 @@ private: IntegrationTableModel* m_integTblModel; std::shared_ptr m_integrator; std::shared_ptr m_signal; + bool m_userDataModified; GUIViewport m_guiViewport; @@ -140,6 +143,7 @@ public slots: signals: void fillDataList(); + void userDataModified(); }; #endif // SIGNALCONTROLLER_H diff --git a/singlerundata.cpp b/singlerundata.cpp index 0b39ff8..276cb9a 100644 --- a/singlerundata.cpp +++ b/singlerundata.cpp @@ -20,10 +20,18 @@ THE SOFTWARE. */ +#include "logger.h" #include "singlerundata.h" +#include +#include +#include +#include +#include + +const QString SingleRunData::ME_SENDER_STR("SingleRunData"); SingleRunData::SingleRunData(const QString& methodName, const QString& operatorName, const QString& sampleInfo, const QDate date, const QTime time, - std::unordered_map>& sigs, std::unordered_map>& ctrls, + SignalsMap& sigs, SignalControllersMap& ctrls, const QString& dirname, const QString& absPath, QObject *parent) : QObject(parent), m_absPath(absPath), @@ -32,10 +40,17 @@ SingleRunData::SingleRunData(const QString& methodName, const QString& operatorN m_methodName(methodName), m_operatorName(operatorName), m_sampleInfo(sampleInfo), + m_userDataModified(false), m_ctrls(ctrls), m_signals(sigs), m_time(time) { + SignalControllersMap::iterator it = ctrls.begin(); + + while (it != ctrls.end()) { + connect(it->second.get(), SIGNAL(userDataModified()), this, SLOT(onUserDataModified())); + ++it; + } } std::vector SingleRunData::allKeys() const @@ -58,6 +73,87 @@ std::shared_ptr SingleRunData::controllerAt(const std::string& } } +void SingleRunData::readUserDataFromJSON() +{ + SignalControllersMap::iterator it = m_ctrls.begin(); + + while (it != m_ctrls.end()) { + std::shared_ptr c = it->second; + QString descriptiveName = QString::fromStdString(c->signal()->descriptiveName()); + QString filename = "ank_" + descriptiveName + ".json"; + QFile jsonFile(m_absPath + "/" + filename); + + if (jsonFile.exists()) { + if (!jsonFile.open(QFile::ReadOnly)) { + QString errMsg = "Cannot open user data file " + filename + " for reading."; + Logger::log(Logger::Level::WARNING, ME_SENDER_STR, errMsg); + QMessageBox::warning(nullptr, "Cannot read user data", errMsg); + ++it; + continue; + } + + QJsonParseError parseErr; + QByteArray bytes = jsonFile.readAll(); + QJsonDocument jsonDoc = QJsonDocument::fromJson(bytes, &parseErr); + if (parseErr.error != QJsonParseError::NoError) { + QString errMsg = "Cannot parse user data file " + filename + " (" + parseErr.errorString() + ")"; + Logger::log(Logger::Level::WARNING, ME_SENDER_STR, errMsg); + QMessageBox::warning(nullptr, "Cannot read user data" , errMsg); + ++it; + continue; + } + QJsonObject jso = jsonDoc.object(); + + if (!c->deserialize(jso)) { + Logger::log(Logger::Level::WARNING, ME_SENDER_STR, "Failed to deserialize saved user data for " + descriptiveName); + QMessageBox::warning(nullptr, "Load single run", "Saved user data for signal " + descriptiveName + + "could not have been read properly."); + } + } + + ++it; + } +} + +bool SingleRunData::saveUserDataToJSON() +{ + SignalControllersMap::const_iterator cit = m_ctrls.cbegin(); + + while (cit != m_ctrls.cend()) { + if (!cit->second->userDataStatus()) { + ++cit; + continue; + } + + QJsonValue val = cit->second->serialize(); + if (!val.isObject()) { + Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " QJsonValue is not an object!"); + return false; + } + QJsonDocument doc(val.toObject()); + + QString filename("ank_" + QString::fromStdString(cit->first) + ".json"); + QFile f(m_absPath + "/" + filename); + QByteArray bytes = doc.toJson(); + + if (!f.open(QFile::WriteOnly)) { + QString errMsg = "Cannot open output file " + filename + " for writing (" + f.errorString() + ")"; + Logger::log(Logger::Level::WARNING, ME_SENDER_STR, errMsg); + QMessageBox::warning(nullptr, "Cannot save user data", errMsg); + return false; + } + f.write(bytes.data(), bytes.size()); + + qDebug() << val; + f.close(); + cit->second->userDataSaved(); + ++cit; + } + + m_userDataModified = false; + return true; +} + std::shared_ptr SingleRunData::signalAt(const std::string& key) { try { diff --git a/singlerundata.h b/singlerundata.h index b0f1c1d..2419717 100644 --- a/singlerundata.h +++ b/singlerundata.h @@ -31,26 +31,32 @@ #include #include +typedef std::unordered_map> SignalControllersMap; +typedef std::unordered_map> SignalsMap; + 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::unordered_map>& sigs, std::unordered_map>& ctrls, + SignalsMap& sigs, SignalControllersMap& ctrls, const QString& dirname, const QString& absPath, QObject* parent = nullptr); QString absPath() const { return m_absPath; } - const std::unordered_map>& allControllers() const { return m_ctrls; } + const SignalControllersMap& allControllers() const { return m_ctrls; } std::vector allKeys() const; - const std::unordered_map>& allSignals() const { return m_signals; } + const SignalsMap& allSignals() const { return m_signals; } std::shared_ptr controllerAt(const std::string& key); QDate date() const { return m_date; } QString dirName() const { return m_dirName; } QString methodName() const { return m_methodName; } QString operatorName() const { return m_operatorName; } + void readUserDataFromJSON(); + bool saveUserDataToJSON(); QString sampleInfo() const { return m_sampleInfo; } std::shared_ptr signalAt(const std::string& key); size_t signalCount() const { return m_signals.size(); } QTime time() const { return m_time; } + bool userDataModified() const { return m_userDataModified; } private: const QString m_absPath; @@ -59,13 +65,17 @@ private: const QString m_methodName; const QString m_operatorName; const QString m_sampleInfo; - std::unordered_map> m_ctrls; - std::unordered_map> m_signals; + bool m_userDataModified; + SignalControllersMap m_ctrls; + SignalsMap m_signals; const QTime m_time; + static const QString ME_SENDER_STR; + signals: public slots: + void onUserDataModified() { m_userDataModified = true; } }; -- 2.43.5