/*! * * Copyright (c) 2021-2024 Diality Inc. - All Rights Reserved. * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file RxProfiles.cpp * \author (last) Behrouz NematiPour * \date (last) 13-Mar-2024 * \author (original) Behrouz NematiPour * \date (original) 04-May-2021 * */ #include "RxProfilesController.h" // Qt #include // Project #include "StorageGlobals.h" #include "FileHandler.h" #include "ApplicationController.h" #include "Logger.h" #include "Settings.h" #include "DeviceController.h" #include "MRxProfilesData.h" using namespace Storage; #define NONE "N/A" #define FLOAT3 0,'f',3 #define ADDTITLE(vTITLE) logContent += QString("[%1]\n").arg(vTITLE) #define ADDALINE(vTEXT ) logContent += QString("%1\n" ).arg(vTEXT ) //#define ADDTOLOG( vINDEX ) index = vINDEX; logContent += title(index) + _sep + value(index) + _sep + unit(index) + "\n"; #define ADDTOLOG_MT(vINDEX, vVALUE, vTITLES ) \ logContent += vTITLES[vINDEX] + _sep + \ ( vVALUE[vINDEX] ) + "\n"; /*! * \brief RxProfiles::RxProfiles * The constructor to initial the Treatment Log * \param parent */ RxProfiles::RxProfiles(QObject *parent) : QObject(parent) { initConnections(); } /*! \brief Connection Initializer \details All the class signal/slot connections are defined here. */ void RxProfiles::initConnections() { connect(&_exportWatcher , SIGNAL(finished()), this , SLOT(onExport())); connect(&_saveWatcher , SIGNAL(finished()), this , SLOT(onSave ())); connect(&_importWatcher , SIGNAL(finished()), this , SLOT(onImport())); connect(&_DeviceController , SIGNAL(didReadFilesList(const QFileInfoList &)), this , SLOT(onReceieveRxProfileList(const QFileInfoList &))); } void RxProfiles::doInitRxProfiles() { emit didFilesList(rxProfilesPath(), { QString("*.%1").arg(_rxProfiles) }); } QString RxProfiles::rxProfilesPath() { if(_rxProfilesPath.trimmed().isEmpty()){ _rxProfilesPath = QString("%1%2") .arg(Storage::Rx_Folder_Base ) // TODO: Adjust to be real base path for RX .arg(Storage::Rx_Folder_Profiles ); } LOG_DEBUG(QString("Rx Profile folder has been set to %1" ).arg(_rxProfilesPath )); return _rxProfilesPath; } RxProfilesData RxProfiles::initModel(const QFileInfo &rxProfile) { RxProfilesData rxData; QSettings rxSettings(rxProfile.absoluteFilePath(), QSettings::IniFormat); for (int i = 0; i < Model::RxProfilesIndex::eRxContentIndexCount; i++){ QString rxTitle = Model::MRxProfilesData::titles()[i]; if ( rxSettings.contains(rxTitle) ) { rxData.rxProfileContent.append(rxSettings.value(rxTitle).toString()); } else goto lError; } //Order of the below does matter to match the enum index rxData.rxProfileContent.append(rxProfile.baseName().replace(_underscore, " ")); //eProfileName rxData.rxProfileContent.append("false"); rxData.rxProfileContent.append(rxProfile.lastModified().date().toString("MM-dd-yyyy")); lError: return rxData; } // ----- Save /*! * \brief RxProfiles::doSave * The save slot to be exposed to the UI to be able to request for save */ void RxProfiles::doSave(const QStringList &RxModel) { if (_saveWatcher.isRunning()) return; isIdle(false); saveLogConcurrent(RxModel); } /*! * \brief RxProfiles::saveLogConcurrent * The treatment log save which is using a thread pool to run the save process. */ void RxProfiles::saveLogConcurrent(const QStringList &RxModel) { LOG_DEBUG("Save Treatment Log Started"); QFuture mFuture = QtConcurrent::run(this, &RxProfiles::saveLog, RxModel); _saveWatcher.setFuture(mFuture); } /*! * \brief RxProfiles::saveLog * The actual treatment log save function which does the save into the Prescription log * \return true on successful save and false otherwise. */ bool RxProfiles::saveLog(const QStringList &RxModel) { bool ok = RxModel.size() >= Model::RxProfilesIndex::eRxProfilesIndexCount - 1; if (!ok) return false; QString logContent ; QString fileName = QString("%1%2.%3").arg(_rxProfilesPath, RxModel[Model::RxProfilesIndex::eRxContentIndexCount], _rxProfiles); fileName.replace(" ", _underscore); ADDTOLOG_MT( Model::RxProfilesIndex::eBloodFlowRate , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eDialysateFlowRate , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eTreatmentDuration , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eAcidConcentrateType , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eBicarbonateConcentrateType , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eDialysateTemperature , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eDialyzerType , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eHeparinConcentration , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eHeparinBolusVolume , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eHeparinDispenseRate , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eHeparinStop , RxModel , Model::MRxProfilesData::titles() ); ADDTOLOG_MT( Model::RxProfilesIndex::eVitalSigns , RxModel , Model::MRxProfilesData::titles() ); // qDebug() << "WRITING FILE: " < mFuture = QtConcurrent::run(this, &RxProfiles::exportLog); _exportWatcher.setFuture(mFuture); } /*! * \brief RxProfiles::exportLog * \details The actual treatment log export function which does the export of the treatment log into the USB drive. * \return true on successful export. */ bool RxProfiles::exportLog() { bool ok = true; QString status = ""; QString dstPath = Storage::USB_Mount_Point ; dstPath += Storage::Rx_Folder_Profiles ; QString srcFile = "meow.txr" ;//TODO: adjust for filename variable QString srcFileName = QFileInfo(srcFile).fileName() ; QString dstFile = dstPath + srcFileName; // HERE: expose to the UI dialog as the rejection/notification result if ( ! Storage::FileHandler::makeFolder ( dstPath ) ) { status = QString( "Couldn't create folder on USB drive to export TxLog" ); ok = false; goto lOut; } if ( ! QFileInfo::exists ( srcFile ) ) { status = QString( "Prescription Log '%1' doesn't exist" ).arg( srcFile ); ok = false; goto lOut; } if ( QFileInfo::exists ( dstFile ) ) { status = QString( "Prescription Log '%1' already exists" ).arg( dstFile ); ok = false; goto lOut; } if ( ! QFile::copy (srcFile, dstFile ) ) { status = QString( "Unable to Export RxLog '%1' to '%2'" ).arg( srcFile ).arg( dstFile ); ok = false; goto lOut; } lOut: if ( ! ok ) { LOG_DEBUG(status); // The log debug order in this block is by design status = "Unable to export Prescription log '" + srcFileName +"'"; } else { status = "Prescription log '" + srcFileName + "' exported successfully"; LOG_APPED_UI(status); } emit didNotification(status); return ok; } /*! * \brief RxProfiles::onExport * The private export slot which is called after the export process is finished exporting. */ void RxProfiles::onExport() { LOG_DEBUG(QString("Export Prescription Log Ended: %1").arg(_exportWatcher.result())); isIdle(true); } // ----- Import /*! * \brief RxProfiles::doImport * The export treatment log slot to be exposed to the UI to be able to request for the import. */ void RxProfiles::doImport() { if (_importWatcher.isRunning()) return; isIdle(false); importLogConcurrent(); } /*! * \brief RxProfiles::importLogConcurrent * The treatment log import which is using a thread pool to run the save process. */ void RxProfiles::importLogConcurrent() { LOG_DEBUG("Import Prescription Log Started"); QFuture mFuture = QtConcurrent::run(this, &RxProfiles::importLog); _importWatcher.setFuture(mFuture); } /*! * \brief RxProfiles::importLog * \details The actual treatment log import function which does the import of the treatment log into the USB drive. * \return true on successful import. */ bool RxProfiles::importLog() { bool ok = true; // QString srcFile = Storage::USB_Mount_Point + Storage::Log_Folder_Rx; // QString dstPath = _rxProfilesPath ; // QString status = ""; // TODO: implement import return ok; } /*! * \brief RxProfiles::onImport * The private import slot which is called after the import process is finished importing. */ void RxProfiles::onImport() { LOG_DEBUG(QString("Import Prescription Log Ended: %1").arg(_exportWatcher.result())); isIdle(true); } void RxProfiles::onReceieveRxProfileList(const QFileInfoList &vRxProfileList) { QList vRxProfileDataList; for (const QFileInfo fileInfo:vRxProfileList){ RxProfilesData rxData = initModel(fileInfo) ; if (rxData.rxProfileContent.size() == Model::RxProfilesIndex::eRxProfilesIndexCount - 1) { vRxProfileDataList.append(rxData); } else LOG_DEBUG(QString("Bad Prescription Log Given: %1, %2").arg(fileInfo.baseName(), QString::number( rxData.rxProfileContent.size() ))); } //below is Test to write a file // QStringList rxDataTest = vRxProfileDataList[0].rxProfileContent; // rxDataTest.replace(Model::RxProfilesIndex::eProfileName, QString("Written New Rx")) ; // // rxProfileContent // doSave(rxDataTest); emit didRxProfileList(vRxProfileDataList); } /*! * \brief RxProfiles::filelimitReached * The actual function that checks if RX file limit has been reached for Duplicate, Add, and import events */ bool RxProfiles::fileLimitReached() { QDir RxProfilesDir(_rxProfilesPath); int fileCount = RxProfilesDir.count(); if (fileCount != _RxLimit){ return false; } LOG_DEBUG(QString("Rx Limit has been reached")); return true; }